Patching VB Applications Using Olly
By: Shub-Nigurrath /ARTeam
http://cracking.accessroot.com

A discussion around DockLight using some tricks to patch

The Target:
Docklight 1.6.8
The Tools:
Ollydbg 1.10
The Protection:
serial check

Other Information:
This tutorial will cover some basic techniques which you can use to approach VB apps, as well as other programs based on languages not easily disassembled by OllyDbg's engine (e.g.Delphi). I will apply the approaches to an example application (DockLight) and I will also present a little how to use P32Dasm in conjunction with OllyDbg.

Best viewed in Firefox at 1280x1024

1. Introduction

What we will cover here is a number of approaches to handle VB apps, using Olly.

VB apps are a little strange for those of you accustomed to C/++ world, due to their "non linear" nature and due to the fact that the call stack is of no usage for Olly users, because the application is continuously inside the VB specific language dlls. This behaviour is common to all those applications using a common language specific dll, such as VB.

We will cover how to use Olly to find the correct point where to patch, how to improve disassembled code readability using P32Dasm [1] and MapConv [2] to import MAP symbol files into Olly. The usual approach using Point-h [3] or Point-A [4] is not workign here, due to several problems the application poses. I will use a (classical indeed) trick involving the application's stack to rebuild the calls sequence.

have phun.

 

 

1. The Victim Application

http://www.docklight.de/ version 1.6.8
also available at: http://www.intechhosting.com/~access/ARTeam/tools/Docklight_168.zip

What it is:
Docklight is a test, analysis and simulation tool for serial communication protocols (RS232, RS485/422 and others. It allows you to monitor the communication between two serial devices or to test the serial communication of a single device. Docklight is easy to use and runs on almost any standard PC using Windows 98/NT 4/2000/XP operating system.
 

 

2. Attacking the application

If you launch PEiD you will easily see that the application is written with VB6 and it's not compressed with a packer. A simple situation then.

Some immediate remarks: method using Point-H doesn't work neither the method called Point-A works. Respectively this happens because the serial is not compared with the way hypotized by Point-H and because the Point-A makes the application stopping too much times, following to interface refresh, making it impossible to obtain anything meaningful. For those of you not knowing these two methods I suggest the two reading in References section below, otherwhise leave them for another occasion, because you will not use them here ^_^

The patch consists simply in finding misleading jmps and then modifiyng them to let the program act as registered.

This tutorial will not give you a complete patch, because its scope is to teach you to reverse applications and not to specifically crack this victim. So you will have to complete the crack on your own if interested or better to buy the application.

 

 

3. Inspecting the protection & limits

Keep the things clean and tidy and start from the beginning, looking at how the program is limited and protected.

The limits are: the DockLight Licence Registration which asks for a registration number and several Nags popping out when you try to use a disabled function such as "Save As".

 

We want to eliminate those limits, but unfortunately the application has been written using another language (VB) for which Olly was not thought to play. OllyDbg is a debugger for compiled languages and works better with languages such as C/C++. VB Applications are fully compiled applications (not relying on a virtual machine such as Java or .NET apps), but have a specific behaviour which get things complicated with Olly.

 

 

4. Some basic concepts about VB apps

Rather than being exaustive, but willing to clarify the approach used here, I would specify some things of VB. All VB programs relies on an external Dll (MSVBVM60.DLL for VB version 6.0 and similar dlls for the other versions, all before VB.NET) which implements all the language APIs and also the event dispachers: the result is that a VB app takes almost all its time inside this Dll or generally goes into it and out of it very frequently. This is a by-design behaviour: being VB a very high language all the VB APIs are implemented into MSVBVM60.DLL. The only thing, almost, that the application owns are the events handlers, used as callbacks from the VB Dll to answer to specific events/messages. The rest of a compiled VB application are the resources, the variables and the functions used to associate events-handlers. The Point-A method [4] just uses a specific point into the MSVBVM60.DLL where the application exits from the Dll to call the application own event handler, using a CALL EAX (where EAX points to the resolved handler).

By default, applications created in Visual Basic are compiled as interpreted or p-code executables. At run time, the instructions in the executables are translated or interpreted by a run-time dynamic-link library (DLL) [6]. When used, the p-code engine is a relatively simple machine that processes a series of "high-level" operation codes ("opcodes"). It is stack-based, meaning that it uses the system stack for virtually all its operations. In contrast, an actual microprocessor uses registers for most of its operations and uses the stack primarily to perform function call mechanics. All operands used by p-code instructions are stored on the stack.

This behaviour looks very efficient by the language point of view (look also at [6]), because VB programmers essentially will not worry about a lot of things, focusing instead on the specific applications' events and behaviours. But this thing results into a problem for OllyDbg , because the call stack (Alt-K) will not be able to give meaningful answers.

For example this is the EP of the application:

004055EC > $ 68 78594000 PUSH Dockligh.00405978 ; ASCII "VB5!6&*"
004055F1 . E8 EEFFFFFF CALL <JMP.&MSVBVM60.#100>
004055F6 . 0000 ADD BYTE PTR DS:[EAX],AL
004055F8 . 0000 ADD BYTE PTR DS:[EAX],AL
004055FA . 0000 ADD BYTE PTR DS:[EAX],AL
004055FC . 3000 XOR BYTE PTR DS:[EAX],AL
004055FE . 0000 ADD BYTE PTR DS:[EAX],AL
00405600 . 70 00 JO SHORT Dockligh.00405602


where CALL <JMP.&MSVBVM60.#100> points to an entry in the Import Table:

004055E4 $- FF25 80124000 JMP DWORD PTR DS:[<&MSVBVM60.#100>] ; MSVBVM60.ThunRTMain

which is the main function of the program, not causally inside the MSVBVM60 dll. But, rather than reversing how the VB Dll works, we would concentrate on the application.

There are other interesting caracteristics of VB apps which we will use:

  • The forms (application's dialogs) are stored all the times with a given format, that must be the same for all the VB apps. This is because the VB engine which draws the dialog, delivers the events and knows the event-handler map, and thus must know in advance where to take information required to build the dialog.

For example search along the application the string "frmLicence" you will land here

Th name of the form is always where the form data starts, following there's the dialog caption's string, local and control variables (DD Dockligh.00433F80) sometimes also containing preassigned strings,  resources.
The interesting thing is that the event handlers are registered into tables, like the import table, where all the handlers are mapped:
 

These maps are referenced by stored variables into the executable, such for example 0040B898 /18BC4000 DD Dockligh.0040BC18 for the previous example.
Beside these local handlers there are also some fixed parts which invoke those functions responsible to call the correct handlers and the events sinks of the form, for example:

0040B86C \10B24000 DD Dockligh.0040B210
0040B870 88AF4000 DD Dockligh.0040AF88
0040B874 A8554000 DD <JMP.&MSVBVM60.EVENT_SINK_QueryInterface>
0040B878 AE554000 DD <JMP.&MSVBVM60.EVENT_SINK_AddRef>
0040B87C B4554000 DD <JMP.&MSVBVM60.EVENT_SINK_Release>


This is an optimal space where to inject your code if you need to alter the form behaviour, changing for example the form related event handlers maps. See for a much more complete tutorial on this subject the document [9], even if in Spanish, it's comprehensible thanks to several screeshots.

  • The forms have names starting with frmXXX
     
  • Almost all the calls are relative to the stack (ESP or EBP) or use some register (EAX, EBX, EDX), direct calls are very rare and often for sub specific tasks. This happens because the real function to call are calculated at runtime by the VB engine (inside the Dll), using all the information read from the form initialization data. The stack relative calls are also used often as an optimizazion used by VB compilers. This makes the code much more difficult to read.

This makes difficult to rebuild the call stack, the path the application took to get into a specific place.

For example, try placing a BP at this address: 0048C07C . C745 88 10E74100 MOV DWORD PTR SS:[EBP-78],Dockligh.0041E710 (why, will be clear later), The application stops when you press register.
Now look the call stack:

it doesn't contain a single reference to our application, everything happens inside MSVBM60! Moreover following the call stack and the names of the called VB APIs you can easily follow what I just told you.

But, as usual there's a trick I will teach to solve the situation more faster..

 

 

5. Finding HOW to patch the application

Just to get hands on start trying to force the application to accept any serial you like, popping you the good boy message.

Our target now is to force the application to accept any serial, just in case it would be useful. The target is to drive the application to the good boy message. The method is to find the string which is used by the Nag as text of the caption bar and place at that address a Memory BP on Access. From what I told you before it should be clear that that information is read from the form builder inside the VB Dll and used to create the dialog.

Now run the application with F9 and wait till it stops at the placed BP.

Pay attention in the lower side of Olly where messages are reported, that must appear the message "Memory breakpoint when reading [...]" and not something else such as an undhandled exceptions messages.

When the application stops you will have to look at the data stack window (lower righ usually), scrolling it down till you see something as Return to DockList.12314 that's the return address where the whole sequence of VB calls has started.

For example search the string "DockLight License Registration" you will find it at 004328C3.

Usually these strings are splitted into several lines, so you can find situation such:
004328C3 . 44 6F 63 6B 6C 69 67 68 74 >ASCII "Docklight Licens"
004328D3 . 65 20 52 65 67 69 73 74 72 >ASCII "e Registration",0

with these cases you will have to search for single words.

At this point place a Memory Breakpoint on Access at 004328C3 and press F9 to run the application.

When you stop you will see in the data stack that the call stack (alt-K) is absolutely useless, but also that there are a lot of returning addresses in the call stack (Olly marks them in red):

Olly mark them in red, also reporting the Activation Record for the calls. What you have to do is to scroll the data stack window down till you see a return addresss into the main application such the following:

0012FC7C |004413F4 RETURN to Dockligh.004413F4

Go at the address 004413F4 and you will see this:

004413EE . FF97 B0020000 CALL DWORD PTR DS:[EDI+2B0]
004413F4 . 85C0 TEST EAX,EAX ; Dockligh.004328C3


The return address is the instruction just after the call which lead the program where we are now. The call you should look to is then the call just an instruction above the return address at 004413F4.

So reasuming we stopped when the VB framework tried to read the string "DockLight License Registration" because of the call at 004413EE. That call is then the original place where the application decided to create the Registration dialog.

Go there and you are done (for this little exercise): search the JMP which allows to skip the whole section of code, which in this case is at 00441367.

00441367 . /E9 A0000000 JMP Dockligh.0044140C ;PATCH 1
0044136C |90 NOP

The initial dialog is nomore called. But this is not a patch indeed, it was just an exercise..

Why this worked?
The trick worked because there are some specific limits to the call stack analysis Olly does and VB apps are just a little forward it. There are too much going into and out of the VB dll which confuse Olly. Anyway the program works and if you know how function call works you should know that all the return data are on the data stack, it's just a matter of finding them. We did just this, looking directly where the return addresses are stored.

 

Using the 2B0 trick
There's another emphyrical trick you can use to find where any nag is created. Use the 2B0 Trick. This was first introduced into a tutorial from CrackLatinos written by CoCo [8] and consists of a simple constant behaviour the VB programs have when a new dialog is being created before displaying it.

The trick consists of:

  • At the program's EP search for all constants in the program and enter 2B0 as constant:

you will find something like the following:

  • Place a BP on all the CALLs you found, surely one of them will be responsible of creating the nag you want to eliminate:

  • Now run the application and wait till it bangs into one of the BP you placed. For this specific case, the initial nag appears after having created the main program's window, so you your is simply the one on which OllyDbg stops after the main program's window is visibile into the application's taskbar.
    It is at:

004413EE FF97 B0020000 CALL DWORD PTR DS:[EDI+2B0] ; MSVBVM60.Adjustor172

If you go backward reading above, you should easily see that this is exactly the same point where we stopped using the data stack trick! The two methods are just equivalent.

 

6. Finding WHERE to patch the application


What we undestood till now is that the VB apps work a little different than usual, that the call stack is useless and why and we also found a way to overcome these limits.

The Memory Breakpoint on Access and the data Stack trick is used all along the application and you will have to similarly fix also the other limits as well.

I will start slowly to let you test what you learnt and will skip forward the remaining patches to complete the patch.

Patch to enable the disabled function
You learnt how to work to find where the nag is called from the program. For the disable functions (start trying to call Sae As) search the string "Evaluation Limit" and act as before.

The routine at:

004427A0 $ 55 PUSH EBP

shows the nag responsible of the "Evaluation Limit". If you analize this call with OllyFlow, or with IDA, you will discover that there's no way out in patching this routine to not show the nag: it's a one way function, so the patch must be in the caller. Go and see where this function is called then.

This time we can use normal methods for Olly, then use CTRL-R to find references to this call

References in Dockligh:.text to 004427A0
Address Disassembly Comment
004427A0 PUSH EBP (Initial CPU selection)
0046D63B CALL Dockligh.004427A0
0046D7C5 CALL Dockligh.004427A0
0047740C CALL Dockligh.004427A0
00482962 CALL Dockligh.004427A0
00482DB5 CALL Dockligh.004427A0
004852D6 CALL Dockligh.004427A0

If you analyze a little you will easily discover that the calling schema is always the same:

call function
...
test
JMP conditional which skips the function

For example this is the situation for Save As

0046D7BF . 8D4D C4 LEA ECX,DWORD PTR SS:[EBP-3C]
0046D7C2 . 51 PUSH ECX
0046D7C3 . 6A 01 PUSH 1
0046D7C5 . E8 D64FFDFF CALL Dockligh.004427A0 ; NOP the call or patch at 004427A0 with a RETN
0046D7CA . 66:8BF8 MOV DI,AX
0046D7CD . 66:F7DF NEG DI
0046D7D0 . 1BFF SBB EDI,EDI
0046D7D2 . 47 INC EDI
0046D7D3 . F7DF NEG EDI
0046D7D5 . 8D4D C4 LEA ECX,DWORD PTR SS:[EBP-3C]
0046D7D8 . FF15 34134000 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeStr>] ; MSVBVM60.__vbaFreeStr
0046D7DE . 66:3BFB CMP DI,BX
0046D7E1 . 0F84 9D060000 JE Dockligh.0046DE84 ; NOP

Unfortunately you can patch the call to return immediately without doing anything but the test conditions in the calling routine used by the JMPs are different case by case. Then even if you can do a smarter patch (and you are invited to try) I chosen to do it quick and dirty pathing the call and all the JMPs spread in the callers functions.

You can NOP the call at 0046D7C5 and the JE at 0046D7E1 or modify the call to return immediately and patch only the JE at 0046D7E1.

All the other patches are similar (hint: see who's calling 004427A0) and I will not explain them in details, do on your own if you like the application.

These are the disabled functions in eval mode:

Save Project
Save As
Print Project
Print Communication
Start Communication Logging

Note:
The 2B0 Trick works also for the nags of the disabled functions. After having set the breakpoints as described in Section 5, let the application continue freely till you are able to select the menu voice "Save As": the application stops at 00442960. This time we stopped the application early enough before it enters into the VB Dlls hell, so ALT-K still gives something meaningful: press alt-k, you will see from the call stack that we landed here from the call at

0046D7C5 . E8 D64FFDFF CALL Dockligh.004427A0

which is exactly the place we found few lines above.
 

Patch to accept any serial you insert

0048C02E 6. Active JNZ Dockligh.0048C0C4 JMP Dockligh.0048C0C4 JMP
0048C0D6 24. Active JNZ Dockligh.0048C180 NOP NO JMP
0048C223 16. Active JE Dockligh.0048C502 NOP NO JMP
0048C471 6. Active JNZ Dockligh.0048C505 JMP Dockligh.0048C505 JMP
0048C50A 6. Active JE Dockligh.0048C5A8 NOP NO JMP

essentially what I do is to guide the routine:

0048BF60 > \55 PUSH EBP

to the good boy message:

0048C55F . C745 88 28EC4100 MOV DWORD PTR SS:[EBP-78],Dockligh.0041EC28 ; UNICODE "Registration successful. Thank you for choosing our product!"

Please note that the call

0048C30F . FF97 B0020000 CALL DWORD PTR DS:[EDI+2B0] ; Show Licence Agreement

shows the licence agreement, you can NOP it.
 

Eliminate the string "(Eval)" from the main window's title
Simply search the Unicode string "(Eval)" and eliminate it placing a 00 00 at the beginning.

 
As I already told the purpose of this tutorial was to discuss a little on VB apps and how they look into Olly and not to patch the application efficiently. As I told there's always a simpler way to patch applications. Just search where the "(Eval)" string is referenced or look around the places I already identified above, don't you see an always recurring memory location? That memory location is the location holding the registered vs unregistered status..

 

 

7. Improving code readability using P32Dasm

If you like you can simplify a little your life with Olly and applications written with other languages than C/C++, inserting the so called MAP files generated by other decompilers.

Usually these files come from other tools such as IDA or Dede (for Delphi programs, see [5]) or P32Dasm (for VB apps). There is a plugin for OllyDbg called MapConv (by +godfather) [2] which will import those MAP files into Olly as funtion names or comments to disassembled code. Applying such things allows to have a much more readable assembler and definitely to do your work faster.

Among the several VB decompilers we will se P32Dasm (from DARKER -SFC) because its free. Lauch the program and open the Docklight executable. P32Dasm will do its work and write a messagebox with "Done" inside, when finished.

What P32Dasm does is to assign, to all the ASM function it can, a corresponding VB action and it can do this task because knows how the forms data are stored into the exe (remember what I told in Section 4). So this tool practically does a first step in decompilation. But the real usage is in conjunction with a Debugger, because P32Dasm produces only dead-listings.

Now select Create MAP file and save the file. After this go into OllyDbg and, using MapConv select "Replace Labels" and "Replace Comments" both. This will insert the items, identified by P32Dasm, as function names for calls and as comments in the disassembly generated by OllyDbg. If you have a runing copy of IDA you can do the same to integrate the two tools, obtaining an extremely readable disassembled code.

For example several JMPs become more readable:

0040BCA2 . /E9 69090800 JMP <Dockligh.frmLicence_18.11__(P32Dasm)>
..
0048C610 > > \55 PUSH EBP ; frmLicence_18.11__(P32Dasm)

All the labels coming from the MAP file are inserted as user comments and user labels so you can review then all into one single window, using the Search For -> User-defined comments function of Olly.

Not everthing is found of course, but you know, better than nothing.

For example the jumps table we saw at section 4 at the address 0040BC18 becomes now:

much more clear now!

P32Dasm has also an excellent form navigator which should help to find at least a first place where to insert a breakpoint and then combining what P32Dasm tells and the method described here, you should be able to find very fast the point where to patch.

 

 

Conclusions

Obviously there's always a better way to patch an application, I chose this one because it allowed me to teach you on the call stack trick and give to you enough examples so as to learn it better. This specific app can be patched in a more elegant way only changing a single magic byte. To find how is your next step, but you will have to do it on your own, as an homework ;-)

I will only tell you that magic bytes are very common for VB applications because of the structure of these applications, imposed by the VB common runtime. For further reading on the VB applications I suggest [6] and [7] (in Spanish)

Just for knowing it also the other products of this company can be handled with the same approach, and the same "smarter" patch is possible too.

Of couse if you plan to use this application professionally or for your work I strongly suggest you to buy it.

 

 

References

I suggest the following further readings from now on to complete this argument..

  1. P32Dasm 2.1, http://www.intechhosting.com/~access/ARTeam/tools/P32Dasm_v2.1.zip 
  2. MapConv 1.4, http://www.intechhosting.com/~access/ARTeam/tools/MapConv_14.zip
  3. Point-H, http://www.intechhosting.com/~access/ARTeam/tutorials/non_arteam/ricardo/punto_h_english.zip and also several tutorial at http://tutorials.accessroot.com using this technique.
  4. Point-A, http://www.intechhosting.com/~access/ARTeam/tutorials/non_arteam/ricardo/235-punto_magico_vb6_Part1.zip and http://www.intechhosting.com/~access/ARTeam/tutorials/non_arteam/ricardo/236-punto_magico_vb6_Part2.zip
  5. “Removing Nag from CaptureNPrint 6.6.6.17”, Shub-Nigurrath, http://tutorials.accessroot.com
  6. Andy Padawer, Microsoft P-code technology. 1992. In Microsoft Developer Network, http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnarvc/html/msdn_c7pcode2.asp
  7. 006-Iniciandonos Con P-Code.zip; 007-Iniciandonos Con P-Code 2da Parte.zip; 008-Iniciandonos Con P-Code 3ra Parte.zip; 009-Iniciandonos Con P-Code 4ta Parte.zip. All are mirrored at http://www.intechhosting.com/~access/ARTeam/tutorials/non_arteam/ricardo/XXX ; to get this reference shorter, you should substitute XXX with the correct filenames to get the real URLs.
  8. "OllyDbg y Visual Basic III", CoCo, http://www.intechhosting.com/~access/ARTeam/tutorials/non_arteam/ricardo/061-Ollydbg Y Visual Basic Iii Por Coco.zip
  9. "OllyDbg y Visual Basic IV:Jugando con el codigo", CoCo, http://www.intechhosting.com/~access/ARTeam/tutorials/non_arteam/ricardo/190-Ollydbg Y Visual Basic Iv Por Coco.rar
     

..and essentially all the tutorials seens around (also others on our tutorials page) which often target checksummed applications..

Just some of the Ricardo Tutorials from CrackLatinos are mirrored on our server

 

 

Greetings

Thanks to the whole ARTeam:
[Nilrem] [Shub-Nigurrath] [MaDMAn_H3rCuL3s] [Kruger] [ThunderPwr] [Eggi] [EJ12N] [Cl0ud]
[Gabri3l][Condzero] [Bone Enterprise]

Thanks to all the people who take time to write tutorials.
Thanks to all the people who continue to develop better tools.
Thanks to Exetools, Woodmann, SND, CrackLatinos and all the others for being a great place of learning.
Thanks also to The Codebreakers Journal.

If you have any suggestions, comments or corrections contact me in usual places..