This version of PESpin is completly indentical as previous 1.3. There are no new things in this public version interesting for unpacking, because this version is out just for compability issues. But in previous tutorials there where no explanation for properly IAT fixing , just some tricks to run dump on user machine, so that part will be covered in this tutorial better.
1. Tools and stuff
Tools are usual:
- OllyDbg 1.10
- ImpREC
- LordPE
- Windows XP
- 
target is here
This tutorial will be short, so it would not be bad that you check previous ones which are more detailed.
2. OEP and stolen code
If you remember from past tutorials, last API that PESpin will use before jumping to OEP is GetTickCount. It will probably use it to get some random value, to destroy code/data that it doesn't need anymore. So we can place breakpoint at the end of that API (PESpin checks first bytes for CC bytes) and return to protectors code. So we are now very close to OEP jump. PESpin will use long jump to jump into original code section. So we can go to beggining of this PESpin section and search for bytes E9??????FF which corespond to long jump. Then we find all those possible jumps and first one that jumps in 401000 section is good one. I found this jump:
00417BC4  -E9 0F9AFEFF      JMP KeygenMe.004015D8
But PESpin also can stole some bytes from OEP, as said before. That stolen code is obfuscated, but it always start with POPAD opcode which is 61 in hexadecimal. So scroll up and search for this byte. You will find it obfuscated within call opcode:
00417AD8   E8 61F7D239      CALL 3A14723E
Patch first byte:
00417AD8   90               NOP
00417AD9   61               POPAD
Now place bp on POPAD , run and you will break there. There starts execution of stolen code, right after POPAD. But stolen bytes are obfuscated with junk code. It is not big problem to find it if we know that our target is Visual C++ program. Code obfuscation isn't hard and I can find exact bytes:
00417B36   55               PUSH EBP
00417B3A   8BEC             MOV EBP,ESP
00417B3F   6A FF            PUSH -1
00417B44   68 3482111F      PUSH 1F118234 <------------------ These 4 opcodes are just obfuscation of two PUSH.
00417B49   812C24 6421D11E  SUB DWORD PTR SS:[ESP],1ED12164
00417B50   68 48F020F7      PUSH F720F048
00417B55   810424 B03D1F09  ADD DWORD PTR SS:[ESP],91F3DB0
00417B5C   64:A1 00000000   MOV EAX,DWORD PTR FS:[0]
00417B65   50               PUSH EAX
00417B69   64:8925 00000000 MOV DWORD PTR FS:[0],ESP
00417B73   83EC 58          SUB ESP,58
00417B79   53               PUSH EBX
00417B7D   56               PUSH ESI
00417B81   57               PUSH EDI
00417B85   8965 E8          MOV DWORD PTR SS:[EBP-18],ESP
00417B8B   FF15 CDA44100    CALL DWORD PTR DS:[41A4CD] <---- Obfuscated API call!
00417B94   33D2             XOR EDX,EDX
00417B99   8AD4             MOV DL,AH
00417B9E   8915 5C764000    MOV DWORD PTR DS:[40765C],EDX
00417BA7   8BC8             MOV ECX,EAX
00417BAC   81E1 FF000000    AND ECX,0FF
00417BB5   890D 58764000    MOV DWORD PTR DS:[407658],ECX
00417BBE   C1E1 08          SHL ECX,8
00417BC4  -E9 0F9AFEFF      JMP KeygenMe.004015D8 <------ Not stolen, it's jump to false OEP.
And we can restore later those bytes. But these 4 ones:
PUSH 1F118234
SUB DWORD PTR SS:[ESP],1ED12164
PUSH F720F048
ADD DWORD PTR SS:[ESP],91F3DB0
with:
PUSH 4060D0
PUSH 402DF8
But all that is not necessery at all. We could just dump at this line:
00417B36   55               PUSH EBP
and dump would be good. Just OEP would be in PESpin section and not in first one.
3. Redirected code
If we execute OEP jump:
00417BC4  -E9 0F9AFEFF      JMP KeygenMe.004015D8
we will be in code section where we can see redirected code
004015EB   . E8 E8EBFFFF    CALL KeygenMe.004001D8
It is all well known from previous version. CALL leads to
004001D8  -E9 E6160000      JMP KeygenMe.004018C3
and that JMP just returns to some location. So CALL to PE header was in original file CALL to some address. 
Second redirection looks like this:
0040169E   .-E9 95EBFFFF    JMP KeygenMe.00400238
jumps to
00400238   68 FF000000      PUSH 0FF <--------------- This is redirected opcode.
0040023D  -E9 61140000      JMP KeygenMe.004016A3 <-- Returning back.
Jumps are substitution pushes.
There is new redirection that I didn't see in 1.3 version of PEspin:
00401687   $-E9 94EBFFFF    JMP KeygenMe.00400220
0040168C     90             NOP
0040168D     90             NOP
jumps to
00400220   833D 38764000 01   CMP DWORD PTR DS:[407638],1 <------ Redirected code.
00400227  -E9 62140000        JMP KeygenMe.0040168E <------------ Returning back.
And now I can write small script for OllyScrip plugn that can fix that code. See it in attachment. That script will work (it should) for all 1.x versions of PESpin.
Blocks of code that are decrypted during runtime, so called "clear and crypt markers" will not be discussed in this tutorial. Check last one for that.
And that is almost all. Just IAT is left to fix :)
4. Problem with IAT
This is not hard problem, but in previous tutorial I didn't have enough knowlege about ImpREC, PE structure, etc. First we need to see what happened with our imports and then we will think how to fix them. I was placing breakpoints on LoadLibraryA and GetProcAddress to catch where imports are being processed, but I found nothing. That means PESpin doesn't use use those api's to load libraries and find api's, instead it may have custom coded functions to do such job. Then I checked already loaded modules when target is opened in olly and sow that all needed dll's are already loaded by windows loader:
Executable modules
Base       Size       Entry      Name       File version      Path
00400000   0001C000   004160D4   KeygenMe                     D:\PESpin\PESpin v1.304\KeygenMe.exe
77340000   0008B000   773419ED   COMCTL32   5.82 (xpsp1.0208  C:\WINDOWS\system32\COMCTL32.DLL
77D40000   0008C000   77D53A05   USER32     5.1.2600.1561 (x  C:\WINDOWS\system32\USER32.DLL
77DD0000   0008D000   77DD1D3D   ADVAPI32   5.1.2600.1106 (x  C:\WINDOWS\system32\ADVAPI32.dll
77E60000   000E6000   77E7ADB3   kernel32   5.1.2600.1560 (x  C:\WINDOWS\system32\kernel32.dll
77F50000   000A7000              ntdll      5.1.2600.1106 (x  C:\WINDOWS\System32\ntdll.dll
78000000   00087000   78001E0D   RPCRT4     5.1.2600.1361 (x  C:\WINDOWS\system32\RPCRT4.dll
7F000000   00041000              GDI32      5.1.2600.1561 (x  C:\WINDOWS\system32\GDI32.dll
If I just run target in olly, no new module is loaded. That give us first possible answer why LoadLibraryA isn't used. Actually it is used couple times, but not for API redirecting purpose. GetProcAddress is also used couple times but not for our api's. So I tok another approach to save time tracing trough code.
Let's find OEP and see where first import jump leads. This is first import jump, ie. call:
00401605   . FF15 C8A44100  CALL DWORD PTR DS:[41A4C8]
we see that is points to PESpin section and not to 406000 which should be IAT one. Check dump at that address:
0041A4C8  4B 02 3B 00 00 6A 02 3B 00 00 8E 02 3B 00 00 A9  K.;..j.;....;..©
0041A4D8  02 3B 00 00 BD 02 3B 00 00 DD 02 3B 00 00 F9 02  .;....;....;....
0041A4E8  3B 00 00 11 03 3B 00 00 30 03 3B 00 00 48 03 3B  ;....;..0.;..H.;
...
We see that PESpin created table with pointers to 003B0000 section. Pointer dwords are separated with 0 bytes. That probably disturb ImpREC to get table, because pointers should be separated with zero terminating dword. And pointer leads to obfuscated api jump, or whole emulated api (if it's very small one, just one line):
003B024B   EB 01            JMP SHORT 003B024E
003B024D   D9A1 1476ED77    FLDENV (28-BYTE) PTR DS:[ECX+77ED7614]
003B0253   C3               RETN
It is easy to write small script for Olly that could rebuild new table, but we can remove obfuscation from import jumps. As easies option, I decide to place memory breakpoint on 003B0000 section so I could find place where PESpin writes obfuscated code there. Ok, bp on VirtualAlloc, and wait untill it allocates that section. Then memory bp on it. And I stopped here:
00416BCE   66:C706 EB01     MOV WORD PTR DS:[ESI],1EB
00416BD3   C646 02 D9       MOV BYTE PTR DS:[ESI+2],0D9
00416BD7   83C6 03          ADD ESI,3
00416BDA   2BD2             SUB EDX,EDX
00416BDC   EB 01            JMP SHORT KeygenMe.00416BDF
00416BDE   EA EB04EAEB 0400 JMP FAR 0004:EBEA04EB
...
...
PESpin writes here something. We are in part of code where obfuscation is in progress. If we remember from previous tutorial, this procedure starts with POPAD and ends with PUSHAD. Scroll up to find PUSHAD:
00416BAF   60               PUSHAD <----------------------- Yep, here it is.
00416BB0   EB 01            JMP SHORT KeygenMe.00416BB3
00416BB2  ^71 EB            JNO SHORT KeygenMe.00416B9F
00416BB4   04 D5            ADD AL,0D5
00416BB6   EB 04            JMP SHORT KeygenMe.00416BBC
00416BB8   6BEB FB          IMUL EBP,EBX,-5
...
...
We are very close to the end of our task, Place hardware bp on execution on that PUSHAD and restart target. Run it in Olly and you should break there. Ance again, in previous tutorial we sow that this procedure can be NOP-ed from PUSHAD to POPAD and we will kill obfuscation:
00416BAF   60               PUSHAD
00416BB0   90               NOP
00416BB1   90               NOP
00416BB2   90               NOP
...
...
...
00416C95   90               NOP
00416C96   90               NOP
00416C97   90               NOP
00416C98   61               POPAD
00416C99   C9               LEAVE
00416C9A   C2 0800          RETN 8
This code also isn't checked with integrity checks so we can just leave it. Now we find stolen code like described in first part of this tutorial (beware, GetTickCount is already used so you need find address of code before this step), and we restore it on right OEP:
00401591  /. 55             PUSH EBP
00401592  |. 8BEC           MOV EBP,ESP
00401594  |. 6A FF          PUSH -1
00401596  |. 68 D0604000    PUSH KeygenMe.004060D0
0040159B  |. 68 F82D4000    PUSH KeygenMe.00402DF8                   ;  SE handler installation
004015A0  |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
004015A6  |. 50             PUSH EAX
004015A7  |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
004015AE  |. 83EC 58        SUB ESP,58
004015B1  |. 53             PUSH EBX
004015B2  |. 56             PUSH ESI
004015B3  |. 57             PUSH EDI                                 ;  KeygenMe.004188EA
004015B4  |. 8965 E8        MOV DWORD PTR SS:[EBP-18],ESP
004015B7  |. FF15 CDA44100  CALL DWORD PTR DS:[41A4CD]               ;  kernel32.GetVersion
004015BD  |. 33D2           XOR EDX,EDX
004015BF  |. 8AD4           MOV DL,AH
004015C1  |. 8915 5C764000  MOV DWORD PTR DS:[40765C],EDX
004015C7  |. 8BC8           MOV ECX,EAX
004015C9  |. 81E1 FF000000  AND ECX,0FF
004015CF  |. 890D 58764000  MOV DWORD PTR DS:[407658],ECX
004015D5  |. C1E1 08        SHL ECX,8
Then we use script for fixing redirected code.
5. Fixing IAT
And now we can fix IAT. I wrote small script just for this VC++ app that will change all pointers to new tab. Example, this call:
004015B7  |. FF15 CDA44100  CALL DWORD PTR DS:[41A4CD]               ;  kernel32.GetVersion
will now point to new place
004015B7  |. FF15 90604100  CALL DWORD PTR DS:[416090]               ;  kernel32.GetVersion
and there I created new tab:
00416000  00 00 00 00 00 00 00 00 E0 56 D6 77 00 00 00 00  .........V.w....
00416010  1F 97 D4 77 00 00 00 00 1D 5F D4 77 00 00 00 00  ...w....._.w....
00416020  52 65 D6 77 00 00 00 00 52 65 D6 77 00 00 00 00  Re.w....Re.w....
00416030  52 65 D6 77 00 00 00 00 E4 D9 D4 77 00 00 00 00  Re.w.......w....
00416040  FE 65 D6 77 00 00 00 00 FE 65 D6 77 00 00 00 00  .e.w.....e.w....
00416050 >FE 65 D6 77 00 00 00 00 0F 6E D5 77 00 00 00 00  .e.w.....n.w....
00416060 >0F 6E D5 77 00 00 00 00 0F 6E D5 77 00 00 00 00  .n.w.....n.w....
00416070  93 5A E7 77 00 00 00 00 0C 16 E6 77 00 00 00 00  .Z.w.......w....
00416080  53 95 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00  S..w.......w....
00416090  95 D0 E7 77 00 00 00 00 AB E2 E7 77 00 00 00 00  ...w.......w....
004160A0  7E 17 E6 77 00 00 00 00 D9 AC E7 77 00 00 00 00  ~..w.......w....
004160B0  63 98 E7 77 00 00 00 00 25 E2 E7 77 00 00 00 00  c..w....%..w....
004160C0  7C 88 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00  |..w.......w....
004160D0  6B 15 F5 77 00 00 00 00 5F 8C F5 77 00 00 00 00  k..w...._..w....
004160E0  A1 16 F5 77 00 00 00 00 C5 AB E7 77 00 00 00 00  ...w.......w....
004160F0  6B 15 F5 77 00 00 00 00 C5 AB E7 77 00 00 00 00  k..w.......w....
00416100  0C E6 E7 77 00 00 00 00 B8 16 E6 77 00 00 00 00  ...w.......w....
00416110  63 98 E7 77 00 00 00 00 95 9B E9 77 00 00 00 00  c..w.......w....
00416120  FC AC E7 77 00 00 00 00 3B 95 E6 77 00 00 00 00  ...w....;..w....
00416130  E8 E4 E7 77 00 00 00 00 3B 95 E6 77 00 00 00 00  ...w....;..w....
00416140  2F E0 E9 77 00 00 00 00 7E 17 E6 77 00 00 00 00  /..w....~..w....
00416150  4E E3 E7 77 00 00 00 00 E7 E3 E7 77 00 00 00 00  N..w.......w....
00416160  4E E3 E7 77 00 00 00 00 A4 E2 E7 77 00 00 00 00  N..w.......w....
00416170  FC AC E7 77 00 00 00 00 E7 E3 E7 77 00 00 00 00  ...w.......w....
00416180  8D F0 E7 77 00 00 00 00 53 95 E7 77 00 00 00 00  ...w....S..w....
00416190  1B E0 E7 77 00 00 00 00 7F C9 E6 77 00 00 00 00  ...w.......w....
004161A0  7F C9 E6 77 00 00 00 00 4F A7 E7 77 00 00 00 00  ...w....O..w....
004161B0  4F A7 E7 77 00 00 00 00 1B E0 E7 77 00 00 00 00  O..w.......w....
004161C0  B1 E2 E7 77 00 00 00 00 B1 E2 E7 77 00 00 00 00  ...w.......w....
004161D0  6B 15 F5 77 00 00 00 00 A1 16 F5 77 00 00 00 00  k..w.......w....
004161E0  B4 D8 E7 77 00 00 00 00 D1 DD E7 77 00 00 00 00  ...w.......w....
004161F0  84 9F E7 77 00 00 00 00 84 9F E7 77 00 00 00 00  ...w.......w....
00416200  4F A7 E7 77 00 00 00 00 4F A7 E7 77 00 00 00 00  O..w....O..w....
00416210  D1 DD E7 77 00 00 00 00 D1 DD E7 77 00 00 00 00  ...w.......w....
00416220  D1 DD E7 77 00 00 00 00 9C A8 E7 77 00 00 00 00  ...w.......w....
00416230  E8 D8 E7 77 00 00 00 00 23 5D E7 77 00 00 00 00  ...w....#].w....
00416240  23 5D E7 77 00 00 00 00 B1 E2 E7 77 00 00 00 00  #].w.......w....
00416250  4F A7 E7 77 00 00 00 00 4F A7 E7 77 00 00 00 00  O..w....O..w....
00416260  E8 D8 E7 77 00 00 00 00 B4 90 E6 77 00 00 00 00  ...w.......w....
00416270  A1 16 F5 77 00 00 00 00 5F 8C F5 77 00 00 00 00  ...w...._..w....
00416280  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00416290  C2 25 E7 77 00 00 00 00 DE AF E7 77 00 00 00 00  .%.w.......w....
004162A0  44 0C F6 77 00 00 00 00 00 00 00 00 00 00 00 00  D..w............
004162B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00     ...............
Now we have thunks where every import value is separated with 4 zero terminating bytes and ImpREC can easily read this. Now we just run ImpREC and fix dumped file. Save file, run,..., yep, it works :)
It is not perfect work because thunks that belong to same dll should be sticked together which would reduce size of file, also we could remove PESpin section, but hey, now dump works on every machine :)
Greets and see you!