AHK2 연습장

2018. 5. 29. 05:180x02 Reverse Engineer/0x02. Reversing.kr

728x90

이 문제는 실시간으로 디버깅하면서 작성해보고 있다. 

문제를 풀게 되면 핵심만 추려서 다시 작성할수도..


바이너리를 열어보면 upx임을 알 수 있다. 


00471020 > $  60            pushad

00471021   .  BE 00104400   mov esi,AHK2.00441000

00471026   .  8DBE 0000FCFF lea edi,dword ptr [esi+0xFFFC0000]

0047102C   .  57            push edi

0047102D   .  89E5          mov ebp,esp

0047102F   .  8D9C24 80C1FF>lea ebx,dword ptr [esp-0x3E80]

00471036   .  31C0          xor eax,eax

00471038   >  50            push eax

00471039   .  39DC          cmp esp,ebx


00471BCB   .  61            popad

00471BCC   .  8D4424 80     lea eax,dword ptr [esp-0x80]

00471BD0   >  6A 00         push 0x0

00471BD2   .  39C4          cmp esp,eax

00471BD4   .^ 75 FA         jnz short AHK2.00471BD0

00471BD6   .  83EC 80       sub esp,-0x80

00471BD9   .^ E9 710FFDFF   jmp AHK2.00442B4F


upx 언패킹 부터 진행하였다.


UPX 언패킹 이후 문자열 검색을 통해 바이너리에서 로드 되는 경고문을 찾을 수 있었다.

00448273  |.  68 34E34500   push AHK2.0045E334                       ;  ASCII "EXE corrupted"

00448278  |.  E9 47110000   jmp AHK2.004493C4

0044827D  |>  8D45 30       lea eax,[arg.11]

00448280  |.  50            push eax                                 ; /Arg3

00448281  |.  8D45 64       lea eax,[arg.24]                         ; |

00448284  |.  50            push eax                                 ; |Arg2

00448285  |.  68 20E34500   push AHK2.0045E320                       ; |Arg1 = 0045E320 ASCII ">AUTOHOTKEY SCRIPT<"

0044828A  |.  8D8D B0FEFFFF lea ecx,[local.84]                       ; |

00448290  |.  895D 14       mov [arg.4],ebx                          ; |

00448293  |.  E8 078A0000   call AHK2.00450C9F                       ; \AHK2.00450C9F


메인 진입 점

00442CD4   .  50            push eax                                 ; |Arg1

00442CD5   .  E8 334A0000   call AHK2.0044770D                       ; \AHK2.0044770D


BP 건 위치 (여기서 STEP OVER 후 EXE Curruption이 떴기 때문)

004478AA  |.  83C4 0C       add esp,0xC

004478AD  |.  8BCE          mov ecx,esi

004478AF  |.  E8 CE8E0000   call AHK2.00450782


BP 건 위치 (이하 동일)

004507E1  |.  53            push ebx

004507E2  |.  FFB6 94040000 push dword ptr [esi+0x494]

004507E8  |.  8BCE          mov ecx,esi

004507EA  |.  E8 F179FFFF   call AHK2.004481E0


패치 해야 할 부분 찾음

00448263  |.  85C0          test eax,eax

00448265  |.  74 16         jmp short AHK2.0044827D                   ;  여기서 패치가 진행 되면 exe Curruption 안감

00448267  |.  53            push ebx

00448268  |.  D9EE          fldz

0044826A  |.  51            push ecx

0044826B  |.  51            push ecx

0044826C  |.  DD1C24        fstp qword ptr [esp]

0044826F  |.  FF75 74       push [arg.28]

00448272  |.  53            push ebx

00448273  |.  68 34E34500   push AHK2.0045E334                       ;  ASCII "EXE corrupted"

00448278  |.  E9 47110000   jmp AHK2.004493C4

0044827D  |>  8D45 30       lea eax,[arg.11]




위의 부분을 패치하면 Could not extract script from EXE라는 문자열이 출력되게 됨


또 다른 부분 패치

004507F2     /EB 04         jmp short AHK2.004507F8                  ;  PATCH jmp 004507f8

004507F4     |B5 00         mov ch,0x0

004507F6     |0000          add byte ptr [eax],al

004507F8  |. \53            push ebx

004507F9  |.  53            push ebx

004507FA  |.  53            push ebx

004507FB  |.  6A 67         push 0x67

004507FD  |.  8BCE          mov ecx,esi

004507FF  |.  E8 91ABFFFF   call AHK2.0044B395


또 다른 부분 패치

00450804  |.  85C0          test eax,eax

00450806      EB 04         jmp short AHK2.0045080C                  ;  PATCH

00450808      A1 00000053   mov eax,dword ptr [0x53000000]

0045080D  |.  53            push ebx                                 ; |Arg2

0045080E  |.  FF36          push dword ptr [esi]                     ; |Arg1

00450810  |.  8BCE          mov ecx,esi                              ; |

00450812  |.  E8 9AD6FFFF   call AHK2.0044DEB1                       ; \AHK2.0044DEB1

00450817  |.  85C0          test eax,eax

00450819  |.  0F84 8E000000 je AHK2.004508AD

0045081F  |.  FF35 847C4600 push dword ptr [0x467C84]                ; /Path = "F:\REVERSING.KR\AHK2\AHK2"

00450825  |.  FF15 68A24500 call near dword ptr [<&KERNEL32.SetCurre>; \SetCurrentDirectoryA


특정 바이너리를 이진으로 읽는 곳을 발견하여 여기로 jmp 해보았음

004508E6  |.  68 04010000   push 0x104                               ; /BufSize = 104 (260.)

004508EB  |.  50            push eax                                 ; |PathBuffer

004508EC  |.  6A 00         push 0x0                                 ; |hModule = NULL

004508EE  |.  FF15 0CA24500 call near dword ptr [<&KERNEL32.GetModul>; \GetModuleFileNameA

004508F4  |.  8D85 C4FEFFFF lea eax,[local.79]

004508FA  |.  68 1C654600   push AHK2.0046651C                       ;  ASCII "rb"

004508FF  |.  50            push eax

00450900  |.  E8 83E2FEFF   call AHK2.0043EB88


MessageBox로 추측

004493B5  |.  53            push ebx

004493B6  |.  51            push ecx

004493B7  |.  51            push ecx

004493B8  |.  DD1C24        fstp qword ptr [esp]

004493BB  |.  FF75 74       push [arg.28]

004493BE  |.  53            push ebx

004493BF  |.  68 E0E04500   push AHK2.0045E0E0                       ;  ASCII "Could not extract script from EXE."

004493C4  |>  E8 3C2EFFFF   call AHK2.0043C205                       ;  MessageBox


String을 좀 더 보다가 password를 발견하였다. 이 녀석을 잘 써먹으면 파일이 깨지는 곳을 알 수 있지 않을까 했다.

004307FC  |.  6A 08         |push 0x8

004307FE  |.  68 D8FE4500   |push AHK2.0045FED8                      ;  ASCII "Password"

00430803  |.  57            |push edi

00430804  |.  E8 3C1D0100   |call AHK2.00442545


무결성 검증으로 보이는 녀석을 찾았다.

004509A8  |> /8B0E          /mov ecx,dword ptr [esi]

004509AA  |. |F641 0C 10    |test byte ptr [ecx+0xC],0x10

004509AE  |. |75 28         |jnz short AHK2.004509D8

004509B0  |. |51            |push ecx

004509B1  |. |53            |push ebx

004509B2  |. |8D45 EC       |lea eax,[local.5]

004509B5  |. |53            |push ebx

004509B6  |. |50            |push eax

004509B7  |. |E8 71820000   |call AHK2.00458C2D

004509BC  |. |83C4 10       |add esp,0x10

004509BF  |. |8D8D C0FAFFFF |lea ecx,[local.336]

004509C5  |. |FF75 EC       |push [local.5]

004509C8  |. |E8 C8050000   |call AHK2.00450F95

004509CD  |. |FF45 0C       |inc [arg.2]

004509D0  |. |8B4D 0C       |mov ecx,[arg.2]

004509D3  |. |3B4D F8       |cmp ecx,[local.2]

004509D6  |.^\7C D0         \jl short AHK2.004509A8

004509D8  |>  35 AAAAAAAA   xor eax,0xAAAAAAAA                       ;  EAX결과 0bf0d5ee

004509DD  |.  3945 F0       cmp [local.4],eax                        ;  무결성검증


여기로 가야 할 것 같은데

00447ADC  /$  55            push ebp

00447ADD  |.  8BEC          mov ebp,esp

00447ADF  |.  83EC 78       sub esp,0x78

00447AE2  |.  53            push ebx

00447AE3  |.  56            push esi

00447AE4  |.  8BF1          mov esi,ecx

00447AE6  |.  8B86 A8040000 mov eax,dword ptr [esi+0x4A8]

00447AEC  |.  33DB          xor ebx,ebx

00447AEE  |.  3BC3          cmp eax,ebx

00447AF0  |.  57            push edi

00447AF1  |.  0F84 88010000 je AHK2.00447C7F

00447AF7  |.  3818          cmp byte ptr [eax],bl

00447AF9  |.  0F84 80010000 je AHK2.00447C7F



자고 일어나서 생각을 해보았다.


Unpacking에서 체크섬을 강제 패치 해도 잘 되지 않아 다른 방법을 모색하였다.

ORIGINAL 3DD40348D303B8E3A5DE8A44AC194732


UNPACK E36D7EB2E7119EF23F5203374540BC98


체크섬이 달랐다. upx를 unpacking하지 않고 디버깅을 시도해보았다.


00442CD5    E8 334A0000     call AHK2.0044770D 

여기에 접근해보았다.


잠시 기록해보고 싶은 것이 있어서 기록해본다.

00442BBC    8B3D 5CA24500   mov edi,dword ptr [0x45A25C]             ; kernel32.GetModuleHandleA

00442BC2    FFD7            call near edi

00442BC4    66:8138 4D5A    cmp word ptr [eax],0x5A4D

00442BC9    75 1F           jnz short AHK2.00442BEA                  ; PE 파일시그니처가 깨져있다면 여기로 분기


GetModuleHandle 함수는 해당 모듈에 대한 핸들 값을 반환해주게 된다. 


흐름을 따라 가다보니 .aut와 .exe를 push하는 부분을 보아서 확인 겸 적어둔다.

00447D9E    68 F4C44500     push AHK2.0045C4F4                       ; ASCII ".aut"

00447DA3    50              push eax                                        ; ".exe"

00447DA4    E8 59A7FFFF     call AHK2.00442502


정확히 무슨 기능을 하는지는 모르겠지만 복호화가 가능하기 때문에 주소 00457CF8에 bp를 걸어 우회했다.

00457CE0    8B01            mov eax,dword ptr [ecx]

00457CE2    BA FFFEFE7E     mov edx,0x7EFEFEFF

00457CE7    03D0            add edx,eax

00457CE9    83F0 FF         xor eax,0xFFFFFFFF

00457CEC    33C2            xor eax,edx

00457CEE    83C1 04         add ecx,0x4

00457CF1    A9 00010181     test eax,0x81010100

00457CF6  ^ 74 E8           je short AHK2.00457CE0

00457CF8    8B41 FC         mov eax,dword ptr [ecx-0x4]


이 부분도 강제 복호화 하였다.

00457CBC    8A01            mov al,byte ptr [ecx]

00457CBE    83C1 01         add ecx,0x1

00457CC1    84C0            test al,al

00457CC3    74 4E           je short AHK2.00457D13

00457CC5    F7C1 03000000   test ecx,0x3

00457CCB  ^ 75 EF           jnz short AHK2.00457CBC

00457CCD    05 00000000     add eax,0x0


흐름이 도무지 눈에 들어오지 않아 처음에 분석한 방식을 재 진행 해보았다.


EXE corrupted라는 문자열 근처의 함수에서의 반환 값 EAX가 루틴을 좌우하기 때문에 004508C7의 기능에 대해 알아보았다.

0044825E    E8 64860000     call AHK2.004508C7

00448263    85C0            test eax,eax

00448265    74 16           je short AHK2.0044827D                   ; jmp 패치 진행 되면 exe Curruption 안감

00448267    53              push ebx

00448268    D9EE            fldz

0044826A    51              push ecx

0044826B    51              push ecx

0044826C    DD1C24          fstp qword ptr [esp]

0044826F    FF75 74         push dword ptr [ebp+0x74]

00448272    53              push ebx

00448273    68 34E34500     push AHK2.0045E334                       ; ASCII "EXE corrupted"

00448278    E9 47110000     jmp AHK2.004493C4


8바이트에 대해 연산하는 부분이다.

00450917    8A88 14654600   mov cl,byte ptr [eax+0x466514]

0045091D    884C05 DC       mov byte ptr [ebp+eax-0x24],cl

00450921    8A88 0C654600   mov cl,byte ptr [eax+0x46650C]

00450927    884C05 E4       mov byte ptr [ebp+eax-0x1C],cl

0045092B    40              inc eax

0045092C    83F8 08         cmp eax,0x8                              ; 8바이트

0045092F  ^ 7C E6           jl short AHK2.00450917


이 부분이 체크섬 부분이라고 생각했다.

004509A8    8B0E            mov ecx,dword ptr [esi]

004509AA    F641 0C 10      test byte ptr [ecx+0xC],0x10

004509AE    75 28           jnz short AHK2.004509D8

004509B0    51              push ecx

004509B1    53              push ebx

004509B2    8D45 EC         lea eax,dword ptr [ebp-0x14]

004509B5    53              push ebx

004509B6    50              push eax

004509B7    E8 71820000     call AHK2.00458C2D

004509BC    83C4 10         add esp,0x10

004509BF    8D8D C0FAFFFF   lea ecx,dword ptr [ebp-0x540]

004509C5    FF75 EC         push dword ptr [ebp-0x14]

004509C8    E8 C8050000     call AHK2.00450F95

004509CD    FF45 0C         inc dword ptr [ebp+0xC]

004509D0    8B4D 0C         mov ecx,dword ptr [ebp+0xC]

004509D3    3B4D F8         cmp ecx,dword ptr [ebp-0x8]

004509D6  ^ 7C D0           jl short AHK2.004509A8




004509D8    35 AAAAAAAA     xor eax,0xAAAAAAAA                       

004509DD    3945 F0         cmp dword ptr [ebp-0x10],eax             ; 무결성검증

004509E0    75 37           jnz short AHK2.00450A19



[ebp-0x10] : 39A64194 


XOR 연산 후 EAX != [ebp-0x10] 

따라서 EAX를 [ebp-0x10]과 똑같이 패치 하였음 


그리고 jnz를 nop하여 우회해보았다.

004509D8    35 AAAAAAAA     xor eax,0xAAAAAAAA                       ; EAX결과 A15A7F44

004509DD    3945 F0         cmp dword ptr [ebp-0x10],eax             ; 무결성검증

004509E0    90              nop

004509E1    90              nop

004509E2    6A 00           push 0x0




곧바로 je가 만족하여 00450A19로 가긴하지만, CMP를 살펴보고 싶어서 NOP 처리하였다.

00450A00   /74 17           je short AHK2.00450A19 ->  NOP

00450A02   |33C0            xor eax,eax

00450A04   |8A4C05 CC       mov cl,byte ptr [ebp+eax-0x34]

00450A08   |3A4C05 DC       cmp cl,byte ptr [ebp+eax-0x24]

00450A0C   |75 06           jnz short AHK2.00450A14

00450A0E   |40              inc eax

00450A0F   |83F8 10         cmp eax,0x10

00450A12  ^|7C F0           jl short AHK2.00450A04

00450A14   |83F8 10         cmp eax,0x10

00450A17   |74 04           je short AHK2.00450A1D

00450A19   \6A 03           push 0x3




그러고 나니 cl과 [ebp+eax-0x24] 메모리의 값을 확인할 수 있었다.

00450A08    3A4C05 DC       cmp cl,byte ptr [ebp+eax-0x24]


Stack ss:[00871A88]=A3

cl=00


cl을 [ebp+eax-0x24]와 동일하게 바꾸어 보았다.


그 이후 ecx를 0x10(16번) 패치하였다. (Crackme푸는 방식을 적용) 

----------> 사실 상 이 루틴은 들어가지 않아도 되는 곳이었다. 쓸데 없이 jmp를 패치하니 이런 일이 벌어지는 것이다 ㅋㅋㅋㅋ 


그 다음 여기로 진입해보았다.

00450A19    6A 03           push 0x3

00450A1B    EB 18           jmp short AHK2.00450A35

00450A1D    FF36            push dword ptr [esi]

00450A1F    8D45 FF         lea eax,dword ptr [ebp-0x1]

00450A22    53              push ebx

00450A23    53              push ebx

00450A24    50              push eax

00450A25    E8 03820000     call AHK2.00458C2D


여기로 강제 점프 하면 eip가 1이 되어 터진다.

00450F16  /$  56            push esi

00450F17  |.  6A 00         push 0x0                                 ; /hTemplateFile = NULL

00450F19  |.  68 80000000   push 0x80                                ; |Attributes = NORMAL

00450F1E  |.  6A 03         push 0x3                                 ; |Mode = OPEN_EXISTING

00450F20  |.  6A 00         push 0x0                                 ; |pSecurity = NULL

00450F22  |.  6A 01         push 0x1                                 ; |ShareMode = FILE_SHARE_READ

00450F24  |.  68 00000040   push 0x40000000                          ; |Access = GENERIC_WRITE

00450F29  |.  FF7424 20     push dword ptr [esp+0x20]                ; |FileName

00450F2D  |.  FF15 0CA14500 call near dword ptr [<&KERNEL32.CreateFi>; \CreateFileA

00450F33  |.  8BF0          mov esi,eax

00450F35  |.  83FE FF       cmp esi,-0x1

00450F38  |.  74 18         je short UNPACK_A.00450F52

00450F3A  |.  FF7424 10     push dword ptr [esp+0x10]                ; /pLastWrite

00450F3E  |.  6A 00         push 0x0                                 ; |pLastAccess = NULL

00450F40  |.  FF7424 14     push dword ptr [esp+0x14]                ; |pCreationTime

00450F44  |.  56            push esi                                 ; |hFile

00450F45  |.  FF15 94A14500 call near dword ptr [<&KERNEL32.SetFileT>; \SetFileTime

00450F4B  |.  56            push esi                                 ; /hObject

00450F4C  |.  FF15 24A24500 call near dword ptr [<&KERNEL32.CloseHan>; \CloseHandle



띠로리... 도대체 어떻게 풀어야 한단 말인가~ 


'0x02 Reverse Engineer > 0x02. Reversing.kr' 카테고리의 다른 글

MetroApp  (0) 2018.05.30
Autohotkey2 완성  (0) 2018.05.30
CustomShell 풀기 전 공부 _ AVR  (0) 2018.05.27
HateIntel  (0) 2018.05.27
Reversing.kr WindowKernel 상세분석2  (0) 2018.05.05