/* * assembly parser * * Copyright 2008 James Hawkins * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <stdarg.h> #include <stdio.h> #include "windef.h" #include "winbase.h" #include "winuser.h" #include "winver.h" #include "wincrypt.h" #include "dbghelp.h" #include "ole2.h" #include "fusion.h" #include "corhdr.h" #include "fusionpriv.h" #include "wine/debug.h" #include "wine/unicode.h" #define TableFromToken(tk) (TypeFromToken(tk) >> 24) #define TokenFromTable(idx) (idx << 24) #define MAX_CLR_TABLES 64 #define MD_STRINGS_BIT 0x1 #define MD_GUIDS_BIT 0x2 #define MD_BLOBS_BIT 0x4 typedef struct tagCLRTABLE { INT rows; DWORD offset; } CLRTABLE; struct tagASSEMBLY { LPWSTR path; HANDLE hfile; HANDLE hmap; BYTE *data; IMAGE_NT_HEADERS *nthdr; IMAGE_COR20_HEADER *corhdr; METADATAHDR *metadatahdr; METADATATABLESHDR *tableshdr; DWORD numtables; DWORD *numrows; CLRTABLE tables[MAX_CLR_TABLES]; DWORD stringsz; DWORD guidsz; DWORD blobsz; BYTE *strings; BYTE *blobs; }; static DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva) { DWORD offset = rva, limit; IMAGE_SECTION_HEADER *img; WORD i; img = IMAGE_FIRST_SECTION(nthdrs); if (rva < img->PointerToRawData) return rva; for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++) { if (img[i].SizeOfRawData) limit = img[i].SizeOfRawData; else limit = img[i].Misc.VirtualSize; if (rva >= img[i].VirtualAddress && rva < (img[i].VirtualAddress + limit)) { if (img[i].PointerToRawData != 0) { offset -= img[i].VirtualAddress; offset += img[i].PointerToRawData; } return offset; } } return 0; } static BYTE *GetData(BYTE *pData, ULONG *pLength) { if ((*pData & 0x80) == 0x00) { *pLength = (*pData & 0x7f); return pData + 1; } if ((*pData & 0xC0) == 0x80) { *pLength = ((*pData & 0x3f) << 8 | *(pData + 1)); return pData + 2; } if ((*pData & 0xE0) == 0xC0) { *pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 | *(pData + 2) << 8 | *(pData + 3)); return pData + 4; } *pLength = (ULONG)-1; return 0; } static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset) { return &assembly->data[offset]; } #define MAX_TABLES_WORD 0xFFFF #define MAX_TABLES_1BIT_ENCODE 32767 #define MAX_TABLES_2BIT_ENCODE 16383 #define MAX_TABLES_3BIT_ENCODE 8191 #define MAX_TABLES_5BIT_ENCODE 2047 static inline ULONG get_table_size(const ASSEMBLY *assembly, DWORD index) { DWORD size; INT tables; switch (TokenFromTable(index)) { case mdtModule: { size = sizeof(MODULETABLE) + (assembly->stringsz - sizeof(WORD)) + 2 * (assembly->guidsz - sizeof(WORD)); break; } case mdtTypeRef: { size = sizeof(TYPEREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)); /* ResolutionScope:ResolutionScope */ tables = max(assembly->tables[TableFromToken(mdtModule)].rows, assembly->tables[TableFromToken(mdtModuleRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtAssemblyRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case mdtTypeDef: { size = sizeof(TYPEDEFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)); /* Extends:TypeDefOrRef */ tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows, assembly->tables[TableFromToken(mdtTypeRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtFieldDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtMethodDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtFieldDef: { size = sizeof(FIELDTABLE) + (assembly->stringsz - sizeof(WORD)) + (assembly->blobsz - sizeof(WORD)); break; } case mdtMethodDef: { size = sizeof(METHODDEFTABLE) + (assembly->stringsz - sizeof(WORD)) + (assembly->blobsz - sizeof(WORD)); size += (assembly->tables[TableFromToken(mdtParamDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtParamDef: { size = sizeof(PARAMTABLE) + (assembly->stringsz - sizeof(WORD)); break; } case mdtInterfaceImpl: { size = sizeof(INTERFACEIMPLTABLE); /* Interface:TypeDefOrRef */ tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows, assembly->tables[TableFromToken(mdtTypeRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case mdtMemberRef: { size = sizeof(MEMBERREFTABLE) + (assembly->stringsz - sizeof(WORD)) + (assembly->blobsz - sizeof(WORD)); /* Class:MemberRefParent */ tables = max(assembly->tables[TableFromToken(mdtTypeRef)].rows, assembly->tables[TableFromToken(mdtModuleRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtMethodDef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows); size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0; break; } case 0x0B000000: /* FIXME */ { size = sizeof(CONSTANTTABLE) + (assembly->blobsz - sizeof(WORD)); /* Parent:HasConstant */ tables = max(assembly->tables[TableFromToken(mdtParamDef)].rows, assembly->tables[TableFromToken(mdtFieldDef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case mdtCustomAttribute: { size = sizeof(CUSTOMATTRIBUTETABLE) + (assembly->blobsz - sizeof(WORD)); /* Parent:HasCustomAttribute */ tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows, assembly->tables[TableFromToken(mdtFieldDef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtParamDef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtInterfaceImpl)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtMemberRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtPermission)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtEvent)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtSignature)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtModuleRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtFile)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtExportedType)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtManifestResource)].rows); size += (tables > MAX_TABLES_5BIT_ENCODE) ? sizeof(WORD) : 0; /* Type:CustomAttributeType */ tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows, assembly->tables[TableFromToken(mdtMemberRef)].rows); size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0; break; } case 0x0D000000: /* FIXME */ { size = sizeof(FIELDMARSHALTABLE) + (assembly->blobsz - sizeof(WORD)); /* Parent:HasFieldMarshal */ tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows, assembly->tables[TableFromToken(mdtParamDef)].rows); size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0; break; } case mdtPermission: { size = sizeof(DECLSECURITYTABLE) + (assembly->blobsz - sizeof(WORD)); /* Parent:HasDeclSecurity */ tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows, assembly->tables[TableFromToken(mdtMethodDef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case 0x0F000000: /* FIXME */ { size = sizeof(CLASSLAYOUTTABLE); size += (assembly->tables[TableFromToken(mdtTypeDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case 0x10000000: /* FIXME */ { size = sizeof(FIELDLAYOUTTABLE); size += (assembly->tables[TableFromToken(mdtFieldDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtSignature: { size = sizeof(STANDALONESIGTABLE) + (assembly->blobsz - sizeof(WORD)); break; } case 0x12000000: /* FIXME */ { size = sizeof(EVENTMAPTABLE); size += (assembly->tables[TableFromToken(mdtTypeDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtEvent)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtEvent: { size = sizeof(EVENTTABLE) + (assembly->stringsz - sizeof(WORD)); /* EventType:TypeDefOrRef */ tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows, assembly->tables[TableFromToken(mdtTypeRef)].rows); tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case 0x15000000:/* FIXME */ { size = sizeof(PROPERTYMAPTABLE); size += (assembly->tables[TableFromToken(mdtTypeDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtProperty)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtProperty: { size = sizeof(PROPERTYTABLE) + (assembly->stringsz - sizeof(WORD)) + (assembly->blobsz - sizeof(WORD)); break; } case 0x18000000: /* FIXME */ { size = sizeof(METHODSEMANTICSTABLE); /* Association:HasSemantics */ tables = max(assembly->tables[TableFromToken(mdtEvent)].rows, assembly->tables[TableFromToken(mdtProperty)].rows); size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtMethodDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case 0x19000000: /* FIXME */ { size = sizeof(METHODIMPLTABLE); /* MethodBody:MethodDefOrRef, MethodDeclaration:MethodDefOrRef */ tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows, assembly->tables[TableFromToken(mdtMemberRef)].rows); size += (tables > MAX_TABLES_1BIT_ENCODE) ? 2 * sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtTypeDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtModuleRef: { size = sizeof(MODULEREFTABLE) + (assembly->stringsz - sizeof(WORD)); break; } case mdtTypeSpec: { size = sizeof(TYPESPECTABLE) + (assembly->blobsz - sizeof(WORD)); break; } case 0x1C000000: /* FIXME */ { size = sizeof(IMPLMAPTABLE) + (assembly->stringsz - sizeof(WORD)); /* MemberForwarded:MemberForwarded */ tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows, assembly->tables[TableFromToken(mdtMethodDef)].rows); size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0; size += (assembly->tables[TableFromToken(mdtModuleRef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case 0x1D000000: /* FIXME */ { size = sizeof(FIELDRVATABLE); size += (assembly->tables[TableFromToken(mdtFieldDef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtAssembly: { size = sizeof(ASSEMBLYTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) + (assembly->blobsz - sizeof(WORD)); break; } case 0x20000001: /* FIXME */ { size = sizeof(ASSEMBLYPROCESSORTABLE); break; } case 0x22000000: /* FIXME */ { size = sizeof(ASSEMBLYOSTABLE); break; } case mdtAssemblyRef: { size = sizeof(ASSEMBLYREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) + 2 * (assembly->blobsz - sizeof(WORD)); break; } case 0x24000000: /* FIXME */ { size = sizeof(ASSEMBLYREFPROCESSORTABLE); size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case 0x25000000: /* FIXME */ { size = sizeof(ASSEMBLYREFOSTABLE); size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows > MAX_TABLES_WORD) ? sizeof(WORD) : 0; break; } case mdtFile: { size = sizeof(FILETABLE) + (assembly->stringsz - sizeof(WORD)) + (assembly->blobsz - sizeof(WORD)); break; } case mdtExportedType: { size = sizeof(EXPORTEDTYPETABLE) + 2 * (assembly->stringsz - sizeof(WORD)); /* Implementation:Implementation */ tables = max(assembly->tables[TableFromToken(mdtFile)].rows, assembly->tables[TableFromToken(mdtMethodDef)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case mdtManifestResource: { size = sizeof(MANIFESTRESTABLE) + (assembly->stringsz - sizeof(WORD)); /* Implementation:Implementation */ tables = max(assembly->tables[TableFromToken(mdtFile)].rows, assembly->tables[TableFromToken(mdtAssemblyRef)].rows); size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0; break; } case 0x29000000: /* FIXME */ { size = sizeof(NESTEDCLASSTABLE); size += (assembly->tables[TableFromToken(mdtTypeDef)].rows > MAX_TABLES_WORD) ? 2 * sizeof(WORD) : 0; break; } default: return 0; } return size; } static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset) { DWORD i, previ, offidx; ULONG currofs; currofs = offset; assembly->tableshdr = assembly_data_offset(assembly, currofs); if (!assembly->tableshdr) return E_FAIL; assembly->stringsz = (assembly->tableshdr->HeapOffsetSizes & MD_STRINGS_BIT) ? sizeof(DWORD) : sizeof(WORD); assembly->guidsz = (assembly->tableshdr->HeapOffsetSizes & MD_GUIDS_BIT) ? sizeof(DWORD) : sizeof(WORD); assembly->blobsz = (assembly->tableshdr->HeapOffsetSizes & MD_BLOBS_BIT) ? sizeof(DWORD) : sizeof(WORD); currofs += sizeof(METADATATABLESHDR); assembly->numrows = assembly_data_offset(assembly, currofs); if (!assembly->numrows) return E_FAIL; assembly->numtables = 0; for (i = 0; i < MAX_CLR_TABLES; i++) { if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) || (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1)) { assembly->numtables++; } } currofs += assembly->numtables * sizeof(DWORD); memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE)); if (assembly->tableshdr->MaskValid.u.LowPart & 1) assembly->tables[0].offset = currofs; offidx = 0; for (i = 0; i < MAX_CLR_TABLES; i++) { if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) || (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1)) { assembly->tables[i].rows = assembly->numrows[offidx]; offidx++; } } previ = 0; offidx = 1; for (i = 1; i < MAX_CLR_TABLES; i++) { if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) || (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1)) { currofs += get_table_size(assembly, previ) * assembly->numrows[offidx - 1]; assembly->tables[i].offset = currofs; offidx++; previ = i; } } return S_OK; } static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz) { METADATAHDR *metadatahdr; BYTE *ptr, *dest; DWORD size, ofs; ULONG rva; rva = assembly->corhdr->MetaData.VirtualAddress; ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL); if (!ptr) return E_FAIL; metadatahdr = (METADATAHDR *)ptr; assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR)); if (!assembly->metadatahdr) return E_OUTOFMEMORY; size = FIELD_OFFSET(METADATAHDR, Version); memcpy(assembly->metadatahdr, metadatahdr, size); assembly->metadatahdr->Version = (LPSTR)&metadatahdr->Version; ofs = FIELD_OFFSET(METADATAHDR, Flags); ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1; dest = (BYTE *)assembly->metadatahdr + ofs; memcpy(dest, ptr, sizeof(METADATAHDR) - ofs); *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1; return S_OK; } static HRESULT parse_clr_metadata(ASSEMBLY *assembly) { METADATASTREAMHDR *streamhdr; ULONG rva, i, ofs; LPSTR stream; HRESULT hr; DWORD hdrsz; BYTE *ptr; hr = parse_metadata_header(assembly, &hdrsz); if (FAILED(hr)) return hr; rva = assembly->corhdr->MetaData.VirtualAddress; ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva + hdrsz, NULL); if (!ptr) return E_FAIL; for (i = 0; i < assembly->metadatahdr->Streams; i++) { streamhdr = (METADATASTREAMHDR *)ptr; ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset); ptr += sizeof(METADATASTREAMHDR); stream = (LPSTR)ptr; if (!lstrcmpA(stream, "#~")) { hr = parse_clr_tables(assembly, ofs); if (FAILED(hr)) return hr; } else if (!lstrcmpA(stream, "#Strings") || !lstrcmpA(stream, "Strings")) assembly->strings = assembly_data_offset(assembly, ofs); else if (!lstrcmpA(stream, "#Blob") || !lstrcmpA(stream, "Blob")) assembly->blobs = assembly_data_offset(assembly, ofs); ptr += lstrlenA(stream) + 1; ptr = (BYTE *)(((UINT_PTR)ptr + 3) & ~3); /* align on DWORD boundary */ } return S_OK; } static HRESULT parse_pe_header(ASSEMBLY *assembly) { IMAGE_DATA_DIRECTORY *datadirs; assembly->nthdr = ImageNtHeader(assembly->data); if (!assembly->nthdr) return E_FAIL; if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { IMAGE_OPTIONAL_HEADER64 *opthdr = (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader; datadirs = opthdr->DataDirectory; } else { IMAGE_OPTIONAL_HEADER32 *opthdr = (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader; datadirs = opthdr->DataDirectory; } 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) return E_FAIL; return S_OK; } HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file) { ASSEMBLY *assembly; HRESULT hr; *out = NULL; assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY)); if (!assembly) return E_OUTOFMEMORY; assembly->path = strdupW(file); if (!assembly->path) { hr = E_OUTOFMEMORY; goto failed; } assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (assembly->hfile == INVALID_HANDLE_VALUE) { hr = HRESULT_FROM_WIN32(GetLastError()); goto failed; } assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY, 0, 0, NULL); if (!assembly->hmap) { hr = HRESULT_FROM_WIN32(GetLastError()); goto failed; } assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0); if (!assembly->data) { hr = HRESULT_FROM_WIN32(GetLastError()); goto failed; } hr = parse_pe_header(assembly); if (FAILED(hr)) goto failed; hr = parse_clr_metadata(assembly); if (FAILED(hr)) goto failed; *out = assembly; return S_OK; failed: assembly_release(assembly); return hr; } HRESULT assembly_release(ASSEMBLY *assembly) { if (!assembly) return S_OK; 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; } static LPWSTR assembly_dup_str(const ASSEMBLY *assembly, DWORD index) { int len; LPWSTR cpy; LPCSTR str = (LPCSTR)&assembly->strings[index]; len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); if ((cpy = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) MultiByteToWideChar(CP_ACP, 0, str, -1, cpy, len); return cpy; } HRESULT assembly_get_name(ASSEMBLY *assembly, LPWSTR *name) { BYTE *ptr; LONG offset; DWORD stridx; offset = assembly->tables[TableFromToken(mdtAssembly)].offset; if (offset == -1) return E_FAIL; ptr = assembly_data_offset(assembly, offset); if (!ptr) return E_FAIL; ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey) + assembly->blobsz; if (assembly->stringsz == sizeof(DWORD)) stridx = *((DWORD *)ptr); else stridx = *((WORD *)ptr); *name = assembly_dup_str(assembly, stridx); if (!*name) return E_OUTOFMEMORY; return S_OK; } HRESULT assembly_get_path(const ASSEMBLY *assembly, LPWSTR *path) { LPWSTR cpy = HeapAlloc(GetProcessHeap(), 0, (strlenW(assembly->path) + 1) * sizeof(WCHAR)); *path = cpy; if (cpy) strcpyW(cpy, assembly->path); else return E_OUTOFMEMORY; return S_OK; } HRESULT assembly_get_version(ASSEMBLY *assembly, LPWSTR *version) { static const WCHAR format[] = {'%','u','.','%','u','.','%','u','.','%','u',0}; ASSEMBLYTABLE *asmtbl; LONG offset; *version = NULL; offset = assembly->tables[TableFromToken(mdtAssembly)].offset; if (offset == -1) return E_FAIL; asmtbl = assembly_data_offset(assembly, offset); if (!asmtbl) return E_FAIL; *version = HeapAlloc(GetProcessHeap(), 0, sizeof(format) + 4 * strlen("65535") * sizeof(WCHAR)); if (!*version) return E_OUTOFMEMORY; sprintfW(*version, format, asmtbl->MajorVersion, asmtbl->MinorVersion, asmtbl->BuildNumber, asmtbl->RevisionNumber); return S_OK; } PEKIND assembly_get_architecture(ASSEMBLY *assembly) { if ((assembly->corhdr->MajorRuntimeVersion == 2) && (assembly->corhdr->MinorRuntimeVersion == 0)) return peNone; /* .NET 1.x assembly */ if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) return peAMD64; /* AMD64/IA64 assembly */ if ((assembly->corhdr->Flags & COMIMAGE_FLAGS_ILONLY) && !(assembly->corhdr->Flags & COMIMAGE_FLAGS_32BITREQUIRED)) return peMSIL; /* MSIL assembly */ return peI386; /* x86 assembly */ } static BYTE *assembly_get_blob(ASSEMBLY *assembly, DWORD index, ULONG *size) { return GetData(&assembly->blobs[index], size); } HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPWSTR *token) { ULONG i, size; LONG offset; BYTE *hashdata, *pubkey, *ptr; HCRYPTPROV crypt; HCRYPTHASH hash; BYTE tokbytes[BYTES_PER_TOKEN]; HRESULT hr = E_FAIL; LPWSTR tok; DWORD idx; *token = NULL; offset = assembly->tables[TableFromToken(mdtAssembly)].offset; if (offset == -1) return E_FAIL; ptr = assembly_data_offset(assembly, offset); if (!ptr) return E_FAIL; ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey); if (assembly->blobsz == sizeof(DWORD)) idx = *(DWORD *)ptr; else idx = *(WORD *)ptr; pubkey = assembly_get_blob(assembly, idx, &size); if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) return E_FAIL; if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash)) return E_FAIL; if (!CryptHashData(hash, pubkey, size, 0)) return E_FAIL; size = 0; if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0)) return E_FAIL; hashdata = HeapAlloc(GetProcessHeap(), 0, size); if (!hashdata) { hr = E_OUTOFMEMORY; goto done; } if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0)) goto done; for (i = size - 1; i >= size - 8; i--) tokbytes[size - i - 1] = hashdata[i]; tok = HeapAlloc(GetProcessHeap(), 0, (TOKEN_LENGTH + 1) * sizeof(WCHAR)); if (!tok) { hr = E_OUTOFMEMORY; goto done; } token_to_str(tokbytes, tok); *token = tok; hr = S_OK; done: HeapFree(GetProcessHeap(), 0, hashdata); CryptDestroyHash(hash); CryptReleaseContext(crypt, 0); return hr; } HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) { *version = assembly->metadatahdr->Version; return S_OK; }