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