[crackme1] abex' 1th crackme 풀이 및 복원
※ crack보다 배우는데 목적이 있기 때문에 여러가지 방법으로 시도해 보았다.
1. 리버싱 과정(순서)
1) 실행파일 실행
[1] 실행파일을 실행해서 뭐하는 프로그램인지 확인해본다.
2) 개발언어 및 링커 확인
[1] 어떤언어로 개발된 프로그램인지 확인한다.
▶ 언어에 따라 어떤 API를 사용했는지 확인이 가능하다.
[2] 어떤 컴파일러를 사용하였는지 확인한다.
▶ 컴파일러에 따라 기계어로 변환하는 방법이 다르기 때문에 컴파일러의 스타일을 확인할 수 있다.
3) 상상
[1] 개발된 언어를 알고 있다면 어떠한 로직으로 구성되었는지 유추해본다.
[2] 만약 C++로 제작되었지만 모른다면 의사코드를 이용해 짐작해본다.
4) 디버거 툴을 사용한 분석
[1] 전체분석
▶ 전체분석의 경우 전체적인 로직을 분석하여 개발 툴의 특성에 따라 구조를 완성할 수 있다.
[2] 부분분석
▶ 부분분석의 경우 문제만 해결하는 방법을 말한다.
5) 문자열 검색
▶ 프로그램에서 출력되는 문자열의 위치를 따라가서 영역을 분석한다.
6) API 검색
▶ 단순하게 출력되는 문자열이 없는 곳은 내부에서 동작하는 System Call함수를 검색해서 분석한다.
7) 분석완료 후 변조
▶ 분석이 완료되었다면 여러가지의 해결방법 중 한 가지방법으로 문제를 해결한다.
2. [abex' 1st crackme] 풀이시연
1) 실행파일 실행
▶ HD가 CD-Rom이라고 생각하도록 만들어야 할 것 같다.
▶ 이 드라이브는 CD-Rom이 아니라는데..
▶ 이 경우 Hard를 CD-Rom으로 변경해주면 해결될 것 같다.
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] 첫 번째 메세지 창에서 출력된 메세지, 두 번째 메세지 창에서 출력된 메세지를 확인해서 유추한다.
[3] 의사코드
MessageBox(핸들번호, "make me think your HD is a CD-Rom.", "abex' 1st crackme", MB_OK);
if (드라이브가 CD-Rom인지 확인) {
//참인경우? 실행할 내용
} else {
MessageBox(핸들번호, "Nah... this is not a CD-Rom Drive!", "Error", MB_OK);
//거짓일경우? 실행할 내용
}
종료..
4) 디버거 툴을 사용한 분석
[1] 디스어셈블한 코드
5) 문자열 검색
[1] 현재 메모리에 존재하는 문자열을 출력한다.
[2] [Nah... this is not a CD-Rom Drive!] 이 문자열이 출력되었으므로 이 문자열의 주소로 이동한다.
[3] 아까 의사코드를 작성하면서 유추했을 때 이 전에 분기문이 있을 것이며 비교 후 위 문자열을 출력했다는 생각이 든다.
[4] 0x00401026주소로 이동해보면 같으면 점프하라는 jmp문이 보인다.
[5] 그 위 0x00401024에서 cmp문으로 비교하는 것을 알 수 있다.
[6] 0x00401026주소의 내용은 eax와 esi가 같으면 0x40103D로 점프하라는 내용이다.
[7] 0x0040103D주소 이후 내용은 HD가 CD-Rom이라는 메세지를 출력하는 메세지박스를 띄우고 있다.
6) API 검색
[1] GetDriveTypeA() 함수의 MSDN
▶ 파라미터는 드라이브의 루트디렉터리이며, 백슬래시(\\)가 뒤에 들어가야 한다.
▶ 매개변수가 NULL일 경우 현재디렉터리의 루트를 사용한다.
▶ 드라이버 타입이 CD-Rom인 경우 EAX에 5를 반환한다.
7) 분석완료 후 변조
[1] GetDriveType( ) 함수의 Return 값을 5(CD)로 변경
▶ 먼저 처음 메세지박스(0x40100E)를 확인할 때까지 F8로 StepOver를 진행한다.
▶ 이 후 파라미터에는 "C://"를 넣고 GetDriveTypeA() 함수를 호출해서 돌아온다.
▶ 이 경우 EAX에는 위에 MSDN에서 나온 것과 같이 DRIVE_FIXED로 하드나 플래시드라이버를 의미하는 3이 저장된다.
▶ 이 값을 CD-Rom을 의미하는 5의 값으로 변경한다.
▶ 계속 다음으로 넘기면 조건문에서 비교 후 CD-Rom이라고 출력해준다.
-------------------------------------------------------------------
[2] GetDriveType( ) 함수의 파라미터 변경
▶ 0x401013에서 0x402094에 있는 값을 GetDriveTypeA( )함수의 파라미터로 사용하기 위해 스택에 저장한다.
▶ 0x402094에 이동해보니 "C:\" 가 저장되어 있다.
▶ 내컴퓨터는 D드라이브가 CD-Rom이므로 "D:\"를 의미하는 아스키코드 16진수 값으로 변경하였다.
▶ 메모리 내에서 변경된 것을 확인할 수 있다.
▶ GetDriveTypeA( ) 함수에 갔다오면 CD-Rom을 의미하는 5가 EAX에 반환된다.
▶ 계속 다음으로 넘기면 조건문에서 비교 후 CD-Rom이라고 출력해준다.
-------------------------------------------------------------------
[3] if(eax==esi) 문에서 비교하는 eax와 esi의 값을 강제로 일치시키도록 변경(단순)
▶ 이 로직대로 실행해보면 eax = [3, 2, 1]이 되고, esi = [0, 1, 2, 3]이 된다.
▶ 만약 eax에 반환 값이 5라면 eax = [5, 4, 3]이 되어 eax와 esi가 같게 된다.
▶ 증가와 감소가 끝난 후 cmp문 실행 전에 eax와 esi를 각각 0x100으로 동일하게 변경한다.
▶ 계속 다음으로 넘기면 조건문에서 비교 후 CD-Rom이라고 출력해준다.
-------------------------------------------------------------------
[4] if(eax==esi) 문을 if(eax != esi) 와 같이 반대로 변경하여 반대로 점프하도록 설정(단순)
▶ 0x401026의 명령어 je는 같은경우 CD-Rom이 맞다는 텍스트를 메세지박스에 출력한다.
▶ 그러나 이미 위에서 값이 같지 않기 때문에 je를 jne로 변경하여 같지않은 경우 맞다는 메세지박스를 출력하도록 변경한다.
▶ 여기서 중요한 것은 기계어코드를 살펴보면 74에서 75로 변경된 것을 알 수 있다.
▶ 즉 원래 기계어가 2바이트라면 명령어 변경시에도 2바이트짜리로 변경하여야 문제가 안생긴다.
▶ 그러지 않을 경우 OPCODE의 주소가 밀려서 문제가 발생한다.
▶ 문제가 발생하였다면 NOP를 넣어서 상대적으로 수정이 가능하다.
-------------------------------------------------------------------
[5] 출력부분의 문자열이나 주소를 교환(무식)
▶ 위와 같이 내부 문자열을 그대로 교환하거나 문자열의 주소를 교환한다.
▶ 결과만 필요한 경우 무식하지만 출력되는 내용을 바꿔서 출력하도록 할 수 있다.
8) 원본소스 가복원
<<Event_start>>
USER32.MessageBoxA(NULL,"abex's 1st crackme","Make me think ...",MB_OK);
<<Event_OK>>
eax = KERNEL32.GetDriveType("C:\")
esi = 0;
esi++;
eas--;
esi++;
esi++;
eax--;
if (eax == esi)
{
USER32.MessageBoxA(NULL,"YEAH!","Ok ...",MB_OK);
}
else
{
USER32.MessageBoxA(NULL,"Error","Nah....",MB_OK);
}
KERNEL32.ExitProcess();
9) C언어 코드 복구
#include<stdio.h> #include<Windows.h> int main() { int eax = 0; int esi = 0; MessageBoxA(NULL, "Make me think your HD is a CD-Rom", "abex' 1st crackme", MB_OK); eax = GetDriveTypeA("C:\\"); esi++; eax--; esi++; esi++; eax--; if (eax == esi) { MessageBoxA(NULL, "Ok, I really think that your HD is a CD-ROM! :p", "YEAH!", MB_OK); } else { MessageBoxA(NULL, "Nah... This is not a CD-ROM Drive!", "Error", MB_OK); } return 0; }
10) 복구한 C언어 코드로 실행
▶ 소스가 어느정도 복원 된 것을 확인할 수 있다.
11) 기타
▶ 그 외 여러가지 방법이 있겠지만 보통 문자열만 가지고 분석했을 때 변조 방법은 한정적이다.
▶ [1]과 [2] 방법은 API함수를 알고 있을 경우에만 사용가능한 방법이다.
▶ 같은 결과지만 변조방법을 5가지정도 예를 들었다.
▶ 현재 리버싱의 목적이 crack하는 것이 목적이라면 이렇게 할 이유는 없다.
▶ 그러나 배우는데 목적이 있다면 여러가지 방법을 시도하는 것을 추천한다.
'Try Attack > Reverse Engineering[basic]' 카테고리의 다른 글
[crackme3] abex' 3rd crackme 풀이 및 복원 (0) | 2018.11.08 |
---|---|
[crackme2] abex' 2nd crackme 풀이 및 복원 (0) | 2018.11.07 |
악성코드와 리버싱 (0) | 2018.10.09 |
전략 (0) | 2018.09.16 |
올리디버거 (0) | 2018.09.16 |
댓글