首页
社区
课程
招聘
How to patch Delphi modules
发表于: 2005-5-12 19:01 6346

How to patch Delphi modules

2005-5-12 19:01
6346
Target: EasyMap VCL (3w.microolap.com/trials/em.zip)

Tools used:

    * Delphi 7 Enterprise version
    * Hiew 6.11 (you can use any hexeditor)

Note: A product version doesn't matter, but it's important that all work. The second thing that you should keep in mind is what all the addresses are represented in hexadimal system, the rest numbers are decimal.

Author : Wizard
Date : 22.12.2003
Level : 3/10
Origin:         I have not failed. I've just found 10,000 ways that won't work. Thomas Jefferson.
Introduction

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:

    * MIF/MID vector maps displaying in Longitude/Lantitude projection;
    * Map objects related data in grid or tabular controls displaying;
    * ZoomIn/ZoomOut/Pan/Selector map tools;

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.
Philosophical story

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.
The sense of the task was simple, but realization wasn't. I should patch three files. One BPL file with two NAG screens and two DCU files with one message inside each.

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.
I spent a lot of hours thinking and analysing of how to do something. I didn't find any information about BPL and DCU file structures over the net. No any information, no tutorials or patchers. I found only one crappy tutorial and lots of links that are just brain-picking of other sites.

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.
When I'm fed up with the shitty plagiarism on the net I decided to kick some ass by myself.
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:

    * TDataBrowser class, which is in module DataBrowser.dcu
    * TLayersComboBox class, which is in module LayersComboBox.dcu

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.
Note: These modules of Delphi are always included into an exe file during a compilation of the last one. That means those two files are always used in run-time, because Delphi compiles them into the final executable.
I suppose DELPHI7 folder can have another name, which depends on Delphi version.

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.
In other way there can be few BPL files. To know which of them has the message you better use SoftIce. But there's more artless way to find out where the NAG is. Start any string searcher (e.g. FAR or an other shell). Type "Evaluation version" in the search string and start the search. As you can see only three forenamed files have that stupid message.
Note: In case of some smart crypted/packed modules use the debugger to find out where a message is. But usually DCU and BPL files are naked (ain't packed), which gives you a real power to create a crack art.
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.

File name         Description         Comments
DataBrowser.dcu         Delphi run-time module         It has one message
LayersComboBox.dcu         Delphi run-time module         It has one message
EasyMapD7.bpl         Delphi design-time module         It has two messages
First, let's remove the NAGs from BPL file. Close Delphi if it were opened.
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.
Why? Because these commands save absolute values, they don't depend upon the memory address or file size, when the last will be compiled. Besides, the code says it pushes zero as the last parameter in stack, which is the first parameter (hWnd) in MessageBox. Well, for you to know - zero is the handle of the screen. It often used by such API functions as GetDC, ReleaseDC, etc. I suppose the components use this handle to draw the message before the form will be shown or even created. That's why you see two NAGs first and only after that the form of an applications appears.

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.
Note: I remind you that when we release the stack we use the back order of the elements that were saved. The second thing, we're "popping up" three values because we have 2 of them in stack before the jump at address 100DA and one element was in stack before those 2 had been saved.

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 fuck 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:

    * 1. before the MessageBox call and after it write down to a paper all values of the registers and the stack from the original (not patched) code;
    * 2. patch the code as best as you can;
    * 3. do the same as in the first step, but in the patched code;
    * 4. compare all the values, which you wrote before the call and after it in the original and the patched code. If there's full match - you did all correctly, but if something wrong - you've made a mistake somewhere. In the last case you have to get back to the first step.

The full patch for the first NAG as a table.

Address         Original opcode         Original mnemonics         Patched opcode         Patched mnemonics
000100DA         6A 00         push 000         EB50         jmps 00001012C
0001012C         45         inc ebp         58         pop eax
0001012D         7661         jbe 000010190         58 58         pop eax, pop eax
0001012F         6C         insb         EB B0         jmps 0000100E1
First step is done. Let's find out where the second NAG lays. To do this call the find dialog again by pressing F7 key. Type "Evaluation" in it and start the search once again.
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.

Address         Original opcode         Original mnemonics         Patched opcode         Patched mnemonics
000111EA         6A 00         push 000         EB 50         jmps 00001123C
0001123C         45         inc ebp         58         pop eax
0001123D         76 61         jbe 0000112A0         58 58         pop eax, pop eax
0001123F         6C         insb         EB B0         jmps 0000111F1
That's all for EasyMapD7.bpl, because if you will try to search the same string again you won't find it. That means we've done with this file.
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,eax

Familiar 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.

Address         Original opcode         Original mnemonics         Patched opcode         Patched mnemonics
000343D         6A 00         push 000         EB 50         jmps 0000348F
000348F         45         inc ebp         58         pop eax
0003490         76 61         jbe 000034F3         58 58         pop eax, pop eax
0003492         6C         insb         EB B0         jmps 00003444

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.

Address         Original opcode         Original mnemonics         Patched opcode         Patched mnemonics
0002643         6A 00         push 000         EB 50         jmps 00002695
0002695         45         inc ebp         58         pop eax
0002696         76 61         jbe 000026F9         58 58         pop eax, pop eax
0002698         6C         insb         EB B0         jmps 0000264A

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.
Living end

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.

[注意]APP应用上架合规检测服务,协助应用顺利上架!

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//