我编写了一个 C# 应用程序,将 DLL 注入到第三方可执行文件中(恰好是使用 Qt 框架构建的)。此 DLL 使用 EasyHook 拦截对许多特定函数的调用。当我注入的代码被调用时,我会尝试检查一些作为这些函数参数的对象。
例如,我截获了一个解析 XML 的调用:
virtual bool __thiscall QXmlSimpleReader::parse(class QXmlInputSource const &)
在我的 C# 代码中,我有一个 PInvoke 签名来匹配这个:
static extern bool XmlParse(IntPtr Reader, IntPtr Source)
我想调用作为“Source”类成员的“data()”函数。也就是说,QXmlSimpleReader 从 QXmlInputSource 解析原始 XML,但在此之前,我试图通过这个“data()”函数检查原始 XML。
根据这里一位专家的建议,我尝试使用 C++/CLI 本地访问对象(请参阅调用第三方 DLL 中的方法)。我在 C++ 中构造了一个包装器对象,它接受来自 C# 代码的 IntPtr:
标题:
public ref class QXmlInputSource
{
public:
// Constructor must be called with C# IntPtr
QXmlInputSource(IntPtr Ptr);
bool LoadQt(void);
bool UnloadQt(void);
String^ Data();
private:
// Pointer to the native Qt object
void * Native;
HINSTANCE DllHandle;
// SIGNATURE: virtual QString QXmlInputSource::data() const
typedef void * (__thiscall *QXmlInputSource_Data)(void *);
QXmlInputSource_Data fpData;
};
CPP 文件:
QXmlInputSource::QXmlInputSource(IntPtr Ptr)
{
LoadQt();
Native = Ptr.ToPointer();
}
bool QXmlInputSource::LoadQt(void)
{
FARPROC Addr;
/* get handle to dll */
std::wstring LibName = QtPath + QtXml;
DllHandle = LoadLibrary(LibName.c_str());
/* get pointer to the function in the dll*/
Addr = GetProcAddress(HMODULE (DllHandle), "?data@QXmlInputSource@@UBE?AVQString@@XZ");
fpData = QXmlInputSource_Data(Addr);
return true;
}
bool QXmlInputSource::UnloadQt()
{
/* Release the Dll */
FreeLibrary(DllHandle);
return true;
}
String^ QXmlInputSource::Data()
{
void* Ptr = fpData(Native);
return "EPIC FAIL";
}
当我尝试调用 fpData() 函数指针时,基于 Qt 的应用程序崩溃。帮助:P
一些可能有帮助也可能没有帮助的附加信息:
我已经使用相同的方法成功地调用了“更简单”对象上的函数,例如 QString.count() 和 QString.data()。(QString 似乎只是标准 unicode 字符串的轻量级包装器)。
在包含我感兴趣的 XML 函数的 QtXml4.dll 文件中,实际上有两个 parse() 方法;Source 是 const & 的一种,另一种是 Source 是 const *。我不知道我是否应该使用其中一个。我认为我的签名无论如何都不会改变。
当我尝试玩耍时,我尝试在 C# 代码中取消引用 IntPtr 并将其传递给 C++:
IntPtr DerefSrc = (IntPtr)Marshal.PtrToStructure(Source, typeof(IntPtr));
如果我打印出这两个 IntPtrs 的值,Source 的值约为 3.5Mb,而 DerefSrc 的值为 1.6Gb - 这与内存中 QtXml4.dll 的地址大致匹配。我的猜测是 3.5Mb 是相对偏移,而 DerefSrc 显然是绝对参考。将 DerefSrc 转换为相对地址并将其传递给 C++ 是否值得一试...?