[드림핵] rev-basic-8
# 문제
https://dreamhack.io/wargame/challenges/22
이 문제는 사용자에게 문자열 입력을 받아 정해진 방법으로 입력값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주어집니다.
해당 바이너리를 분석하여 correct를 출력하는 입력값을 찾으세요!
1. main 함수 찾기
main 함수 찾는 방법은 rev-basic-0 에 적어두었습니다. (그러나 별 거 없어요..)
2. 실행 흐름 파악하기
basic 시리즈의 특징인.. test eax, eax를 통해 correct와 wrong을 분기하고 있습니다. (더 자세한 설명은 https://hyunhe2e.tistory.com/111 에)
중요한 건 test eax, eax 전에 call chall8.7FF6030B1210 함수에서 eax가 0이 아닌 값을 리턴 받아야 한다는 것 정도만 알고 해당 함수 내부로 진입해봅시다.
3. 디버깅
해당 함수 내부에 주석문을 포함한 화면 입니다. 반복문을 통한 비교 및 실행흐름은 rev-basic-6과 유사하므로, Flag를 찾아내는 중요한 단락으로 넘어가겠습니다.
중요한 부분은 cmp eax, ecx를 통해 두 값을 비교하고 같으면 je 명령어를 통해 맨 위에 반복문을 시작하여 0x15번(21번) 비교 과정을 반복하는 것이고, 두 값이 다르면 xor eax,eax를 통해 eax는 0이 된채 해당 함수는 종료되고 맙니다. 그러나 해당 함수 뒤에 바로 test eax, eax를 통해 correct와 wrong이 분기되므로 eax와 ecx값이 같아야 하구나! 정도만 머리에 박아두고 eax와 ecx가 어떻게 구해지는 지 알아봅시다.
1. eax 값
먼저 rsp 값은 0이므로 rax는 0 이 됩니다. rsp에 무슨 값이 들어있는지 어떻게 알아요! 하시는 분은 레지스터 뷰를 보며 찬찬히 f8로 진행해보면 됩니다. 그럼 rax 값이 0인 것을 확인할 수 있습니다.
다음으로는 rsp+20의 값을 rcx에 저장하는데, rsp+20값은 나의 입력값입니다. 그 다음으로는 imul 명령어로 eax에 어떤 연산이 시작됩니다. imul 명령어는 처음 봐서 아래에 간략히 정리해두었습니다.
1) imul 명령어
: 부호 있는 곱셈.
- 형태: imul 목적지, 소스, 정수
- 정수 * 소스 값을 목적지에 저장한다. 그 값이 커서 목적지에 못 들어갈 경우 edx 레지스터에 저장된다.
즉, 내 입력값 중 첫 번째 * 0xFB 하여 eax에 저장한다고 볼 수 있겠습니다. 그 후 and 연산으로 해당 eax AND 0xFF 가 되네요.
이 때까지 식을 한 번 세워보면... (내 입력값 * 0xFB) AND 0xFF
2. ecx 값
주석을 통해 rcx와 rdx에 어떤 값이 저장되는지 상세히 설명해두었습니다. 저희가 알아야 하는 건 rdx(7FF6030B3000) + rcs(0) = 7FF6030B3000 라는 것이고, ecx에 해당 값이 저장된다는 것입니다.
그럼 우리는 비교될 eax값과 ecx값이 어떻게 연산되는 지 알고 있고 eax값((내 입력값 * 0xFB) AND 0xFF)는 ecx값( 7FF6030B3000의 값)과 같아야 합니다.
해당 주소에는 아래와 같은 값이 있고 21번 비교하기에 21번째 문자열까지만 같으면 됩니다.
더 쉬운 방식이 있을 지 모르나 rev-basic-6과 같이 아스키 코드 값 내에서 무작위 대입을 하여 7FF6030B3000의 값과 (내 입력값 * 0xFB) AND 0xFF 결과 값이 같으면 flag 배열에 저장하여 출력하도록 코드를 짜보도록 했습니다.
4. 마무리 코딩 작업
#include <stdio.h>
int main() {
int num_3000[] = {0xAC, 0xF3, 0x0C, 0x25, 0xA3, 0x10, 0xB7, 0x25, 0x16, 0xC6, 0xB7, 0xBC, 0x07, 0x25, 0x02, 0xD5, 0xC6, 0x11, 0x07, 0xC5, 0x00 };
int flag[22] = {0};
for(int i = 0; i<21; i++) {
for(int j = 0; j < 256; j++) {
if (((j * 0xFB)&0xFF) == num_3000[i]) {
flag[i] = j;
break;
}
}
}
printf("flag is :");
for(int i = 0; i<21; i++) {
printf("%c", flag[i]);
}
return 0;
}