Level : intermediate
Patch commercial VCL modules (Delphi/Borland C++) instead of patching your built executables over and over.
Lets take a dive in the Borland package libraries (BPL files)
Target: EasyMap VCL (3w.microolap.com/trials/em.zip)
Level : 3/10
EasyMap VCL is a Delphi/C++Builder components set for creating your own GIS-related solutions without MapInfo, MapX, MapObjects, WinGIS and so on.
EasyMap VCL allows to add following functionalities in Delphi/C++Builder application:
EasyMap Object Model allows to display on the map embedded into your application data from most of known datasources: RDBMS, flat DBs, your own formats etc.
One day my father asked me to look at some Delphi component that was
shareware. I said that I'll take a look at it and crack it like piece of cake.
That was an arrogance from my side, because when I made an observation of the
components I concluded that a crack task won't be as simple as I thought.
I found the places where the NAGs were. The problem was only in one thing,
how to patch these files. One might think, what so hard in that. Nothing, except
that DCU files are not just executables.
During the search I understood that inet is one big scrap-heap and when
you need something you won't find it, you will only get it when you don't
need it. Well, who need information that he needed some years ago? Hah,
of course no one.
What is what?
First of all, extract em.zip, than run easymapvcl_trial.exe and follow the
setup program instructions to install the components.
Now fire up Delphi. Open the demo project EasyMapDemo.dpr in it. Activate Form1 (Shift + F12). You should see two message boxes, one after another, which say: "Evaluation version of EasyMap VCL. For purchasing info visit...". Each message connected to a specified component. Therefore there're two components:
How do I know that? Simple, look into EasyMap directory in Delphi. It contains
three folders and six files in the its root. Go into DELPHI7 subdirectory of
EasyMap folder. In there you're gonna find forenamed DCU files. Besides the
messages say for themselves, because each message has a caption with inscription,
which tells you the name of a component. As a rule components have the same
name as modules, but without first "T" letter.
You ought to see file EasyMapD7.bpl in the same directory. This file is
used by Delphi during design-time. Lemme explain why. BPL file is the same
DLL file, but renamed. It's called by Delphi, when a programmer edits a form,
which contains such components or when he edits the components properties.
Let's find out where to dig
Now we know what files have the message inside. To be exact I'm giving the
whole list below with the explanation.
Open EasyMapD7.bpl with Hiew and search for the "Evaluation" string. You can do that by pressing F7 in Hiew and type forenamed word in the search string.
I've found one at address 410D2C. Press F4 and select Hex mode (or just press Enter key to do the same). Press Alt + F1 to switch from relative addresses to absolute. Once you've done it you'll get 1012C instead of memory address 410D2C.
Enter the decode mode by pressing enter or F4/Decode. Now hold on up key to scroll up till you see this part of the code:
000100BF : 8D45FC lea eax,[ebp][-0004] ; <= the place you are now 000100C2 : BA03000000 mov edx,000000003 000100C7 : E8C404FFFF call 000000590 000100CC : 8B45FC mov eax,[ebp][-0004] 000100CF : E8D404FFFF call 0000005A8 000100D4 : 50 push eax ; address of title of message box 000100D5 : 682C0D4100 push 000410D2C ; address of text in message box 000100DA : 6A00 push 000 ; handle of owner window 000100DC : E8EB08FFFF call 0000009CC ; MessageBoxA itself 000100E1 : 33C0 xor eax,eax 000100E3 : 5A pop edx 000100E4 : 59 pop ecx 000100E5 : 59 pop ecx 000100E6 : 648910 mov fs:[eax],edx 000100E9 : 68030D4100 push 000410D03 000100EE : 8D45F8 lea eax,[ebp][-0008] 000100F1 : BA02000000 mov edx,000000002 000100F6 : E85504FFFF call 000000550 000100FB : C3 retn ... skipped ... ;.................................................................. ; Attention! Below goes the disassemble of the code the part, where ; 'Evaluation version' strings lays. But here we'll need only ; five bytes of the mentioned string. Therefore you should treat ; below disassemble not as a string, but as a disassemble. That's ; because we're gonna use the space destined for the string as a ; piece of code, which will do what we want and then it will bring ; back the control to the point we need. Keep on reading and you'll ; understand what do I mean. ;.................................................................. 0001012C : 45 inc ebp ; 'E' <= the place you've found 0001012D : 7661 jbe 000010190 ; 'va' 0001012F : 6C insb ; 'l' 00010130 : 7561 jne 000010193 ; 'ua' 00010132 : 7469 je 00001019D ; 'ti' 00010134 : 6F outsd ; 'o' 00010135 : 6E outsb ; 'n'The main idea is that you ought to avoid the MessageBox call at address 100DC. How to do this? Let's ask Windows API help about that. It says next:
int MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box );Ok, now we know that MessageBox has 4 parameters. Now look again at the next piece of the code.
000100CF : E8D404FFFF call 0000005A8 000100D4 : 50 push eax ; address of title of message box 000100D5 : 682C0D4100 push 000410D2C ; address of text in message box 000100DA : 6A00 push 000 ; handle of owner window 000100DC : E8EB08FFFF call 0000009CC ; MessageBoxA itself 000100E1 : 33C0 xor eax,eax
As you can see there're only 3 parameters which will be passed to MessageBox function. According to help there should be another one parameter before those three. But there's no such one, because instead of it there's a call at address 100CF.
Therefore, we can conclude that the last parameter (uType) is in stack already. You're maybe thinking now, let's release the stack from one uType parameter by a command e.g. pop eax and then just "nop" all the rest or jump over the MessageBox.
Not a bad idea at all, but there's one problem here. When I did so Delphi caused an GPF (General protection fault) and suddenly exited. When I've put a breakpoint at address 100D4 in SoftIce and ran Delphi again I saw strange thing. Everything was disassembled correctly in Hiew, but it was wrongly disassembled in Delphi during design-time. That means EasyMapD7.bpl isn't just renamed DLL or maybe I should change something else in it to make Delphi treat the code correctly.
I've been thinking for a long time how to patch it. I tried many times to patch it with different ways, but nothing worked out...
Breaking up the horizons
In one day I suddenly wondered about one simple thing, what if I had changed the part of the code, which was never changed. I mean that all the jmp, call and push commands will be replaced with different addresses appropriate to a situation. That means, for a BPL file Delphi can change commands in memory. E.g. if there were a command like push 410D2C, such command might look in memory as push 470D2C or elsewise. Because it's BPL (DLL) and who knows how Delphi treats it, what procedures/functions uses, in what memory ranges, etc. To answer all these questions we have to know the BPL file structure, but we don't and there's no place to get it yet. That's why we're just wondering to patch it correctly without knowing its structure.
Anyway the conjecture was right. When I patched forenamed push command only the first byte was interpreted correctly, the rest din't. That was because push command (its long equivalent) consists of 5 bytes, 1st byte is mnemonics, the rest 4 are an address, e.g. 68 2C 0D 41 00 (push 410D2C). That's why when I patched another byte than the first I got wrong values in memory during design-time. The same was during run-time, when I compiled an executable the code was wrong in exe file, but only in places where I touched such commands as push (ONLY 5 bytes long), call and jmp.
By knowing that I can conclude only one correct solution. Look at the parts of the code again more attentively.
000100CF : E8D404FFFF call 0000005A8 ; uType is in stack already 000100D4 : 50 push eax ; saving 3rd parameter 000100D5 : 682C0D4100 push 000410D2C ; saving 2nd parameter 000100DA : 6A00 push 000 ; saving 1st parameter 000100DC : E8EB08FFFF call 0000009CC ; MessageBoxA 000100E1 : 33C0 xor eax,eax ... skipped ... 0001012C : 45 inc ebp ; 'E', the first letter of the NAG 0001012D : 7661 jbe 000010190 ; 'va' 0001012F : 6C insb ; 'l' 00010130 : 7561 jne 000010193 ; 'ua' 00010132 : 7469 je 00001019D ; 'ti' 00010134 : 6F outsd ; 'o' 00010135 : 6E outsb ; 'n'If you're pretty attentive you are obviusly guessed already what we're gonna change. Let's transform the code parts above to another.
000100CF : E8D404FFFF call 0000005A8 ; uType is in stack already 000100D4 : 50 push eax ; saving 3rd parameter 000100D5 : 682C0D4100 push 000410D2C ; saving 2nd parameter 000100DA : EB50 jmps 00001012C ; jump to our patch procedure 000100DC : E8EB08FFFF call 0000009CC ; MessageBoxA 000100E1 : 33C0 xor eax,eax ; <= we will back here ... skipped ... 0001012C : 58 pop eax ; release the 4th parameter 0001012D : 58 pop eax ; release the 3rd parameter 0001012E : 58 pop eax ; release the 2nd parameter 0001012F : EBB0 jmps 0000100E1 ; jump back over the call 00010131 : 61 popad ; 'a' 00010132 : 7469 je 00001019D ; 'ti' 00010134 : 6F outsd ; 'o' 00010135 : 6E outsb ; 'n'
Now the explanation of all we did. First, we changed push 00 to jmps 1012C at address 100DA. That's because Delphi won't change push and
jmp commands, which are 2 bytes long.
As you can see the jump at address 100DA jumps to the first byte of our string
that you've seen already. We're using 5 bytes of it to release the stack from values,
which will never be used by MessageBox, because the last won't be called ever too.
The last jump at address 1012F brings back the control to the program.
At this point the stack is clear from our 3 values that were saved before the
jump to our patch procedure. That's how we're preventing the NAG appearing.
Everything should be pretty clear here, except one thing. Why do we use eax as the releasing register? That's because if you look at address 100E1 you'll see the command xor eax,eax. This command lays right after the MessageBox call. Which means that MessageBox function changes eax register. That's why program makes it null after the call. And that's why we're using it as "pop-up" register when releasing our 3 values. If we would use some other register we could *censored* up something in stack or in program, 'cause we don't know what the program does with what registers. That's why we should be very careful when changing something.If you use some other register to release the stack you better do next steps:
You have found another and the last one (in this file) at address 1123C. Look a bit up and you will see the same piece of code that you've seen before, when we were patching the first NAG. Nothing different here, but the addresses. Thus, there's no sense to give the same explanation as above. Instead of doing that just look at the table below to check out the addresses, but the algorithm is the same.
Keep on diggin'
I spent a lot of time on the net trying to find any information about DCU files. I found some shitty article about how to write an emulator of Delphi IDE to run programs without Delphi IDE. All the rest I found were the same crap, but in different sites. I couldn't also find DCU structure description. There was only one info that I found about it on some russian forum. There was a public speaking of Borland. The sense of it was very simple: DCU is a private format of Borland and won't be spreaded around the world. What an arrogance! That's why I'm gonna tell you how to patch such files.Open DataBrowser.dcu with Hiew and search for "Evaluation" string. I've found it at address 348F. Switch to decode mode. Press Ctrl + F1 to change your disassembly settings from 16 bit mode to 32. Do here the same as we do when we were cracking the BPL file. Elevate the cursor till you see almost the same code that we see in BPL.
00003432 : E800000000 call 000003437 00003437 : 50 push eax 00003438 : 68C0000000 push 0000000C0 0000343D : 6A00 push 000 0000343F : E800000000 call 000003444 ; MessageBoxA 00003444 : 33C0 xor eax,eaxFamiliar code, ain't it? Sure it is! Thus, you have to patch it exactly like we do before. Check out the table below to compare you patch.
Try to search the string again. No such one, which means that this file is done and we have to crack the last file.
Now open LayersComboBox.dcu in Hiew and make the same search. You should find the string at address 2695. Scroll a little up and you will see absolutely the same code as in the first dcu, only the addresses are different. At this point I suppose you know what to do with it, but nevertheless compare your patch results with mine.
Search again the string to make sure there's no more such one. The search is failed, which means we've cracked it. As all of three files have been cracked this issue is over.
That's was an essay of Delphi cracking. It wasn't very hard and it wasn't too smart, but anyway this is one of the first public steps of cracking Delphi components and related files. I hope this steam of fresh knowledge will give people some more imagination to create their own cracking art.
It isn't too hard when you know what to do and how, but when don't you can waste a lot of time trying to understand how does a thing work. You may ask questions to people, you may search info over the net, etc. But the most important information for you is your own experience. In some cases some people can help if you stuck somewhere, in some cases they can't. That's why first of all, you have to dig by yourself, study yourself and public your work.
When you find a good solution of something real worthy don't put the knowledge away from people. Don't also make brain-picking, because it won't give you more respect. Share it with the mass, because we're all mortal. So don't take your knowledge to tomb.
The great shouts go to all the crackers all over the world.
All rights reversed (c)2003 - BiW Reversing - http://www.reversing.be - The challenge is yours