New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix ID2D1Device5/6 hook offsets #938
Conversation
ID2D1Device4 has two additional interface members: Set and GetMaximumColorGlyphCacheMemory. These two were unaccounted for in HookDevice, leading to crashes when any of these functions were called.
MyDebug(L"ID2D1Device5 hooked"); | ||
} | ||
CComPtr<ID2D1Device6> ptr7; | ||
hr = (d2dDevice)->QueryInterface(&ptr7); | ||
if SUCCEEDED(hr) { | ||
HOOK(ptr7, CreateDeviceContext7, 18); | ||
HOOK(ptr7, CreateDeviceContext7, 20); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have received a number of crash reports for Windows Terminal Preview 1.18 when MacType is being used. While debugging I found that this occurs whenever we call ID2D1Device4::SetMaximumColorGlyphCacheMemory
.
I don't understand how MacType or even just how EasyHook works, but I noticed that the indices for these two members seem to be highly inconsistent with the others, when you list them up (copied out of the D2D headers and simplified):
MIDL_INTERFACE("00000000-0000-0000-C000-000000000046") IUnknown
{
/* 0 */ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) = 0;
/* 1 */ virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
/* 2 */ virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
};
interface DX_DECLARE_INTERFACE("2cd90691-12e2-11dc-9fed-001143a055f9") ID2D1Resource : public IUnknown
{
/* 3 */ STDMETHOD_(void, GetFactory)(_Outptr_ ID2D1Factory **factory) CONST PURE;
};
interface DX_DECLARE_INTERFACE("47dd575d-ac05-4cdd-8049-9b02cd16f44c") ID2D1Device : public ID2D1Resource
{
/* 4 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext **deviceContext) PURE;
/* 5 */ STDMETHOD(CreatePrintControl)(_In_ IWICImagingFactory *wicFactory, _In_ IPrintDocumentPackageTarget *documentTarget, _In_opt_ CONST D2D1_PRINT_CONTROL_PROPERTIES *printControlProperties, _COM_Outptr_ ID2D1PrintControl **printControl) PURE;
/* 6 */ STDMETHOD_(void, SetMaximumTextureMemory)(UINT64 maximumInBytes) PURE;
/* 7 */ STDMETHOD_(UINT64, GetMaximumTextureMemory)() CONST PURE;
/* 8 */ STDMETHOD_(void, ClearResources)(UINT32 millisecondsSinceUse = 0) PURE;
};
interface DX_DECLARE_INTERFACE("d21768e1-23a4-4823-a14b-7c3eba85d658") ID2D1Device1 : public ID2D1Device
{
/* 9 */ STDMETHOD_(D2D1_RENDERING_PRIORITY, GetRenderingPriority)() PURE;
/* 10 */ STDMETHOD_(void, SetRenderingPriority)(D2D1_RENDERING_PRIORITY renderingPriority) PURE;
/* 11 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext1 **deviceContext1) PURE;
};
interface DX_DECLARE_INTERFACE("a44472e1-8dfb-4e60-8492-6e2861c9ca8b") ID2D1Device2 : public ID2D1Device1
{
/* 12 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext2 **deviceContext2) PURE;
/* 13 */ STDMETHOD_(void, FlushDeviceContexts)(_In_ ID2D1Bitmap *bitmap) PURE;
/* 14 */ STDMETHOD(GetDxgiDevice)(_COM_Outptr_ IDXGIDevice **dxgiDevice) PURE;
};
interface DX_DECLARE_INTERFACE("852f2087-802c-4037-ab60-ff2e7ee6fc01") ID2D1Device3 : public ID2D1Device2
{
/* 15 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext3 **deviceContext3) PURE;
};
interface DX_DECLARE_INTERFACE("d7bdb159-5683-4a46-bc9c-72dc720b858b") ID2D1Device4 : public ID2D1Device3
{
/* 16 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext4 **deviceContext4) PURE;
/* 17 */ STDMETHOD_(void, SetMaximumColorGlyphCacheMemory)(UINT64 maximumInBytes) PURE;
/* 18 */ STDMETHOD_(UINT64, GetMaximumColorGlyphCacheMemory)() CONST PURE;
};
interface DX_DECLARE_INTERFACE("d55ba0a4-6405-4694-aef5-08ee1a4358b4") ID2D1Device5 : public ID2D1Device4
{
/* 19 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext5 **deviceContext5) PURE;
};
interface DX_DECLARE_INTERFACE("7bfef914-2d75-4bad-be87-e18ddb077b6d") ID2D1Device6 : public ID2D1Device5
{
/* 20 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext6 **deviceContext6) PURE;
};
I've not tested this change, but I'm still very confident about the correctness of this fix.
Basically, these indices are the index of the function pointers in their respective vtable. We use easyhook to find the actual function and hijack it to our function. If the indice is wrong, then the wrong function will be intercepted, and the data could be corrupted. |
Confirmed that vtbl index for ID2D1Device5/6 is incorrect because of the two functions introduced by ID2D1Device4. |
Published as a preview release. |
Thank you so much for your help! |
ID2D1Device4 has two additional interface members: Set and
GetMaximumColorGlyphCacheMemory. These two were unaccounted for in
HookDevice, leading to crashes when any of these functions were called.