[리버싱] BombLab phase_6 분석하기

이 포스팅을 작성한 달숏달숏은 어셈블리언어를 처음 배운 사람이며, 리버싱이란 것도 이번 BombLab을 통해서 처음 접한 사람입니다.

저도 배우는 학생의 입장인지라 틀린 정보가 섞여있을 수 있으니 너그러이 양해해주시고, 틀린 점이 있는 경우 편하게 피드백해주시면 감사하겠습니다 :)

BombLab은 phase1부터 phase6까지 6개의 문제가 있으며, 총 6개의 암호를 입력받아 다음 단계로 진행된다. 중간에 틀린 암호를 입력하면 "BOOM!!!"메시지와 함께 종료된다.

  1. 바이너리의 역어셈블을 통해 기계수준 프로그램의 구조 이해
  2. 일반적인 디버거 사용법과 리버싱 체험
  3. 6단계의 암호 입력 과정을 분석하여 바이너리 폭탄 해제

가 BombLab과제의 목표라고 할 수 있겠다.


  • Phase_6 : linked list, 포인터, struct 자료구조
phase_6를 disas한다





개인적으로... phase_5에서 에너지 소모를 많이 했는데 갑자기 코드가 확 길어진 것이 달갑지는 않다 ㅋㅋ; (살려줘..)
이번 포스팅은 좀 길다. 이거 쓰는데에 3일 걸렸다.(대충 각오하라는 의미)



코드를 잘 읽어보면 <+32>에 read_six_numbers가 보인다. 입력값이 6개의 정수라는 의미인 것 같다.


코드를 쭉 읽으면서 내려와보자. <+32>에서 read_six_numbers가 호출되고 나면, <+43>에서 jump문을 만나게 되는데, unconditional jump이므로 <+45>의 explode_bomb은 생각할 필요가 없이 <+82>로 이동된다.
<+82>에서 mov와 sub를 시행한 후, <+92>에서 cmp로 값을 비교한 다음 <+95>에서 ja문을 만나는데, 잠깐 ja문에 대해서 짚고 넘어가겠다.




  • ja, jb, je 명령어
     cmp    b,a    가 있을 때
    1. ja : a > b 인 경우 jump (unsigned계열, 부호가 없을 때)
    2. jb : a < b 인 경우 jump (unsigned계열, 부호가 없을 때)
    3. je : a = b 인 경우 jump 

즉, $eax > $0x5가 될 경우에 jump가 실행되어 <+45>의 explode_bomb이 실행된다는 의미이므로, $eax가 5보다 작거나 같아야 한다.
그럼 ja문이 존재하는 <+95>에서의 $eax를 알아야 하므로 <+95>에 breapoint를 걸고 프로그램을 실행해본다.
phase_6에 넣을 암호를 임의로 1 2 3 4 5 6 으로 정하고 입력해보았다.


breakpoint에 걸린 것을 확인할 수 있다. (breakpoint 1은 phase_6, breakpoint 2는 explode_bomb, breakpoint 3이 phase_6+95 이다.)
이 상태에서 $eax의 값을 확인해보면



0이라는 결과가 나온다.<+95>시점에서 $eax가 0이기 때문에 $eax < 0x5 이므로 ja문이 실행되지 않을 것이다.
그러면 왜 $eax는 0인 것일까?

<+92>의 cmp가 등장하기 전에, <+89>의 sub를 보면, $eax-1 된 결과가 0이라는 것을 알 수 있다. 그럼 혹시 맨 처음에 입력했던 1 2 3 4 5 6 중 1에서 -1이 되었기 때문에 0이 된 것은 아닐까 하는 생각을 해볼 수 있다.

그래서 6 2 3 4 5 6 을 입력해보았다. 만약 내 추측이 맞다면 <+92>에서 $eax는 5가 될 것이고, $eax <= 5이기 때문에 ja가 실행되지 않을 것이기 때문이다.


$rax에 5가 들어있으므로, 내 예상이 맞은 것을 알 수 있다. $rax에는 암호 6자리 중 첫번째 숫자가 들어가며, 이 숫자는 6이하의 수이다.




<+105>부분을 보면 je문이 있고, <+101>에서 $r13d와 6을 비교하고 있는 것을 볼 수 있다. 그런데 $r13d는 <+37>에서 mov를 통해 0이 들어간 뒤부터 <+97>에 도달하기 전까지 값을 변화시킬만한 instruction이 존재하지 않는다. 즉, <+97>시점까지의 $r13d는 0일 것이며 레지스터를 확인한 결과도 이와 동일했다.



그렇다는 것은, <+97>에서 $r13d는 1이 되고, <+101>에서 0x6과 비교를 하게 되겠지만 무조건 0x6과 다를 수 밖에 없으므로 <+105>의 je문은 실행되지 않는다.
<+107>이 실행되면 %ebx에는 %r13d에 담겨있던 1이 담기게 되며 그 상태로 <+110>에서 <+60>으로 jump하게 된다.
<+60>에는 낯선 movsql 명령어가 존재한다.


  • movsql 명령어
     32bit value를 64bit destination으로 sign-extend 하며 move하는 명령어이다.



sign-extension이라 함은 간단하게 말하자면, 부호 확장을 할 때 새로 생겨난 빈 bit를 무엇으로 채울것이냐 라고 했을 때 기존 수의 부호에 따라 음수였을 경우 1로 채우고 양수였을 경우 0으로 채우는 것을 의미한다.




<+60>의 movesql    %ebx,%rax    에서, %rax는 8byte지만 %ebx는 4byte이다. 4byte를 8byte로 옮기는 것이기 때문에 상위 4byte의 공백이 생긴다. 이 공백을 어떤 bit로 채울까의 문제인데, 우리는 어차피 양수를 넣었기 때문에 공백을 전부 0으로 채우게 되며 결론적으로 %rax의 값과 %ebx의 값이 같아지게 된다.


따라서 <+60>에서 %rax에는 0x1이 담기게 된다.
<+63>에서 (%rsp,%rax,4)을 %eax에 담는다.
<+66>에서 $eax와 $rbp를 비교해서 그 값이 같지 않으면 <+69>에서 jump를 하게 된다.
값이 같으면, <+71>의 explode_bomb을 호출하게 되므로 값이 같으면 안된다.


%rbp에 대한 정보가 나와있는 부분이 어딘지 확인해보았을 때, read_six_number을 실행한 이후 만나는 <+43>의 jmp를 실행하고 나면 <+82>에 %r12의 값을 담는 부분이 있다.
그 이후로는 $rbp의 값을 변화시키는 instruction이 없기 때문에 <+82>에서 담긴 값이 유지가 된다. 
그래서 $rbp가 무엇인지 확인해보았다.


$rbp는 1이다. 이 값은 
<+82>에서부터 유지되어온 값이다.
<+63>시점에서 연산을 수행하기 전 $rsp가 무엇인지 확인해 보았다.



$rsp도 1이다. 그런데, %rbp와 %rsp에 담긴 메모리 주소가 같은 값을 가리키고 있는 것을 확인할 수 있다. 이 메모리 주소는 도대체 어디일까?

바로, 첫번 째 입력한 정수가 담겨있는 위치 값이다. 6 2 3 4 5 6 을 입력하면, 동일한 위치에 6이 담기기 때문이다.



정리해보면
<+63>에서 (%rsp,%rax,4)의 값을 $eax에 담게 되는데,
$rsp는 맨 처음에 입력한 정수 값이고, $rax에는 항상 0x1이 담긴다(위에서 설명)
그러면 %rsp + %rax*4는 결국 %rsp에 담긴 주소값에서 0x4만큼 이동한 값인데, int 1개의 크기가 0x4에 해당하므로 두 번째로 입력한 정수를 가리키게 된다.
즉, <+63>에서는 (두번째로 입력한 정수의 값)을 $eax에 담는 것이다.


이 상태로 <+66>에 도달하면 $eax값과 $rbp를 비교하게 되는데 $rbp에는 맨 처음에 입력한 정수의 값이 담겨있다.
즉, <+66>에서는 (두 번째로 입력한 정수의 값)과 (맨 처음에 입력한 정수의 값) 을 비교하고 있는 셈이다.

따라서 <+69>의 jne문에서 jump가 일어나게 하려면 첫 번째로 입력한 정수의 값과 두 번째로 입력한 정수의 값이 달라야 한다. 나는 1 2 3 4 5 6 을 입력했으므로 1과 2는 서로 다르기 때문에 jne문에서 jump가 일어난다.




jne에서 jump하고 나면 <+52>로 이동되는데, 이 부분을 잘 살펴보면 <+52>부터 <+69>까지는 loop인 것을 알 수 있고 loop가 돌게 하는 값은 $ebx의 값이다.
또한 <+60>부터 <+69>까지는 바로 위에서 보았던 부분이다. 바로 위에서는 암호로 첫번째로 입력한 정수와 두 번째로 입력한 정수가 같은지 체크하는 용도로 사용되었다.

$ebx는 원래 0x1인 상태였고, <+52>에서 $ebx에 1을 더했으니 0x2가 된다. <+60>이 실행되면 $rax는 0x2가 된다. 이렇게 되면 (%rsp,%rax,4)는 첫번째 로 입력한 값에서 0x8만큼 이동하게 되므로 세 번째로 입력한 정수를 가리키게 된다. 그 정수 값이 <+66>에서 $eax에 담긴다. 그리고 <+69>에서 $eax와 $rbp를 비교하는 것이다. 즉, (세 번째로 입력한 정수의 값)과 (첫 번째로 입력한 정수의 값)을 비교하게 된다.

그렇다면 이 loop는 이렇게 해석할 수 있다:
$ebx가 2일 때부터 5일 때까지 4번의 loop를 돌면서, 첫 번째로 입력한 정수의 값과 세 번째~여섯번째 입력한 정수의 값이 같은지 비교하는 것이다. 이 때 두 값이 같을 경우 explode_bomb을 호출한다.

잠시 <+58>에 나온 jg명령어에 대해서 짚고 넘어가겠다.




  • jg, jl 명령어
     cmp    b,a    가 있을 때
    1. jg : a > b 인 경우 jump (signed계열, 부호가 있을 때)
    2. jl : a < b 인 경우 jump (signed계열, 부호가 있을 때)



$ebx의 값이 6이 되고, 0x5보다 커지게 되면 <+58>의 jg명령어에 의해 loop를 빠져나오며 <+78>로 jump하게 된다.


이 뒤부터가 좀 대환장파티이다.
정신을 똑바로 차려야한다 .. ..

여기서 잠깐 헷갈릴 수 있는 개념을 짚고 넘어가려고 한다.
때로는 너무 당연해서 제대로 설명해주지 않는 개념들이 정말 많다. 이런 근소한 개념을 정확히 알아야 공부에 어려움이 없다고 생각한다.


  • (%레지스터)와 %(레지스터)
     add    %rax,%rbxadd    %rax,(%rbx)의 차이는 무엇일까?

'()'는 de-reference를 의미한다. %rbx일 때는 %rbx에 %rax에 있는 값을 넣는 것이지만, (%rbx)인 경우에는 %rbx에 %rax의 값을 넣는 것이 아니라 %rbx가 가리키고 있는 메모리 주소에 %rax의 값을 넣는 것이다. 다음의 예시를 보자.

 


     0x120에 담긴 123을 %rax에 옮기고 싶을 때, 둘 중 어느 것을 사용해야 할까?

    1. mov    %rdi,%rax
    2. mov    (%rdi),%rax

답은 2이다. 123은 %rdi 자체에 담긴 값이 아니라, %rdi에 담겨있는 메모리 주소인 0x120에 담긴 값이기 때문이다.


 

다시 원래 하던 얘기로 돌아와보자.


음.. 지금 상황은 <+58>의 jg명령어에 의해 loop를 빠져나와 <+78>에 도달한 상태이다.

<+78>의 add를 주목해보자.
일단 %r12에 무엇이 들어있는지 먼저 보여주겠다.


익숙한 위치이다. 첫 번째 입력한 정수가 들어있는 위치값이며, 내가 첫 번째로 입력했던 1 이 들어가 있는 것을 확인할 수 있다.

그럼 add    $0x4,%r12    의 결과는 무엇일까?
이 부분의 개념을 잡기 위해서 위의 설명을 굳이 했다.
답은 5가 아니기 때문이다😂 왜 설명을 했냐면, 나는 초짜라서 5라고 생각했다ㅋㅋ 근데 5가 아니다. $r12가 1이 아니다. 엄밀히 따지면 %r12안에 있는 주소가 가리키는 메모리에 들어있는 값이 1인 것이다.
위의 instruction을 실행하면, 마치 %r12가 가지고 있는 위치 값에 0x4의 offset이 작용한듯한 결과가 나온다. add    $0x4,%r12    의 결과는 다음과 같다.


%r12에 들어있던 주소값에서 4byte만큼 이동을 했다. 이것은 무엇을 의미할까? 바로 '두 번째로 입력한 정수의 값'을 의미하게 된다. 정수 1개는 4byte니까, 첫 번째로 입력한 정수의 값에서 4byte 옆으로 가면 두 번째로 입력한 정수의 값이 나오는 것이다.

따라서 만약에 맨 처음에 1 2 3 4 5 6 을 입력했다면 add    $0x4,%r12    의 결과는 2이다.




<+82>에서 %r12(주소)을 %rbp에 넣는다.
<+85>에서는 %r12에 들어있는 값(두 번째로 입력한 정수의 값, 여기서는 2)을 %eax에 넣기 위해 ()를 사용한 것이다.
<+89>에서 %eax값에서 1을 뺀다.
<+92>에서 cmp를 통해 %eax값을 0x5와 비교하고 있음을 확인할 수 있다.

$eax가 0x5보다 크다면 <+95>의 ja문에 의해 jump를 하게 되는데, <+45>에는 explode_bomb이 있기 때문에 $eax <= 0x5 여야 한다.

%eax에는 두 번째로 입력한 정수의 값이 들어가므로, 정리하자면 두 번째로 입력되는 정수의 값은 6보다 작거나 같아야 한다. 2도 가능하다. 5보다 작으니까.



<+97>에서의 %r13d에는 0이 들어있다.


코드를 유심히 읽어보면 
<+97>부터 <+101>에 걸쳐서 %r13d의 값이 0부터 1씩 증가하고, 0x6이 되기 전까지 총 6번 loop를 돌도록 설계되어 있다.

%r13d의 값이 0x6이 되기 전까지 <+105>의 je문은 실행될 일이 없고, <+110>의 jmp에 의해 <+60>으로 jump하게 된다.
그런데 <+60>은 위에서 다룬 loop가 있는 구간이다. 굳이 자세히 뜯어볼 필요는 없지만 주의해야할 점은, <+82>에서 %rbp의 값을 다음 정수로 update하고 있다는 점이다. 위에서 살펴보았을 때는 %rbp의 값을 update하는 instruction이 없었기 때문에 %rbp는 첫 번째 입력한 정수로 고정이었지만, 지금은 계속 다음 정수로 update되며 loop를 돌기 때문에 매 loop를 돌 때 첫 번째 정수와 나머지 정수의 값을 비교하고, 두 번째 정수와 나머지 정수의 값을 비교하고, 세 번째 정수와 나머지 정수의 값을 비교하고 ... 이런식으로 6개의 정수 중 같은 것이 없는지 겁사하게 된다. (같은 것이 있을 경우 explode_bomb을 호출한다)
위에서와 같이 loop를 다 돌고 나면 <+58>에서 <+78>로 이동하게 될 것이다.
<+78>에서 %r12에 담긴 값은 '두 번째로 입력한 정수의 값을 가리키는 주소값'에서 0x4만큼 이동했으므로 '세 번째로 입력한 정수의 값을 가리키는 주소값'이 된다.
그리고 <+82><+85>에서 위와 동일하게 %rbp에 %r12의 값을, %eax에 세 번째로 입력한 정수의 값을 넣는다.
<+89>에서 %eax에서 1을 뺀 다음, 그 값을 0x5와 비교한다. %eax가 5보다 크면 explode_bomb을 호출하게 된다.

이 과정을 한 번 끝낼 때마다 아까의 %r13d의 값이 1씩 증가하게 되는 것이다. 이중 loop인 것이다.
즉 이 loop를 통해서 검사하는 것은 다음과 같다
  1. 입력받은 모든 정수 중 서로 같은 값이 없어야 한다.
  2. 세 번째~여섯 번째 정수들의 값도 (두 번째 정수와 동일하게) 6보다 작거나 같아야 한다
따라서 1 2 3 4 5 6 이라는 입력값은 조건에 부합한다.
1 2 3 4 5 5 이런 암호도 안된다. 5가 두 번 나오기 때문이다.

0 1 2 3 4 5 은 사용해도 될까?
안된다. 위에서 %eax에서 1을 빼는 과정이 있는데, 0에서 1을 빼면 음수가 되는 것이 아니라 매우 큰 양수 값이 되기 때문이다. 그렇게 되면 ja문에 바로 걸리게 된다.






%r13d의 값이 0x6에 도달하는 순간, <+105>의 je문을 통해 <+160>으로 이동하게 된다.



<+160>에서 %esi에 0을 넣는다.
<+165>에서 <+138>로 이동한다.

이 상태에서 %rsp에는 첫 번째로 입력한 정수가 담겨있는 위치가 저장되어 있고, %rsi는 0이다. 따라서 위에서 보았던 경우와 같게 <+138>에서는 %rsi값에 따라 n번째 정수의 값을 %ecx에 담게 되리라는 예측을 할 수 있다.




<+156>의 jg문에서는 %ecx에 담긴 값이 0x1보다 클 경우 jump한다. 조건에 맞지 않을 경우 <+158>에서 jmp를 통해 <+123>으로 가게 되는데, 나의 경우에는 첫 번째 정수인 1인 경우밖에 이에 해당하지 않는다. 0은 사용할 수 없고, 나머지 정수는 1보다 크기 때문이다.

첫 번째 정수가 1이어서 <+123>으로 이동을 했다.
<+123>의 mov가 실행되면 %rdx값이 0x20(%rsp,%rsi,8)에 담긴다.
%rdx에는 6이 담겨있다. 



%rdx에 들어있는 메모리 주소는 입력한 첫 번째 정수가 들어있는 %rsp에 들어있는 메모리 주소에서 0x4*5 만큼 더한 값으로, 여섯 번째 정수가 들어있는 메모리 위치를 가리키고 있음을 알 수 있다. (1 2 3 4 5 6 중 6이 들어있는 위치라는 의미)

%rsi에는 0이 들어있으니 0x20+%rsp에 6이 담긴다는 의미인데, %rsp에는 첫 번째 정수의 위치가 들어있다. 0x20은 10진수로 32니까, 0x4*8에 해당한다. 

<+128>에서 %rsi의 값에 1을 더해서 1로 만들고, <+132><+136>은 건너뛰게 된다 (%rsi의 값이 0x6과 다르므로).

다시 <+138>에 도달했고, %ecx에 두 번째로 입력한 정수의 위치를 담게 된다(나의 경우는 2).

<+141>에서 %eax에 1을 담고
<+146>을 실행하면 심기를 거스르는 복잡해보이는 값이 담겨있다. 일단은 지금 당장 중요한 값은 아니기 때문에 <node1>이 뭐지? 정도의 생각만 하면서 슬쩍 넘어가자.




<+156>에서 %ecx에 담긴 값(2)은 0x1보다 크기 때문에 <+112>로 이동하게 된다.
<+112>에서 또 다시 %rdx값의 연산이 있는데 위와 비슷하게 크게 신경쓰진 말고 엥 이번에는 <node2>잖아? 하고 넘어가보자.




<+116>에서 %eax에 들어있는 값(1)에 1을 더하고(결과는 2), <+119>에서 %ecx(2)와 비교한다.
두 결과가 동일하기 때문에 <+121>에서 jump가 일어나지 않는다.
<+123>에서 %rdx에 담긴 값을 0x20(%rsp,%rsi,8)에 담는다.
<+128>에서 %rsi+1을 해서 %rsi는 2가 됐고, <+132>와 <+136>은 건너뛰게 된다.

그리고 또 다시 <+138>에 세 번째 정수의 값을 담고, %eax를 0x1로 update하고... 이런 과정이 반복이 된다.

그러다가 %rsi의 값이 0x6이 되었을 때, 그러니까 총 6번 loop를 돌고 난 뒤에 loop를 빠져나와 <+167>로 이동한다.



%rsp에는 첫 번째로 입력한 정수가 들어있는 위치가 담겨있다.
%rax와 %rbx는 6이 담겨있다.
이 6은 내가 입력했던 6이 아니다. 내가 입력했던 6을 표현하기 위해서는 주소값을 담아야 할 것이기 때문이다. 아마 loop를 돌며 사용했던 조건을 위해 생겨난 0x6이 아닐까 추측하고 있다.


이 이후부터는 계속 위에서 보았던 의미심장한 값을 여기 넣었다가 저기 넣었다가를 신나게 반복한다.


이런 식의 값의 이동이 <+167>부터 <+217>까지 이어진다.
그리고 나서 %ebp에 0x5를 넣고 나면 <+241>로 이동한다.



%rax와 %rbx에 담긴 값들은 의미를 모르겠는 값들이지만 <+247>에서 비교를 해야한다. <+249>의 jge에 걸리지 않으면 explode_bomb이 호출되기 때문에 (%rbx)가 %eax보다 크거나 같아야한다.

<+247>의 시점에서 $eax와 $rbx는 다음과 같다.




따라서 jge문에 해당되기 때문에 explode_bomb을 호출하지 않고 <+232>로 jump한다.



<+225>에 의해서 %ebp에는 0x5가 담겨있다.
<+232>에서 mov를 실행하고, %ebp에서 -1을 한 다음 je문으로 가는 구조이다.
만약 이 <+239>의 je문이 실행된다면, <+258>로 jump하여 stack canary의 값을 비교하고 프로그램이 정상종료되게 된다. 즉, je문이 실행되게 해야한다.

je문이 실행되려면 %ebp의 값이 0x1이 되어야 하는데 그럼 %ebp가 끝나기 전까지 loop를 돌게 될 것임을 예측할 수 있다.

<+241>부터 <+247>을 수행하기 위해서는 %rbx에 담긴 것이 도대체 무엇인지 정체를 알아야 할 필요성이 있다.

위에서는 '일단 그냥 넘어가자' 라는 말로 일축하고 넘어갔지만, 기억을 되돌려보면 <node1>, <node2>와 같은 표현이 있던 것을 떠올릴 수 있다.
그럼 이 node는 도대체 무엇을 의미할까?

이것의 정체는 바로 linked list이다.
x/20x로 %rbx를 뜯어보자.



아까 보았던 <node1>부터 <node5>가 보인다. 한번 전체적으로 보고 추측을 해보자.
일단 각 node의 두 번째 값들은 차례대로 나열되어 있다. node의 번호처럼 보인다.
node의 첫번째 값들은 사실 계속해서 %rbx나 %rax에 담기는 값이다. 즉, <+247>에서 비교를 할 때 쓰이는 값이다.
세번째 값과 네번째 값은 떨어져있어서 헷갈릴 수 있지만, 두 값을 합치면 완전한 하나의 주소가 된다. <node1>기준으로 세번째 값과 네번째 값을 뒤에서부터 합치면 0x0000555555758210이다. 이 위치는 어디일까? 바로 <node2>의 위치이다. 즉, 각 node를 잇고있는 포인터가 저장되는 곳이다.

입력한 정수는 6개였는데, node가 5개만 있을리 없다. 역시, <node5>의 세번째, 네번째 값이 존재했고 이 값을 합쳐서 x/4x로 값을 추적해보았더니 <node6>까지 찾아낼 수 있었다.

보기 좋게 표로 정리하면 이런 느낌이 된다

<node1>

0x2da

1

<node2>

0x1ad

2

<node3>

0x093

3

<node4>

0x0d1

4

<node5>

0x076

5

<node6>

0x169

6


여기서 다시 아까의 instruction을 상기해보자.





%rbx가 어떤 node를 가리키게 될 것이다. 이 node를 <node1>이라고 한다면, %rax에는 거기서 0x8만큼 이동하면 있는 <node1>에 있는 <node2>를 가리키는 포인터가 담기게 된다. 그리고 이 포인터를 참조해서 얻은 <node2>가 %eax가 담기게 되는 것이다.
즉, %rax에는 %rbx의 다음 node가 담긴다.
그런데 %rbx가 항상 %eax보다 크거나 같아야 한다. 그렇게 되면 node의 값이 큰 순으로 정렬을 해야한다. 왜냐하면 loop를 돌면서 모든 node들을 비교하게 될 것이고, 그 모든 node들 사이에서 어떤 node는 이전 node보다 크거나 같은 값을 가져야 한다는 규칙이 성립해야하기 때문이다.

위의 linked list를 값이 작은 것부터 정렬하면 이렇게 된다.

 

<node5>

0x076

5

<node3>

0x093

3

<node4>

0x0d1

4

<node6>

0x169

6

<node2>

0x1ad

2

<node1>

0x2da

1

 


우리는 값이 큰 순서대로 숫자를 배치해야하므로 아래에서부터 값을 읽으면, 1 2 6 4 3 5 라는 결과가 나온다.





암호는 1 2 6 4 3 5 이다.




BombLab을 하고있다면 이 BombLab에는 secret phase가 존재한다는 것을 알 것이다. secret phase에 대한 힌트를 하나 주자면, main함수를 disas해보길 바란다.


댓글

이 블로그의 인기 게시물

[리버싱] BombLab phase_5 분석하기

[리버싱] BombLab phase_1 분석하기