4 * Copyright 2008 James Hawkins
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "fusionpriv.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
37 #define MAX_CLR_TABLES 64
39 typedef struct tagCLRTABLE
53 IMAGE_NT_HEADERS32
*nthdr
;
54 IMAGE_COR20_HEADER
*corhdr
;
56 METADATAHDR
*metadatahdr
;
58 METADATATABLESHDR
*tableshdr
;
61 CLRTABLE tables
[MAX_CLR_TABLES
];
68 const DWORD COR_TABLE_SIZES
[64] =
102 sizeof(ASSEMBLYTABLE
),
110 sizeof(MANIFESTRESTABLE
),
136 static LPSTR
strdupWtoA(LPCWSTR str
)
144 len
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
145 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
147 WideCharToMultiByte(CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
152 static DWORD
rva_to_offset(IMAGE_NT_HEADERS
*nthdrs
, DWORD rva
)
154 DWORD offset
= rva
, limit
;
155 IMAGE_SECTION_HEADER
*img
;
158 img
= IMAGE_FIRST_SECTION(nthdrs
);
160 if (rva
< img
->PointerToRawData
)
163 for (i
= 0; i
< nthdrs
->FileHeader
.NumberOfSections
; i
++)
165 if (img
[i
].SizeOfRawData
)
166 limit
= img
[i
].SizeOfRawData
;
168 limit
= img
[i
].Misc
.VirtualSize
;
170 if (rva
>= img
[i
].VirtualAddress
&&
171 rva
< (img
[i
].VirtualAddress
+ limit
))
173 if (img
[i
].PointerToRawData
!= 0)
175 offset
-= img
[i
].VirtualAddress
;
176 offset
+= img
[i
].PointerToRawData
;
186 static BYTE
*GetData(BYTE
*pData
, ULONG
*pLength
)
188 if ((*pData
& 0x80) == 0x00)
190 *pLength
= (*pData
& 0x7f);
194 if ((*pData
& 0xC0) == 0x80)
196 *pLength
= ((*pData
& 0x3f) << 8 | *(pData
+ 1));
200 if ((*pData
& 0xE0) == 0xC0)
202 *pLength
= ((*pData
& 0x1f) << 24 | *(pData
+ 1) << 16 |
203 *(pData
+ 2) << 8 | *(pData
+ 3));
207 *pLength
= (ULONG
)-1;
211 static VOID
*assembly_data_offset(ASSEMBLY
*assembly
, ULONG offset
)
213 return (VOID
*)&assembly
->data
[offset
];
216 static HRESULT
parse_clr_tables(ASSEMBLY
*assembly
, ULONG offset
)
218 DWORD i
, previ
, offidx
;
222 assembly
->tableshdr
= (METADATATABLESHDR
*)assembly_data_offset(assembly
, currofs
);
223 if (!assembly
->tableshdr
)
226 currofs
+= sizeof(METADATATABLESHDR
);
227 assembly
->numrows
= (DWORD
*)assembly_data_offset(assembly
, currofs
);
228 if (!assembly
->numrows
)
231 assembly
->numtables
= 0;
232 for (i
= 0; i
< MAX_CLR_TABLES
; i
++)
234 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.LowPart
>> i
) & 1) ||
235 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.HighPart
>> i
) & 1))
237 assembly
->numtables
++;
241 currofs
+= assembly
->numtables
* sizeof(DWORD
);
242 memset(assembly
->tables
, -1, MAX_CLR_TABLES
* sizeof(CLRTABLE
));
244 if (assembly
->tableshdr
->MaskValid
.LowPart
& 1)
246 assembly
->tables
[0].offset
= currofs
;
247 assembly
->tables
[0].rows
= assembly
->numrows
[0];
252 for (i
= 1; i
< MAX_CLR_TABLES
; i
++)
254 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.LowPart
>> i
) & 1) ||
255 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.HighPart
>> i
) & 1))
257 currofs
+= COR_TABLE_SIZES
[previ
] * assembly
->numrows
[offidx
- 1];
258 assembly
->tables
[i
].offset
= currofs
;
259 assembly
->tables
[i
].rows
= assembly
->numrows
[offidx
];
268 static HRESULT
parse_clr_metadata(ASSEMBLY
*assembly
)
270 METADATASTREAMHDR
*streamhdr
;
276 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
277 assembly
->metadatahdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
279 if (!assembly
->metadatahdr
)
282 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
283 rva
+ sizeof(METADATAHDR
), NULL
);
287 for (i
= 0; i
< assembly
->metadatahdr
->Streams
; i
++)
289 streamhdr
= (METADATASTREAMHDR
*)ptr
;
290 ofs
= rva_to_offset(assembly
->nthdr
, rva
+ streamhdr
->Offset
);
292 ptr
+= sizeof(METADATASTREAMHDR
);
295 if (!lstrcmpA(stream
, "#~"))
297 hr
= parse_clr_tables(assembly
, ofs
);
301 else if (!lstrcmpA(stream
, "#Strings"))
302 assembly
->strings
= (BYTE
*)assembly_data_offset(assembly
, ofs
);
303 else if (!lstrcmpA(stream
, "#Blob"))
304 assembly
->blobs
= (BYTE
*)assembly_data_offset(assembly
, ofs
);
306 ptr
+= lstrlenA(stream
);
313 static HRESULT
parse_pe_header(ASSEMBLY
*assembly
)
315 IMAGE_DATA_DIRECTORY
*datadirs
;
317 assembly
->nthdr
= ImageNtHeader(assembly
->data
);
318 if (!assembly
->nthdr
)
321 datadirs
= assembly
->nthdr
->OptionalHeader
.DataDirectory
;
325 if (!datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
||
326 !datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].Size
)
331 assembly
->corhdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
332 datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
, NULL
);
333 if (!assembly
->corhdr
)
339 HRESULT
assembly_create(ASSEMBLY
**out
, LPCWSTR file
)
346 assembly
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ASSEMBLY
));
348 return E_OUTOFMEMORY
;
350 assembly
->path
= strdupWtoA(file
);
357 assembly
->hfile
= CreateFileW(file
, GENERIC_READ
, FILE_SHARE_READ
,
358 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
359 if (assembly
->hfile
== INVALID_HANDLE_VALUE
)
361 hr
= HRESULT_FROM_WIN32(GetLastError());
365 assembly
->hmap
= CreateFileMappingW(assembly
->hfile
, NULL
, PAGE_READONLY
,
369 hr
= HRESULT_FROM_WIN32(GetLastError());
373 assembly
->data
= MapViewOfFile(assembly
->hmap
, FILE_MAP_READ
, 0, 0, 0);
376 hr
= HRESULT_FROM_WIN32(GetLastError());
380 hr
= parse_pe_header(assembly
);
381 if (FAILED(hr
)) goto failed
;
383 hr
= parse_clr_metadata(assembly
);
384 if (FAILED(hr
)) goto failed
;
390 assembly_release( assembly
);
394 HRESULT
assembly_release(ASSEMBLY
*assembly
)
399 HeapFree(GetProcessHeap(), 0, assembly
->path
);
400 UnmapViewOfFile(assembly
->data
);
401 CloseHandle(assembly
->hmap
);
402 CloseHandle(assembly
->hfile
);
403 HeapFree(GetProcessHeap(), 0, assembly
);
408 static LPSTR
assembly_dup_str(ASSEMBLY
*assembly
, WORD index
)
410 return strdup((LPSTR
)&assembly
->strings
[index
]);
413 HRESULT
assembly_get_name(ASSEMBLY
*assembly
, LPSTR
*name
)
415 ASSEMBLYTABLE
*asmtbl
;
418 offset
= assembly
->tables
[0x20].offset
; /* FIXME: add constants */
422 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
426 *name
= assembly_dup_str(assembly
, asmtbl
->Name
);
428 return E_OUTOFMEMORY
;
433 HRESULT
assembly_get_path(ASSEMBLY
*assembly
, LPSTR
*path
)
435 *path
= strdup(assembly
->path
);
437 return E_OUTOFMEMORY
;
442 HRESULT
assembly_get_version(ASSEMBLY
*assembly
, LPSTR
*version
)
445 VS_FIXEDFILEINFO
*ffi
;
449 size
= GetFileVersionInfoSizeA(assembly
->path
, NULL
);
451 return HRESULT_FROM_WIN32(GetLastError());
453 verdata
= HeapAlloc(GetProcessHeap(), 0, size
);
455 return E_OUTOFMEMORY
;
457 if (!GetFileVersionInfoA(assembly
->path
, 0, size
, verdata
))
459 hr
= HRESULT_FROM_WIN32(GetLastError());
463 if (!VerQueryValueA(verdata
, "\\", (LPVOID
*)&ffi
, &size
))
465 hr
= HRESULT_FROM_WIN32(GetLastError());
469 *version
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
);
476 sprintf(*version
, "%d.%d.%d.%d", HIWORD(ffi
->dwFileVersionMS
),
477 LOWORD(ffi
->dwFileVersionMS
), HIWORD(ffi
->dwFileVersionLS
),
478 LOWORD(ffi
->dwFileVersionLS
));
481 HeapFree(GetProcessHeap(), 0, verdata
);
485 HRESULT
assembly_get_architecture(ASSEMBLY
*assembly
, DWORD fixme
)
491 static BYTE
*assembly_get_blob(ASSEMBLY
*assembly
, WORD index
, ULONG
*size
)
493 return GetData(&assembly
->blobs
[index
], size
);
496 static void bytes_to_str(BYTE
*bytes
, DWORD len
, LPSTR str
)
500 static const char hexval
[16] = {
501 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
504 for(i
= 0; i
< len
; i
++)
506 str
[i
* 2] = hexval
[((bytes
[i
] >> 4) & 0xF)];
507 str
[i
* 2 + 1] = hexval
[(bytes
[i
]) & 0x0F];
511 #define BYTES_PER_TOKEN 8
512 #define CHARS_PER_BYTE 2
513 #define TOKEN_LENGTH (BYTES_PER_TOKEN * CHARS_PER_BYTE + 1)
515 HRESULT
assembly_get_pubkey_token(ASSEMBLY
*assembly
, LPSTR
*token
)
517 ASSEMBLYTABLE
*asmtbl
;
518 ULONG i
, offset
, size
;
523 BYTE tokbytes
[BYTES_PER_TOKEN
];
529 offset
= assembly
->tables
[0x20].offset
; /* FIXME: add constants */
533 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
537 pubkey
= assembly_get_blob(assembly
, asmtbl
->PublicKey
, &size
);
539 if (!CryptAcquireContextA(&crypt
, NULL
, NULL
, PROV_RSA_FULL
,
540 CRYPT_VERIFYCONTEXT
))
543 if (!CryptCreateHash(crypt
, CALG_SHA1
, 0, 0, &hash
))
546 if (!CryptHashData(hash
, pubkey
, size
, 0))
550 if (!CryptGetHashParam(hash
, HP_HASHVAL
, NULL
, &size
, 0))
553 hashdata
= HeapAlloc(GetProcessHeap(), 0, size
);
560 if (!CryptGetHashParam(hash
, HP_HASHVAL
, hashdata
, &size
, 0))
563 for (i
= size
- 1; i
>= size
- 8; i
--)
564 tokbytes
[size
- i
- 1] = hashdata
[i
];
566 tok
= HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH
);
573 bytes_to_str(tokbytes
, BYTES_PER_TOKEN
, tok
);
574 tok
[TOKEN_LENGTH
- 1] = '\0';
580 HeapFree(GetProcessHeap(), 0, hashdata
);
581 CryptDestroyHash(hash
);
582 CryptReleaseContext(crypt
, 0);