[系统安全19] 面向对象逆向-虚函数、MFC逆向

这篇具有很好参考价值的文章主要介绍了[系统安全19] 面向对象逆向-虚函数、MFC逆向。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

虚函数存在是为了克服类型域解决方案的缺陷,以使程序员可以在基类里声明一些能够在各个派生类里重新定义的函数。

1 识别简单的虚函数

代码示例:

#include "stdafx.h"
#include <Windows.h>

class CObj
{
public:
	CObj():m_Obj_1(0xAAAAAAAA),m_Obj_2(0xBBBB)
	{
		printf("CObj() Constructor...\r\n");
	}
	~CObj()
	{
		printf("CObj() Destructor...\r\n");
	}
	virtual void Show(int nID)     // 注意这里
	{
		m_Obj_1 = 1;
		printf("ID:%d Who is your God? I am!\r\n",nID);
	}
private:
	int  m_Obj_1;
	WORD m_Obj_2;
};

class CPeople : public CObj
{
public:
	CPeople():m_People_1(0xCCCCCCCC),m_People_2(0xDDDD)
	{
		printf("CPeople() Constructor...\r\n");
	}
	~CPeople()
	{
		printf("CPeople() Destructor...\r\n");
	}
	void Show(int nID)
	{
		printf("ID:%d People!\r\n",nID);
	}
private:
	int  m_People_1;
	WORD m_People_2;
};


int _tmain(int argc, _TCHAR* argv[])
{
	CObj obj;
	CPeople people;
	CObj *pobj;

	pobj = &obj;
	pobj->Show(0);
	pobj = &people;
	pobj->Show(1);
	return 0;
}
// ---------- 输出结果 ----------
// CObj() Constructor...
// CObj() Constructor...
// CPeople() Constructor...
// ID:0 Who is your God? I am!
// ID:1 People!
// CPeople() Destructor...
// CObj() Destructor...
// CObj() Destructor...
// ----------------------------

反汇编代码:

int _tmain(int argc, _TCHAR* argv[])
{
001273B0  push        ebp  
001273B1  mov         ebp,esp  
001273B3  push        0FFFFFFFFh  
001273B5  push        1B3730h  
001273BA  mov         eax,dword ptr fs:[00000000h]    
001273C0  push        eax  
001273C1  sub         esp,108h  
001273C7  push        ebx  
001273C8  push        esi  
001273C9  push        edi  
001273CA  lea         edi,[ebp+FFFFFEECh]  
001273D0  mov         ecx,42h  
001273D5  mov         eax,0CCCCCCCCh  
001273DA  rep stos    dword ptr es:[edi]  
001273DC  mov         eax,dword ptr ds:[001D9004h]
001273E1  xor         eax,ebp  
001273E3  push        eax  
001273E4  lea         eax,[ebp-0Ch]  
001273E7  mov         dword ptr fs:[00000000h],eax              ; 栈保护基址相关代码
	CObj obj;
001273ED  lea         ecx,[ebp-1Ch]                             ; this 指针
001273F0  call        00123D87                                  ; CObj::CObj (0123D87h)  
001273F5  mov         dword ptr [ebp-4],0                       ; 异常处理的辅助标志,以-1为结尾
	CPeople people;
001273FC  lea         ecx,[ebp-38h]                             ; this指针
001273FF  call        001211DB                                  ; CPeople::CPeople (01211DBh)  
00127404  mov         byte ptr [ebp-4],1  
	CObj *pobj;
	pobj = &obj;
00127408  lea         eax,[ebp-1Ch]                             ; 将obj的this指针给eax
0012740B  mov         dword ptr [ebp-44h],eax                   ; 将this指针给pobj的指针
	pobj->Show(0);
0012740E  mov         esi,esp  
00127410  push        0                                         ; 参数压栈
00127412  mov         eax,dword ptr [ebp-44h]  
00127415  mov         edx,dword ptr [eax]  
00127417  mov         ecx,dword ptr [ebp-44h]                   ; 将Obj的指针(指向的是   Obj的this指针)给ecx
0012741A  mov         eax,dword ptr [edx]                       ; 将Obj的this指针所指向的第一项的内容(即Vtbl的第一个元素)给eax 
0012741C  call        eax  
0012741C  ; 在调用完CPeople的构造后,程序采用如下步骤实现
0012741C  ; pobj = &obj;
0012741C  ; pobj ->Show(0);
0012741C  ; 
0012741C  ; 1、将创建完的Obj对象的this指针传递给pobj
0012741C  ; 2、将指this指针给eax
0012741C  ; 3、将this指针第一项(即虚函数表指针)传递给edx
0012741C  ; 4、将pobj的值传递给ecx(注意此步)
0012741C  ; 5、将既虚函数表数组的地址传递给eax
0012741C  ; 6、调用eax
0012741E  cmp         esi,esp  
00127420  call        00122329  
	pobj = &people;
00127425  lea         eax,[ebp-38h]            ; 将People的this指针传给eax
00127428  mov         dword ptr [ebp-44h],eax  ; 将People的this指针给Obj
	pobj->Show(1);
0012742B  mov         esi,esp       
0012742D  push        1                        ; 参数压栈
0012742F  mov         eax,dword ptr [ebp-44h]  ; 将People的this指针给eax
00127432  mov         edx,dword ptr [eax]      ; 将this指针中的第一项,即Vptr给edx
00127434  mov         ecx,dword ptr [ebp-44h]  ; 将People的this指针给ecx
00127437  mov         eax,dword ptr [edx]      ; 将Vptr指向的Vtbl给eax
00127439  call        eax                      ; 调用eax
0012743B  cmp         esi,esp  
0012743D  call        00122329                 ; __RTC_CheckEsp
	return 0;
00127442  mov         dword ptr [ebp+FFFFFEF0h],0  
0012744C  mov         byte ptr [ebp-4],0  
00127450  lea         ecx,[ebp-38h]  
00127453  call        00121E10  
00127458  mov         dword ptr [ebp-4],0FFFFFFFFh  
0012745F  lea         ecx,[ebp-1Ch]  
00127462  call        00123BC0  
00127467  mov         eax,dword ptr [ebp+FFFFFEF0h]  
}

如果没有Debug的符号文件,或者逆向过程中代码不是我们自己写的,那就要先判断它是否是一个类的应用。

跟进函数内部情况:

class CObj
{
00126FD0  push        ebp  
00126FD1  mov         ebp,esp  
00126FD3  sub         esp,0CCh  
00126FD9  push        ebx  
00126FDA  push        esi  
00126FDB  push        edi  
00126FDC  push        ecx  
00126FDD  lea         edi,[ebp-0CCh]  
00126FE3  mov         ecx,33h  
00126FE8  mov         eax,0CCCCCCCCh  
00126FED  rep stos    dword ptr es:[edi]  
00126FEF  pop         ecx  
00126FF0  mov         dword ptr [this],ecx        ; 取this指针 this == [ebp-8] 
00126FF3  mov         eax,dword ptr [this]        ; 取this指针
00126FF6  mov         dword ptr [eax],offset CObj::`vftable' (01B5E54h)  
public:
	CObj():m_Obj_1(0xAAAAAAAA),m_Obj_2(0xBBBB)
00126FFC  mov         eax,dword ptr [this]  
00126FFF  mov         dword ptr [eax+4],0AAAAAAAAh  ; 初始化m_Obj_1为0xAAAAAAAA
00127006  mov         eax,0BBBBh                    ; 初始化m_Obj_2为0xBBBB
0012700B  mov         ecx,dword ptr [this]          ; this指针 this == ecx-8
0012700E  mov         word ptr [ecx+8],ax  
		printf("CObj() Constructor...\r\n");
00127012  push        offset string "CObj() Constructor...\r\n" (01B5E5Ch)  
		printf("CObj() Constructor...\r\n");
00127017  call        _printf (0123D00h)  
0012701C  add         esp,4  
	}
0012701F  mov         eax,dword ptr [this]         ; 将this指针作为返回值 this == ebp-8
00127022  pop         edi  
00127023  pop         esi  
00127024  pop         ebx  
00127025  add         esp,0CCh  
0012702B  cmp         ebp,esp  
0012702D  call        __RTC_CheckEsp (0122329h)  
00127032  mov         esp,ebp  
00127034  pop         ebp  
00127035  ret

通过阅读以上代码可以得出以下过程:

1)找出虚表位置,以及操作的流程

  • 代码里的例子操作了虚表 00126FF6 mov dword ptr [eax],offset CObj::`vftable' (01B5E54h)

这是一个保存函数地址的指针,再通过汇编上下文的猜测,则可大致确定这就是一个虚表,且将值传到了寄存器参数ecx记录地址的第一项。

  • 以寄存器参数ecx为首地址,分别给其4偏移与8偏移处赋值

  • 寄存器参数ecx又作为返回值传了回去。

  • 通过调用函数的分析,ecx里保存的是this指针,并且根据类的内存结构可知,this里的第一项是Vptr。

2)识别构造函数

  • 由于此成员函数是第一个被调用的,通过代码看出汇编函数中的第二件事是初始化数据成员。最后一件事是将this指针当做返回值返回,所以推测该函数为构造函数。

3)逐步分析函数

  • 构造函数与析构函数会对Vptr操作。
  • 在VS默认设置下,构造与析构前都会有相应的异常处理标记置位操作。
  • 虚函数的调用一般采用eax。

2 识别较复杂的虚函数

经验小结:

  • new出来的对象会以其在堆中申请空间的指针作为this指针传入参与构造。
  • new出来的对象其虚函数调用的寻址方式与普通构造出来的不同。
  • delete对象时会先析构自己,再析构父类,最后再执行delete。
  • new出来的对象如果其成员函数派生于纯虚函数,在delete时只调用父类的析构。
  • 如果此类为抽象类(包含纯虚函数),那么其虚表的对应项会填充指向库函数__purecall的函数指针。

虚函数调用的固定模式,紧盯对各个虚表的操作。从而根据上下文即可大致确定虚函数的调用与类的析构与构造。

3 识别类的继承关系

  • 根据构造函数内的构造顺序分辨此函数所属类的继承情况
  • 总结并记录分析结果
  • VS的release版中存在同时使用ecx、esi寄存器传递this指针的情况。

4 逆向MFC程序

MFC程序关键特征点

版本 对应动态库 静态库中使用MFC时的特征 动态库中使用MFC的特征
4.0 mfc40.dll call [ebp+0x14] call [ebp+0x14]
6.0 mfc42.dll call [ebp+0x14] call [ebp+0x14]
7.1 mfc71.dll call [ebp+0x14] call [ebp+0x14]
10.0 mfc100.dll call [ebp+0x14] mov edx,[ebp+0x14]

分析核心重点

1)判断目标程序是不是MFC程序,如果是,判断其MFC版本

OD快捷键:Ctrl+E 打开模块窗口,并在模块窗口寻找类似于mfc*.dll这样的模块。

如果找到了就可以根据DLL的名称判定程序所用的MFC版本,如果找不到则证明这是一个在静态库中使用MFC的程序。

2)根据目标程序调用MFC方式的不同而采取不同的方式搜索特征

OD快捷键:Ctrl+F 搜索特征 call [ebp+0x14]

由于搜索的特征位于消息分发函数里,因此特征指令所在的位置应该是一个非常大的switch-case。

3)在合适的地方下断点,并跟进到相应消息的函数中。

设置按钮点击事件下断点,即可跟进到达相应消息的函数中。

这里可以参考:

看雪《MFC程序逆向》https://bbs.pediy.com/thread-54150.htm文章来源地址https://www.toymoban.com/news/detail-729031.html

到了这里,关于[系统安全19] 面向对象逆向-虚函数、MFC逆向的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • VS2019 MFC CreateFontW 创建字体函数详细解读

    项目 2022/09/28 4 个参与者 反馈 CreateFont  函数创建具有指定特征的逻辑字体。 随后可将逻辑字体选为任何设备的字体。 C++复制 [in] cHeight 字体字符单元格或字符的高度(以逻辑单位为单位)。 字符高度值 (也称为 em 高度) 是字符单元格高度值减去内部前导值。 字体映射器按以

    2024年02月16日
    浏览(38)
  • MFC使用友元函数访问窗体类成员变量

    首先创建一个窗体类指针的全局变量 在窗体类的OnInitDialog函数中将指针赋值this,在OnInitDialog中窗体已经创建完成。这样指针就可以指向窗体实例

    2024年02月07日
    浏览(27)
  • 【计算机图形学基础教程】MFC基本绘图函数2

    CGdiObject类:GDI绘图工具的基类 CBitmap类:封装了GDI画刷,可以选作设备上下文的当前画刷,用于填充图形的内部 CFont类:封装了GDI字体,可以选作设备上下文的当前字体 CPalette类:封装了GDI调色板,提供应用程序和显示器之间的颜色接口 CPen类:封装了GDI画笔,可以选作设备

    2024年02月03日
    浏览(45)
  • MFC为资源对话框添加消息处理函数和初始化控件

    现在我VC6新建了一个对话框工程;又在资源添加了一个新的对话框,并为新的对话框添加了名为CTestDlg的类; 在主对话框的cpp文件包含#include \\\"TestDlg.h\\\"; 在主对话框的cpp文件的OnInitDialog()成员函数中,添加2句,     CTestDlg tdlg;     tdlg.DoModal(); 就可以弹出这个对话框; 在新

    2024年01月18日
    浏览(36)
  • MFC 简单的SendMessage子窗口调用主窗口函数(消息映射)的实现

    只说实现,不讲原理 环境:VS2022 community版 0.先建立一个全局调用的主对话框的指针g_pMainThis; 1.建立一个基于对话框的MFC工程; 2.在预编译头文件“phc.h”或“stdafx.h”定义消息调用的宏,其值要“WM_USER+100”以上; 3.在主对话框类建立消息映射的功能实现函数; 4.建立一个子

    2024年02月11日
    浏览(34)
  • MFC管理系统

    初始化窗口实列 添加控件变量 WM_SIZE 消息设置窗口大小变化 初始化列表 WM_SIZE 消息设置列表大小 添加员工对话框 添加类 添加控件变量 设置按钮 添加下拉框内容 判断工号是否为空 做一个和添加一样的对话框 添加类 初始化 关闭窗口进行保存 // CAddDlg.h 对话框 //CAddDlg.cpp: 实

    2024年02月13日
    浏览(23)
  • 简易MFC的成绩管理系统

    掌握MFC控件的基本使用,结合了面向对象和Window消息机制的知识。 选择做简单的成绩管理系统,该项目切合大学生实际情况。易于更好理解。 项目实现了成绩的增加、修改、删除、存储(文件读写操作)的功能。 打开软件:VS2022;创建新项目 MFC应用 ;选择 基于对话框 ;有

    2024年02月11日
    浏览(26)
  • vs2019(MFC)--简单登录系统(1)

    (接上一条ado连接数据库)(关于ado接数据库的使用,见登录程序) 1.建立数据库access   2.在mfc对话框中添加控件  (我这里选择的是每个按钮登录到对应界面,也可以添加限制条件,通过一个按钮转到对应身份的对应界面,道理一样) 关于身份编辑框中下拉框内容的设置

    2024年02月09日
    浏览(29)
  • 【MFC】学生成绩管理系统(期末项目)

    如果需要代码请评论区留言或私信 E-R图 关系模式 教师(工号,姓名,学院) 主键(工号) 学生(学号,姓名,性别,年龄,班级,专业,学分) 主键(学号) 课程(课程编号,教师编号,课程名称,课程学分) 主键(课程编号) 外键(教师编号) 选课(学号,课程编号,分数) 主键(学号,课

    2024年01月17日
    浏览(40)
  • MFC中的窗体绘制事件函数:OnCtlColor、OnPaint、OnNcPaint、OnDrawItem、OnEraseBkgnd、OnDraw

    参考:https://learn.microsoft.com/ 即将绘制子控件时,框架会调用此成员函数。 参数 pDC 包含指向子窗口的显示上下文的指针。 可能是暂时性指针。 pWnd 包含指向请求颜色的控件的指针。 可能是暂时性指针。 nCtlColor 包含以下用于指定控件类型的值之一: CTLCOLOR_BTN 按钮控件 CTL

    2024年02月12日
    浏览(24)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包