Log in

View Full Version : How PEX 0.99 Redirects API's


Kayaker
April 27th, 2001, 23:36
Hi All,

Madmax!'s post made me dig up some old notes that I'll pass on if it can help anyone. You're right, Revirgin doesn't seem to handle what Pex does. But that's not why I'm writing. Pex .99 is actually a very interesting packer to study for anyone wanting to see an example of wtf a "redirected API" is, what with all this talk of it with Asprotect and such (you listening Clandestiny

I'll use the example of packing Win98SE Notepad with Pex 0.99 with the Import encryption option. The IAT start RVA is 4062e0 in the regular file, same in the packed file.

I'll actually be discussing what's happening in the packed file, but if you want to unpack it, what I did was to break into the Import encryption routine by setting BP's on pops and popads until I found it. There's probably a better way to do it using an API, I just kind of winged it through the code as I went along. I've found that *sometimes* pops and popads are like little stable islands in Self Modifying Code (SMC) that you can set breakpoints on. Actually, a quick way to get close to the OEP and bypass even the Import encryption routine is to break on VirtualFree. A few SMC runs with RET's after this is the jump to the OEP, where you can dump an unpacked file, albeit with corrupted IT, as usual.

:0040D03C 50 PUSH EAX ;4010CC for Notepad
:0040D03D C3 RET


Now comes the interesting part. Continue into notepad after unpacking. The 1st Call is at
4010d3 Call [4063e0]
If you display the contents of 4063e0, which is an address within the IAT, you see it points to 40d6d7. This is actually the concept of a "redirected" API. Normally this should point to the ASCII API name, but, well, it's redirected.

Go to 40d6d7 and there's an immediate jump to GetCommandLineA:
:0040D6D7 E9FEEEB7BF JMP KERNEL32!GetCommandLineA

This is the simplest situation, a direct jump. Now how do we know that the bytes E9FEEEB7BF jump to that API? If you add the effective RVA at the end of the 40d6d7 line, where the jump actually takes place from, with the offset in the bytes, you get the API address. i.e.
40d6d7 + 5 bytes = 40d6dc.
Add 40d6dc + BF B7 EE FE (reverse order) = BFFBC5DA = Address GetCommandLineA
E9 is just the opcode for far jump.

You can use Exescope for example on Kernel32.dll to confirm that BFFBC5DA is the start of the GetCommandLineA function.

...continued...

Kayaker
April 27th, 2001, 23:37
OK, on to the next Call in notepad.
401119 Call [406390] which addresses 40d4e8
Take a look at 40d4e8 and you see

:0040D4E8 EB01 JMP 0040D4EB (JUMP )
:0040D4EA AD LODSD
==> 0040D4EB 2BD2 SUB EDX,EDX
:0040D4ED EB01 JMP 0040D4F0
:0040D4EF AF SCASD
:0040D4F0 68041DFABF PUSH BFFA1D04
:0040D4F5 E9BAA2B6BF JMP BFF777B4

Now that's an ugly collection of bytes. The jump to the API is the last one and can be calculated the same as before.
40d4f5 + 5 bytes = 40d4fa
40d4fa + BF B6 A2 BA = BFF777B4 and jumps to GetStartupInfoA.

The only problem is that the real GetStartupInfoA is actually addressed at BFF777AD, 7 bytes earlier. What's happening? Well *some* of the jumps to API's in Pex actually have up to several lines run in program code instead of API code. If you look at the start of this API, you see where they would normally be run:

KERNEL32!GetStartupInfoA
:BFF777AD 2BD2 SUB EDX,EDX
:BFF777AF 68041DFABF PUSH BFFA1D04
:BFF777B4 64FF32 PUSH DWORD PTR FS:[EDX]


Notice the 2 "EB01" lines in the program code. This equates to "jump 1 byte", so you can see how the LODSD and SCASD lines are just pure garbage code and are never executed. Instead the SUB EDX,EDX and PUSH BFFA1D04 lines, which are the first 2 lines of the API code, are executed in program code, then the final jump is offset by the number of bytes already executed.

...continued...

Kayaker
April 27th, 2001, 23:40
This type of redirection is done throughout the code, generally only an EB01 is used in Pex .99, so it's simple to follow, but it could be anything. Here's another example, in this case the EB01 creates SMC, so you need to *read* the bytes, not the converted ASM line.


:0040D4FA EB01 JMP 0040D4FD (JUMP )
:0040D4FC 16 PUSH SS
==> 0040D4FD 57 PUSH EDI
:0040D4FE EB01 JMP 0040D501
:0040D500 17 POP SS
:0040D501 6A21 PUSH 21
:0040D503 EB01 JMP 0040D506
:0040D505 192B SBB [EBX],EBP
:0040D507 D2EB SHR BL,CL
:0040D509 011B ADD [EBX],EBX
:0040D50B 68671DFABF PUSH BFFA1D67
:0040D510 E90BA2B6BF JMP BFF77720 ;jump to API

But the real API address is at:

KERNEL32!GetModuleHandleA 
:BFF77716 57 PUSH EDI
:BFF77717 6A21 PUSH 21
:BFF77719 2BD2 SUB EDX,EDX
:BFF7771B 68671DFABF PUSH BFFA1D67
:BFF77720 64FF32 PUSH DWORD PTR FS:[EDX]


Cool huh?

...continued, I hate the message size limit...

Kayaker
April 27th, 2001, 23:41
Here's one more, with a bit more SMC. See if you can sort out what's important in these bytes in "encrypted" code and then see if that matches up with what would normally be done at the start of the API.

:0040D791 EB01 JMP 0040D794 
:0040D793 0F58EB ADDPS XMM5,XMM3 
:0040D796 0110 ADD [EAX],EDX
:0040D798 59 POP ECX
:0040D799 EB01 JMP 0040D79C
:0040D79B 115AEB ADC [EDX-15],EBX
:0040D79E 0112 ADD [EDX],EDX
:0040D7A0 6840800000 PUSH 00008040
:0040D7A5 EB01 JMP 0040D7A8
:0040D7A7 17 POP SS
:0040D7A8 6A00 PUSH 00
:0040D7AA EB01 JMP 0040D7AD
:0040D7AC 196A00 SBB [EDX+00],EBP
:0040D7AF EB01 JMP 0040D7B2
:0040D7B1 1B6A02 SBB EBP,[EDX+02]
:0040D7B4 EB01 JMP 0040D7B7
:0040D7B6 1D52EB011E SBB EAX,1E01EB52
:0040D7BB 51 PUSH ECX
:0040D7BC EB01 JMP 0040D7BF
:0040D7BE 1F POP DS
:0040D7BF 50 PUSH EAX
:0040D7C0 E95B82B4BF JMP BFF55A20

Real API:

USER32!LoadCursorA 
:BFF55A0F 58 POP EAX 
:BFF55A10 59 POP ECX
:BFF55A11 5A POP EDX
:BFF55A12 6840800000 PUSH 00008040
:BFF55A17 6A00 PUSH 00
:BFF55A19 6A00 PUSH 00
:BFF55A1B 6A02 PUSH 02
:BFF55A1D 52 PUSH EDX
:BFF55A1E 51 PUSH ECX
:BFF55A1F 50 PUSH EAX
:BFF55A20 E9B9B8FFFF JMP USER32!LoadImageA


Hope this was enlightening.

Regards,
Kayaker

beierno
April 28th, 2001, 00:45
Hi kayaker

Just to clear something up for me, but its not actually the redirected API calls that 'confuses' revirgin but more the adding of a offset to the API call or......
I'm on deep water
beierno

goatass
April 28th, 2001, 10:34
Kayaker, that was very cool thanks for that post it's very informative.

great job.

goatass

Clandestiny
April 28th, 2001, 10:58
Hiya Kayaker,

Many thanks for sharing your notes. I've already read it through a couple of times...and saved it on my hd for future reference

Cheers,
Clandestiny

Kayaker
April 28th, 2001, 12:47
Hi,

Hey, I'm glad people found the scheme used by Pex as interesting as I did. I forgot to mention there's an article on API hooking that discusses a somewhat similar redirection technique. A lot of people have probably been to this site before anyway, but there's some great articles here too:

API Spying Techniques for Windows 9x, NT and 2000
Yariv Kaplan

http://www.internals.com/articles_main.htm


BTW, I realize I was using the phrase RVA (Relative Virtual Address), when I 'spose VA would've been more accurate.

beierno, I can't answer your question because I don't know how Revirgin traces redirected calls. If I did know, I'd have to be killed anyway to protect the secret. So it's just safer if I don't even hazard a guess ^_^

Kayaker

madmax!
April 28th, 2001, 15:03
Well, understanding it is the "easy" part...Now its about unpacking it...I guess the only solution lies in customized unpacker for these situations..Unless you wanna fix all the "modified" API entries, but that could be cumbersome =P

madmax!

SplAj
April 29th, 2001, 04:14
Hi kayaker.

read your 'tut' with interest and I am sure Tsehp is 'heads down' as we speak .... I have not DL pex or tried it out yet, but my thought about using code to emulate 'part' of the API call is a little dangerous and not 'future' proof ? if Kernel32.dll changes slightly then the packed proggy passes incorrect parameters based on an old Win 95 API then who knows what the f*ck will happen. OR does this re-direction actually TAKE code from the beginning of the API and THEN emulate it so as always to be current ?

Just a thought before I have my morning coffe and I wake up ...duh }>

SplAj

Kayaker
April 29th, 2001, 06:15
Hi Splaj,

That's a darn good question to be asking before your morning coffee

Luckily Pex comes with source. I certainly don't profess to fully understand it, even after several coffees, but it appears to be an implementation of that Yariv Kaplan API hooking technique I mentioned. The compression routine itself is based on the APLIB compression library. The API redirection routine is down near the bottom of pex_loader.asm.

It does seem to read the first few lines of the API's while the file is mapped into memory. Apparently it uses the original IAT to get the API name, then GetProcAddress to get the function address. It seems to use internal 1 and 2 byte opcode tables to match valid opcodes with the API code.

At line 592 you can see where the EB01 + garbage byte are inserted into the code:

@fix_pointers:
push 3
pop ecx
mov word ptr[ebx],01EBh ; junk jmp $+3
mov byte ptr[ebx+2],al ; bogus byte
add dword ptr[ebp+@passed],ecx ; inc counter
add ebx,ecx ; inc pointer
_trash 0C7h

movzx edx,dl ; mask edx
add dword ptr[ebp+@passed],edx ; inc global counter
@copy_func_bytes:
mov cl,byte ptr[eax] ; copy bytes from
mov byte ptr[ebx],cl ; *eax to *ebx
inc eax ; increment pointers
inc ebx ;
dec edx ; decrement counter
jne @copy_func_bytes
jmp @next_opcode ; go to next opcode


I'm hoping someone can explain to me what the "_trash 0C7h" line means. The author uses "_trash" and "_junk" lines throughout the code, always tabbed over in the comments section. I've not seen this before, what does the underscore signify in MASM?

An interesting study in any case, there's BPX detection in there as well.

Kayaker

+SplAj
April 29th, 2001, 08:24
Greetz Kayaker,

I tried in vain to get pex.zip and nfo.zip from protools :-( -.......jeez I am as crap at web surfing as fishing for serials in crackmes even after my coffee !

Could you 'upload' these two zip files (only teeny size according to protoooooooools) as attachments here on the MB. I am sure Bart don';t mind !

TIA

SplAj

Kayaker
April 29th, 2001, 12:32
I'll try, but this board (not the other boards) has always kicked me out of being logged in when I post a message.

Even if it doesn't work, I just now got the file anyway from

http://www.suddendischarge.com/download.query?id=0x30A4141F

()whore
April 29th, 2001, 23:06
hello kayaker. Very nice, I even understood it which is the amazing part. But a little knowledge is a dangerous thing. Now for some strange reason I think I can trace through smc and understand it.