1

I have written a C# application that injects a DLL into a third-party executable (which happens to have been built using the Qt framework). This DLL uses EasyHook to intercept calls to a number of specific functions. When my injected code is called, I then try to inspect some of the objects that are parameters to these functions.

For example, I have intercepted a call made to parse some XML:

virtual bool __thiscall QXmlSimpleReader::parse(class QXmlInputSource const &)

In my C# code, I have a PInvoke signature to match this:

static extern bool XmlParse(IntPtr Reader, IntPtr Source)

I would like to call the "data()" function which is a member of the "Source" class. That is, the QXmlSimpleReader parses the raw XML from the QXmlInputSource, but before it does so, I am trying to inspect the raw XML via this "data()" function.

On the advice of one of the experts here, I have tried to use C++/CLI to access the object natively (see Calling methods in third-party DLLs ). I have constructed a wrapper object in C++ that accepts the IntPtr from the C# code:

Header:

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 file:

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";
}

The Qt-based application crashes when I try to call the fpData() function pointer. Help :P

Some additional information which may or may not help:

  • I have successfully called functions on "simpler" objects, such as QString.count() and QString.data() using the same methodology. (QString seems to be just a lightweight wrapper for a standard unicode string).

  • In the QtXml4.dll file that contains the XML functions I am interested in, there are actually TWO parse() methods; one where the Source is a const &, and in the other, Source is a const *. I have no idea if I should be using one or the other. I don't think my signatures will change in any event.

  • While I was trying to play around, I tried dereferencing the IntPtr in the C# code and passing it to C++:

    IntPtr DerefSrc = (IntPtr)Marshal.PtrToStructure(Source, typeof(IntPtr));

If I print out the values of these two IntPtrs, Source has a value of around 3.5Mb, while the DerefSrc has a value of 1.6Gb - which roughly matches the address of the QtXml4.dll in memory. My guess is that the 3.5Mb is a relative offset, while the DerefSrc is clearly an absolute reference. Is it worth a shot converting the DerefSrc to a relative address and passing that to C++ instead ... ?

Community
  • 1
  • 1
  • 1
    The first rule of injecting code is to inject the absolute minimum amount of code. That makes C++/CLI a **very** poor candidate, you also have to inject the jitter and the CLR to make it run. Odds you'll be able to figure out how to do that are zero. Even if you do figure it out, the chance that the process already has the CLR loaded and it is the wrong version is high as well. Do not attempt this. – Hans Passant Mar 03 '13 at 13:18
  • We have a case of dueling experts!! See the link to my previous question, and David Heffernan's response. – Roman Holiday Mar 03 '13 at 20:22
  • Your previous question wasn't about injecting code into another process. – Hans Passant Mar 03 '13 at 20:57

1 Answers1

1

I see several problems:

1.: You don't check the return value of LoadLibrary and GetProcAddress. Is QXmlInputSource::data even a DLL-exported method? If not then GetProcAddress will obviously fail.

2.: How do you instantiate the QXmlInputSource class? I ask because it seems you are trying to do it in the C# code, which is hard to do right (you need to know the size required for the class, allocate a properly aligned chunk of memory of that size, and call the constructor on it).

3.: The way you're invoking the function pointer is wrong. You need to declare a method pointer of the appropriate type:

FARPROC fp = ::GetProcAddress(...);

typedef QString (QXmlInputSource::*DataMethod)();
DataMethod mpData = reinterpret_cast<DataMethod>(fp);

QXmlInputSource source;
QString data = (source.*mpData)();

4.: Looking at the documentation for QXmlInputSource::data, I see that it returns a QString, which is woefully different from a pointer (as you're currently treating it). To convert it to a System.String, you need code like this:

QString s1 = (QChar*)L"example string";
String^ s2 = gcnew String((wchar_t*)s1.data()); // calls the String::String(wchar_t*) constructor overload
user1610015
  • 6,561
  • 2
  • 15
  • 18
  • 1. Sorry, I removed various lines of debugging code before posting - one of those checked GetLastError() and it returns zero. 2. I'm not instantiating a native QXmlInputSource object anywhere. I instantiate a wrapper class that takes a pointer to an already-existing object. Remember the goal here i to basically snoop on the data being passed around inside the Qt-based application. If I'm instantiating my own object it's just going to be blank ... 3. & 4. I'll have a play around with these today. – Roman Holiday Mar 03 '13 at 20:20
  • I'm stuck already :P The code fragments you've posted seem to assume that I have access to QString, QChar and QXmlInputSource classes as native classes. But I don't! The header and source files I have posted are merely wrappers that take a void pointer that points to the address of the native object. QtXml4.dll is a third party library, and I don't have a lib file to import. I haven't touched the Qt environment at all yet, but it's possible that I could get a lib file .. – Roman Holiday Mar 03 '13 at 20:50
  • Yes, you can get a .lib file for Qt. Then you could avoid all the GetProcAddress and function pointer stuff, and just call the .lib file's methods even on objects that were created in the target executable (but you do have to make sure that the Qt libraries' versions match). Anyway, I'd consider Hans Passant's comment before going further with this route. I'm just not familiar with DLL injection. – user1610015 Mar 03 '13 at 22:47