+DaFixer谁呢,用过DeDe的人应该了解的!这里只是一部分,余下的我还没有找到,还请小楼指点:
--------------------------------------
本文告诉你如何改变Delphi程序的事件处理,如何用HEX编辑方式增加自己的功能。阅读本文之前需要有一些Delphi的编程经验。
----------------
Delphi逆向工程
--------给Delphi程序增加自己的功能
原著:+DaFixer
地址:http://www.balbaro.com/dafixer/D1.html
翻译:upfeed
----------------
介绍:
------
这是我的第一篇关于Delphi逆向工程的文章,主要是讲解如何加入自己的功能,并且能直接使用到VCL库(控件)。这里会给出一些Delphi可
执行文件格式、类信息以及DFM资源。目的不是为了加什么代码或者破解什么程序,仅仅是给出Delphi事件处理的原理,我们能够以哪些方式修
改程序。希望你能够喜欢它。
需要的工具:
------------
HEX编辑器,别无它物。
目标:
------
没有特别的目标,你可以使用任何一个Delphi程序作为练习对象(但是它们可不能被加壳)。然而文中还是要用一些程序作为例子,这里
(http://www.balbaro.com/dafixer/files/test1.zip)有一个我自己写的,你可以下载。
正文:
------
第一部分:
* Delphi可执行程序、类信息和DFM资源。
*
事件处理程序。
* 修改DFM资源和类信息来重定位事件处理程序。
在开始之前,我先解释Delphi可执行程序的内部结构。由Delphi3,4,5编译的可执行程序有以下几个节:CODE,DATA,BSS,.idata,tls
,.rdata,.rsrc。根据我们的需要,CODE和.rsrc节比较重要。
.rsrc节:
---------
这里除了一般的资源以外,还有工程信息和DFM资源信息,这一节开始部分是常规的资源表,接着是工程信息,最后就是DFM资源了。DFM资
源包括了所有控件的描述,控件(不论是不是可视)published的属性的初始设置。不同Form的资源在不同的区段里(就像小节一样),每个都是以
#54,#50,#46,#30(TPF0)开始,紧跟其后的就是Form的名字,以pascal串形式存放(第一个字节是长度)。每一个DFM小节都是在连接的时候,由
编译器直接从原始的.dfm文件中考过来的。注意DFM资源也称为RCDATA类型的资源,在.rsrc节的资源表中也有描述,所以可以用资源编辑软件
来编辑,效果就像Borland自己的资源编辑环境一样。更有趣的是在DFM资源中到底包含一些什么,答案就是你在Delphi中用对象察看器(左边的
浮动窗口)看到的所有东西。这就是说我们可以仅仅编辑DFM资源数据,来让控件的任何published属性改变。其中就包括了重定位对象的事件处
理程序。
另外,Delphi中的VCL控件有一些过程可以允许你读取RCDATA资源,也可以把它们转存成TXT格式。在classes.pas文件中定义了以下过程:
ObjectBinaryToText()
ObjectResourceToText()
ObjectTextToBinary()
ObjectTextToResource()
用它们可以简单把2进制的DFM RCDATA资源转换成其它的表示形式。一种常见的Form描述如下所示,它其实就是我写的程序中的Form1:
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
当你在设计Form的时候,Delphi程序本身就在频繁的调用这几个过程。如果不相信,可以在Form中选择某些控件,然后Ctrl+C复制,如果
你在Form中Ctrl+V粘贴可以得到一份复制的,如果在文本界面中粘贴的话,Delphi就会调用ObjectBinaryToText(),粘贴的效果就是控件的文
本表现方式。
接下来举一个小例子:我编译了一个简单的小程序,有2个Forms,Form1有2个按钮,按钮1会显示Form2,按钮2出现一个提示框;Form2只
有一个按钮,也是出现一个提示框。下面通过改变DFM资源来修改Form1的2个按钮的事件处理程序。把例子程序用HEX编辑器打开,然后找到下
面:
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 <---这里有按钮1的响应事件名称
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 <---这里有按钮2的响应事件名称
0004A5A0 436C 6963 6B00 0000 5450 4630 0654 466F Click...TPF0.TFo
我们把按钮1和按钮2的事件处理位置对换:
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 <---按钮1的响应事件名称改成按钮2的
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
<---按钮2的响应事件名称改成按钮1的
0004A5A0 436C 6963 6B00 0000 5450 4630
0654 466F Click...TPF0.TFo
这样就可以了!把它另存为一个新的可执行,然后运行,你会发现按钮1和按钮2的效果已经交换了。
用这种方法可以重新定位同一个Form中的控件的事件处理程序,但是也要注意重定位的事件是否匹配,例如把TButton1.OnClick定位到
TForm.OnKeyDown就不行!也不能把Form1.Button1.OnClick定位到Form2.Button1Click事件上,但是我们却可以用另外的方法办到,往下看。
CODE节:
-------
这里存放着所有的类信息和汇编代码。CODE节的最后就是dpr的代码。
我不会解释类信息中的所有数据的含义,主要要介绍如何找一个事件处理程序的RVA地址。还是用HEX编辑器打开那个程序,我们知道有
Form1和Form2,在CODE节中查找字符串'TForm2',可以找到2项:
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....
首先注意到所有的字符串是以pascal的格式存放的。
就在'Button1Click'前面有一个'B8044400',用猜的就知道这个就是Form2.Button1Click的RVA地址。如果我们反编译一下,然后跳到
'004404B8',就会看到下面的代码:
* 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
这里就是处理TForm2.Button1.OnClick事件的程序了。很自然的想到改变这个RVA地址,就可以让它的响应程序变到别的Form中了,那么我
们要知道的就是那个RVA地址了。要注意的是我们不是简单的把事件处理指到任何程序段就可以了,因为不同的处理程序要求不同的参数传递。
所以在我们的例子中是把Form1.Button1.OnClick指到Form2.Button1OnClick,把Form2.Button1.OnClick指到Form1.Button1OnClick,它们都
是TNotifyEvent类型的处理程序,有如下的定义:
Type TNotifyEvent = procedure
(Sender : TObject) of object;
所以我们可以把TNotifyEvent类型的任何过程赋给TButton.OnClick。好!动手干吧。在改变之前我们先找到2个按钮各自的处理程序的RVA
。我们可以在CODE节中找到'TForm1'字符串,然后可以看到下面:
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....
与是我们知道TForm1.Button1Click的RVA是 - 004406D8,TForm1.Button2Click的RVA是 - 004406B0。下面就可以把
TForm1.Button1.OnClick的RVA改成 - 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....
然后把TForm2.Button1.OnClick的RVA改成 - 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....
做完了就另存为一个可执行文件然后运行它,是不是可以了?