[crackme3] abex' 3rd crackme 풀이 및 복원
1. [abex' 3rd crackme] 풀이시연
1) 실행파일 실행
[1] 파일 열기
▶ 첫 번째 메세지박스는 키파일을 체크 후 확인을 클릭하라고 한다.
▶ 두 번째 메세지박스는 파일을 찾을 수 없다고 한다.
2) 개발언어 및 링커 확인
[1] Pascal계열의 Delphi로 작성됨을 알 수 있다.
[2] 32비트 실행파일임을 알 수 있다.
[3] Terbo 링커를 사용하여 링킹한 것을 알 수 있다.
[4] 헤더타입이 PE라고 적힌 것이 확인되어 Windows용 실행파일임을 알 수 있다.
[5] ImageBase(기준주소)가 0x400000임을 알 수 있다
[6] EntryPoint(시작주소)가 기준주소로부터 0x1000 만큼 떨어진 곳임을 알 수 있다.
[7] 기타 시그니쳐 및 옵션 세부사항은 직접 하나씩 확인해보면 된다.
[8] 필자는 Detect It Easy 2.0 툴을 사용하였다.
3) 상상
[1] 1)에서 실행해본 결과 특정파일 이름이 있는지 확인하는 조건문이 있을 것으로 추측된다.
[2] 의사코드
MessageBox(핸들번호, "Click OK to check for the keyfile.", "abex' 3rd crackme", MB_OK);
if (특정파일이 있다면?) {
//참인 경우? 실행할 내용
//실행할 내용을 예측해보면 파일을 열기 때문에 WinAPI라면 OPENFILENAME을 사용할 것으로 추측된다.
} else {
MessageBox(핸들번호, "Hmmmmm, I can't find the file!", "Error", MB_OK);
}
종료..
4) 디버거 툴을 사용한 분석
[1] Main함수 실행
▶ 아까 기준주소와 상대적인 상대주소를 얻었으므로 더해서 메인함수의 시작주소가 0x401000임을 알 수 있다,
▶ 디버거프로그램으로 F9를 누르면 자동으로 브레이크포인트가 있는 것으로 체크해서 멈춘다.
▶ 프로그램을 시작하자마자 MessageBoxA( )함수가 보인다.
▶ 0x401000에서 0을 PUSH하는 것으로 보아 OK버튼만 있는 메세지박스가 실행될 것으로 보인다.
▶ OK를 누르고 난 뒤 CreateFileA( ) 함수가 보인다.
[2] CreateFileA( ) API 검색
HANDLE CreateFileA(
LPCSTR lpFileName,
//파일이나 장치명 = "abex.l2c"
DWORD dwDesiredAccess,
//요청한 access = 0x80000000은 읽기권한을 부여한다.
DWORD dwShareMode,
//공유모드 = 0x0은 다른 프로세스에서 사용하지 않는다.
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
//보안속성 = 0x0은 보안구조체를 가리키지 않는다.
DWORD dwCreationDisposition,
//기능 = 0x3은 파일이나 장치가 있으면 열고 없으면 ERROR_FILE_NOT_FOUND(2)를 확인한다.
DWORD dwFlagsAndAttributes,
//플래그 = 0x80은 특별한속성x
HANDLE hTemplateFile
// 기존에 열린파일의 핸들 = 0x0은 참고하지 않는다는 의미이다.
);
▶ CreateFileA( ) 함수를 호출 전에 스택에 push한 내용을 대입해서 비교해본다.
▶ 종합해보면 [abex' 3rd crackme.exe]파일이 있는 곳에 [abex.l2c]파일을 읽으려고 한다.
▶ 이후 내용은 전부 조건문에 따른 메세지박스를 호출하는 것으로 보인다.
5) 풀이
[1] 시작
▶ 먼저 "abex' 3rd crackme" 타이틀바, "Click OK to check for the keyfile." 내용, OK버튼이 있는 메세지박스를 띄운다.
[2] CreateFileA( ) 함수 호출
▶ "abex.l2c"라는 파일을 읽기위해 열 수 없다면 eax에 -1을 반환한다.
▶ eax가 -1("abex.l2c"라는 파일이 없다면)이면 0x401075로 jmp한다.
▶ 만약 파일이 있다면 그에 따른 핸들 값을 0x4020CA에 저장한다.
▶ 처음 실행하면 [3]으로 이동하고 [3]에서 깨달음을 얻으면 [4]로 이동한다.
[3] 0x401075 내용
▶ "Error!" 타이틀바, "Hmmmmm, I can't find the file!" 내용, OK버튼이 있는 메세지박스를 띄운다.
▶ OK버튼을 누르면 0x401088에서 프로세스종료 함수를 호출한다.
▶ 즉, 나는 파일을 찾을 수 없다는 메세지를 띄우고 종료하게 된다.
▶ 여기서 "abex' 3rd crackme.exe"와 같은 위치에 "abex.l2c"파일을 만들어주어야겠다는 생각이 든다.
[4] 0x401039 내용
▶ CreateFileA( )함수에서 반환받은 핸들 값을 첫 번째 파라미터에 넣고 GetFileSize( ) 함수를 실행한다.
▶ 현재는 NULL로 적혀있지만 실제로 실행하면 0xBC값을 가지고 GetFileSize( ) 함수를 실행한다.
▶ 함수 종료 후 파일 사이즈(바이트)를 eax에 반환한다.
▶ eax가 0x12(10진수 18)이 아니면 0x401060으로 jmp한다.
▶ 즉, CreateFileA( ) 함수에서 열은 "abex.l2c"파일의 사이즈가 18바이트가 아니면 0x401060으로 jmp한다.
▶ 처음 실행하면 [5]로 이동하고 깨달음을 얻었다면 [6]으로 이동한다.
[5] 0x401060 내용
▶ "Error" 타이틀바, "The found file is not a valid keyfile!" 내용, OK버튼이 있는 메세지박스를 띄운다.
▶ OK버튼을 누르면 0x401088에서 프로세스종료 함수를 호출한다.
▶ 즉, 찾는 파일의 키파일이 아니라는 메세지를 띄우고 종료한다.
▶ 여기서 "abex.l2c"파일의 사이즈를 18바이트를 지정해주어야겠다는 생각이 든다.
[6] 0x40104B 내용
▶ "Well done!" 타이틀바, "Yep, keyfile found!" 내용, OK버튼이 있는 메세지박스를 띄운다.
▶ OK버튼을 누르면 0x401088에서 프로세스종료 함수를 호출한다.
▶ 키파일을 찾았다는 메세지를 띄우고 종료한다.
[7] 파일생성
▶ 위 분석결과로 유추했을거라고 생각한다.
▶ 파일명이 "abex.l2c"인 파일을 [abex' 3rd crackme.exe] 파일과 동일경로에 저장한다.
▶ 아무내용이나 18바이트만큼 입력 후 저장한다.
▶ [abex' 3rd crackme.exe]을 실행한다.
6) 원본소스 가복원
<<Event_start>>
USER32.MessageBoxA(NULL,"Click OK to check for the keyfile.","abex' 3rd crackme", MB_OK);
<<Event_OK>>
eax = KERNEL32.CreateFileA(
"abex.l2c", GENERIC_READ, 0, NULL, OPEN_EXISTING, NORMAL, NULL
);
int imsi = eax;
if (eax == -1) {
USER32.MessageBoxA(NULL, "Hmmmmm, I can't find the file!", "Error", MB_OK);
KERNEL32.ExitProcess();
}
else {
eax = KERNEL32.GetFileSize(imsi, NULL);
if (eax != 0x12) {
USER32.MessageBoxA(NULL, "The found file is not a valid keyfile!", "Error", MB_OK);
KERNEL32.ExitProcess();
}
else {
USER32.MessageBoxA(NULL, "Yep, keyfile found!", "Well done!", MB_OK);
KERNEL32.ExitProcess();
}
}
KERNEL32.ExitProcess();
7) C언어 코드로 복구
#include<stdio.h> #include<Windows.h> int main() { int eax; MessageBoxA(NULL, "Click OK to check for the keyfile.", "abex' 3rd crackme", MB_OK); eax = CreateFileA( "abex.l2c", GENERIC_READ, 0, NULL, OPEN_EXISTING, NULL, NULL ); if (eax == -1) { MessageBoxA(NULL, "Hmmmmm, I can't find the file!", "Error", MB_OK); } else { eax = GetFileSize(eax, NULL); if (eax != 0x12) { MessageBoxA(NULL, "The found file is not a valid keyfile!", "Error", MB_OK); } else { MessageBoxA(NULL, "Yep, keyfile found!", "Well done!", MB_OK); } } return 0; }
8) 복구한 C언어 코드로 실행
'Try Attack > Reverse Engineering[basic]' 카테고리의 다른 글
Code Caving (0) | 2018.12.18 |
---|---|
[crackme5] abex' 5th crackme 풀이 및 복원 (0) | 2018.11.16 |
[crackme2] abex' 2nd crackme 풀이 및 복원 (0) | 2018.11.07 |
[crackme1] abex' 1th crackme 풀이 및 복원 (0) | 2018.11.07 |
악성코드와 리버싱 (0) | 2018.10.09 |
댓글