1

我编写了一个 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++ 是否值得一试...?

4

1 回答 1

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
于 2013-03-03T13:03:37.870 回答