This tutorial is intended for getting people use to using and understanding WKTVBDE debugger as well as to introduce people to the world of VB6 P-Code byte patching. I am by no means an expert in its use here...i have only been able to find only one tutorial on using it ! This paper is an overview of my experimentation and discovery as I test theories and ideas and discover stuff. I am sharing it to help speed others along.

 By the end of this tutorial you will able to:

    The crackme I have created has tried to encompass as many testable variables as I could think of. it should also be at least kinda fun :D I have included an easter egg as well as numerous cracker traps :) dont worry all they do is show a "You Cheater" message :)

    If you dont know whats goign on...look at the source try to parallel what you are seeing in the debugger to what you see in the source...learn to identify bulky unnessary code and step over it or learn how to break outside of it.

    Hopefully this will help you understand and test your own apps better and raise the bar on what it will take for someone to break your programs. Note that the level of this tutorial is very basic. I am not concerned with creating strong verification routines or identifying CRC checks,learning to unpack compressed executables, or how to work across multiple code libraries. All of that comes latter :). Here the main emphasis is on acquainting the new user with the tools of the trade and giving them a foundation to understand code from the view of a debugger and the tools it presents to them.

    My own intrest in reverse engineering is rooted in deep intrest in how things work under the hood and to give me the ability to not only try to discover security flaws with software but also in giving me the ability / understanding to reverse malware and undo the damage caused by others.


  1. WKT P-code debugger (WKTVBDE)
  2. HexEditor of your choice (winhex is still my favorite)
  3. dzzies super duper lameorama crackme
  4. 50/50 Mix of curosity and bordom :P

The beginning

First thing we are going to look at is the overall file structure in our trusty hex editor...this is going to be a general overview and is only designed to show the types of things readily readable in our programs. This includes function names, literal strings, and function argument names. Latter in the debugger we will also see that all of our objects, forms, and classes are also plainly readable!

Afternote: its been about a year since I wrote this, since this time I have found some other really cool tools for analyzing vb apps and object layout, more articles and research to come in this area, for now, take this table below with a grain of salt

Address RangeDescription
0-116b MZ header, PE header this is code to load the exe and set it up in memory to run we dont have to deal with this at all...
116b-1670 table declaring all of forms objects, names, and inital values strange how it has full path to project file from compiling system in it.
1a4c-1a90 looks like table to all the functions in the app, notice names are in plaintext and are NOT unicode [1].
1b40-1ebf strings table...all the strings set in the exe notice how they ARE unicode
1ec0-2ac0looks like icon resource but dont hold me to it :P
2acc-2aebtable of all function arguments names
3ac4-3a3c VB import table - lists functions called from external dll's here just vb6 runtimes (I think that is what this is..note that this is NOT the PE import table)
41f0-4414 file version, author information
4988-58fb0 bitmap image held in a resource file (normally exe ends with fileversion junk unless a res file is used...if this was held in a picture box then it would have appeared in main body of program.
58fbe-58ffe string resource in resource file...notice where it starts..with the hex val 00 20 00 now count the characters in unicode saved string..there are 32..20h=32 see how VB adds a length counter to the beginning of the string? See my article on saving configured objects with memory dumps for more on this.
59000-58014 string resouce in res file #2..declared as 0A in length..yup ten characters

Ok now onto the debugging !


    a couple notes on WKTVBDB...after you install it make sure to also download the vb6 runtime they have on thier sight...put it in the install directory and rename it to its proper name (msvbvm60.dll) for some reason it doesn't seem to reliably find the system copy in %WINDIR%\system32 and it seems to like thier version better anyway.

    When you go to debug an app...make a copy of the app and place it in the WKT home directory...load that copy for seems to load more reliably that way.

and were off...

    After we have loaded up the exe and hit the execute button we are dumped right into the main program window. What has happened is that it has set a break point at the first instruction to be executed and the code window is what is waiting to for us to let it proceede. If there was no form load event defined then the programs main window would be all black and look like it wasnt working and the exe would popup. For programs like this WKT will break on the first event fired like a button press. Note that just the existance of Sub form_load in the source is enough to raise the event...even if contains no code! Also note that sometimes WKT will not break on the form_load event and the exe seems to be running outside of it...i have no idea why or how this happens...I just know that i have seen it.

So lets not worry whats going on in the form_load (because i bloated it up to make it a mess for us in the debugger :)\ so hit F5 (the GO button) and it will run on its merry way, initalize and show us the main form.

Now we need to find a place to break into the authorization routines to examine the code. Since there is both a check and a text box, we know the program must get the values of these before it starts its registration routines. We can set a break point where the debugger will halt execution on each of these respectivly with calls to the opcode for:

VCAllHresult get__ipropValueCheck VCAllHresult get__ipropTextEdit

you can set these breakpoints under the opcodes menu, general tab for the VCallHresult opcode VcallAd is probably also a good one in that it will show you which object is being accessed.

another trick is if we want to break on the event for say a button click..goto form manager, select form1..all used objects will highlight in button click on command ...this will fill the drop down list at the top with names of all the command buttons on the form. now select command1 and a new form will pop up...hit bpx and now a break point is set on that event

go back to the running app and click on the top command button (labeled easy)..the debugger will popup and you will be on the opcode FldRfvar <address> will be highlighted this must be the function call code (function loader f? variable?)

now to step through the code...

F8 Step Trace examine each and every call even going into other functions and subs that get called
F10 Trace Over examine each and every call but just run through subs and functions on own i dont want to see them
F12 Trace Ret run through all the code in the current function until it is ready to return
F5 Go just let the program run normally again until it hits another breakpoint

    ok lets step through the code with F8 so we can trace into each function we hit so lets say we want to find the text entered and where it is saved in memory... step step function..step aghh see a call to VCAllHresult get__ipropTextEdit ...good its grabbing the textbox where can we find it in memory?

    well right after the call to get__ipropTextEdit we see IldRF <address> my guess is this is telling it to save the data grabbed from the textbox and load it into this address..goto memory dump and enter the address shown and bingo there is the text from the textbox in a unicode string.

lets take a quick look at the "disassembly"

00402EFA: 0D VCallHresult get__IpropTEXTEDIT    #get the text from textbox
00402EFF: 6C ILdRf 00000000h                    #save it to this address 
00402F02: 08 FLdPr
00402F05: 8A MemLdStr                           #load string from memory (cant find though:(
00402F08: 30 EqStr                              #test for equality
00402F0A: 2F FFree1Str
00402F0D: 1A FFree1Ad
00402F10: 1C BranchF 00402F26 (Jump )          #if strings not equal then goto address
00402F13: 04 FLdRfVar 0012F5A8h			 

    note that the jump addr in the branch statements is the corrsponds to the addy you see in the code you can set breakpoints on that as well by address and can sometimes see what it will do..

    now since we know we entered the wrong registration code...and it shows it is going to jump how about we crack it? ok you twisted my arm ;) to patch code in memory step until you get to the actual branch statement. it shows it is going to jump..we dont want that so click the edit button and it will bring you to new will see the first code in the memory window is 1C this is the opcode for branchf (jump if false) well vb opcodes have no nop's to just remove the best we can do for now is to invert the jump so we want to change it to brancht whos opcode is 1D. (you can examine the opcodes in the set breakpoint dialogues as well as the WKT help file) so double click on that top line and a new dialogue will pop up and let you change the 1C to 1D. Hit the "Patchit!" button and close the memory window...hey look the command has now been changed to 1D BRANCHT :) note that the (Jump) may still be showing even though it changed...WKT doesn't seem to always update this but it shouldnt jump.

hit F8 and look no jump :)

now lets be brave and hit F5 (go) and look happy message! you have successfull cracked a very simple registration routine! (note that most shareware authors have very little knowledge about bit-toggling software and what resources are at crackers finger tips, so you will actually find alot of very simple routines in even commercial software):

ok so that was the easy one..and we only patched it in time you run the exe outside of the debugger it will work as normal and we still have no idea what the real registration is..

a) well why dont we permanetly patch it :D
b) i want to know what the real registration is!

a) patching the exe

    hop back in the debugger and step to the line where we patched it. see the file offset textbox next to the edit button? that is the raw file location this opcode can be found at. open up the exe in your hexeditor and goto that offset and hey that 1C sure looks familiar! thats right...just change it to the brancht opcode 1D and save and now any incorrect registration code will work.

b) finding the real registration

    i am sure there are alot of ways to do this i tried finding the string in memory with addresses given near and around the EqStr tests in the comparision routines but no luck :( so i am going to take another walk down research alley and bring you along for the ride.

start up the crackme in the debugger and land in the form load event.

so we get to stepping and find ourselves in a for i=1 to 500 loop !

004032D8: 28 LitVarI2 0012FA24h 1F4h , 500 
004032DD: FE Lead3/ForVar
ok ughh i dont want to step through all this 500 times so how do i skip it? i cant trace over because i am in the same proceedure....sooo ok lets step through the loop once and see where it ends.

0040332d: FE Lead3/NextStepVar
ok there is the end of the loop and where it sends us back to the how do we bypass it without having to trace through it all? easy..we just snag the next address to execute after the loop and set a breakpoint on it. click the "On execution" button, enter the address 403333 and click add you will see a red mark appear in the window next to the addy. now hit the go button and let it run through the loop.

bingo immediatly were dropped back in the debugger at the breakpoint.

so now how about finding that registration code....ok we see the command

LitVarStr "dont worry just testing"

a little further down we see ThisVCallHResult which means a function is about to be called...lets trace into this function and see whats going on...what has just happened is that a function has been called with "dont worry just testing" as its argument.

in the function you can see it does some real simple manipulations of the string you can probably figure it out from there (but only because its simple)...the first serial set is of variant datatype and for the life of me i cant find it in memory :( that kinda bugs me in time i will find it but for now i fail the variant test

so moving on keep tracing...we see another LitVarStr "yep still me testing" then we see a call to that same function...

 0040335A: 3A LitVarStr 'yep still me still    testing' # Literal String
Variable 0040335F: 4E FStVarCopyObj
0012F9E4h 00403362: 04 FLdRfVar
0012F9E4h 00403365: 10 ThisVCallHresult00402BEC->00402B88       # Call this function (step over it)	
0040336A: 04 FLdRfVar 0012F9D4h                        # think result saved here
0040336D: 60 CStrVarTmp
0040336E: 23 FStStrNoPop			                   # watch what happens here	
00403371: 08 FLdPr
00403374: FD Lead2/MemStStrCopy
00403378: 2F FFree1Str
0040337B: 36 FFreeVar -> 2
00403382: 13 ExitProcHresult                           #form_load ends here

    now we already know whats in that trace right up to it then when you are on it lets just step right over it with the F10 key. All the code in the function was still executed we just werent bothered by having to look through step step then look what happens when you get to FStStrNoPop...the serial pops up in the message window. WKT automatically tracks string data types for you on certain functions... you will be able to watch as strings are built up or returned..although i will still be damned if i know where to find them on my own..but there is the serial anyway.

From Here

    Ok we did the easiest example..the crack me still has 3 other levels, cracker traps and even an easter egg...I will be writing a tutorial on the observations i gleam from each of these levels as i go through them and discover new and better ways to crack through and gain more insight into the process. Until then you are on your own!


    working with the innerknowledge of whats going on behind the scenes is the only way to make sense of it with no documentation and having to experiment and learn from scratch What i am working for here is to try to glimpse a basic understanding of the innerworkings of things in a new and foreign there is going to be alot of things that i am quite foolish and flat out wrong about..such are the costs of learning! 


[1] Unicode string- aka wide char format - characters in teh ANSI character set range from 0-255 which can be represented by a single byte of data. Other character sets such as Chinese have more than 255 possible characters, to standardize support for these other languages an expanded format is used that allots a 2 byte segment for each character. these double wide slots when used with ANSI characters will always have the apperance of each character being seperated by nulls since the actual char will fit in the first byte. A typical hexdump of the string "Unicode" saved in Unicode format it will look like this:

55 00 6E 00 69 00 63 00 6F 00 64 00 65 00 [U.n.i.c.o.d.e.]