2018. 5. 29. 05:18ㆍ0x02 Reverse Engineer/0x02. Reversing.kr
이 문제는 실시간으로 디버깅하면서 작성해보고 있다.
문제를 풀게 되면 핵심만 추려서 다시 작성할수도..
바이너리를 열어보면 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 |