I have hooked QtGui4.dll's unmanaged function QPainter::drawTextItem(const QPointF &p, const QTextItem &ti);
using EasyHook in C#. I have wrapped the QPointF
and QTextItem
classes into managed structs and can get the data from these parameters by marshaling them. However, I would like to call member functions of the unmanaged QPainter
class using managed code, so I am trying to wrap the QPainter
class into a managed class. I have access to the unmanaged code for testing purposes, but will not have access to it in production. I have looked at the memory layout of the unmanaged classes QPainter
and QPaintDevice
. The QPainter
class is just a single pointer and the QPaintDevice
class is just two pointers (one for the virtual function table). I tried following the techniques in this blog, but when I call the wrapped QPainter::device()
method just to see if I can get a pointer, my target (unmanaged, hooked) application crashes with either an access violation error (Access violation reading location 0x00000078
) or an argument exception error (EEArgumentException at memory location 0x003786f4
), depending on whether my wrapped QPainter
class uses a sequential layout or not, respectively. I don’t expect someone to correct all the source code, but I was hoping if someone could point out some of the mistakes I am making in my approach. By the way, this is the first time I've ever posted a question on Stack Overflow because I usually find the answers to my problems from one or more existing questions. I apologize for the long question, but I tried to simplify the problem as much as possible without leaving out potentially relevant information. Thanks in advance for your help.
Memory Dump:
class QPainter (size = 4):
(0) d_ptr
class QPaintDevice (size = 8):
(0) {vfptr}
(4) painters
Unmanaged Code (qpainter.h):
class QPainter
{
QPainter();
explicit QPainter(QPaintDevice *);
~QPainter();
QPaintDevice *device() const; // trying to call this function
void drawTextItem(const QPointF &p, const QTextItem &ti); // hooked function
// class has additional functions, but left out for brevity
}
Managed Hook (hook.cs):
[DllImport("QtGui4.dll", CharSet = CharSet.Unicode, SetLastError = true,
CallingConvention = CallingConvention.ThisCall,
EntryPoint = "?drawTextItem@QPainter@@QAEXABVQPointF@@ABVQTextItem@@@Z")]
public static extern void QPainter_drawTextItem(IntPtr obj, IntPtr pt, IntPtr ti);
[UnmanagedFunctionPointer(CallingConvention.ThisCall, CharSet = CharSet.Unicode,
SetLastError = true)]
delegate void D_QPainter_drawTextItem(IntPtr obj, IntPtr pt, IntPtr ti);
static unsafe void QPainter_drawTextItem_Hooked(IntPtr obj, IntPtr pt, IntPtr ti)
{
QTextItem qti = (QTextItem)Marshal.PtrToStructure(ti, typeof(QTextItem));
QPointF qpt = (QPointF)Marshal.PtrToStructure(pt, typeof(QPointF));
QPainter painter = (QPainter)Marshal.PtrToStructure(obj, typeof(QPainter));
__QPaintDevice* pd = painter.device(); // ERROR
QPainter_drawTextItem(obj, pt, ti);
}
Managed Wrapper (wrap.cs):
[StructLayout(LayoutKind.Sequential, Size=8)]
public unsafe struct __QPaintDevice
{
public IntPtr *vfptr;
public IntPtr painters;
};
[StructLayout(LayoutKind.Sequential, Size=4)]
public unsafe struct __QPainter
{
public IntPtr d_ptr;
};
// When the following line is included, I get this error:
// Access violation reading location 0x00000078.
// When the following line is excluded, I get this error:
// EEArgumentException at memory location 0x003786f4.
[StructLayout(LayoutKind.Sequential)] // is this useful?
public unsafe class QPainter : IDisposable
{
private __QPainter* _this;
private __QPaintDevice* _pd;
[DllImport("QtGui4.dll", EntryPoint = "??0QPainter@@QAE@XZ",
CallingConvention = CallingConvention.ThisCall)]
private static extern int _QPainter_Constructor(__QPainter* ths);
[DllImport("QtGui4.dll",
EntryPoint = "??0QPainter@@QAE@PAVQPaintDevice@@@Z",
CallingConvention = CallingConvention.ThisCall)]
private static extern int _QPainter_Constructor(__QPainter* ths,
__QPaintDevice* pd);
[DllImport("QtGui4.dll", EntryPoint = "??1QPainter@@QAE@XZ",
CallingConvention = CallingConvention.ThisCall)]
private static extern int _QPainter_Destructor(__QPainter* ths);
[DllImport("QtGui4.dll",
EntryPoint = "?device@QPainter@@QBEPAVQPaintDevice@@XZ",
CallingConvention = CallingConvention.ThisCall)]
private static extern __QPaintDevice* _device(__QPainter* ths);
public QPainter()
{
_this = (__QPainter*)Marshal.AllocHGlobal(sizeof(__QPainter));
_QPainter_Constructor(_this);
}
public QPainter(__QPaintDevice* pd)
{
_this = (__QPainter*)Marshal.AllocHGlobal(sizeof(__QPainter));
_pd = (__QPaintDevice*)Marshal.AllocHGlobal(sizeof(__QPaintDevice));
_QPainter_Constructor(_this, pd);
}
public void Dispose()
{
_QPainter_Destructor(_this);
Marshal.FreeHGlobal((IntPtr)_this);
Marshal.FreeHGlobal((IntPtr)_pd);
_this = null;
_pd = null;
}
public __QPaintDevice* device()
{
return _device(_this);
}
};
User contributions licensed under CC BY-SA 3.0