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 d_fixer@hotmail.com
=