将 Windows PE 可执行文件加载到 Ghidra SRE 后,从 MFC90U.DLL Ghidra 导入的某些函数未检测到:
DAT_00aea270 FUN_004ae180:004ae1ee,
FUN_004b0f40:004b1b84,
FUN_004bb2b0:004bb475,
FUN_0067a2f0:0067a332, [more]
00aea270 af ?? AFh XREF[892]:
00aea271 09 ?? 09h
00aea272 00 ?? 00h
00aea273 80 ?? 80h
我确切地知道这是 CStringT :: Find 的一个函数。同样,Ghidra 也未定义 CStringT :: Replace 函数。
如果我强制地址 0x00AEA270 处的字节为指针类型,那么我将光标悬停在 DAT_800009af 变量上,Ghidra 会抱怨“地址:ram:800009af,地址不在内存中”:
PTR_DAT_00aea270 FUN_004ae180:004ae1ee,
FUN_004b0f40:004b1b84,
FUN_004bb2b0:004bb475,
FUN_0067a2f0:0067a332, [more]
00aea270 af 09 00 80 addr DAT_800009af XREF[892]:
+----------------------+
|Address: ram: 800009af|
|Address not in memory |
+----------------------+
同时,正确检测到来自同一个 MFC90U.DLL 的其他函数:
**************************************************************
* POINTER to EXTERNAL FUNCTION *
**************************************************************
CStringT<wchar_t,class_StrTraitMFC_DLL<wchar_t,class_ATL
CStringT<wchar EAX:4 <RETURN>
CStringT<wchar ECX:4 (auto) this
CStringT<wchar Stack[0x4]:4 param_1
811 Ordinal_811 <<not bound>>
PTR_operator=_00aea26c FUN_004cdbe0:004ce2e5,
FUN_00911be0:00914605, [more]
00aea26c 2b 03 00 80 addr MFC90U.DLL::ATL::CStringT<wchar_t,class_StrTra XREF[4517]:
**************************************************************
* POINTER to EXTERNAL FUNCTION *
**************************************************************
int __thiscall ShowWindow(CWnd * this, int param_1)
int EAX:4 <RETURN>
CWnd * ECX:4 (auto) this
int Stack[0x4]:4 param_1
6604 Ordinal_6604 <<not bound>>
PTR_ShowWindow_00aea278 ShowWindow:00947004
00aea278 cc 19 00 80 addr MFC90U.DLL::CWnd::ShowWindow XREF[1]:
此外,Ghidra 未检测到的函数地址(0x800009af 是 CStringT::Find 和 0x80001723 是 CStringT::Replace)位于地址 0x8000032b 和 0x800019cc 之间,即 Ghidra SRE 检测到的那些函数的地址之间。也就是说,这些地址无论如何都不能是“地址不在内存中”!
结果,在列表窗口中:
006c88a2 68 8c 98 PUSH u_</HeaderData>_00b6988c
b6 00
006c88a7 8d 8d 34 LEA ECX=>local_26d0,[EBP + 0xffffd934]
d9 ff ff
-> DAT_800009af
006c88ad ff 15 70 CALL dword ptr [PTR_DAT_00aea270]
a2 ae 00
006c88b3 85 c0 TEST EAX,EAX
006c88b5 7c 13 JL LAB_006c88ca
并在反编译器窗口中:
iVar4 = (*(code *)&DAT_800009af)(L"</HeaderData>",0);
if (-1 < iVar4) {
我只看到来自间接未知地址的未知调用。
但 IDA Pro 正确检测到相同的导入。这是从 IDA Pro 导入相同的导入窗口:
.idata:00AEA26C ; public: class ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>> & __thiscall ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>>::operator=(class ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>> const &)
.idata:00AEA26C extrn ??4?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QAEAAV01@ABV01@@Z:dword
.idata:00AEA26C ; CODE XREF: sub_4016D0+15E↑p
.idata:00AEA26C ; sub_402E30+30↑p ...
.idata:00AEA270 ; public: int __thiscall ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>>::Find(wchar_t const *, int)const
.idata:00AEA270 extrn ?Find@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QBEHPB_WH@Z:dword
.idata:00AEA270 ; CODE XREF: sub_401680+1A↑p
.idata:00AEA270 ; sub_403210+8B↑p ...
.idata:00AEA274 ; public: int __thiscall ATL::CStringT<wchar_t, class StrTraitMFC_DLL<wchar_t, class ATL::ChTraitsCRT<wchar_t>>>::Replace(wchar_t const *, wchar_t const *)
.idata:00AEA274 extrn ?Replace@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QAEHPB_W0@Z:dword
.idata:00AEA274 ; CODE XREF: sub_4011C0+269↑p
.idata:00AEA274 ; sub_41A3F0+D7↑p ...
.idata:00AEA278 ; __declspec(dllimport) public: int __thiscall CWnd::ShowWindow(int)
.idata:00AEA278 extrn __imp_?ShowWindow@CWnd@@QAEHH@Z:dword
.idata:00AEA278 ; DATA XREF: CWnd::ShowWindow(int)↑r
这是 IDA Pro 列表窗口,显示了可执行文件中的相同位置:
.text:006C88A2 push offset aHeaderdata ; "</HeaderData>"
.text:006C88A7 lea ecx, [ebp+var_26CC]
.text:006C88AD call ds:?Find@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QBEHPB_WH@Z ; ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Find(wchar_t const *,int)
.text:006C88B3 test eax, eax
.text:006C88B5 jl short loc_6C88CA
调用此函数的 Hex-Rays 反编译器窗口也位于可执行文件内的同一位置:
v18 = ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::Find(&v39, L"</HeaderData>", 0);
if ( v18 >= 0 )
{
但是,与 Hex-Rays 反编译器相比,我更喜欢 Ghidra 反编译器的结果,因此我希望至少对这个特定的可执行文件使用 Ghidra。
如何使用 Ghidra 实现正确导入?我应该怎么做才能修复它?我怎么能告诉 Ghidra 这些是位于可执行进程内正常地址的正常导入函数?
是的,文件中有 CStringT::Find 和 CStringT::Replace 的描述~/ghidra_9.1.2_PUBLIC/Ghidra/Features/Base/data/symbols/win32/mfc90u.exports
:
[...]
<EXPORT ORDINAL="2479" NAME="?Find@?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QBEHPB_WH@Z" PURGE="-1" COMMENT="" />
[...]
所以 Ghidra SRE 知道这些函数是否存在以及如何正确命名它们,但由于某种原因,它没有像从 MFC90U.DLL 导入的那样正确检测和定义它们。为什么?
我运行 Ghidra 9.1.2 public release 2020 年 2 月 12 日 1149 EST 和 IDA Pro 版本 7.1.180227。