vbox 4.5 defeated - r2 (june 2001)
published by +Tsehp
Introduction:
Target: SoftQuad XMetaL 2.1 (http://www.softquad.com/products/xmetal/eval/download/sqxm21.exe)
SoftQuad, the makers of HoTMetaL, once again trust previewsystems and decide to use the new vbox 4.5
on their head product: XMetaL. is it a good choice? ofcourse no.
Protection: Previewsystem's VBox 4.5 30 days timelimit
VBox is a well-known software wrapper, you can get more infos on its features there:
http://208.240.131.116/products/vbox/download.html
(the trial version of vbox builder is unavailable.. guess why..)
Tools used: softice, procdump, import reconstructor 1.2 by MackT (optional)
First look:
Ahhh that good old VBox dialog popups everytime you run the program..
Vbox's dll are there.. and packed of course:
C:\Program Files\Common Files\Vbox\Common\vboxt.dll
vboxr.dll
vboxm.dll
vboxa.dll
vboxten-us.vboxlm
C:\Program Files\Common Files\Vbox\Licenses\XMetaL_2.1_B293.lic
XMetaL_2.1_B293.prf
now Vbox invokes 3 processes when its ran: 2x rundll32.exe (vboxr.dll), and vboxm.dll
Part 0.1: Resetting the trial period
It's been a total failure so far =( regmon and filemon didnt really help me..
i can only give you these few tips:
-the timetrial is stored somewhere in your C drive
-you can't kill the 2 rundll32 processes? suspend all their threads using a process tool like ATM,
then *kill*kill*
-deleting c:\program files\common files\vbox won't help
-uninstalling and deleting c:\program files\softquad won't help too
-deleting c:\windows\system\ws*.ocx doesnt work anymore
Part 1: Foreplay (getting the OEP)
First method:
This is pretty easy, if you've read the vbox 4.3 tut by Dezzy/DOD (hi and thanks =)
-run the app, dont click on the 'Open' button yet
-put a breakpoint on GetProcAddress
-now, click on the open button, softice will break
-disable your breakpoint, and press f12 (p ret) until you return from a 'CALL EDI'
(the first p ret can take some time, this is normal)
-put a bpm on this CALL EDI (bpm [address] x), then exit softice
-u'll break again, and this time trace into everything (F8) untill you reach
the entrypoint at 5B4865 (easy to find, it'll be some normal (non-selfmodifying) code)
Second method:
every heard of GetVersion? bpx on it, you'll be 10lines down the entrypoint..
this method is great, as long as you're sure the program will call that api, by example VB progs wont.
Ok, now u have your OEP (original entry point), dont dump the file yet, just put a 'bpm 5B4865 x'.
Part 2: Dealing with the fucked IAT
i tell you, im not an expert at unpacking.. im sure my method can be improved greatly
(with revirgin by example, ive just discovered it unpacks mangled IAT's. i couldnt find
out howto deal with it properly though)
***Note from +Tsehp
Actually, Revirgin in its latest version just fix everything very easily.
Here's what I used on win 2000 :
Oep : 0x5b002f
IAT start 0x407000 watch out this is RVA
Lenght 0xD10
ensure you already dumped the target, just select auto fix sections+ paste It not mangled IAT.
trace them and produce the IT.bin that will be auto pasted inside the dumped target, and it works.
I provided here the it.bin and traced iat's to check if you're not wrong.
The xmetal used was Version#: 2.1.3.099 (Unicode)
Important : absolutely no mangled iat were found on win2000 version...
regards,
+Tsehp
****
the first API call you have after the entrypoint is:
.005B488B: FF159CF48000 call d,[00080F49C]
80F49C points to the dword '00 00 60 02' <- will change at each execution of the vboxed app
a little look at the address 02600000 in softice will reveal a jump to 700EDDB (in vboxt.dll)
tho, this address wont exist if you dump the exe, you'll see some nice INVALID instructions all over the code window..
ok stop! lets see how the IAT looks like (its easy to notice it starts at 80f000):
00 00 F5 03-00 00 F6 03-00 00 F7 03-00 00 F8 03
00 00 F9 03-00 00 FA 03-00 00 FB 03-00 00 FC 03
00 00 FD 03-00 00 FE 03-00 00 FF 03-00 00 00 04
00 00 01 04-00 00 02 04-00 00 03 04-00 00 04 04
hmmm.. quite a lot of 0xxx0000 dwords (00 00 xx 0x), and they all point to the same thing: a CALL 700EDDB
this is what tsehp call a mangled IAT:
'the same iat entry can lead to several api addresses, it just depends from where the call was coming from.'
here's what the magic call does. lets trace it a bit, we'll notice some points:
017F:0700EDDB PUSH EBB
017F:0700EDDC MOV EBP,ESP ; EBP+4=02600000 (where we're coming from)
017F:0700EDDE SUB ESP,10
017F:0700EDE1 PUSH EBX
017F:0700EDE2 MOV [EBP-04],EAX
017F:0700EDE5 MOV [EBP-08],EBX
017F:0700EDE8 MOV [EBP-0C],ECX
017F:0700EDEB MOV [EBP-10],EDX
017F:0700EDEE LEA EAX,[EBP-10]
017F:0700EDF1 PUSH EAX
017F:0700EDF2 LEA EAX,[EBP-0C]
017F:0700EDF5 PUSH EAX
017F:0700EDF6 LEA EAX,[EBP-08]
017F:0700EDF9 PUSH EAX
017F:0700EDFA LEA EAX,[EBP-04]
017F:0700EDFD PUSH EAX
017F:0700EDFE CALL 0700EE15 ; does some magic stuff with EBP+4
017F:0700EE03 ADD ESP,10 ; EBP+4=BFF92F1B (GetVersion address)
017F:0700EE06 MOV EAX,[EBP-04]
017F:0700EE09 MOV EBX,[EBP-08]
017F:0700EE0C MOV ECX,[EBP-0C]
017F:0700EE0F MOV EDX,[EBP-10]
017F:0700EE12 POP EBX
017F:0700EE13 LEAVE
017F:0700EE14 RET ; where are we RET'n to? EBP+4 of course.
hmm.. this looks easy: the 700EE15 proc knows where the call is from, and it returns the good address in consequence.
you can exploit that! lets make the call return the good addresses for every 0xxx0000 dword in the IAT.
how? a dirty inline patch with softice ofcourse!
we'll need some space to put the patch.. lets 'bpm 700ed91 x' to see if the 700edxx proc uses this space.
no? good, this space between 700ed91 and 700eddb will be used to patch a IAT recovering proc.
lets make the proc looks like that:
017F:0700ED91 MOV EAX,[EBP+04] ; ebp+4=real pointer to the api's address now
017F:0700ED94 NOP
017F:0700ED95 MOV [EBX],EAX ; moving it to its place in the iat
017F:0700ED97 ADD EBX,04 ; go to the next dword
017F:0700ED9A MOV EAX,[EBX] ; eax now contains the fake iat entry
017F:0700ED9C CMP AX,0000 ; eax=xxxx0000, to check if its not a BFFxxxxx (ok) address
017F:0700EDA0 JNZ 0700EDBD ; ax doesnt have 0's? we dont need to fix that entry, its a real api already
017F:0700EDA2 CMP EBX,0080FC70 ; finished fishing?
017F:0700EDA8 JZ 0700EDC3 ; place to break
017F:0700EDAA CMP EAX,00000000 ; no need to decode 0's entries
017F:0700EDAF JZ 0700EDBD
017F:0700EDB1 ADD EAX,00000005 ; needed, the 700EDD0 proc wants that
017F:0700EDB6 NOP
017F:0700EDB7 MOV [EBP+04],EAX ; place the fake iat entry into ebp+4
017F:0700EDBA JMP 0700EDE1 ; lets go to the decode
017F:0700EDBC NOP
017F:0700EDBD MOV [EBP+04],EAX ; dont do anything with this good entry
017F:0700EDC0 JMP 0700EDD0 ; skip the decoding
017F:0700EDC2 NOP
017F:0700EDC3 NOP ; we'll go there when weve finished..
(place alot of NOP's there)
017F:0700EDD0 JMP 0700ED91 ; up! (c) r.e.m =)
017F:0700EDD2 NOP
(place more NOP's there)
017F:0700EDDB NOP ; we dont need the ebp/esp stuff anymore. btw we start here.
017F:0700EDDC NOP
017F:0700EDDD NOP
017F:0700EDDE NOP
017F:0700EDDF NOP
017F:0700EDE0 NOP
017F:0700EDE1 PUSH EBX ; iat decoding proc starts
*snap* leave this part unpatched
017F:0700EE12 POP EBX ; iat decoding proc ends
017F:0700EE13 JMP 0700EDD0 ; dont forget to make it loop =) but a straight jump to 700ED91 would make the
; instruction bigger than 2bytes..
017F:0700EE15 MOV EAX,07045630 ; yeah the api decoding proc starts here
when we're at offset 700EDDB, type this to initiate the IAT reconstruction at the right place:
:r ebx=80f000 ; IAT start
:dd ebx ; <- remember the value of the first dword
:e ebp+4 xxxxxx ; in place of xxxxxx, enter the value you had in *ebx (thats the first IAT entry)
put a 'bpm 700edc3 x', just to make sure the proc wont look for dwords after 80fc70.
lets goooo! exit softice and wait some milliseconds
..
uh oh
..
two 'VBOX Error UGC' messageboxes appear, then a windows interruption happens
hmm, thats not good, but lets check how the IAT looks like now
it doesnt contain the fake entries nemore! it seems that the patch did his work huh.
Part 3: Dumping and Fixing
where are we, now? in some windows api, just after a 'windows requested interruption'..
oh bah lets dump the exe anyway.
just type this in softice:
:a eip
then type 'jmp eip'
(yes i dunno why i did that in some unknown code, but oh well this freezes xmetal, and thats all i want)
fire up procdump, dump the exe, replace the entrypoint by 1B4865 (5B4865-400000=1B4865)
lets run the dumped exe.. and.. hmm.. pooof, it crashes shortly after the nagscreen.
why? the answer is at offsets 80f74c and 80f780: dwords 7000F587 and 7000F5F6.
these imports couldnt be fixed by our call, but they belong to vboxt.dll again.
by running the original vbox program again, we'll notice that:
:u 7000F587
017F:0700F587 CALL 0700F5A5
017F:0700F58C PUSH DWORD PTR [ESP+10]
017F:0700F590 PUSH DWORD PTR [ESP+10]
017F:0700F594 PUSH DWORD PTR [ESP+10]
017F:0700F598 PUSH DWORD PTR [ESP+10]
017F:0700F59C CALL [USER32!GetMessageA]
017F:0700F5A2 RET 0010
:u 7000F5F6
017F:0700F5F6 PUSH EBP
017F:0700F5F7 MOV EBP,ESP
017F:0700F5F9 CALL 0700F5A5
017F:0700F5FE PUSH DWORD PTR [EBP+18]
017F:0700F601 PUSH DWORD PTR [EBP+14]
017F:0700F604 PUSH DWORD PTR [EBP+10]
017F:0700F607 PUSH DWORD PTR [EBP+0C]
017F:0700F60A PUSH DWORD PTR [EBP+08]
017F:0700F60D CALL [USER32!PeekMessageA]
017F:0700F613 POP EBP
hmm.. these procs look familiar.
basically, its just another vbox trick that calls GetMessage or PeekMessage.
why? because these apis are called often, and decoding their real address all the time would dramatically reduce the speed of xmetal..
so, lets fix them manually: replace 87 F5 00 07 by the GetMessageA offset: 3D 57 F5 BF (BFF5573D)
F6 F5 00 07 by the PeekMessageA offset: 0D 58 F5 BF (BFF5580D)
great, now the dumped exe runs fine, and is not vboxed anymore.
tho, try running it on another windows.. hmm.. yes it wont work.
theres a simple solution to that:
-get a fresh dump of your program
(go to the oep, make a procdump dump, but dont fix the iat; then correct the oep of the dump)
-run your unvboxed app
-use mackt's Import Reconstructor to rebuild the imports of your fresh dump, from our clean unvboxed exe.
voila.
-r2