我编写了一个C#应用程序,它将DLL注入第三方可执行文件(恰好是使用Qt框架构建的)。此DLL使用EasyHook拦截对许多特定功能的调用。当我调用注入的代码时,我会尝试检查作为这些函数的参数的一些对象。
例如,我拦截了一个解析一些XML的调用:
virtual bool __thiscall QXmlSimpleReader::parse(class QXmlInputSource const &)
在我的C#代码中,我有一个PInvoke签名来匹配:
static extern bool XmlParse(IntPtr Reader, IntPtr Source)
我想调用“data()”函数,它是“Source”类的成员。也就是说,QXmlSimpleReader从QXmlInputSource解析原始XML,但在此之前,我试图通过这个“data()”函数检查原始XML。
根据其中一位专家的建议,我尝试使用C ++ / CLI本地访问该对象(请参阅Calling methods in third-party DLLs)。我在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
一些可能有帮助或可能没有帮助的其他信息:
我使用相同的方法成功调用了“simpler”对象上的函数,例如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 ++而不是......?
答案 0 :(得分:1)
我看到了几个问题:
1:您不检查LoadLibrary和GetProcAddress的返回值。 QXmlInputSource :: data甚至是DLL导出的方法吗?如果没有,则GetProcAddress显然会失败。
2。:如何实例化QXmlInputSource类?我问,因为你似乎是在C#代码中尝试这样做,这很难做到(你需要知道类所需的大小,分配一个正确对齐的大小的内存,并调用构造函数它)。
3:你调用函数指针的方式是错误的。您需要声明适当类型的方法指针:
FARPROC fp = ::GetProcAddress(...);
typedef QString (QXmlInputSource::*DataMethod)();
DataMethod mpData = reinterpret_cast<DataMethod>(fp);
QXmlInputSource source;
QString data = (source.*mpData)();
4:看一下QXmlInputSource :: data的文档,我看到它返回一个QString,它与指针(正如你当前正在处理它)有很大的不同。要将其转换为System.String,您需要这样的代码:
QString s1 = (QChar*)L"example string";
String^ s2 = gcnew String((wchar_t*)s1.data()); // calls the String::String(wchar_t*) constructor overload