#define _X86_
#include <minwindef.h>
#include <basetyps.h>
#include <rpcsal.h>
#include <winerror.h>
#define interface __STRUCT__
typedef WCHAR OLECHAR;
typedef /* [string] */ __RPC_string OLECHAR* LPOLESTR;
DECLARE_HANDLE(HWND);
#define __RPC_FAR
struct IBindCtx;
struct IMoniker;
#define MIDL_INTERFACE(x) struct DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
extern "C"
{
HWND
WINAPI
GetDesktopWindow(
VOID);
DWORD
WINAPI
GetTickCount(
VOID
);
}
#define NO_USE_ALIGN
#define NO_USE_PACK
#ifdef NO_USE_ALIGN
#undef DECLSPEC_ALIGN
#define DECLSPEC_ALIGN(x)
#endif
#ifndef NO_USE_PACK
#pragma pack(push, 2)
#endif
MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
CUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR * __RPC_FAR * ppvObject) = 0;
virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
};
MIDL_INTERFACE("0000011a-0000-0000-C000-000000000046")
DECLSPEC_ALIGN(8) CParseDisplayName : public CUnknown
{
public:
bool IParseDisplayName_Ok;
int IParseDisplayName_ID;
bool IParseDisplayName_Valid;
int IParseDisplayName_Value;
virtual HRESULT STDMETHODCALLTYPE ParseDisplayName(
/* [unique][in] */ __RPC__in_opt IBindCtx* pbc,
/* [in] */ __RPC__in LPOLESTR pszDisplayName,
/* [out] */ __RPC__out ULONG* pchEaten,
/* [out] */ __RPC__deref_out_opt IMoniker** ppmkOut) = 0;
};
#ifndef NO_USE_PACK
#pragma pack(pop)
#pragma pack(push, 1)
#endif
MIDL_INTERFACE("00000114-0000-0000-C000-000000000046")
DECLSPEC_ALIGN(16) COleWindow : public CUnknown
{
public:
bool IOleWindow_Ok;
int IOleWindow_ID;
bool IOleWindow_Ok2;
short IOleWindow_SValue;
bool IOleWindow_Valid;
int IOleWindow_Value;
virtual /* [input_sync] */ HRESULT STDMETHODCALLTYPE GetWindow(
/* [out] */ __RPC__deref_out_opt HWND* phwnd) = 0;
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
/* [in] */ BOOL fEnterMode) = 0;
};
#ifndef NO_USE_PACK
#pragma pack(pop)
#pragma pack(push, 16)
#endif
MIDL_INTERFACE("0000010c-0000-0000-C000-000000000046")
DECLSPEC_ALIGN(8) CPersist : public CUnknown
{
public:
bool IPersist_Ok;
int IPersist_ID;
short IPersist_SValue;
int IPersist_Value;
virtual HRESULT STDMETHODCALLTYPE GetClassID(
/* [out] */ __RPC__out CLSID* pClassID) = 0;
};
#ifndef NO_USE_PACK
#pragma pack(pop)
#pragma pack(push, 1)
#endif
MIDL_INTERFACE("DF0B3D60-548F-101B-8E65-08002B2BD119")
DECLSPEC_ALIGN(16) CSupportErrorInfo : public CUnknown
{
public:
int ISupportErrorInfo_ID;
int ISupportErrorInfo_Value;
virtual HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(
/* [in] */ __RPC__in REFIID riid) = 0;
};
#ifndef NO_USE_PACK
#pragma pack(pop)
#pragma pack(push, 8)
#endif
interface DECLSPEC_ALIGN(8) CGetFrameOptions : CUnknown
{
public:
short IGetFrameOptions_ID;
bool IGetFrameOptions_Ok;
int IGetFrameOptions_Value;
virtual HRESULT STDMETHODCALLTYPE GetFrameOptions(DWORD* pdwFlags) = 0;
};
#ifndef NO_USE_PACK
#pragma pack(pop)
#pragma pack(push, 16)
#endif
class DECLSPEC_ALIGN(16) CMyMI :public CParseDisplayName, COleWindow, CPersist, CSupportErrorInfo, CGetFrameOptions
{
private:
long nRefs;
HWND hWnd;
CLSID clsid;
public:
CMyMI()
{
nRefs = GetTickCount();
hWnd = (HWND)0x12345678;
clsid = __uuidof(CPersist);
int base_size_think = sizeof(CParseDisplayName) + sizeof(COleWindow) + sizeof(CPersist) + sizeof(CSupportErrorInfo) + sizeof(CGetFrameOptions);
int base_size_real = (char*)&nRefs - (char*)this;
if (base_size_real != base_size_think)
{
__debugbreak();
return;
}
}
protected:
virtual void DeleteObject()
{
delete this;
}
public:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR * __RPC_FAR * ppvObject)
{
return (HRESULT)(DWORD_PTR)hWnd;
}
ULONG STDMETHODCALLTYPE AddRef()
{
//ATLASSERT(nRefs >= 0);
return nRefs++;
}
ULONG STDMETHODCALLTYPE Release()
{
//ATLASSERT(nRefs != 0);
long nRefs_Result = nRefs--;
if (nRefs_Result <= 0)
{
DeleteObject();
}
return nRefs_Result;
}
//IParseDisplayName
public:
virtual HRESULT STDMETHODCALLTYPE ParseDisplayName(
/* [unique][in] */ __RPC__in_opt IBindCtx * pbc,
/* [in] */ __RPC__in LPOLESTR pszDisplayName,
/* [out] */ __RPC__out ULONG * pchEaten,
/* [out] */ __RPC__deref_out_opt IMoniker * *ppmkOut)
{
IParseDisplayName_ID = GetTickCount();
IOleWindow_ID = GetTickCount();
IPersist_ID = GetTickCount();
ISupportErrorInfo_ID = GetTickCount();
IGetFrameOptions_ID = GetTickCount();
hWnd = GetDesktopWindow();
return E_NOTIMPL;
}
//IOleWindow
public:
virtual /* [input_sync] */ HRESULT STDMETHODCALLTYPE GetWindow(
/* [out] */ __RPC__deref_out_opt HWND * phwnd)
{
*phwnd = hWnd;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
/* [in] */ BOOL fEnterMode)
{
return E_NOTIMPL;
}
//IPersist
public:
virtual HRESULT STDMETHODCALLTYPE GetClassID(
/* [out] */ __RPC__out CLSID * pClassID)
{
IParseDisplayName_ID = GetTickCount();
IOleWindow_ID = GetTickCount();
IPersist_ID = GetTickCount();
ISupportErrorInfo_ID = GetTickCount();
IGetFrameOptions_ID = GetTickCount();
*pClassID = clsid;
return S_OK;
}
//ISupportErrorInfo
public:
HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(
/* [in] */ __RPC__in REFIID riid)
{
IParseDisplayName_ID = GetTickCount();
IOleWindow_ID = GetTickCount();
IPersist_ID = GetTickCount();
ISupportErrorInfo_ID = GetTickCount();
IGetFrameOptions_ID = GetTickCount();
return riid == clsid ? S_OK : S_FALSE;
}
//IGetFrameOptions
public:
HRESULT STDMETHODCALLTYPE GetFrameOptions(DWORD * pdwFlags)
{
IParseDisplayName_ID = GetTickCount();
IOleWindow_ID = GetTickCount();
IPersist_ID = GetTickCount();
ISupportErrorInfo_ID = GetTickCount();
IGetFrameOptions_ID = GetTickCount();
nRefs += GetTickCount();
*pdwFlags = nRefs;
return S_OK;
}
};
#ifndef NO_USE_PACK
#pragma pack(pop)
#endif
int main()
{
CMyMI my;
my.ParseDisplayName(0, 0, 0, 0);
HWND hWnd;
my.GetWindow(&hWnd);
DWORD dwFlags;
my.GetFrameOptions(&dwFlags);
return (int)((DWORD_PTR)(hWnd)+dwFlags);
}
Compile the above code with vc x86, then load the generated exe with IDA and let IDA automatically load the pdb of this exe. You will see the following IDA decompiled code for CMyMI::GetWindow
:
HRESULT __stdcall CMyMI::GetWindow(CMyMI *this, HWND__ **phwnd)
{
*phwnd = (HWND__ *)this->ISupportErrorInfo_Value;
return 0;
}
But its original code is:
virtual /* [input_sync] */ HRESULT STDMETHODCALLTYPE GetWindow(
/* [out] */ __RPC__deref_out_opt HWND * phwnd)
{
*phwnd = hWnd;
return S_OK;
}
The hWnd
field is incorrectly identified as ISupportErrorInfo_Value
. The reason for the error is that the type of the this
parameter is incorrectly applied. Its type should be CMyMI[adjustor for COleWindow]*
, which represents this + the offset of the base class where the current interface function is located
, for example, as follows :
struct CMyMI_DataPart
{
int nRefs;
HWND__ *hWnd;
_GUID clsid;
}
struct __cppobj CMyMI[adjustor for COleWindow] :COleWindow, CPersist, CSupportErrorInfo, CGetFrameOptions
{
CMyMI_DataPart;
};
This is one problem. There is another problem. Comment out the
#define NO_USE_ALIGN
#define NO_USE_PACK
in the code, then compile and generate again and open it with IDA. You will see that the definition of CMyMI
changes from
struct __cppobj CMyMI : CParseDisplayName, COleWindow, CPersist, CSupportErrorInfo, CGetFrameOptions
{
int nRefs;
HWND__ *hWnd;
_GUID clsid;
};
to
struct __cppobj __declspec(align(16)) CMyMI : CParseDisplayName, COleWindow, CSupportErrorInfo, CGetFrameOptions
{
_BYTE _bytes_30[16];
HWND__ *hWnd;
_GUID clsid;
};
. The member field nRefs
is missing, and the base class CPersist
is also missing. The reason for the error is that IDA mistakenly believes that the starting offset of the first field nRefs
of CMyMI
is equal to sizeof(CParseDisplayName) + sizeof(COleWindow) + sizeof(CPersist) + sizeof(CSupportErrorInfo) + sizeof(CGetFrameOptions)
. In fact, it is the sum of the sizes of each base class excluding the end padding
field, The pseudo code is as follows:
sizeof(CParseDisplayName_NoTailPadding) + sizeof(COleWindow_NoTailPadding) + sizeof(CPersist_NoTailPadding) + sizeof(CSupportErrorInfo_NoTailPadding) + sizeof(CGetFrameOptions_NoTailPadding)