SVKP 1.32 - manually unpacking

Saturday, December 17 2005 @ 08:26 PM CET

Contributed by: haggar

Level : beginner

=====================
SVKP 1.32 - manually unpacking
=====================


Hi folks, this tutorial will describe unpacking of SVKP 1.32 version.

target is here :
http://www.reversing.be/binaries/articles/20051217202455291.rar


1. OEP

There is very easy way how to find OEP, olly can do it for us. In options, under SFX tab, set "Trace real entry bytewise (very slow!)" and just load exe in olly. After second or two, oly will stop on OEP:

00402259 C705 AC374000 00>MOV DWORD PTR DS:[4037AC],0
00402263 B8 01000000 MOV EAX,1
00402268 0FA2 CPUID
0040226A F7C2 00008000 TEST EDX,800000
00402270 74 0A JE SHORT unsafedi.0040227C
00402272 C705 AC374000 01>MOV DWORD PTR DS:[4037AC],1
0040227C 6A 00 PUSH 0
0040227E E8 33020000 CALL unsafedi.004024B6
00402283 A3 40B96000 MOV DWORD PTR DS:[60B940],EAX ; unsafedi.00402259
00402288 68 9C224000 PUSH unsafedi.0040229C
0040228D 6A 00 PUSH 0
0040228F 6A 67 PUSH 67
00402291 FF35 40B96000 PUSH DWORD PTR DS:[60B940]
00402297 E8 7A020000 CALL unsafedi.00402516
0040229C C8 000000 ENTER 0,0
004022A0 817D 0C 11010000 CMP DWORD PTR SS:[EBP+C],111
...
...





2. Imports redirection

Now we need to fix imports. Following first call at 40227E we will find import jumps:

0040249E $-FF25 B8C06000 JMP DWORD PTR DS:[60C0B8]
004024A4 $-FF25 BCC06000 JMP DWORD PTR DS:[60C0BC]
004024AA $-FF25 C0C06000 JMP DWORD PTR DS:[60C0C0]
004024B0 $-FF25 C4C06000 JMP DWORD PTR DS:[60C0C4]
004024B6 $-FF25 C8C06000 JMP DWORD PTR DS:[60C0C8]
004024BC $-FF25 CCC06000 JMP DWORD PTR DS:[60C0CC]
004024C2 $-FF25 D0C06000 JMP DWORD PTR DS:[60C0D0]
004024C8 $-FF25 D4C06000 JMP DWORD PTR DS:[60C0D4]
004024CE $-FF25 D8C06000 JMP DWORD PTR DS:[60C0D8]
004024D4 $-FF25 DCC06000 JMP DWORD PTR DS:[60C0DC]
004024DA $-FF25 E0C06000 JMP DWORD PTR DS:[60C0E0]
004024E0 $-FF25 E4C06000 JMP DWORD PTR DS:[60C0E4]
004024E6 $-FF25 E8C06000 JMP DWORD PTR DS:[60C0E8]
004024EC $-FF25 F0C06000 JMP DWORD PTR DS:[60C0F0]
004024F2 $-FF25 F4C06000 JMP DWORD PTR DS:[60C0F4]
004024F8 $-FF25 F8C06000 JMP DWORD PTR DS:[60C0F8]
004024FE $-FF25 FCC06000 JMP DWORD PTR DS:[60C0FC]
00402504 $-FF25 00C16000 JMP DWORD PTR DS:[60C100]
0040250A $-FF25 04C16000 JMP DWORD PTR DS:[60C104]
00402510 $-FF25 08C16000 JMP DWORD PTR DS:[60C108]
00402516 $-FF25 0CC16000 JMP DWORD PTR DS:[60C10C]
0040251C $-FF25 10C16000 JMP DWORD PTR DS:[60C110]
00402522 $-FF25 18C16000 JMP DWORD PTR DS:[60C118]

It is small target and there are just few imports. If you follow first jump you will see:

108875DC EB 01 JMP SHORT 108875DF
108875DE 93 XCHG EAX,EBX
108875DF 68 2C020000 PUSH 22C
108875E4 EB 01 JMP SHORT 108875E7
108875E6 98 CWDE
108875E7 68 60BEE977 PUSH 77E9BE60
108875EC -E9 AC3E6167 JMP kernel32.77E9B49D
...
...

Jump leads to allocated block where import is little emulated and obfuscated. In dump, we can see import table:

0060C050 46 C1 20 00 5C C1 20 00 6C C1 20 00 74 C1 20 00 F. .. .l. .t. .
0060C060 82 C1 20 00 96 C1 20 00 A4 C1 20 00 B2 C1 20 00 .. ... ... ... .
0060C070 C0 C1 20 00 D0 C1 20 00 DC C1 20 00 EA C1 20 00 .. ... ... ... .
0060C080 F6 C1 20 00 00 00 00 00 06 C2 20 00 14 C2 20 00 .. ....... ... .
0060C090 2A C2 20 00 38 C2 20 00 46 C2 20 00 52 C2 20 00 *. .8. .F. .R. .
0060C0A0 62 C2 20 00 76 C2 20 00 88 C2 20 00 00 00 00 00 b. .v. ... .....
0060C0B0 98 C2 20 00 00 00 00 00 DC 75 88 10 F1 75 88 10 .. ......u...u..
0060C0C0 FF 75 88 10 85 20 87 10 FC 33 87 10 09 76 88 10 .u... ...3...v..
0060C0D0 0E 76 88 10 1C 76 88 10 32 76 88 10 40 76 88 10 .v...v..2v..@v..
0060C0E0 52 76 88 10 60 76 88 10 72 76 88 10 00 00 00 00 Rv..`v..rv......
0060C0F0 77 76 88 10 8D 76 88 10 9B 76 88 10 A0 76 88 10 wv...v...v...v..
0060C100 A5 76 88 10 B3 76 88 10 B8 76 88 10 C1 76 88 10 .v...v...v...v..
0060C110 D7 76 88 10 00 00 00 00 E9 76 88 10 00 00 00 00 .v.......v......




3. Fixing imports

Imports can be fixed very easy too. First remove that tracing option in Olly, set it to "Stop at entry of self-extractor." and then restart target in olly. Then set bp on the end of GetModuleHandleA api and run:

77E7ACD9 > 837C24 04 00 CMP DWORD PTR SS:[ESP+4],0
77E7ACDE 0F84 37010000 JE kernel32.77E7AE1B
77E7ACE4 FF7424 04 PUSH DWORD PTR SS:[ESP+4]
77E7ACE8 E8 F8050000 CALL kernel32.77E7B2E5
77E7ACED 85C0 TEST EAX,EAX
77E7ACEF 74 08 JE SHORT kernel32.77E7ACF9
77E7ACF1 FF70 04 PUSH DWORD PTR DS:[EAX+4]
77E7ACF4 E8 27060000 CALL kernel32.GetModuleHandleW
77E7ACF9 C2 0400 RETN 4 <---------------------------- Bp here!!!

Remove bp and place now meory brekpoint on access to that import table in dump (below snippet). Jut select all bytes from 60C050 to 60C11C and place mem. bp. Then run.

0060C050 46 C1 20 00 5C C1 20 00 6C C1 20 00 74 C1 20 00 F. .. .l. .t. .
0060C060 82 C1 20 00 96 C1 20 00 A4 C1 20 00 B2 C1 20 00 .. ... ... ... .
0060C070 C0 C1 20 00 D0 C1 20 00 DC C1 20 00 EA C1 20 00 .. ... ... ... .
0060C080 F6 C1 20 00 00 00 00 00 06 C2 20 00 14 C2 20 00 .. ....... ... .
0060C090 2A C2 20 00 38 C2 20 00 46 C2 20 00 52 C2 20 00 *. .8. .F. .R. .
0060C0A0 62 C2 20 00 76 C2 20 00 88 C2 20 00 00 00 00 00 b. .v. ... .....
0060C0B0 98 C2 20 00 00 00 00 00 46 C1 20 00 5C C1 20 00 .. .....F. .. .
0060C0C0 6C C1 20 00 74 C1 20 00 82 C1 20 00 96 C1 20 00 l. .t. ... ... .
0060C0D0 A4 C1 20 00 B2 C1 20 00 C0 C1 20 00 D0 C1 20 00 .. ... ... ... .
0060C0E0 DC C1 20 00 EA C1 20 00 F6 C1 20 00 00 00 00 00 .. ... ... .....
0060C0F0 06 C2 20 00 14 C2 20 00 2A C2 20 00 38 C2 20 00 .. ... .*. .8. .
0060C100 46 C2 20 00 52 C2 20 00 62 C2 20 00 76 C2 20 00 F. .R. .b. .v. .
0060C110 88 C2 20 00 00 00 00 00 98 C2 20 00 .. ....... .


First break is where protector takes dword from table:

107D4D16 8B18 MOV EBX,DWORD PTR DS:[EAX]

Second stop is where it writes new pointer in table, this is point of our interest:

107D6D00 8907 MOV DWORD PTR DS:[EDI],EAX

You can remove mem. bp now.



We are at the place where new pointer is written. But check stack window:

0012FF74 0060C0B8 unsafedi.0060C0B8
0012FF78 0060C000 unsafedi.0060C000
0012FF7C 107B0000
0012FF80 0012FF94
0012FF84 0060C148 unsafedi.0060C148
0012FF88 00400000 ASCII "MZP"
0012FF8C 77E7B534 RETURN to kernel32.77E7B534 from kernel32.77E7A2F2
0012FF90 77E9B493 kernel32.OutputDebugStringA

In stack you can see what API is redirected, in this case it is OutputDebugStringA. We can change few bytes in protector code in order to trick protector. But we need little place for injection so I will just NOP couple junk opcodes to make space. Scroll up and check:

107D6CF7 EB 02 JMP SHORT 107D6CFB
107D6CF9 CD 20 INT 20
107D6CFB 58 POP EAX ; unsafedi.0060C0B8
107D6CFC EB 02 JMP SHORT 107D6D00
107D6CFE 0FE889 077C03EB PSUBSB MM1,QWORD PTR DS:[ECX+EB037C07]
107D6D05 03E9 ADD EBP,ECX
107D6D07 ^74 FB JE SHORT 107D6D04
107D6D09 61 POPAD

After patching junk code:

107D6CF7 90 NOP
107D6CF8 90 NOP
107D6CF9 90 NOP
107D6CFA 90 NOP
107D6CFB 58 POP EAX ; unsafedi.0060C0B8
107D6CFC 90 NOP
107D6CFD 90 NOP
107D6CFE 90 NOP
107D6CFF 90 NOP
107D6D00 8907 MOV DWORD PTR DS:[EDI],EAX

I will move POP EAX to the top and inject line that will give to EAX correct api from stack:

107D6CF7 58 POP EAX ; unsafedi.0060C0B8
107D6CF8 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C] ; kernel32.OutputDebugStringA
107D6CFC 90 NOP
107D6CFD 90 NOP
107D6CFE 90 NOP
107D6CFF 90 NOP
107D6D00 8907 MOV DWORD PTR DS:[EDI],EAX

And final touch, right click on 107D6CF8 line and select "New origin here", and injection is done.



To stop on OEP, go to 402259 and place bp there and run. When you break, check import jumps:

0040249E $-FF25 B8C06000 JMP DWORD PTR DS:[60C0B8] ; kernel32.OutputDebugStringA
004024A4 $-FF25 BCC06000 JMP DWORD PTR DS:[60C0BC] ; kernel32.CreateThread
004024AA $-FF25 C0C06000 JMP DWORD PTR DS:[60C0C0] ; kernel32.Sleep
004024B0 $-FF25 C4C06000 JMP DWORD PTR DS:[60C0C4]
004024B6 $-FF25 C8C06000 JMP DWORD PTR DS:[60C0C8]
004024BC $-FF25 CCC06000 JMP DWORD PTR DS:[60C0CC] ; kernel32.CloseHandle
004024C2 $-FF25 D0C06000 JMP DWORD PTR DS:[60C0D0] ; kernel32.CreateFileA
004024C8 $-FF25 D4C06000 JMP DWORD PTR DS:[60C0D4] ; kernel32.GetFileSize
004024CE $-FF25 D8C06000 JMP DWORD PTR DS:[60C0D8] ; kernel32.VirtualAlloc
004024D4 $-FF25 DCC06000 JMP DWORD PTR DS:[60C0DC] ; kernel32.ReadFile
004024DA $-FF25 E0C06000 JMP DWORD PTR DS:[60C0E0] ; kernel32.VirtualFree
004024E0 $-FF25 E4C06000 JMP DWORD PTR DS:[60C0E4] ; kernel32.WriteFile
004024E6 $-FF25 E8C06000 JMP DWORD PTR DS:[60C0E8] ; kernel32.GetTickCount
004024EC $-FF25 F0C06000 JMP DWORD PTR DS:[60C0F0] ; USER32.CharLowerA
004024F2 $-FF25 F4C06000 JMP DWORD PTR DS:[60C0F4] ; USER32.SendDlgItemMessageA
004024F8 $-FF25 F8C06000 JMP DWORD PTR DS:[60C0F8] ; USER32.MoveWindow
004024FE $-FF25 FCC06000 JMP DWORD PTR DS:[60C0FC] ; USER32.MessageBoxA
00402504 $-FF25 00C16000 JMP DWORD PTR DS:[60C100] ; USER32.LoadIconA
0040250A $-FF25 04C16000 JMP DWORD PTR DS:[60C104] ; USER32.GetWindowRect
00402510 $-FF25 08C16000 JMP DWORD PTR DS:[60C108] ; USER32.GetDesktopWindow
00402516 $-FF25 0CC16000 JMP DWORD PTR DS:[60C10C] ; USER32.DialogBoxParamA
0040251C $-FF25 10C16000 JMP DWORD PTR DS:[60C110] ; USER32.SendMessageA
00402522 $-FF25 18C16000 JMP DWORD PTR DS:[60C118]

Two API's are wrong !?! Last jump at 402522 is good, but those two at the begining lead to protector's code. What's the problem? SVKP uses another procedures for those two API's. I placed memory bp's on these two addresses and found that missing two API's are:

004024B0 .-FF25 0CF06100 JMP DWORD PTR DS:[<&kernel32.ExitProcess>; kernel32.ExitProcess
004024B6 $-FF25 10F06100 JMP DWORD PTR DS:[<&kernel32.GetModuleHa>; kernel32.GetModuleHandleA

Only thing that is left is to dump and rebuild imports with ImpREC. Dumped file is lot bigger than packed, it's data section is pretty big, author of app coded it like that so I will just leave it. But I removed SVKP secion, the last one.



This way of unpacking SVKP is maybe little dirty or lame, but I didn't wan't to waste too much time with it. I'm playing now with 1.42 which has some more tricks, but that will wait for new tutorial.



And that's all! See you :)



haggar

0 comments



http://www.reversing.be/article.php?story=20051217202658990