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.
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
|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 .|
|1b40-1ebf||strings table...all the strings set in the exe notice how they ARE unicode|
|1ec0-2ac0||looks like icon resource but dont hold me to it :P|
|2acc-2aeb||table 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 debugging..it 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__ipropTextEdityou 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.
|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 step...new function..step aghh see a call to VCAllHresult get__ipropTextEdit ...good its grabbing the textbox value...now 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
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 window...so 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 window..you 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 it...so 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 memory...next 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/ForVarok 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/NextStepVarok there is the end of the loop and where it sends us back to the top..so 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.
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.
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 function...so 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 it...so 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.
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 land....so there is going to be alot of things that i am quite foolish and flat out wrong about..such are the costs of learning!
 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.]