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; }
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; }
static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset) { DWORD i, count; ULONG currofs; ULONGLONG mask; 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; memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE)); for (i = count = 0, mask = 1; i < MAX_CLR_TABLES; i++, mask <<= 1) { if (assembly->tableshdr->MaskValid.QuadPart & mask) assembly->tables[i].rows = assembly->numrows[count++]; } assembly->numtables = count; currofs += assembly->numtables * sizeof(DWORD); for (i = 0, mask = 1; i < MAX_CLR_TABLES; i++, mask <<= 1) { if (assembly->tableshdr->MaskValid.QuadPart & mask) { assembly->tables[i].offset = currofs; currofs += get_table_size(assembly, i) * assembly->tables[i].rows; } } 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; }
HRESULT assembly_get_external_files(ASSEMBLY *assembly, LPWSTR **files, DWORD *count) { LONG offset; INT i, num_rows; WCHAR **ret; BYTE *ptr; DWORD idx; *count = 0; offset = assembly->tables[TableFromToken(mdtFile)].offset; if (offset == -1) return S_OK; ptr = assembly_data_offset(assembly, offset); if (!ptr) return S_OK; num_rows = assembly->tables[TableFromToken(mdtFile)].rows; if (num_rows <= 0) return S_OK; ret = HeapAlloc(GetProcessHeap(), 0, num_rows * sizeof(WCHAR *)); if (!ret) return E_OUTOFMEMORY; for (i = 0; i < num_rows; i++) { ptr += sizeof(DWORD); /* skip Flags field */ if (assembly->stringsz == sizeof(DWORD)) idx = *(DWORD *)ptr; else idx = *(WORD *)ptr; ret[i] = assembly_dup_str(assembly, idx); if (!ret[i]) { for (; i >= 0; i--) HeapFree(GetProcessHeap(), 0, ret[i]); HeapFree(GetProcessHeap(), 0, ret); return E_OUTOFMEMORY; } ptr += assembly->stringsz; /* skip Name field */ ptr += assembly->blobsz; /* skip Hash field */ } *count = num_rows; *files = ret; return S_OK; }
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; }