Adding functionality to a Delphi program
PART 1 * Delphi executable, Class information and DFM resources * Event Handlers. * Re-assigning events editing DFM resources and class information. Before all I whould like to explain the internal format of a Delphi executable according to our reversing goals. All Delphi programs compiled by Delphi 3, 4 or 5 has the following sections : CODE, DATA, BSS, .idata, tls, .rdata, .rsrc. The most important from our point of view are the CODE and .rsrc sections. The .rsrc section ------------------------------------------------------------------------------------------ Here except the "normal" resources are situated also the Project Information and DFM resources. The section begins with the usual resource tables. After that starts the Project Information and finally the DFM resources. They are the description of the forms, all contained controls and also all initialization settings for published properties of the visual and not visual controls in the forms. The resources for separate forms are in separate "sections" (separate resource). Each of them begins with the bytes : #54,#50,#46,#30 (TPF0) and immediately after that the name of the form as pascal string ( this means the first byte is the length of the string). Each DFM section is exactly copied by the linker from your original .dfm file when your project is linked. Note that DFM resources are so called RCDATA type resources that are also described in the resource tables in .rsrc PE section. This means that you can edit them with a resource editor - like Borland Resource Workshop. The more interesting for us is what each DFM resource contains. The simple answer is that there is stored all the information that the Delphi Object Inspector shows you when you have the project opened. And this means that you can reassign all these published properties of the controls in the forms simply by editing the DFM RCDATA resources. One of the important things is that you can also reassign the event handlers. Another thing is that there are procedures in the Delphi VCL itself that allows you to read these RCDATA resources and also to save them as RES ot TXT format. In the classes.pas are defined these procedures: ObjectBinaryToText() ObjectResourceToText() ObjectTextToBinary() ObjectTextToResource() Using them you can simply transform binary DFM RCDATA resources into other ways of representing them. One usual text description of a form, that in our case contains one TButton looks like this: object Form1: TForm1 Left = 192 Top = 105 Width = 215 Height = 109 Caption = 'Test Project 1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style =  OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Button1: TButton Left = 8 Top = 16 Width = 75 Height = 25 Caption = 'Show Form2' TabOrder = 0 OnClick = Button1Click end end By the way while you are designing your forms, Delphi uses these procedures very often. Try for example to select some object in your form. Then press Ctrl+C to copy it. Now if you press Ctrl+V you will paste this button in the form, but if you are in the unit code of Delphi editor and press there Ctrl+V you will see that Delphi will call ObjectBinaryToText() and will past in the editor the text representation of the button! Now let's have a little example. I have compiled a very simple project that has 2 forms. Form1 contains 2 buttons. When you press the Button1 the second form (Form2) is shown and when you press the Button2 a text is displayed. The Form2 has only one button that shows a text when pressed. So now we will change the event handlers of the two buttons of Form1 by changing the DFM resources. Open the sample executable with hex editor and find the following: 0004A4E0 020D 0007 5442 7574 746F 6E07 4275 7474 ....TButton.Butt 0004A4F0 6F6E 3104 4C65 6674 0208 0354 6F70 0210 on1.Left...Top.. 0004A500 0557 6964 7468 024B 0648 6569 6768 7402 .Width.K.Height. 0004A510 1907 4361 7074 696F 6E06 0A53 686F 7720 ..Caption..Show 0004A520 466F 726D 3208 5461 624F 7264 6572 0200 Form2.TabOrder.. 0004A530 074F 6E43 6C69 636B 070C 4275 7474 6F6E .OnClick..Button 0004A540 3143 6C69 636B 0000 0754 4275 7474 6F6E 1Click...TButton 0004A550 0742 7574 746F 6E32 044C 6566 7402 0803 .Button2.Left... 0004A560 546F 7002 3005 5769 6474 6802 4B06 4865 Top.0.Width.K.He 0004A570 6967 6874 0219 0743 6170 7469 6F6E 0604 ight...Caption.. 0004A580 496E 666F 0854 6162 4F72 6465 7202 0107 Info.TabOrder... 0004A590 4F6E 436C 6963 6B07 0C42 7574 746F 6E32 OnClick..Button2 0004A5A0 436C 6963 6B00 0000 5450 4630 0654 466F Click...TPF0.TFo We will change the Button1.OnClick property to Button2Click and Button2.OnClick property to Button1Click: 0004A4E0 020D 0007 5442 7574 746F 6E07 4275 7474 ....TButton.Butt 0004A4F0 6F6E 3104 4C65 6674 0208 0354 6F70 0210 on1.Left...Top.. 0004A500 0557 6964 7468 024B 0648 6569 6768 7402 .Width.K.Height. 0004A510 1907 4361 7074 696F 6E06 0A53 686F 7720 ..Caption..Show 0004A520 466F 726D 3208 5461 624F 7264 6572 0200 Form2.TabOrder.. 0004A530 074F 6E43 6C69 636B 070C 4275 7474 6F6E .OnClick..Button 0004A540 3243 6C69 636B 0000 0754 4275 7474 6F6E 2Click...TButton 0004A550 0742 7574 746F 6E32 044C 6566 7402 0803 .Button2.Left... 0004A560 546F 7002 3005 5769 6474 6802 4B06 4865 Top.0.Width.K.He 0004A570 6967 6874 0219 0743 6170 7469 6F6E 0604 ight...Caption.. 0004A580 496E 666F 0854 6162 4F72 6465 7202 0107 Info.TabOrder... 0004A590 4F6E 436C 6963 6B07 0C42 7574 746F 6E31 OnClick..Button1 0004A5A0 436C 6963 6B00 0000 5450 4630 0654 466F Click...TPF0.TFo This is all. Now save the new executable and run it. You'll find that when you click Button1 instead of showing Form2 a text will be shown and when you click Button2 the Form2 will be shown. In this way you can reassign events to be handled by other event handlers defined in the same form. Also note that you can assign a event handler to an event only if they are compatable. This means you can not assign a TButton.OnClick event handler to fot example TForm.OnKeyDown. We are also not able by editing DFM RCDATA resources to assign to Form1.Button1.OnClick the Form2.Button1Click handler for example. But this can be done in a different way. Read below. The CODE section ------------------------------------------------------------------------------------------ Here all classes information and code is situated. The last procedure in CODE section is the DPR code. I will not explain the meaning of all data in the class information but will talk about how the RVA offset of an event handler can be found. Open the test project in a hex editor. We know that there are Form1 and Form2 in this project. Seek for the string resource TForm2 in the CODE section. You'll find it 2 times here: 0003F870 746F 6E31 0100 1300 B804 4400 0C42 7574 ton1......D..But 0003F880 746F 6E31 436C 6963 6B06 5446 6F72 6D32 ton1Click.TForm2 0003F890 0100 58C3 4100 8BC0 9C04 4400 0706 5446 ..X.A.....D...TF 0003F8A0 6F72 6D32 8C03 4400 4440 4300 5500 0555 orm2..D.D@C.U..U 0003F8B0 6E69 7432 0000 8BC0 B8CC 0444 00E8 8EFC nit2.......D.... First note that all the strings are in pascal format. Immediately before the Button1Click stays this: B804 4400. As you can guess this is the RVA offset of the event handler Form2.Button1Click. If we disassemble the test project and go to offset 004404B8 we will see the following: * Possible String Reference to: "Hello from Form2" | 004404B8 B8CC044400 mov eax, $004404CC * Reference to: Dialogs.ShowMessage(System.AnsiString) | 004404BD E88EFCFFFF call 00440150 004404C2 C3 ret Well this is the code of TForm2.Button1.OnClick event handler. Now you may be already have the idea how to change the RVA offsets of event handlers in different forms. Have you ? Well we just need to know the RVA of the procedure. Note that you can not simply assign every procedure to be an event handler because event handlers of different events have different parameters. So in our case we will assigne to Form1.Button1.OnClick the Form2.Button1OnClick handler and to Form2.Button1.OnClick the Form1.Button1OnClick handler. They both are handlers of TNotifyEvent type wich has the declaration: Type TNotifyEvent = procedure (Sender : TObject) of object; So we can assign to TButton.OnClick every procedure that is an event handler from this type - TNotifyEvent. OK lets do it now. Before changing event handlers of the two buttons we should know the RVA of the other handler. We can find TForm1 string in the CODE section and this will lead us to the following: 0003FA50 0000 0742 7574 746F 6E32 0200 1300 B006 ...Button2...... 0003FA60 4400 0C42 7574 746F 6E32 436C 6963 6B13 D..Button2Click. 0003FA70 00D8 0644 000C 4275 7474 6F6E 3143 6C69 ...D..Button1Cli 0003FA80 636B 0654 466F 726D 3101 0058 C341 0090 ck.TForm1..X.A.. 0003FA90 9406 4400 0706 5446 6F72 6D31 6405 4400 ..D...TForm1d.D. 0003FAA0 4440 4300 5500 0555 6E69 7431 0000 8BC0 D@C.U..Unit1.... So we can see that TForm1.Button1Click has RVA offset - 004406D8 and TForm1.Button2Click has RVA - 004406B0. Now we will change the TForm1.Button1.OnClick handler with the one at offset 004404B8: 0003FA50 0000 0742 7574 746F 6E32 0200 1300 B804 ...Button2...... 0003FA60 4400 0C42 7574 746F 6E32 436C 6963 6B13 D..Button2Click. 0003FA70 00D8 0644 000C 4275 7474 6F6E 3143 6C69 ...D..Button1Cli 0003FA80 636B 0654 466F 726D 3101 0058 C341 0090 ck.TForm1..X.A.. 0003FA90 9406 4400 0706 5446 6F72 6D31 6405 4400 ..D...TForm1d.D. 0003FAA0 4440 4300 5500 0555 6E69 7431 0000 8BC0 D@C.U..Unit1.... And also the TForm2.Button1.OnClick handler with the one at offset 004406D8: 0003F870 746F 6E31 0100 1300 D806 4400 0C42 7574 ton1......D..But 0003F880 746F 6E31 436C 6963 6B06 5446 6F72 6D32 ton1Click.TForm2 0003F890 0100 58C3 4100 8BC0 9C04 4400 0706 5446 ..X.A.....D...TF 0003F8A0 6F72 6D32 8C03 4400 4440 4300 5500 0555 orm2..D.D@C.U..U 0003F8B0 6E69 7432 0000 8BC0 B8CC 0444 00E8 8EFC nit2.......D.... Well this is all. Save the new executable and run it! So let now have more fun and write our own event handler, adding the code to the executable, that will change the caption of a button. Before doing this we should point to the following: * VCL classes in executable. * Finding RVAs of VCL class methods. * Conrol IDs. * Reading and writing TEdit.Text and TLabel.Caption properties using VCL Have you ever asked the question why Delphi executables are so big in size? The answer is that in them is stored also the code of all classes from the VLC (Visual Component Library) that is needed for your program to run. There is also another way - to compile the program with runtime packages. In this case the program will be very small, but will need the vclxx.bpl library to run (The same as the C++ MFC library, but mfcxx.dll goes with windows). So we saw that in the CODE section in a Delphi executable is stored class information that is not executable code. All the VCL stuff needed by the program is also there but there it has no published properties. The exact structure of this class info is known and you can restore most of the binary code to pascal code and retrieve *ALL* the typeinfos. You can find more information about this at Python's site at http://thunder.prohosting.com/~pytho/index.shtml. If we want to find the RVA offset of a certain VCL method we can use the ideology of byte-to-byte recognition that IDA and DeDe uses. In this way most of the methods from component libraries like VCL and MFC can be found. There is almost a unique byte sequence for every method. If you have the asm soure of a method and corresponding byte opcodes and if you remove all memory offsets that are used in the instructions of this method you'll have such a pattern that can be used to identify the method. This technology of recognition is called FLIRT (Fast Library Identification and Recognition Technology). You can find more information about the IDA FLIRT at: http://www.datarescue.com/idabase/flirt.htm http://www.datarescue.com/idabase/idaflirt.htm So lets return to our goals and find the TControl.SetText VCL method RVA offset in the test project we have. This method is used to set the labels and buttons captions and also for all classes that inherits TControl. We can find using DeDe DSF function view or just "spying" with Delphi CPU Viewer. The ID of TControl.SetText(System.AnsiString) is: 558BEC6A0053568BF28BD833C055680000000064FF306489208D55FC8BC3E8000000008B45FC8BD6...... Here 6800000000 is a push instruction but the memory offset is removed/set to 00000000. Lets search for this pattern in the test executable. You'll find that the pattern 558BEC6A0053568BF28BD833C05568 is found to often. More easy will be in this case to seek for 64FF306489208D55FC8BC3E8, then ignore the next four bytes and seek for 8B45FC8BD6 after that. We will find this sequence here: 00021270 FFFF FF5F 5E5B C390 558B EC6A 0053 568B 00021270 F28B D833 C055 68CD 1E42 0064 FF30 6489 00021270 208D 55FC 8BC3 E8AD FFFF FF8B 45FC 8BD6 With easy calculation we can find that the physical offset 21278 corresponds to RVA 00421E78 in the CODE section. So this is the RVA offset of TControl.SetText. Well lets have fun now and "write" our own event handler to Form1.Button1.OnClick and in this handler to change the caption of TForm1.Button2. Before doing this we should know a how the params are passed to TControl.SetText. It is not in the usual C way pushing them ontto the stack. If the procedure is a class method, as in our case, EAX contains the pointer to the class instance - in our case TForm.Button1. The first parameter is passed in EDX. So the pseudo code of our handler should look like this: mov eax, offset_of_Button1 mov edx, offset_of_new_caption call TControl.SetText And this is all. Well the problem is how to find the offset (pointer) to our Button1. If you are a Delphi programmer you have many times seen this parameter in event handlers of type TObject and having the name Sender. Normaly when the event handler is called by the generated event this Sender is the Form. And due to convention it (the Form pointer) is in EAX while steping in the code of handler. Now I will point on the class info of our TForm1 again. May be you have noticed that except the event handlers names, and RVAs, there were also the name of controls in the Form: 00003FA30 58AC 4300 947A 4300 0200 8906 4400 C402 X.C..zC.....D... 00003FA30 0000 0000 0742 7574 746F 6E31 C802 0000 .....Button1.... Note this 000002C4 value before "Button1". May be you wonder what is this. Well this is the offset after the offset of TForm2 where the pointer to Button1 can be found. So may be you are wondering were will point EAX+000002C4 in our event handler. YES, correct answer - to Button1. So this will be our code: 8B80C8020000 mov eax, [eax+000002C8] BAxxxxxxxx mov edx, the_offset_of_the_new_caption E8xxxxxxxx call 00421E78 Now we need to find some "free space" for the code of our handler, to calculate the relative offset off TControl.SetText and to set the RVA offset of our handler as a handler of TForm1.Button1.OnClick event. First we can put our code at the end of .rsrc section. A good offset will be physical 0004A7A0. This will correspond to RVA 0044F1A0 in .rsrc section. So now we can input the relative offset of our call: 0044F1A0 8B80C8020000 mov eax, [eax+000002C8] 0044F1A6 BAB1F14400 mov edx, 0044F1B1 0044F1AB E8C82CFDFF call 00421E78 0044F1B0 C3 ret Finally we need to add these bytes at physical offset 0004A7A0 : 8B80C8020000BAB1F14400E8C82CFDFFC36269672066756E And also to change the TForm1 class info : 0003FA70 00A0 F144 000C 4275 7474 6F6E 3143 6C69 ...D..Button1Cli This is all now. Save new executable and run it to see the result! See ya again in PART 2.
If you are interested in Delphi reversing and you still havent found the power of DeDe you may want to test it. Feel free to send any coments and feedbacks to firstname.lastname@example.org