reversing

layer7 리버싱 5차시 과제(2) - prob3 분석

leesu0605 2022. 8. 1. 16:37

목차

1. prob3 분석 및 코드 복원


1. prob3 분석 및 코드 복원


일단 gdb를 켠 후, main 함수를 뜯어보았다.

하나씩 분석해보자.

처음에 스택프레임을 만든 후, time 함수를 호출하고 있다.

time의 인자는 하나로, 원래는 NULL이 들어가지만 NULL은 0이기 때문에 0x0을 edi에 복사해 인자로 전해주었다.

그 바로 다음 코드에선 time의 결과값으로 srand를 호출하고 있는데, 이는 같은 시드라면 언제 실행해도 같은 랜덤값이 나오는 걸 방지하기 위해 1초마다 바뀌는 시드값을 이용한 것이다.

다음 코드에선 rbp-0xc에 있는 값을 0x0으로 만들고, main+143으로 점프하고 있다.
이젠 익숙해진 for문 전개이다.
아마 rbp-0xc에 반복횟수를 저장한 for문일 것이다.

그렇다, 총 10회를 반복하는 반복문이다.
그럼 for문의 내용은 main+54부터 main+139의 전까지 일테므로 수고가 분석해야할 코드가 약간 줄어들었다.

 

for문의 내용이다.
for문의 초반부에서는 scanf를 호출해 사용자로부터 어떤 값을 rbp-0x10에 입력받고 있는데, 어떤 자료형으로 받는지 확인해보자.

%d로 받는 걸 보아, 정수형을 입력받는다는 사실을 알 수 있다.

그 다음으론 rand함수를 호출해 이상한 연산들을 진행하고 있는데,

이는 10으로 나눈 나머지 연산을 진행하는 코드이다.

이게 왜 나머지 연산이 되는지 알아보도록 하자.
일단 저걸 보기 편하게 코드로 나타낸다면,

int input = rand();
input - ((((0x66666667 * input) / 0x100000000) >> 2) - (input >> 0x1f)) * 10

이렇게 된다.
그런데 뜬금없이 0x66666667이라는 숫자가 나왔다.
이는 2.0 ^ 33 / 5 의 근사값으로 0x66666667이라는 숫자 대신 2.0 ^ 33 / 5 로 식을 다시 표현해보도록 하겠다.

int input = rand();
input - ((((0x66666667 * input) / 0x100000000) >> 2) - (input >> 0x1f)) * 10

= input - ((((input * 2^33/5) / 2^32) / 2^2) - (input / 2^31) * 10

= input - ((input / 10) - (input / 2^31)) * 10

그러나, 2^31으로 나눈다는 뜻은 int형에서 부호 비트가 1인지 체크한다는 뜻이고, rand()함수로 얻어낸 값은 음수가 없으므로 무시해도 좋다.
즉, 식은 이렇게 나온다.

int input = rand();
input - (input / 10) * 10

맞다.
10으로 나눈 나머지를 구하는 과정이다.
int형은 10으로 나눴을 때 일의 자리를 버리므로 일의 자리만이 남게 된다.

그럼 저 긴 연산이 모두 나머지 연산이라는 것을 알았으니 계속 분석을 진행해보자.

만일 아까 사용자가 입력했던 값과 rand()로 얻어낸 값을 10으로 나눈 나머지가 같으면 main+139로 가고, 아니면 0x400947 주소에 있는 문자열("Wrong!!")을 출력하고 프로세스를 종료한다.
그럼 만일 10번의 반복에서 모두 rand()값을 맞히면 어떻게 될까?

flag_generator에서 얻은 문자열을 출력하고, 프로세스를 종료한다.
time함수로 얻은 랜덤값은 예측이 불가능하기 때문에 디버깅 도중 jump 명령어를 사용해 eip를 이동시켜 강제로 flag_generator를 출력하도록 해보겠다.
일단 for문을 타기 전에 flag_generator로 이동하기 위해 반복 횟수 값을 초기화해주는 명령어에 브레이크포인트를 걸고 실행시켰다.

그 다음,

flag_generator를 호출하기 전 eax를 초기화해주는 main+149로 eip를 점프시켰다.

그랬더니 프로그램이 플래그를 정상적으로 출력하고 프로세스가 종료됐다.
flag : LAYER7{3V4NGEL10N_3.0+1.0_THR1C3_UP0N_4_T1M3}

그럼 이 어셈블리어를 C코드로 복원시켜보겠다.