본문 바로가기

Bomb Lab

[Bomb Lab] Phase1

<Bomb Lab이란?>

https://studyforall.tistory.com/98

 

[Bomb Lab]Bomb Lab이란?

Bomb Lab은 컴퓨터 사이언스로 유명한 카네기 멜론 대학교에서 만든 실습 프로그램이다. 이 프로그램을 통해 디버거 사용법을 익히고 바이너리 분석을 연습해볼 수 있다. 폭탄을 터뜨리지 않고 안

studyforall.tistory.com

 

실습 환경에 대해서는 위의 게시물 하단에 적어놓았다.

 

본격적으로 phase1부터 시작해본다.

먼저 disassemble phase_1 명령어를 입력하여 phase_1 함수를 어셈블리 코드로 출력해보았다.

<+18>에 explode_bomb이 있다.

이 부분을 밟지 않고 phase_1 함수를 종료해야 폭탄을 해체할 수 있으므로 <+23>부터가 안전지대이다.

 

<+16>에서 je명령어가 <+23>으로 분기할 수 있는 부분인데,

je는 ZF가 1일 때 jump하는 명령어이므로

여기에서 <+23>으로 넘어가려면 ZF가 1이어야 한다.

 

<+14>에 있는 test 명령어 수행 결과 ZF가 설정될 것이다.

test 명령어는 두 피연산자를 AND 연산한 결과가 0이면 ZF를 1으로 설정한다.

이 명령어에서는 test eax, eax를 하고 있으므로 ZF가 1로 설정되려면

eax 값이 0x00000000 이어야 한다.

(eax 값에서 한 비트라도 1이 들어있으면 AND 연산했을 때 0이 나올 수 없다)

 

이로써 phase1에서의 목표설정을 다음과 같이할 수 있다.

"<+14>지점에 왔을 때 eax의 값이 0이 되도록 하는 문자열 입력값 찾기"

 

 

그렇다면 <+14>지점에서의 eax의 값은 언제 결정될까?

바로 이전 명령어에서 strings_not_equal 함수를 호출하고 있다.

이 함수의 실행 결과로 eax 값이 설정되는 것이 아닐까 하는 추측을 할 수 있다.

 

정말 그런가 strings_not_equal 함수를 disassemble 해보자.

함수의 후반부인 <+99>에서 edx 값을 eax에 저장하는 것을 확인할 수 있다.

그 위의 코드들을 보면 일련의 연산 과정에서 edx에는 0x0, 0x1 등의 특정 상수가 저장되는 것을 볼 수 있다.

 

이제 어떤 값을 입력해야 eax에 0이 저장되는지를 확인하기 위해

strings_not_equal 함수를 더욱 면밀히 분석해보자.

 

동적 분석을 시작한다.

먼저 strings_not_equal 을 호출하는 지점에 breakpoint를 건다.

 

 

그리고 run을 입력해서 프로그램을 실행시킨다.

(run 대신 r을 입력해도 됨)

Welcome ~가 출력되고 사용자의 입력을 대기한다.

phase_1() 실행 전에 있는 read_line()함수가 실행 중인 것 같다.

아직 어떤 입력값을 넣어야하는지 모르니까 일단 임의의 문자열로 interlude를 입력해보았다.

 

[DISASM] 영역을 보면 bp를 걸어놓은 strings_not_equal 지점에서 rip가 멈춘 것을 확인할 수 있다.

[REGISTERS] 영역을 보면 나의 입력값인 interlude는 rax, rdi, r9에 저장된 것을 볼 수 있는데,

우리는 rdi에 주목할 것이다.

왜냐하면 rdi가 함수 호출 시 전달된 인자를 저장하는 역할을 하는 레지스터이기 때문이다.

따라서 내가 함수에 입력한 값을 추적할 때는 rdi를 살펴봐야겠다는 판단이 든다.

 

여기에서 유용한 상식을 하나 짚고 넘어가면 좋을 것 같다.

함수 호출시 전달되는 인자는 rdi, rsi에 저장되어 전달된다.

구체적으로 rdi에 첫번째 인자, rsi에 두번째 인자가 저장된다.

그럼 인자가 3개 이상이면 어떻게 될까? -> 이건 나중에  알아보자.

 

rdi와 rsi를 통해 argument가 전달되었다는데,

rdi에는 내가 입력한 값이 있는 것은 확인하였다.

그런데 rsi에도 어떤 문자열이 저장되어있다.

strings_not_equal 함수에 전달된 문자열이 내가 입력한 값 말고 또 있는 것이다!

그렇다면 rsi에 있는 문자열이 내가 입력한 값과 비교할 문자열이지 않을까..?

 

일단 이런 느낌을 검증하기 위해 프로그램을 다시 실행해서 rsi에 있던 문자열을 입력해본다.

위와 같이 문자열을 입력하였고

 

c (혹은 continue)를 입력해서 프로그램을 계속 실행시켰더니

Phase 1 defused. 가 떴다!!

 

나의 추측이 맞았음을 확인할 수 있다.

 

 

하지만 여기에서 끝내면 뭔가 공부를 덜 한 느낌이니

rdi에 저장된 나의 입력값과 rsi에 들어있던 저 문자열을 비교하는 코드를 정확히 확인하고 넘어가자.

rdi와 rsi를 추적해보자.

<+4>에서 rdi는 rbx로 mov되었다.

<+7>에서 rsi는 rbp로 mov되었다.

 

그리고 string_length함수를 두번 호출한 뒤

<+34>에서 r12d와 eax를 비교한다.

<+34>에서는 jne문이 있는데 <+34>에서 r12d와 eax가 다르면 <+99>로 jump한다.

<+99>에서는 edx 값을 eax에 저장하는데, <+26>에서 edx 값에 0x1이 저장된 상태이므로

이대로라면 eax에는 0x1이 저장된다.

앞서 살펴본 바에 따르면 eax가 0x0이어야만 폭탄을 해체할 수 있었다.

따라서 폭탄이 안 터지려면 <+34>에서 r12d와 eax값이 같았어야 한다는 결론이 난다.

 

<stings_not_equal+10>에 bp를 걸고

해당 부분부터 한 줄씩 실행시켜봤다. (한 줄씩 실행하는 명령어: ni)

<+15>에 왔을 때 eax의 값은 0x9이다. 이 값은 r12d에 저장된다.

함수 이름이 string_length였던 것에서 유추하자면,

0x9는 "interlude"의 문자열 길이인 것 같다.

그리고 <+31>에 왔을 때 eax의 값은 0x34이다.

0x32는 "Border relations with Canada have never been better."의 문자열 길이인 52와 일치한다.

 

따라서 strings_not_equal함수에서는 먼저 입력받은 문자열이 정답 문자열과 길이가 일치하는지를 확인한다는 것을 알 수 있다.

 

이제 다음 명령어를 살펴보자.

다음 명령어들은 요약하자면 rbx(rdi에 입력했던 값)의 문자열과 rbp(rsi에 있던 문자열)을 한 글자씩 비교하는 내용이다.

<+36>부터 <+56>까지는 rbx의 첫 문자와 rbp의 첫문자를 비교하는 부분이다.

여기에서 문자가 서로 다르면 결국 폭탄이 터지는 flow를 타게 된다.

<+58><+62>는 다음 문자로 포인터를 이동하는 부분이다.

<+66>부터 <+73>까지는 종결문자를 만났는지 확인하고 종결문자를 만났으면 문자열 비교를 마치는 부분이다.

이런 알고리즘을 통해 종결문자를 만날 때까지 모든 문자가 일치하면 eax에 0x0이 들어간 상태로 함수가 종료된다.

 

 

이제 오늘치 공부는 충분히 한 것 같으니 끝.

'Bomb Lab' 카테고리의 다른 글

[Bomb Lab] phase4  (0) 2024.05.10
[Bomb Lab] Phase3  (0) 2024.03.24
[Bomb Lab] Phase2  (0) 2024.03.24
[Bomb Lab]Bomb Lab이란?  (1) 2024.03.24