Fun with VRAMDIR v1.07
I first met VRAMDRIVE when I tryed using Micro$oft's own RAMDRIVE.SYS, which as always had
troubles in it, like: "Invalid DOS version and stuff...". So I searched the web for some new
RAM drive replacer and found this wonderfull tool.
It is especially usefull if you are working to much with many files, like the archives you
download from the web to check out, and you don't want to strain your harddrive. At the same
time you are getting higher perfomance and less fragmentation :) So I hope I made my point
about the usage of this program, so let's take a closer look at it...
The first interesting thing is that there is no installation program, just a simple
batchfile, which copies some registry updating files and merges them into the registry.
That's good, cause there is no "hidden" installation going on... only the things needed :)
This application consists of two main files: the control panel applet and the VXD driver.
The control panel applet is very simple and is only used for adding/deleting the RAM
folders. There is even no nag in it. The other thingie is much more advanced: a virtual file
system hooking VXD, which mapps the content of the directories into the memory and this way
it speeds up the disk access. The most wonderfull thing is that it resizes the used memory
according to the directory emptyness...Well other perfomance stats can be read in the README
file supplied with application.
The only nasty thing is that this is a demo, and it unloads itself from the memory in 30
minutes, writing all the virtual files to disk. So unless you want to boot ya machine at
1/1800 Hz (remember this number - "once every 1800 seconds, or 1800000 miliseconds" :) ,
you'll need it to reverse this program.
At first let me say that there would be used no live debugging at all. This can be explained
with the fact, that WinIce loads itself as a VXD, therfor it can't debug other drivers at
the boot time (correct me if I am wrong, but I tryed and failed). Therefor we'll only be
using the deadlist approach which I learned from +ORC's tutorials from Fravia's site :)
Try loading the vxd in the wdasm - you'll get some garbage without any x-refs and even
without the entry point !!! So I loaded it into my trusty ida (Grrrr...) Which unassembled
it pretty good. Many procedures were left as undiscovered, so it is recommended to mark them
manually. (Use the "C" to mark as Code, and then as a "P" for procedure).
When I first saw the deadlisting I was astonished how nice it was. I mean all instructions
are very clear and all intentions seem throw. It is a perfekt vxd learning material, the
only thing is the size of the asmfile - about 260 kb, which is too much to comment and see
through in one day. So I started to browse through all procedures, and almost forgot that I
was looking for the protection sheme. Then I had to interrupt myself and to continue the
standart "Register..." search :)
But now I know what I'd do on my school holidays - A nice garden chair, 2 liters of herbtea,
and 200 pages of vramdir asmcode to enjoy...
Suddenly I saw this:
aThisIsTheTrial db 'This is the trial version of VRAMDIR. The 30-minute trial period has
db 'From now on files will be written to disk. You',27h,'ll get another '
db '30-minute the next time Windows starts.',0Ah
db 'See README.TXT for information on how to get a registered copy.',0
This is easyer than it could have been. The following is just a standart "How I cracked that
I checked the reference where this string points to:
;here is the proc which snaps both message and then disables the virtual effect of a folder
SubTheNag proc near ; DATA XREF: SubMainEngine+483o
xor eax, eax
push eax <-- series of NULL pushes for the following call
mov ds:hTimeOutReturn, eax <-- Erases the handle to 30 minute timer
push offset aThisIsTheTrial <-- Message to show
push offset SubShowNagMsg <-- Sub to continue on, after the VXDJumpCall
call SubVJAtAppTime <-- Combination of the call and VXDJumpCall
mov ds:fNagOccuredFlag, 1 <-- Bool Flag which indicates if the program
add esp, 10h should begin writing virtual files to disk
;this proc is called by the SubTheNag, and it illustrates how VXD's use their vxdAPI
SubVJAtAppTime proc near ; CODE XREF: SubTheNag+13p
;After the jump, it returns to previously pushed location, in our case SubShowNagScreen
; we even prepared the offsets for it in the SubTheNag
;this proc is returned to after disabling the ramfolder and it shows a message
SubShowNagMsg proc near ; DATA XREF: SubTheNag+Eo
mov ebp, esp <-- Stack Frame, DUH
push offset aVramdir <-- A string "VRAMDIR"
push dword ptr [ebp+8] <-- 2 Params for the next call
call SubVGetCurVMhan <-- Again that funny call and jump iside the proc
call SubVSysModMsg <-- !!! SysModalMessage to show the nag
; 2 jumpprocs called in the abouve proc
SubVGetCurVMhan proc near ; CODE XREF: SubShowNagMsg+10p
mov ebp, esp
mov eax, ebx
SubVSysModMsg proc near ; CODE XREF: SubShowNagMsg+16p
mov ebp, esp
mov ebx, [ebp+8]
mov eax, [ebp+0Ch]
or eax, 1000h
mov ecx, [ebp+10h]
mov edi, [ebp+14h]
; The interesting thing is the use of the SHELL_SYSMODAL_Message to show the nagbox. This
type of messages is only used, when you write directly to the harddrive and other critical
Ok we've seen the nag showing routines, and the program-effect deactivation routines (I mean
the one where it disables it's virtual ramdrive effekt by setting a flag). If you want, you
can see where in other parts of the program this flag is used, and you'll see, that it is
only used in a CMP,JNE instructions.
But what about the priming routine, which activates the whole avalanche... Well after a
little more browsing around the code, I saw a very big and strange number: 1B7740 beeing
pushed on the stack. I tryed setting is as an offset but it responded with a BEEP :) I tryed
setting is as a relative offset... BEEP. (I am describing the wonderfull capabilities of
IDA). At last I pressed H to change the numberbase, and I got... 1800000. Then it struck me
1800000 msec = 1800 sec = 30 min !!! Well, here comes the code:
loc_20633: ; CODE XREF: SubMainEngine+45Fj
xor esi, esi
call sub_20868 <-- some crappy stuff
mov eax, ds:dword_784
push esi ; param ofs: 18h <-- NULL as a param
push offset SubTheNag ; param ofs: 14h <-- Sub to return to after the call
mov ds:dword_788, eax <-- some more crap, need mo tea
push esi ; param ofs: 0Ch <-- another NULL as param
push 1800000 ; param ofs: 08h <--- 30 min, AHHHH !
call sub_20B84 ; call ofs: 04h <-- Calls a sub and installs a systimer
mov ds:hTimeOutReturn, eax <-- saves it's handle
cmp eax, esi <--- check if successfull
mov eax, 1Fh <--- some param for the next proc
jz short lExitTheSub <-- if error on systimer, then bail out
push 0 ; stack ofs: 0Ch <-- more crappy params
push offset sub_1100E ; stack ofs: 08h <-- Sub to continue execution on
call sub_20B54 ; stack ofs: 04h <-- after this Nice guy sub
xor eax, eax
lExitTheSub: ; CODE XREF: SubMainEngine+24j
;As you can see here it uses that strange technique again: pushing the offset of another sub
to return to, instead of a normal jump. 8-}
;here is the sub which calls another one to instal a system timer
sub_20B84 proc near ; CODE XREF: SubMainEngine+493p
push ebp ; stack ofs: 00h
mov ebp, esp
mov esi, [ebp+14h] <-- Some crap for the sub which handles some local vars
mov eax, [ebp+10h]
mov edx, offset word_1AB4
push offset sub_20BA2 <-- Push'n'continue technique
; there has just been pushed offset of the sub which instals the timer. It would be executed
after the following jump to a proc returns.
jmp ds:off_20B9E <-- Jump to a strange local variable handling sub
;timer installation procedure
sub_20BA2 proc near ; DATA XREF: sub_20B84+Fo
mov eax, [ebp+8] ; timeout in msec (18000000)
mov edx, [ebp+0Ch] ; null
mov eax, esi
;the previous proc loads the registers from the stack and sets a system timer, which returns
a timer handle in the ESI. Which is fast loaded into the EAX and returned to the first
listing higher up on the page.
That way is the protection sheme reversed, just like any ordinary win proggy.
(actually we were lucky that the programmer didn't use some crazy encryption and stuff,
cause vxd's run at the ring 0, where everything is allowed !
I leave the actual patching for you. There can be done several patches, try patching
everything in one place :) I myself patched it in two places.
HINT 1: That system timer installation is quite unnessesary in our purpose...
HINT 2: It must also return a valid handle from the Set_Global_Time_Out, probably not NULL
PS: Where to find some documentation about those vxdcalls ? This can be an interesting
project for +HCU. ("Reversing the secrets of vxdapi")
The fully disassembled and partly commented by me deadlisting can be downloaded from here.
Free web-based email, Forever, From anywhere! http://www.mailexcite.com