吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 1308|回复: 3

[Delphi] Delphi的面向对象

[复制链接]
李沉舟 发表于 2018-7-15 16:51 | 显示全部楼层 |阅读模式

  • 静态方法与类字段

[Delphi] 纯文本查看 复制代码
implementation

{$R *.dfm}
type

  TWorker = class(TObject)
  public
    Name: string;
    Age: Cardinal;
    procedure SetWorker(sName: string; nAge: Cardinal);
  end;

procedure TWorker.SetWorker(sName: string; nAge: Cardinal);
begin
  Name := sName;
  Age := nAge;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Worker: TWorker;
begin
  Worker := TWorker.Create;
  Worker.SetWorker('Marx', 55);
end;


反汇编代码如下。

[Asm] 纯文本查看 复制代码
CODE:0044E00C _TForm1_Button1Click proc near          ; DATA XREF: CODE:0044DF10o
CODE:0044E00C                 mov     dl, 1
CODE:0044E00E                 mov     eax, off_44DF50
CODE:0044E013                 call    unknown_libname_26 ; BDS 2005-2007 and Delphi6-7 Visual Component Library ;TWorker.Create
CODE:0044E018                 mov     ecx, 37h ;nAge
CODE:0044E01D                 mov     edx, offset _str_Marx.Text ;sString
CODE:0044E022                 call    sub_44DFB8 ;Worker.SetWorker
CODE:0044E027                 retn
CODE:0044E027 _TForm1_Button1Click endp


调用TWorker.Create后,成功返回一个对象的实例,接着,按照fastcall调用约定,调用了Worker.SetWorker方法。
此处实际隐含了一个Self指针,即C++里的this指针。
寄存器说明
EAXSelf
EDXsString
ECXnAge

Work.SetWorker的反汇编代码如下。

[Asm] 纯文本查看 复制代码
CODE:0044DFB8 sub_44DFB8      proc near               ; CODE XREF: _TForm1_Button1Click+16p
CODE:0044DFB8
CODE:0044DFB8 var_4           = dword ptr -4
CODE:0044DFB8
CODE:0044DFB8                 push    ebp
CODE:0044DFB9                 mov     ebp, esp
CODE:0044DFBB                 push    ecx
CODE:0044DFBC                 push    ebx
CODE:0044DFBD                 push    esi
CODE:0044DFBE                 mov     esi, ecx
CODE:0044DFC0                 mov     [ebp+var_4], edx
CODE:0044DFC3                 mov     ebx, eax        ; EBX - > Self
CODE:0044DFC5                 mov     eax, [ebp+var_4]
CODE:0044DFC8                 call    @System@@LStrAddRef$qqrpv ; System::__linkproc__ LStrAddRef(void *)
CODE:0044DFCD                 xor     eax, eax
CODE:0044DFCF                 push    ebp
CODE:0044DFD0                 push    offset loc_44DFFF
CODE:0044DFD5                 push    dword ptr fs:[eax]
CODE:0044DFD8                 mov     fs:[eax], esp
CODE:0044DFDB                 lea     eax, [ebx+4]    ; EAX - > Self + 4
CODE:0044DFDE                 mov     edx, [ebp+var_4] ; EDX - > sName
CODE:0044DFE1                 call    @System@@LStrAsg$qqrpvpxv ; 执行字符串拷贝工作
CODE:0044DFE6                 mov     [ebx+8], esi    ; [Self + 8] = nAge
CODE:0044DFE9                 xor     eax, eax
CODE:0044DFEB                 pop     edx
CODE:0044DFEC                 pop     ecx
CODE:0044DFED                 pop     ecx
CODE:0044DFEE                 mov     fs:[eax], edx


此时,Worker的内存布局如下。
00943DB0  9C DF 44 00 C8 3D 94 00 37 00 00 00              溸D.??7.....


0x943DC8指向[Marx]字符串,0x37(55)即nAge。

  • 类的继承与虚方法


[Delphi] 纯文本查看 复制代码
implementation

{$R *.dfm}
type
  TClassA = class(TObject)
  public
    procedure GetName(); virtual;
  end;

procedure TClassA.GetName();
begin
  ShowMessage('My Name is "TClassA"');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ClassA: TClassA;
begin
  classA := TClassA.Create;
  ClassA.GetName;
  ClassA.Free;
end;


反汇编代码如下。
此时ClassA的内存构造如下。
00953D8C  48 27 45 00                                      H'E.

0x452748的内存如下。
00452748  54 27 45 00                                      T'E.

0x452754,即虚方法地址。
反汇编代码如下。

[Asm] 纯文本查看 复制代码
00452754   .  B8 68274500   mov eax,Project1.00452768
00452759   .  E8 2E8DFDFF   call Project1.0042B48C
0045275E   .  C3            retn


[Delphi] 纯文本查看 复制代码
implementation

{$R *.dfm}
type
  TClassA = class(TObject)
  public
    procedure GetName(); virtual;
  end;

  TClassB = class(TClassA)
  public
    procedure GetAge(); virtual;
    procedure GetInfor(); virtual;
  end;

procedure TClassA.GetName();
begin
  ShowMessage('My Name is "TClassA"');
end;

procedure TClassB.GetAge();
begin
  ShowMessage('I am 16');
end;

procedure TClassB.GetInfor();
begin
  ShowMessage('I am a senior school teacher');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ClassB: TClassB;
begin
  ClassB := TClassB.Create;
  ClassB.GetName();
  ClassB.GetAge();
  ClassB.GetInfor();
  ClassB.Free;
end;


反汇编代码如下。

[Asm] 纯文本查看 复制代码
CODE:00452830 _TForm1_Button1Click proc near          ; DATA XREF: CODE:004526BCo
CODE:00452830                 push    ebx
CODE:00452831                 mov     dl, 1
CODE:00452833                 mov     eax, off_452754
CODE:00452838                 call    unknown_libname_26 ; BDS 2005-2007 and Delphi6-7 Visual Component Library
CODE:0045283D                 mov     ebx, eax
CODE:0045283F                 mov     eax, ebx
CODE:00452841                 mov     edx, [eax]
CODE:00452843                 call    dword ptr [edx]
CODE:00452845                 mov     eax, ebx
CODE:00452847                 mov     edx, [eax]
CODE:00452849                 call    dword ptr [edx+4]
CODE:0045284C                 mov     eax, ebx
CODE:0045284E                 mov     edx, [eax]
CODE:00452850                 call    dword ptr [edx+8]
CODE:00452853                 mov     eax, ebx        ; this
CODE:00452855                 call    @System@TObject@Free$qqrv ; System::TObject::Free(void)
CODE:0045285A                 pop     ebx
CODE:0045285B                 retn
CODE:0045285B _TForm1_Button1Click endp


此时ClassB的内存构造如下。
00953D8C  A0 27 45 00                                      ?E..

0x4527A0的内存如下。
004527A0  B4 27 45 00 E0 27 45 00 FC 27 45 00              ?E.?E.?E.TC


0x4527B4、0x4527E0、0x4527FC。这是虚方法表,分别对应了3个虚方法。其中第一个是从父类TClassA里继承下来的。

  • 类的动态方法


[Delphi] 纯文本查看 复制代码
implementation

{$R *.dfm}
type
  TClassA = class(TObject)
  public
    procedure GetName(); dynamic;
  end;

procedure TClassA.GetName();
begin
  ShowMessage('I am Mike');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ClassA: TClassA;
begin
  ClassA := TClassA.Create;
  ClassA.GetName();
  ClassA.Free;
end;


反汇编代码如下。

[Asm] 纯文本查看 复制代码
CODE:00452778 _TForm1_Button1Click proc near          ; DATA XREF: CODE:004526BCo
CODE:00452778                 push    ebx
CODE:00452779                 push    esi
CODE:0045277A                 mov     dl, 1
CODE:0045277C                 mov     eax, off_4526FC
CODE:00452781                 call    unknown_libname_26 ; BDS 2005-2007 and Delphi6-7 Visual Component Library
CODE:00452786                 mov     ebx, eax
CODE:00452788                 mov     eax, ebx
CODE:0045278A                 mov     si, 0FFFFh
CODE:0045278E                 call    @System@@CallDynaInst$qqrv ; System::__linkproc__ CallDynaInst(void)
CODE:00452793                 mov     eax, ebx        ; this
CODE:00452795                 call    @System@TObject@Free$qqrv ; System::TObject::Free(void)
CODE:0045279A                 pop     esi
CODE:0045279B                 pop     ebx
CODE:0045279C                 retn
CODE:0045279C _TForm1_Button1Click endp


与虚方法的调用不同,动态方法使用索引调用,而且是通过CallDynaInst这个库函数实现。
而该库函数只是简单的从Self指针里取出了VMT([Self + 0]),就转给另一个库函数了。该库函数的反汇编代码如下。

[Asm] 纯文本查看 复制代码
CODE:00403668 unknown_libname_28 proc near            ; CODE XREF: System::__linkproc__ CallDynaInst(void)+4p
CODE:00403668                                         ; System::__linkproc__ FindDynaInst(void)+5p ...
CODE:00403668                 push    edi
CODE:00403669                 xchg    eax, esi
CODE:0040366A                 jmp     short loc_40366E
CODE:0040366C ; ---------------------------------------------------------------------------
CODE:0040366C
CODE:0040366C loc_40366C:                             ; CODE XREF: unknown_libname_28+1Fj
CODE:0040366C                 mov     esi, [esi]
CODE:0040366E
CODE:0040366E loc_40366E:                             ; CODE XREF: unknown_libname_28+2j
CODE:0040366E                 mov     edi, [esi-30h]
CODE:00403671                 test    edi, edi
CODE:00403673                 jz      short loc_403682
CODE:00403675                 movzx   ecx, word ptr [edi]
CODE:00403678                 push    ecx
CODE:00403679                 add     edi, 2
CODE:0040367C                 repne scasw
CODE:0040367F                 jz      short loc_40368B
CODE:00403681                 pop     ecx
CODE:00403682
CODE:00403682 loc_403682:                             ; CODE XREF: unknown_libname_28+Bj
CODE:00403682                 mov     esi, [esi-24h]
CODE:00403685                 test    esi, esi
CODE:00403687                 jnz     short loc_40366C
CODE:00403689                 pop     edi
CODE:0040368A                 retn
CODE:0040368B ; ---------------------------------------------------------------------------
CODE:0040368B
CODE:0040368B loc_40368B:                             ; CODE XREF: unknown_libname_28+17j
CODE:0040368B                 pop     eax
CODE:0040368C                 add     eax, eax
CODE:0040368E                 sub     eax, ecx
CODE:00403690                 mov     esi, [edi+eax*2-4]
CODE:00403694                 pop     edi
CODE:00403695                 retn
CODE:00403695 unknown_libname_28 endp


代码我没有标注释,简单解释一下意思吧。首先,从[VMT– 0x30]处,得到动态方法的表起始地址。
本例中的动态方法表如下。
00452748  01 00 FF FF 58 27 45 00                          .

评分

参与人数 5威望 +1 HB +13 THX +3 收起 理由
消逝的过去 + 2
agan8888 + 1
zxjzzh + 1 [吾爱汇编论坛52HB.COM]-学破解防破解,知进攻懂防守!
playboy + 1
Shark恒 + 1 + 10 + 1 [快捷评语] - 评分=感恩!简单却充满爱!感谢您的作品!

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 李沉舟 发表于 2018-7-15 16:52 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 李沉舟 发表于 2018-7-15 16:53 | 显示全部楼层

本例中的动态方法表如下。

00452748  01 00 FF FF 58 27 45 00                          .
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
 楼主| 李沉舟 发表于 2018-7-15 16:54 | 显示全部楼层

只是取出Source的VMT进行比对。

  • 虚表HOOK


[Delphi] 纯文本查看 复制代码
implementation

{$R *.dfm}

type
  TClassA = class(TObject)
  public
    procedure GetName(); virtual;
  end;

procedure TClassA.GetName();
begin
  ShowMessage('我是ClassA');
end;

procedure MyGetName(Self: Cardinal);
begin
  ShowMessage('我才不是什么ClassA');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  ClassA: TClassA;
  pVMT: Pointer;
  dwFlag: Cardinal;
begin
  ClassA := TClassA.Create;
  ClassA.GetName(); //第一次正常调用
  //开始HOOK
  pVMT := Pointer(PCardinal(ClassA)^); //得到VMT
  VirtualProtect(pVMT, 4, PAGE_READWRITE, dwFlag); //修改VMT的内存属性为可写
  PCardinal(pVMT)^ := Cardinal(@MyGetName); //替换
  VirtualProtect(pVMT, 4, dwFlag, dwFlag); //还原VMT的内存属性
  ClassA.GetName(); //第二次非正常调用
  ClassA.Free;
end;


只要得到VMT,并对其中的虚方法表进行替换就可以了。前提必须知道要HOOK的虚方法的索引位置。


  • 结尾

本文权当抛砖引玉,如果想要更深入研究,请阅读Delphi帮助文件中和RTTI有关的内容。

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

快速回复 返回顶部 返回列表