我正在反编译 MFC 4.0 应用程序,现在MFCS42.PDB
将 MFC 4.2 源代码加载到 IDA 7.0(没有 MFC 4.0 源代码),以使其创建表示许多 MFC 类和虚拟函数表的适当结构。
但是,IDA 似乎只*Vtbl
为非常基类(如 )创建结构CObject
,而不是为像 之类的子类创建结构,CCmdTarget
如下所示:
struct CObjectVtbl // totally correct
{
CRuntimeClass *(__thiscall *GetRuntimeClass)(CObject *this);
void (__thiscall *~CObject)(CObject *this);
void (__thiscall *Serialize)(CObject *this, CArchive *);
void (__thiscall *AssertValid)(CObject *this);
void (__thiscall *Dump)(CObject *this, CDumpContext *);
};
struct __cppobj CObject // totally correct
{
CObjectVtbl *vfptr;
};
struct __cppobj CCmdTarget : CObject // wrong, makes it have only a CObject vftable
{
int m_dwRef;
IUnknown *m_pOuterUnknown;
unsigned int m_xInnerUnknown;
CCmdTarget::XDispatch m_xDispatch;
int m_bResultExpected;
CCmdTarget::XConnPtContainer m_xConnPtContainer;
AFX_MODULE_STATE *m_pModuleState;
};
实际上,这会导致 缺少新的虚函数CCmdTarget
,因为它仅CObjectVtbl
通过继承自 来引用CObject
,但CCmdTarget
还有 7 个方法。
我之前手工制作了这些结构(你可以猜到这很乏味),它实际上应该看起来更像这样:
// CObject and CObjectVtbl same as above
struct CCmdTargetVtbl : CObjectVtbl // inherit to keep base methods
{
BOOL (__thiscall *OnCmdMsg)(CCmdTarget *this, UINT nID, int nCode, void *pExtra, void *pHandlerInfo);
void (__thiscall *OnFinalRelease)(CCmdTarget *this);
AFX_MSGMAP *(__thiscall *GetMessageMap)(CCmdTarget *this);
int field_20; // Don't know names yet
int field_24;
int field_28;
int field_2C;
};
struct CCmdTargetMembers // member struct to reuse it in child classes
{
int m_dwRef;
IUnknown *m_pOuterUnknown;
unsigned int m_xInnerUnknown;
CCmdTarget::XDispatch m_xDispatch;
int m_bResultExpected;
CCmdTarget::XConnPtContainer m_xConnPtContainer;
AFX_MODULE_STATE *m_pModuleState;
};
struct CCmdTarget
{
CCmdTargetVtbl *vfptr;
CCmdTargetMembers members;
};
只有这样,访问子类上的虚函数才有意义,因为它们的 vftables 是已知的。一个 hexrays 反编译示例表明,只有可用的基本 vftables 没有多大意义:
用子 vftables 反编译:
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
int nReturnCode; // esi MAPDST
CWinApp *pWinApp; // edi
CWinThreadVtbl *pThread; // ebx
nReturnCode = -1;
pWinApp = (CWinApp *)CBumperApp::instance;
if ( AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nShowCmd) )
{
pThread = &pWinApp->vftable->CWinThread;
if ( pWinApp->vftable->InitApplication(pWinApp) )
{
if ( pThread->InitInstance((CWinThread *)pWinApp) )
{
nReturnCode = pThread->Run((CWinThread *)pWinApp);
}
[...]
没有子 vftables 的反编译:
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
int nReturnCode; // esi MAPDST
CWinApp *pWinApp; // edi
CObjectVtbl *pThread; // ebx
nReturnCode = -1;
pWinApp = CBumperApp::instance;
if ( AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nShowCmd) )
{
pThread = pWinApp->vfptr;
if ( pWinApp->vfptr[5].GetRuntimeClass(pWinApp) ) // nonsense
{
if ( (pThread[2].Serialize)(pWinApp) ) // nonsense
{
nReturnCode = (pThread[2].AssertValid)(pWinApp); // nonsense
}
[...]
有什么方法可以让 IDA 从 PDB 加载子类的 vftables 并创建所有必需的结构?或者这在 IDA 7.0 中是不可能的?
据我所知,PDB 应该有这些信息。是否有工具可以查看 PDB 文件以查看它是否确实包含此信息?