From d2d1c6d8246df302a8c91596fec43b66fd338f97 Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Thu, 20 Oct 2011 13:23:35 -0500 Subject: [PATCH] mscoree: Detect when a CLR DLL requests vtable fixups. --- dlls/mscoree/assembly.c | 102 +++++++++++++++++++++++++++------ dlls/mscoree/corruntimehost.c | 38 ++++++++++++ dlls/mscoree/mscoree_main.c | 15 ----- dlls/mscoree/mscoree_private.h | 15 ++++- 4 files changed, 134 insertions(+), 36 deletions(-) diff --git a/dlls/mscoree/assembly.c b/dlls/mscoree/assembly.c index 07723f9edb7..a1e3dc7478b 100644 --- a/dlls/mscoree/assembly.c +++ b/dlls/mscoree/assembly.c @@ -63,10 +63,13 @@ typedef struct tagCLRTABLE struct tagASSEMBLY { - LPWSTR path; + int is_mapped_file; + /* mapped files */ + LPWSTR path; HANDLE hfile; HANDLE hmap; + BYTE *data; IMAGE_NT_HEADERS *nthdr; @@ -89,6 +92,29 @@ static inline LPWSTR strdupW(LPCWSTR src) return dest; } +void* assembly_rva_to_va(ASSEMBLY *assembly, ULONG rva) +{ + if (assembly->is_mapped_file) + return ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL); + else + return assembly->data + rva; +} + +static ULONG assembly_datadir_get_data(ASSEMBLY *assembly, + IMAGE_DATA_DIRECTORY *datadir, void **data) +{ + if (!datadir->VirtualAddress || !datadir->Size) + { + *data = NULL; + return 0; + } + else + { + *data = assembly_rva_to_va(assembly, datadir->VirtualAddress); + return datadir->Size; + } +} + static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz) { METADATAHDR *metadatahdr; @@ -97,7 +123,7 @@ static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz) ULONG rva; rva = assembly->corhdr->MetaData.VirtualAddress; - ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL); + ptr = assembly_rva_to_va(assembly, rva); if (!ptr) return E_FAIL; @@ -158,20 +184,24 @@ static HRESULT parse_pe_header(ASSEMBLY *assembly) if (!datadirs) return E_FAIL; - if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress || - !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size) - { - return E_FAIL; - } - - assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data, - datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL); - if (!assembly->corhdr) + if (!assembly_datadir_get_data(assembly, &datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR], (void**)&assembly->corhdr)) return E_FAIL; return S_OK; } +HRESULT parse_headers(ASSEMBLY *assembly) +{ + HRESULT hr; + + hr = parse_pe_header(assembly); + + if (SUCCEEDED(hr)) + hr = parse_clr_metadata(assembly); + + return hr; +} + HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) { ASSEMBLY *assembly; @@ -183,6 +213,8 @@ HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) if (!assembly) return E_OUTOFMEMORY; + assembly->is_mapped_file = 1; + assembly->path = strdupW(file); if (!assembly->path) { @@ -213,10 +245,7 @@ HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) goto failed; } - hr = parse_pe_header(assembly); - if (FAILED(hr)) goto failed; - - hr = parse_clr_metadata(assembly); + hr = parse_headers(assembly); if (FAILED(hr)) goto failed; *out = assembly; @@ -227,16 +256,43 @@ failed: return hr; } +HRESULT assembly_from_hmodule(ASSEMBLY **out, HMODULE hmodule) +{ + ASSEMBLY *assembly; + HRESULT hr; + + *out = NULL; + + assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY)); + if (!assembly) + return E_OUTOFMEMORY; + + assembly->is_mapped_file = 0; + + assembly->data = (BYTE*)hmodule; + + hr = parse_headers(assembly); + if (SUCCEEDED(hr)) + *out = assembly; + else + assembly_release(assembly); + + return hr; +} + HRESULT assembly_release(ASSEMBLY *assembly) { if (!assembly) return S_OK; + if (assembly->is_mapped_file) + { + UnmapViewOfFile(assembly->data); + CloseHandle(assembly->hmap); + CloseHandle(assembly->hfile); + } HeapFree(GetProcessHeap(), 0, assembly->metadatahdr); HeapFree(GetProcessHeap(), 0, assembly->path); - UnmapViewOfFile(assembly->data); - CloseHandle(assembly->hmap); - CloseHandle(assembly->hfile); HeapFree(GetProcessHeap(), 0, assembly); return S_OK; @@ -248,3 +304,13 @@ HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) return S_OK; } + +HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) +{ + ULONG size; + + size = assembly_datadir_get_data(assembly, &assembly->corhdr->VTableFixups, (void**)fixups); + *count = size / sizeof(VTableFixup); + + return S_OK; +} diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c index 1750f12926a..31c02eaace3 100644 --- a/dlls/mscoree/corruntimehost.c +++ b/dlls/mscoree/corruntimehost.c @@ -803,6 +803,26 @@ static void get_utf8_args(int *argc, char ***argv) HeapFree(GetProcessHeap(), 0, argvw); } +static void FixupVTable(HMODULE hmodule) +{ + ASSEMBLY *assembly; + HRESULT hr; + VTableFixup *vtable_fixups; + ULONG vtable_fixup_count; + + hr = assembly_from_hmodule(&assembly, hmodule); + if (SUCCEEDED(hr)) + { + hr = assembly_get_vtable_fixups(assembly, &vtable_fixups, &vtable_fixup_count); + if (vtable_fixup_count) + FIXME("vtable fixups are not implemented; expect a crash\n"); + + assembly_release(assembly); + } + else + ERR("failed to read CLR headers, hr=%x\n", hr); +} + __int32 WINAPI _CorExeMain(void) { int exit_code; @@ -830,6 +850,8 @@ __int32 WINAPI _CorExeMain(void) if (!filenameA) return -1; + FixupVTable(GetModuleHandleW(NULL)); + hr = get_runtime_info(filename, NULL, NULL, 0, 0, FALSE, &info); if (SUCCEEDED(hr)) @@ -862,6 +884,22 @@ __int32 WINAPI _CorExeMain(void) return exit_code; } +BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + FIXME("(%p, %d, %p): stub\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + FixupVTable(hinstDLL); + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + HRESULT RuntimeHost_Construct(const CLRRuntimeInfo *runtime_version, loaded_mono *loaded_mono, RuntimeHost** result) { diff --git a/dlls/mscoree/mscoree_main.c b/dlls/mscoree/mscoree_main.c index 1e06909b45e..09f6dad586d 100644 --- a/dlls/mscoree/mscoree_main.c +++ b/dlls/mscoree/mscoree_main.c @@ -236,21 +236,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) return TRUE; } -BOOL WINAPI _CorDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - FIXME("(%p, %d, %p): stub\n", hinstDLL, fdwReason, lpvReserved); - - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - __int32 WINAPI _CorExeMain2(PBYTE ptrMemory, DWORD cntMemory, LPWSTR imageName, LPWSTR loaderName, LPWSTR cmdLine) { TRACE("(%p, %u, %s, %s, %s)\n", ptrMemory, cntMemory, debugstr_w(imageName), debugstr_w(loaderName), debugstr_w(cmdLine)); diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h index 62cf240c61b..12a1e5685ef 100644 --- a/dlls/mscoree/mscoree_private.h +++ b/dlls/mscoree/mscoree_private.h @@ -27,11 +27,20 @@ extern HRESULT CLRMetaHost_CreateInstance(REFIID riid, void **ppobj) DECLSPEC_HI extern HRESULT WINAPI CLRMetaHost_GetVersionFromFile(ICLRMetaHost* iface, LPCWSTR pwzFilePath, LPWSTR pwzBuffer, DWORD *pcchBuffer) DECLSPEC_HIDDEN; +typedef struct _VTableFixup { + DWORD rva; + WORD count; + WORD type; +} VTableFixup; + typedef struct tagASSEMBLY ASSEMBLY; -HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) DECLSPEC_HIDDEN; -HRESULT assembly_release(ASSEMBLY *assembly) DECLSPEC_HIDDEN; -HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) DECLSPEC_HIDDEN; +extern void* assembly_rva_to_va(ASSEMBLY *assembly, ULONG rva) DECLSPEC_HIDDEN; +extern HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) DECLSPEC_HIDDEN; +extern HRESULT assembly_from_hmodule(ASSEMBLY **out, HMODULE hmodule) DECLSPEC_HIDDEN; +extern HRESULT assembly_release(ASSEMBLY *assembly) DECLSPEC_HIDDEN; +extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) DECLSPEC_HIDDEN; +extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; /* Mono embedding */ typedef struct _MonoDomain MonoDomain;