vbox 4.5 defeated - r2 (june 2001)

published by +Tsehp


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:
(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
C:\Program Files\Common Files\Vbox\Licenses\XMetaL_2.1_B293.lic

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#: (Unicode)

Important : absolutely no mangled iat were found on win2000 version...



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.