最近分析了一下MFC中的一些核心机制。写出一些心得与各位大佬前辈们探讨交流。文本主要讨论是的MFC中的RTTI机制与MFC中消息路由机制探讨与利用。(本文是探讨MFC原理和攻防心得请不要使用文中提到技术去触犯法律事情,发生后果与作者无关。如有侵权请联系作者删除。)
编译器: Microsoft Visual Studio Community 2019 16.11.44
系统:Windows 10 专业版 22H2 19045.5487
MFC版本:14.29.30040.0
在MFC中是有RTTI机制的。这个可以在微软的官方文档查询到。我们在创建一个MFC程序的时候IDE会生成一个 xx(工程名)App类,并且继承与CWinApp类。主要负责程序的初始化运行退出等工作。并且会生成一个全局变量。
MFC在开发过程中是不可能预测到用户写类的是什么,如果要对本身的框架内的组件进行扩展怎么办?在真正的初始化过程中是如何进行的呢?所以需要RTTI机制,让框架能识别类型,并且能动态创建对象。
在创建一个工程的时候IDE会自动给我们的xxApp类重写一个InitInstance,这里就使用了RTTI。
首先介绍一下CRuntimeClass
他是一个RTTI结构体MFC中RTTI信息都存储于这个结构体中。关键信息如下:
介绍一下这些方法
首先MFC在设计之初就设计了类似Java一样顶层父类CObject,其它类都继承与它。这里借用一下微软的MFC框架图。

在CObject中有一个这样的方法和和这样的一个成员。这样就具备了动态创建和获取类的能力。
根据架构图可以得知,MFC中所有类都继承与CObjec,所以整个框架都有RTTI了。
现在有个问题?用户的类是怎么加入RTTI的呢?以CTestDocDoc这个类为例
着重关注一下这个宏:
把它扩展开来是这样的
DECLARE_DYNAMIC 展开
这样CTestDocDoc 就具备动态识别和动态创建的能力了。
现在还有一个问题,这些RTTI是在什么时候创建的并且怎么把他们关联起来用?
在CTestDocDoc.cpp中有这样的一个宏
我们展开后,可以看到创建了一个CRuntimeClass,并且填写了RTTI信息,绑定了父类。
解释一下RUNTIME_CLASS宏
展开后就是这样
所以我们可以得知RTTI是一个向上绑定关系。也就是IDE窗口的类和MFC本身类中都会存在RTTI机制。
从上源码分析中可以看到这些类都依靠自身的静态成员xx::classxx来实现。所以说明在程序编译的时候已经生产,我猜测应该是在RDATA节中存放。可以通过静态分析来显示所有RTTI机制的类。
实现思路如下:

相关核心代码:
定义关键结构
工具函数实现
利用内存文件共享,实现文件打开和关闭和读取
找到Cobjec
Dump类关系
最后的效果:

当然这个思路仅限静态链接的MFC动态链接需要稍微修改一下。
在MFC中用户的按钮与控件的绑定一直都是使用UI界面进行实现的。用户只需要拖动和点击就可以创建一个响应函数。这里就是使用了消息路由机制。我们可以从看到这两个比较关键的宏
假设展开后是这样的
主要就是创建了这个表
static const AFX_MSGMAP_ENTRY _messageEntries[]
和重写几个虚函数,最关键是这个表结构是什么样的?
主要就是控件消息ID,和消息签名,还有消息成员函数指针。
这里的nSig主要是表示这个AFX_PMSG pfn函数指针的参数类型。在消息派发中处理不同控件参数不一致的问题。MFC定义了所有的可能情况
如何把父类和子类相连呢?假设子类中没有消息响应处理怎么办?所以回到宏那
我们可以看到有这样一个代码:
AFX_MSGMAP 结构体是这样的:他有指向上一个 theClass::GetThisMessageMap(),然后根据宏DECLARE_MESSAGE_MAP ,他是一个静态函数。这样就构成一个单向向上链表,相当于这是一个元素节点。当子类没有消息的时候会直接找父类的
在用户视角中是这样的

在MFC中窗口绑定有点特殊所以需要讨论一下,后面用得上。窗口的创建主要在CWnd::CreateEx中实现的
这里有个特殊的地方
这里框架自己HOOK了自己
内部实现可以看到SetWindowsHookEx他hook的主要还是窗口创建消息这些。转到过程函数中可以发现主要是对窗口进行过滤,因为窗口创建的这些消息是无法再消息循环中拿到的所以需要提前拦截获取。并且修改了消息循环最后绑定到MFC自己的回调中。
这样MFC就可以把所有子窗口都绑定到一个消息循环中来这样集中派发消息。核心函数主要就是这个AfxWndProc。
这里简单介绍一下消息派发。篇幅有限望各位大佬理解。在HOOK的过程有一个关键函数
主要作用就是hWnd和CWnd对象加入到Hash表里面来,这个表放在Tls中存储。
MFC有一个线程管理类专门管理这些信息
在消息循环中MFC会从MAP中访问这些
拿到对应的pWnd 后就会使用消息路由机制找到相对于的处理函数,主要就是循环遍历。
我们知道了在MFC中过程函数是唯一的,并且存在一个消息路由表,可以拿到这个消息路由表并且打印这些虚函数和对应消息映射方便我们的逆向查找相关按钮和组件。实现思路如下:

首先我们创建一个MFCDLL工程方便我们使用MFC头文件。
关键实现代码:
遍历顶层窗口函数实现:
拿到消息循环过程函数
替换过程函数成我们的
自己过程函数实现
拿到FromHandlePermanent ,这里展示release版本,主要是通过函数偏移进行计算从而拿到地址。
打印单链路上的RTTI信息
RTTI实现
通过虚表拿到 CWnd::FromHandlePermanent
这里有个小技巧,自己计算虚表太麻烦我们可以遍历虚表并且使用VS自带的提示去判断到底是哪个。不同的版本可以下载不同的版本的mfc自行编译计算偏移位置。大致思路是这样的

最后在解析信息,这里就罗列主要核心代码,因为有很多字符串处理代码就简化展示一下
最后的效果图:

上面提到过MAP这些关键信息是从tls里面拿到的,而且是有一个类进行管理所以肯定有一个创建过程。通过逆向分析可以看到
在initterm中可以看到

在Initerm表中

我们回到源码中:
当_afxThreadState为空的时候就会创建 AFX_MODULE_STATE
在函数内部有这样的函数
由于编译器的优化会导致只剩下这个_afxBaseModuleState.GetData();,这个可以拿到AFX_MODULE_STATE类,并且整个进程只有一个唯一的。
而AFX_MODULE_STATE 继承与CNoTrackObject
并且存在一个m_pmapHWND成员在回调的时候afxMapHWND就是使用它,所以拿到他几乎就拿到所有信息。
我们只需要定位这个函数就行了。然后进行调用即可。

首先个人觉得需要对CRunTime进行加密,尤其是字符串加密这样就可以防止静态分析,其次需要对注入进行检测比如对模块进行扫描。
extern xxxApp xxApp;
/
/
....部分代码实现
pDocTemplate
=
new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDocDoc),
RUNTIME_CLASS(CMainFrame),
/
/
主 SDI 框架窗口
RUNTIME_CLASS(CTestDocView));
/
/
....部分代码实现
/
/
....部分代码实现
pDocTemplate
=
new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CTestDocDoc),
RUNTIME_CLASS(CMainFrame),
/
/
主 SDI 框架窗口
RUNTIME_CLASS(CTestDocView));
/
/
....部分代码实现
struct CRuntimeClass
{
/
/
Attributes
LPCSTR m_lpszClassName;
int
m_nObjectSize;
UINT m_wSchema;
/
/
schema number of the loaded
class
CObject
*
(PASCAL
*
m_pfnCreateObject)();
/
/
NULL
=
> abstract
class
CRuntimeClass
*
(PASCAL
*
m_pfnGetBaseClass)();
CRuntimeClass
*
m_pBaseClass;
/
/
Operations
CObject
*
CreateObject();
BOOL
IsDerivedFrom(const CRuntimeClass
*
pBaseClass) const;
/
/
dynamic name lookup
and
creation
static CRuntimeClass
*
PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass
*
PASCAL FromName(LPCWSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCWSTR lpszClassName);
/
/
Implementation
void Store(CArchive& ar) const;
static CRuntimeClass
*
PASCAL Load(CArchive& ar, UINT
*
pwSchemaNum);
/
/
CRuntimeClass objects linked together
in
simple
list
CRuntimeClass
*
m_pNextClass;
/
/
linked
list
of registered classes
const AFX_CLASSINIT
*
m_pClassInit;
};
struct CRuntimeClass
{
/
/
Attributes
LPCSTR m_lpszClassName;
int
m_nObjectSize;
UINT m_wSchema;
/
/
schema number of the loaded
class
CObject
*
(PASCAL
*
m_pfnCreateObject)();
/
/
NULL
=
> abstract
class
CRuntimeClass
*
(PASCAL
*
m_pfnGetBaseClass)();
CRuntimeClass
*
m_pBaseClass;
/
/
Operations
CObject
*
CreateObject();
BOOL
IsDerivedFrom(const CRuntimeClass
*
pBaseClass) const;
/
/
dynamic name lookup
and
creation
static CRuntimeClass
*
PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass
*
PASCAL FromName(LPCWSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCWSTR lpszClassName);
/
/
Implementation
void Store(CArchive& ar) const;
static CRuntimeClass
*
PASCAL Load(CArchive& ar, UINT
*
pwSchemaNum);
/
/
CRuntimeClass objects linked together
in
simple
list
CRuntimeClass
*
m_pNextClass;
/
/
linked
list
of registered classes
const AFX_CLASSINIT
*
m_pClassInit;
};
/
/
类的名称
LPCSTR m_lpszClassName;
/
/
对象的大小,用于动态内存分配
int
m_nObjectSize;
/
/
Schema 版本号
UINT m_wSchema;
/
/
schema number of the loaded
class
/
/
用于 MFC 动态对象创建
CObject
*
(PASCAL
*
m_pfnCreateObject)();
/
/
指向基类的 CRuntimeClass 结构
CRuntimeClass
*
m_pBaseClass;
/
/
类的名称
LPCSTR m_lpszClassName;
/
/
对象的大小,用于动态内存分配
int
m_nObjectSize;
/
/
Schema 版本号
UINT m_wSchema;
/
/
schema number of the loaded
class
/
/
用于 MFC 动态对象创建
CObject
*
(PASCAL
*
m_pfnCreateObject)();
/
/
指向基类的 CRuntimeClass 结构
CRuntimeClass
*
m_pBaseClass;
/
/
通过类名 动态创建对象
CObject
*
CreateObject();\
/
/
通过字符串断继承层次
BOOL
IsDerivedFrom(const CRuntimeClass
*
pBaseClass) const;
/
/
dynamic name lookup
and
creation
/
/
通过类名(char
*
或 wchar_t
*
)查找该类对应的 CRuntimeClass 结构
static CRuntimeClass
*
PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass
*
PASCAL FromName(LPCWSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCWSTR lpszClassName);
/
/
通过类名 动态创建对象
CObject
*
CreateObject();\
/
/
通过字符串断继承层次
BOOL
IsDerivedFrom(const CRuntimeClass
*
pBaseClass) const;
/
/
dynamic name lookup
and
creation
/
/
通过类名(char
*
或 wchar_t
*
)查找该类对应的 CRuntimeClass 结构
static CRuntimeClass
*
PASCAL FromName(LPCSTR lpszClassName);
static CRuntimeClass
*
PASCAL FromName(LPCWSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCSTR lpszClassName);
static CObject
*
PASCAL CreateObject(LPCWSTR lpszClassName);
virtual CRuntimeClass
*
GetRuntimeClass() const;
static const CRuntimeClass classCObject;
virtual CRuntimeClass
*
GetRuntimeClass() const;
static const CRuntimeClass classCObject;
class
CTestDocDoc : public CDocument
{
protected:
/
/
仅从序列化创建
CTestDocDoc() noexcept;
DECLARE_DYNCREATE(CTestDocDoc)
class
CTestDocDoc : public CDocument
{
protected:
/
/
仅从序列化创建
CTestDocDoc() noexcept;
DECLARE_DYNCREATE(CTestDocDoc)
DECLARE_DYNCREATE(CTestDocDoc)
DECLARE_DYNCREATE(CTestDocDoc)
DECLARE_DYNCREATE
```cpp
DECLARE_DYNAMIC(CTestDocDoc)
/
/
提供运行时类型识别(RTTI)支持
static CObject
*
PASCAL CreateObject();
DECLARE_DYNCREATE
```cpp
DECLARE_DYNAMIC(CTestDocDoc)
/
/
提供运行时类型识别(RTTI)支持
static CObject
*
PASCAL CreateObject();
public:
static const CRuntimeClass classCTestDocDoc;
/
/
运行时类信息
virtual CRuntimeClass
*
GetRuntimeClass() const;
/
/
获取 CRuntimeClass
public:
static const CRuntimeClass classCTestDocDoc;
/
/
运行时类信息
virtual CRuntimeClass
*
GetRuntimeClass() const;
/
/
获取 CRuntimeClass
IMPLEMENT_DYNCREATE(CTestDocDoc, CDocument)
IMPLEMENT_DYNCREATE(CTestDocDoc, CDocument)
CObject
*
PASCAL CTestDocDoc::CreateObject()
{
return
new CTestDocDoc;
/
/
运行时动态创建 CTestDocDoc 对象
}
AFX_COMDAT const CRuntimeClass CTestDocDoc::classCTestDocDoc
=
{
"CTestDocDoc"
,
/
/
记录类名
sizeof(CTestDocDoc),
/
/
记录对象大小
0xFFFF
,
/
/
序列化 Schema 版本
CTestDocDoc::CreateObject,
/
/
指向 CreateObject() 方法(用于动态创建对象)
RUNTIME_CLASS(CDocument),
/
/
指向基类 CDocument 的 CRuntimeClass 结构
NULL,
/
/
MFC 内部字段
NULL
/
/
MFC 内部字段
};
CRuntimeClass
*
CTestDocDoc::GetRuntimeClass() const
{
return
RUNTIME_CLASS(CTestDocDoc);
}
CObject
*
PASCAL CTestDocDoc::CreateObject()
{
return
new CTestDocDoc;
/
/
运行时动态创建 CTestDocDoc 对象
}
AFX_COMDAT const CRuntimeClass CTestDocDoc::classCTestDocDoc
=
{
"CTestDocDoc"
,
/
/
记录类名
sizeof(CTestDocDoc),
/
/
记录对象大小
0xFFFF
,
/
/
序列化 Schema 版本
CTestDocDoc::CreateObject,
/
/
指向 CreateObject() 方法(用于动态创建对象)
RUNTIME_CLASS(CDocument),
/
/
指向基类 CDocument 的 CRuntimeClass 结构
NULL,
/
/
MFC 内部字段
NULL
/
/
MFC 内部字段
};
CRuntimeClass
*
CTestDocDoc::GetRuntimeClass() const
{
return
RUNTIME_CLASS(CTestDocDoc);
}
((CRuntimeClass
*
)(&CTestDocDoc::classCTestDocDoc))
((CRuntimeClass
*
)(&CTestDocDoc::classCTestDocDoc))
class
CObject {
};
struct CRuntimeClass
{
/
/
Attributes
LPCSTR m_lpszClassName;
int
m_nObjectSize;
UINT m_wSchema;
CObject
*
(PASCAL
*
m_pfnCreateObject)();
CRuntimeClass
*
m_pBaseClass;
CRuntimeClass
*
m_pNextClass;
const void
*
m_pClassInit;
};
class
CObject {
};
struct CRuntimeClass
{
/
/
Attributes
LPCSTR m_lpszClassName;
int
m_nObjectSize;
UINT m_wSchema;
CObject
*
(PASCAL
*
m_pfnCreateObject)();
CRuntimeClass
*
m_pBaseClass;
CRuntimeClass
*
m_pNextClass;
const void
*
m_pClassInit;
};
DWORD VaToFileOffset(MY_INT VaPoint, MY_INT PointerToRawData, MY_INT VirtualAddress , MY_INT ImageBase) {
return
VaPoint
+
PointerToRawData
-
VirtualAddress
-
ImageBase;
}
DWORD FileOffsetToVa(MY_INT VaPoint, MY_INT PointerToRawData, MY_INT VirtualAddress , MY_INT ImageBase) {
return
VaPoint
-
PointerToRawData
+
VirtualAddress
+
ImageBase;
}
DWORD VaToFileOffset(MY_INT VaPoint, MY_INT PointerToRawData, MY_INT VirtualAddress , MY_INT ImageBase) {
return
VaPoint
+
PointerToRawData
-
VirtualAddress
-
ImageBase;
}
DWORD FileOffsetToVa(MY_INT VaPoint, MY_INT PointerToRawData, MY_INT VirtualAddress , MY_INT ImageBase) {
return
VaPoint
-
PointerToRawData
+
VirtualAddress
+
ImageBase;
}
/
/
文件打开函数,返回需要的所有句柄和指针
bool
OpenFile(const char
*
szPath, HANDLE
*
phFile, HANDLE
*
phMapFile,
LPVOID
*
ppMapView, unsigned char
*
*
ppFilePoint) {
/
/
打开文件
*
phFile
=
CreateFileA(
szPath,
/
/
文件路径
GENERIC_READ | GENERIC_WRITE,
/
/
读写权限
0
,
/
/
共享模式(不共享)
NULL,
/
/
安全属性
OPEN_EXISTING,
/
/
只打开已存在的文件
FILE_ATTRIBUTE_NORMAL,
/
/
普通文件
NULL
/
/
模板文件句柄
);
if
(
*
phFile
=
=
INVALID_HANDLE_VALUE) {
std::cerr <<
"无法打开文件,错误码:"
<< GetLastError() << std::endl;
return
false;
}
/
/
创建文件映射
*
phMapFile
=
CreateFileMapping(
*
phFile, NULL, PAGE_READWRITE,
0
,
0
, NULL);
if
(
*
phMapFile
=
=
NULL) {
std::cerr <<
"无法创建文件映射,错误码:"
<< GetLastError() << std::endl;
CloseHandle(
*
phFile);
*
phFile
=
INVALID_HANDLE_VALUE;
return
false;
}
/
/
映射视图
*
ppMapView
=
MapViewOfFile(
*
phMapFile,
/
/
文件映射对象句柄
FILE_MAP_ALL_ACCESS,
/
/
读写访问权限
0
,
0
,
/
/
偏移量
0
/
/
映射整个文件
);
if
(
*
ppMapView
=
=
NULL) {
std::cerr <<
"无法映射文件,错误码:"
<< GetLastError() << std::endl;
CloseHandle(
*
phMapFile);
CloseHandle(
*
phFile);
*
phMapFile
=
NULL;
*
phFile
=
INVALID_HANDLE_VALUE;
return
false;
}
*
ppFilePoint
=
static_cast<unsigned char
*
>(
*
ppMapView);
return
true;
}
/
/
关闭文件和清理资源
void CloseFile(HANDLE hFile, HANDLE hMapFile, LPVOID pMapView) {
if
(pMapView) {
UnmapViewOfFile(pMapView);
}
if
(hMapFile) {
CloseHandle(hMapFile);
}
if
(hFile !
=
INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
}
/
/
文件打开函数,返回需要的所有句柄和指针
bool
OpenFile(const char
*
szPath, HANDLE
*
phFile, HANDLE
*
phMapFile,
LPVOID
*
ppMapView, unsigned char
*
*
ppFilePoint) {
/
/
打开文件
*
phFile
=
CreateFileA(
szPath,
/
/
文件路径
GENERIC_READ | GENERIC_WRITE,
/
/
读写权限
0
,
/
/
共享模式(不共享)
NULL,
/
/
安全属性
OPEN_EXISTING,
/
/
只打开已存在的文件
FILE_ATTRIBUTE_NORMAL,
/
/
普通文件
NULL
/
/
模板文件句柄
);
if
(
*
phFile
=
=
INVALID_HANDLE_VALUE) {
std::cerr <<
"无法打开文件,错误码:"
<< GetLastError() << std::endl;
return
false;
}
/
/
创建文件映射
*
phMapFile
=
CreateFileMapping(
*
phFile, NULL, PAGE_READWRITE,
0
,
0
, NULL);
if
(
*
phMapFile
=
=
NULL) {
std::cerr <<
"无法创建文件映射,错误码:"
<< GetLastError() << std::endl;
CloseHandle(
*
phFile);
*
phFile
=
INVALID_HANDLE_VALUE;
return
false;
}
/
/
映射视图
*
ppMapView
=
MapViewOfFile(
*
phMapFile,
/
/
文件映射对象句柄
FILE_MAP_ALL_ACCESS,
/
/
读写访问权限
0
,
0
,
/
/
偏移量
0
/
/
映射整个文件
);
if
(
*
ppMapView
=
=
NULL) {
std::cerr <<
"无法映射文件,错误码:"
<< GetLastError() << std::endl;
CloseHandle(
*
phMapFile);
CloseHandle(
*
phFile);
*
phMapFile
=
NULL;
*
phFile
=
INVALID_HANDLE_VALUE;
return
false;
}
*
ppFilePoint
=
static_cast<unsigned char
*
>(
*
ppMapView);
return
true;
}
/
/
关闭文件和清理资源
void CloseFile(HANDLE hFile, HANDLE hMapFile, LPVOID pMapView) {
if
(pMapView) {
UnmapViewOfFile(pMapView);
}
if
(hMapFile) {
CloseHandle(hMapFile);
}
if
(hFile !
=
INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
}
bool
FindCObject(unsigned char
*
pFilePoint, IMAGE_SECTION_HEADER
*
pRdataSectionHeader , MY_INT ImageBase, CRuntimeClass
*
*
CobjectRtti , MY_INT& CobjectAddress) {
MY_INT CobjectCharPoint;
if
(!pFilePoint || !pRdataSectionHeader) {
std::cerr <<
"无效的文件指针或Rdata段指针"
<< std::endl;
return
false;
}
MY_INT BaseAddr
=
(MY_INT)pFilePoint;
for
(DWORD i
=
0
; i < pRdataSectionHeader
-
>SizeOfRawData; i
+
+
) {
const char
*
FindAddr
=
(const char
*
)(pRdataSectionHeader
-
>PointerToRawData
+
BaseAddr
+
i);
if
(strcmp(FindAddr,
"CObject"
)
=
=
0
) {
if
(
*
(FindAddr
-
1
)
=
=
0
) {
CobjectCharPoint
=
FileOffsetToVa((DWORD)(FindAddr)
-
BaseAddr, pRdataSectionHeader
-
>PointerToRawData,
pRdataSectionHeader
-
>VirtualAddress, ImageBase);
std::cout <<
"CObject VA "
<< std::
hex
<< std::showbase << CobjectCharPoint << std::endl;
for
(DWORD i
=
0
; i < pRdataSectionHeader
-
>SizeOfRawData; i
+
=
4
) {
MY_INT
*
FindAddr
=
(MY_INT
*
)(pRdataSectionHeader
-
>PointerToRawData
+
BaseAddr
+
i);
if
(
*
FindAddr
=
=
CobjectCharPoint) {
*
CobjectRtti
=
(CRuntimeClass
*
)FindAddr;
CobjectAddress
=
FileOffsetToVa((DWORD)(FindAddr)
-
BaseAddr, pRdataSectionHeader
-
>PointerToRawData,
pRdataSectionHeader
-
>VirtualAddress, ImageBase);
std::cout <<
"CObject VA "
<< std::
hex
<< std::showbase << CobjectAddress << std::endl;
return
true;
}
}
std::cout <<
"未找到CObject 引用"
<< std::endl;
return
false;
}
}
}
std::cout <<
"未找到CObject"
<< std::endl;
return
false;
}
bool
FindCObject(unsigned char
*
pFilePoint, IMAGE_SECTION_HEADER
*
pRdataSectionHeader , MY_INT ImageBase, CRuntimeClass
*
*
CobjectRtti , MY_INT& CobjectAddress) {
MY_INT CobjectCharPoint;
if
(!pFilePoint || !pRdataSectionHeader) {
std::cerr <<
"无效的文件指针或Rdata段指针"
<< std::endl;
return
false;
}
MY_INT BaseAddr
=
(MY_INT)pFilePoint;
for
(DWORD i
=
0
; i < pRdataSectionHeader
-
>SizeOfRawData; i
+
+
) {
const char
*
FindAddr
=
(const char
*
)(pRdataSectionHeader
-
>PointerToRawData
+
BaseAddr
+
i);
if
(strcmp(FindAddr,
"CObject"
)
=
=
0
) {
if
(
*
(FindAddr
-
1
)
=
=
0
) {
CobjectCharPoint
=
FileOffsetToVa((DWORD)(FindAddr)
-
BaseAddr, pRdataSectionHeader
-
>PointerToRawData,
pRdataSectionHeader
-
>VirtualAddress, ImageBase);
std::cout <<
"CObject VA "
<< std::
hex
<< std::showbase << CobjectCharPoint << std::endl;
for
(DWORD i
=
0
; i < pRdataSectionHeader
-
>SizeOfRawData; i
+
=
4
) {
MY_INT
*
FindAddr
=
(MY_INT
*
)(pRdataSectionHeader
-
>PointerToRawData
+
BaseAddr
+
i);
if
(
*
FindAddr
=
=
CobjectCharPoint) {
*
CobjectRtti
=
(CRuntimeClass
*
)FindAddr;
CobjectAddress
=
FileOffsetToVa((DWORD)(FindAddr)
-
BaseAddr, pRdataSectionHeader
-
>PointerToRawData,
pRdataSectionHeader
-
>VirtualAddress, ImageBase);
std::cout <<
"CObject VA "
<< std::
hex
<< std::showbase << CobjectAddress << std::endl;
return
true;
}
}
std::cout <<
"未找到CObject 引用"
<< std::endl;
return
false;
}
}
}
std::cout <<
"未找到CObject"
<< std::endl;
return
false;
}
void Dump(
int
CObjectAddress , MY_INT BaseAddr, unsigned char
*
Buf ,
int
BufSize , MY_INT ImageBase, MY_INT PointerToRawData,
MY_INT VirtualAddress ,
int
Level , const char
*
parentInfo) {
/
/
如果该父类已经处理过,则直接返回
if
(g_visitedAddresses.find(CObjectAddress) !
=
g_visitedAddresses.end())
return
;
g_visitedAddresses.insert(CObjectAddress);
for
(
int
i
=
0
; i < BufSize; i
+
=
4
) {
if
(CObjectAddress
=
=
*
(
int
*
)(Buf
+
i)) {
CRuntimeClass
*
pRtti
=
(CRuntimeClass
*
)(Buf
+
i
-
sizeof(void
*
)
-
sizeof(UINT)
-
sizeof(
int
)
-
sizeof(void
*
));
MY_INT Va
=
FileOffsetToVa((MY_INT)pRtti
-
BaseAddr, PointerToRawData, VirtualAddress , ImageBase);
MY_INT FileOffset
=
VaToFileOffset((MY_INT)pRtti
-
>m_lpszClassName, PointerToRawData, VirtualAddress, ImageBase);
for
(
int
indent
=
0
; indent < Level; indent
+
+
) {
std::cout <<
" "
;
}
std::cout <<
"RootClassName: "
<< parentInfo << std::endl;
for
(
int
indent
=
0
; indent < Level; indent
+
+
) {
std::cout <<
" "
;
}
std::cout <<
"ClassName: "
<< (char
*
)(FileOffset
+
BaseAddr) << std::endl;
for
(
int
indent
=
0
; indent < Level; indent
+
+
) {
std::cout <<
" "
;
}
std::cout <<
"ObjSize: "
<< pRtti
-
>m_nObjectSize << std::endl;
Dump(Va, BaseAddr, Buf, BufSize, ImageBase, PointerToRawData, VirtualAddress , Level
+
1
, (char
*
)(FileOffset
+
BaseAddr));
}
}
}
void Dump(
int
CObjectAddress , MY_INT BaseAddr, unsigned char
*
Buf ,
int
BufSize , MY_INT ImageBase, MY_INT PointerToRawData,
MY_INT VirtualAddress ,
int
Level , const char
*
parentInfo) {
/
/
如果该父类已经处理过,则直接返回
if
(g_visitedAddresses.find(CObjectAddress) !
=
g_visitedAddresses.end())
return
;
g_visitedAddresses.insert(CObjectAddress);
for
(
int
i
=
0
; i < BufSize; i
+
=
4
) {
if
(CObjectAddress
=
=
*
(
int
*
)(Buf
+
i)) {
CRuntimeClass
*
pRtti
=
(CRuntimeClass
*
)(Buf
+
i
-
sizeof(void
*
)
-
sizeof(UINT)
-
sizeof(
int
)
-
sizeof(void
*
));
MY_INT Va
=
FileOffsetToVa((MY_INT)pRtti
-
BaseAddr, PointerToRawData, VirtualAddress , ImageBase);
MY_INT FileOffset
=
VaToFileOffset((MY_INT)pRtti
-
>m_lpszClassName, PointerToRawData, VirtualAddress, ImageBase);
for
(
int
indent
=
0
; indent < Level; indent
+
+
) {
std::cout <<
" "
;
}
std::cout <<
"RootClassName: "
<< parentInfo << std::endl;
for
(
int
indent
=
0
; indent < Level; indent
+
+
) {
std::cout <<
" "
;
}
std::cout <<
"ClassName: "
<< (char
*
)(FileOffset
+
BaseAddr) << std::endl;
for
(
int
indent
=
0
; indent < Level; indent
+
+
) {
std::cout <<
" "
;
}
std::cout <<
"ObjSize: "
<< pRtti
-
>m_nObjectSize << std::endl;
Dump(Va, BaseAddr, Buf, BufSize, ImageBase, PointerToRawData, VirtualAddress , Level
+
1
, (char
*
)(FileOffset
+
BaseAddr));
}
}
}
DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CTestDocDoc, CDocument)
END_MESSAGE_MAP()
DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CTestDocDoc, CDocument)
END_MESSAGE_MAP()
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
PTM_WARNING_DISABLE \
const
AFX_MSGMAP* theClass::GetMessageMap()
const
\
{
return
GetThisMessageMap(); } \
const
AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ \
typedef
theClass ThisClass; \
typedef
baseClass TheBaseClass; \
__pragma(warning(push)) \
__pragma(warning(disable: 4640))
\
static
const
AFX_MSGMAP_ENTRY _messageEntries[] = \
{
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
PTM_WARNING_DISABLE \
const
AFX_MSGMAP* theClass::GetMessageMap()
const
\
{
return
GetThisMessageMap(); } \
const
AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ \
typedef
theClass ThisClass; \
typedef
baseClass TheBaseClass; \
__pragma(warning(push)) \
__pragma(warning(disable: 4640))
\
static
const
AFX_MSGMAP_ENTRY _messageEntries[] = \
{
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
__pragma(warning(pop)) \
static
const
AFX_MSGMAP messageMap = \
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
return
&messageMap; \
} \
PTM_WARNING_RESTORE
#define END_MESSAGE_MAP() \
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
}; \
__pragma(warning(pop)) \
static
const
AFX_MSGMAP messageMap = \
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
return
&messageMap; \
} \
PTM_WARNING_RESTORE
PTM_WARNING_DISABLE
const
AFX_MSGMAP* CMyWnd::GetMessageMap()
const
{
return
GetThisMessageMap();
}
const
AFX_MSGMAP* PASCAL CMyWnd::GetThisMessageMap()
{
typedef
CMyWnd ThisClass;
typedef
CWnd TheBaseClass;
__pragma(warning(push))
__pragma(warning(disable: 4640))
static
const
AFX_MSGMAP_ENTRY _messageEntries[] =
{
{ WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwii,
(AFX_PMSG)(AFX_PMSGW)(
static_cast
<
void
(CMyWnd::*)(
UINT
, CPoint)>(&CMyWnd::OnLButtonDown)) },
{ WM_RBUTTONDOWN, 0, 0, 0, AfxSig_vwii,
(AFX_PMSG)(AFX_PMSGW)(
static_cast
<
void
(CMyWnd::*)(
UINT
, CPoint)>(&CMyWnd::OnRButtonDown)) },
{ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};
__pragma(warning(pop))
static
const
AFX_MSGMAP messageMap =
{
&TheBaseClass::GetThisMessageMap, &_messageEntries[0]
};
return
&messageMap;
}
public
:
static
const
AFX_MSGMAP* PASCAL GetThisMessageMap();
virtual
const
AFX_MSGMAP* GetMessageMap()
const
;
PTM_WARNING_RESTORE
PTM_WARNING_DISABLE
const
AFX_MSGMAP* CMyWnd::GetMessageMap()
const
{
return
GetThisMessageMap();
}
const
AFX_MSGMAP* PASCAL CMyWnd::GetThisMessageMap()
{
typedef
CMyWnd ThisClass;
typedef
CWnd TheBaseClass;
__pragma(warning(push))
__pragma(warning(disable: 4640))
static
const
AFX_MSGMAP_ENTRY _messageEntries[] =
{
{ WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwii,
(AFX_PMSG)(AFX_PMSGW)(
static_cast
<
void
(CMyWnd::*)(
UINT
, CPoint)>(&CMyWnd::OnLButtonDown)) },
{ WM_RBUTTONDOWN, 0, 0, 0, AfxSig_vwii,
(AFX_PMSG)(AFX_PMSGW)(
static_cast
<
void
(CMyWnd::*)(
UINT
, CPoint)>(&CMyWnd::OnRButtonDown)) },
{ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};
__pragma(warning(pop))
static
const
AFX_MSGMAP messageMap =
{
&TheBaseClass::GetThisMessageMap, &_messageEntries[0]
};
return
&messageMap;
}
public
:
static
const
AFX_MSGMAP* PASCAL GetThisMessageMap();
virtual
const
AFX_MSGMAP* GetMessageMap()
const
;
PTM_WARNING_RESTORE
struct
AFX_MSGMAP_ENTRY
{
UINT
nMessage;
UINT
nCode;
UINT
nID;
UINT
nLastID;
UINT_PTR
nSig;
AFX_PMSG pfn;
};
struct
AFX_MSGMAP_ENTRY
{
UINT
nMessage;
UINT
nCode;
UINT
nID;
UINT
nLastID;
UINT_PTR
nSig;
AFX_PMSG pfn;
};
enum
AfxSig{
AfxSig_end = 0,
AfxSig_b_D_v,
AfxSig_b_b_v,
AfxSig_b_u_v,
AfxSig_b_h_v,
AfxSig_b_W_uu,
AfxSig_b_W_COPYDATASTRUCT,
AfxSig_b_v_HELPINFO,
AfxSig_CTLCOLOR,
AfxSig_CTLCOLOR_REFLECT,
AfxSig_i_u_W_u,
AfxSig_i_uu_v,
AfxSig_i_W_uu,
AfxSig_i_v_s,
AfxSig_l_w_l,
AfxSig_l_uu_M,
AfxSig_v_b_h,
}
enum
AfxSig{
AfxSig_end = 0,
AfxSig_b_D_v,
AfxSig_b_b_v,
AfxSig_b_u_v,
AfxSig_b_h_v,
AfxSig_b_W_uu,
AfxSig_b_W_COPYDATASTRUCT,
AfxSig_b_v_HELPINFO,
AfxSig_CTLCOLOR,
AfxSig_CTLCOLOR_REFLECT,
AfxSig_i_u_W_u,
AfxSig_i_uu_v,
AfxSig_i_W_uu,
AfxSig_i_v_s,
AfxSig_l_w_l,
AfxSig_l_uu_M,
AfxSig_v_b_h,
}
static
const
AFX_MSGMAP messageMap =
{
&TheBaseClass::GetThisMessageMap, &_messageEntries[0]
};
static
const
AFX_MSGMAP messageMap =
{
&TheBaseClass::GetThisMessageMap, &_messageEntries[0]
};
struct
AFX_MSGMAP
{
const
AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
const
AFX_MSGMAP_ENTRY* lpEntries;
};
struct
AFX_MSGMAP
{
const
AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
const
AFX_MSGMAP_ENTRY* lpEntries;
};
AfxHookWindowCreate(this);
AfxHookWindowCreate(this);
void AFXAPI AfxHookWindowCreate(CWnd
*
pWnd)
{
_AFX_THREAD_STATE
*
pThreadState
=
_afxThreadState.GetData();
if
(pThreadState
-
>m_pWndInit
=
=
pWnd)
return
;
if
(pThreadState
-
>m_hHookOldCbtFilter
=
=
NULL)
{
pThreadState
-
>m_hHookOldCbtFilter
=
::SetWindowsHookEx(WH_CBT,
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
if
(pThreadState
-
>m_hHookOldCbtFilter
=
=
NULL)
AfxThrowMemoryException();
}
ASSERT(pThreadState
-
>m_hHookOldCbtFilter !
=
NULL);
ASSERT(pWnd !
=
NULL);
ASSERT(pWnd
-
>m_hWnd
=
=
NULL);
/
/
only do once
ASSERT(pThreadState
-
>m_pWndInit
=
=
NULL);
/
/
hook
not
already
in
progress
pThreadState
-
>m_pWndInit
=
pWnd;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2025-3-12 16:52
被BitWarden编辑
,原因: