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
];
67 const DWORD COR_TABLE_SIZES
[64] =
75 sizeof(METHODDEFTABLE
),
78 sizeof(INTERFACEIMPLTABLE
),
79 sizeof(MEMBERREFTABLE
),
80 sizeof(CONSTANTTABLE
),
81 sizeof(CUSTOMATTRIBUTETABLE
),
82 sizeof(FIELDMARSHALTABLE
),
83 sizeof(DECLSECURITYTABLE
),
84 sizeof(CLASSLAYOUTTABLE
),
85 sizeof(FIELDLAYOUTTABLE
),
86 sizeof(STANDALONESIGTABLE
),
87 sizeof(EVENTMAPTABLE
),
90 sizeof(PROPERTYMAPTABLE
),
92 sizeof(PROPERTYTABLE
),
93 sizeof(METHODSEMANTICSTABLE
),
94 sizeof(METHODIMPLTABLE
),
95 sizeof(MODULEREFTABLE
),
96 sizeof(TYPESPECTABLE
),
98 sizeof(FIELDRVATABLE
),
101 sizeof(ASSEMBLYTABLE
),
102 sizeof(ASSEMBLYPROCESSORTABLE
),
103 sizeof(ASSEMBLYOSTABLE
),
104 sizeof(ASSEMBLYREFTABLE
),
105 sizeof(ASSEMBLYREFPROCESSORTABLE
),
106 sizeof(ASSEMBLYREFOSTABLE
),
108 sizeof(EXPORTEDTYPETABLE
),
109 sizeof(MANIFESTRESTABLE
),
110 sizeof(NESTEDCLASSTABLE
),
111 sizeof(GENERICPARAMTABLE
),
112 sizeof(METHODSPECTABLE
),
113 sizeof(GENERICPARAMCONSTRAINTTABLE
),
135 static LPSTR
strdupWtoA(LPCWSTR str
)
143 len
= WideCharToMultiByte(CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
144 ret
= HeapAlloc(GetProcessHeap(), 0, len
);
146 WideCharToMultiByte(CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
151 static DWORD
rva_to_offset(IMAGE_NT_HEADERS
*nthdrs
, DWORD rva
)
153 DWORD offset
= rva
, limit
;
154 IMAGE_SECTION_HEADER
*img
;
157 img
= IMAGE_FIRST_SECTION(nthdrs
);
159 if (rva
< img
->PointerToRawData
)
162 for (i
= 0; i
< nthdrs
->FileHeader
.NumberOfSections
; i
++)
164 if (img
[i
].SizeOfRawData
)
165 limit
= img
[i
].SizeOfRawData
;
167 limit
= img
[i
].Misc
.VirtualSize
;
169 if (rva
>= img
[i
].VirtualAddress
&&
170 rva
< (img
[i
].VirtualAddress
+ limit
))
172 if (img
[i
].PointerToRawData
!= 0)
174 offset
-= img
[i
].VirtualAddress
;
175 offset
+= img
[i
].PointerToRawData
;
185 static BYTE
*GetData(BYTE
*pData
, ULONG
*pLength
)
187 if ((*pData
& 0x80) == 0x00)
189 *pLength
= (*pData
& 0x7f);
193 if ((*pData
& 0xC0) == 0x80)
195 *pLength
= ((*pData
& 0x3f) << 8 | *(pData
+ 1));
199 if ((*pData
& 0xE0) == 0xC0)
201 *pLength
= ((*pData
& 0x1f) << 24 | *(pData
+ 1) << 16 |
202 *(pData
+ 2) << 8 | *(pData
+ 3));
206 *pLength
= (ULONG
)-1;
210 static VOID
*assembly_data_offset(ASSEMBLY
*assembly
, ULONG offset
)
212 return (VOID
*)&assembly
->data
[offset
];
215 static HRESULT
parse_clr_tables(ASSEMBLY
*assembly
, ULONG offset
)
217 DWORD i
, previ
, offidx
;
221 assembly
->tableshdr
= (METADATATABLESHDR
*)assembly_data_offset(assembly
, currofs
);
222 if (!assembly
->tableshdr
)
225 currofs
+= sizeof(METADATATABLESHDR
);
226 assembly
->numrows
= (DWORD
*)assembly_data_offset(assembly
, currofs
);
227 if (!assembly
->numrows
)
230 assembly
->numtables
= 0;
231 for (i
= 0; i
< MAX_CLR_TABLES
; i
++)
233 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.u
.LowPart
>> i
) & 1) ||
234 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.u
.HighPart
>> i
) & 1))
236 assembly
->numtables
++;
240 currofs
+= assembly
->numtables
* sizeof(DWORD
);
241 memset(assembly
->tables
, -1, MAX_CLR_TABLES
* sizeof(CLRTABLE
));
243 if (assembly
->tableshdr
->MaskValid
.u
.LowPart
& 1)
245 assembly
->tables
[0].offset
= currofs
;
246 assembly
->tables
[0].rows
= assembly
->numrows
[0];
251 for (i
= 1; i
< MAX_CLR_TABLES
; i
++)
253 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.u
.LowPart
>> i
) & 1) ||
254 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.u
.HighPart
>> i
) & 1))
256 currofs
+= COR_TABLE_SIZES
[previ
] * assembly
->numrows
[offidx
- 1];
257 assembly
->tables
[i
].offset
= currofs
;
258 assembly
->tables
[i
].rows
= assembly
->numrows
[offidx
];
267 static HRESULT
parse_clr_metadata(ASSEMBLY
*assembly
)
269 METADATASTREAMHDR
*streamhdr
;
275 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
276 assembly
->metadatahdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
278 if (!assembly
->metadatahdr
)
281 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
282 rva
+ sizeof(METADATAHDR
), NULL
);
286 for (i
= 0; i
< assembly
->metadatahdr
->Streams
; i
++)
288 streamhdr
= (METADATASTREAMHDR
*)ptr
;
289 ofs
= rva_to_offset(assembly
->nthdr
, rva
+ streamhdr
->Offset
);
291 ptr
+= sizeof(METADATASTREAMHDR
);
294 if (!lstrcmpA(stream
, "#~"))
296 hr
= parse_clr_tables(assembly
, ofs
);
300 else if (!lstrcmpA(stream
, "#Strings") || !lstrcmpA(stream
, "Strings"))
301 assembly
->strings
= (BYTE
*)assembly_data_offset(assembly
, ofs
);
302 else if (!lstrcmpA(stream
, "#Blob"))
303 assembly
->blobs
= (BYTE
*)assembly_data_offset(assembly
, ofs
);
305 ptr
+= lstrlenA(stream
);
312 static HRESULT
parse_pe_header(ASSEMBLY
*assembly
)
314 IMAGE_DATA_DIRECTORY
*datadirs
;
316 assembly
->nthdr
= ImageNtHeader(assembly
->data
);
317 if (!assembly
->nthdr
)
320 datadirs
= assembly
->nthdr
->OptionalHeader
.DataDirectory
;
324 if (!datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
||
325 !datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].Size
)
330 assembly
->corhdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
331 datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
, NULL
);
332 if (!assembly
->corhdr
)
338 HRESULT
assembly_create(ASSEMBLY
**out
, LPCWSTR file
)
345 assembly
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ASSEMBLY
));
347 return E_OUTOFMEMORY
;
349 assembly
->path
= strdupWtoA(file
);
356 assembly
->hfile
= CreateFileW(file
, GENERIC_READ
, FILE_SHARE_READ
,
357 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
358 if (assembly
->hfile
== INVALID_HANDLE_VALUE
)
360 hr
= HRESULT_FROM_WIN32(GetLastError());
364 assembly
->hmap
= CreateFileMappingW(assembly
->hfile
, NULL
, PAGE_READONLY
,
368 hr
= HRESULT_FROM_WIN32(GetLastError());
372 assembly
->data
= MapViewOfFile(assembly
->hmap
, FILE_MAP_READ
, 0, 0, 0);
375 hr
= HRESULT_FROM_WIN32(GetLastError());
379 hr
= parse_pe_header(assembly
);
380 if (FAILED(hr
)) goto failed
;
382 hr
= parse_clr_metadata(assembly
);
383 if (FAILED(hr
)) goto failed
;
389 assembly_release( assembly
);
393 HRESULT
assembly_release(ASSEMBLY
*assembly
)
398 HeapFree(GetProcessHeap(), 0, assembly
->path
);
399 UnmapViewOfFile(assembly
->data
);
400 CloseHandle(assembly
->hmap
);
401 CloseHandle(assembly
->hfile
);
402 HeapFree(GetProcessHeap(), 0, assembly
);
407 static LPSTR
assembly_dup_str(ASSEMBLY
*assembly
, WORD index
)
409 return strdup((LPSTR
)&assembly
->strings
[index
]);
412 HRESULT
assembly_get_name(ASSEMBLY
*assembly
, LPSTR
*name
)
414 ASSEMBLYTABLE
*asmtbl
;
417 offset
= assembly
->tables
[0x20].offset
; /* FIXME: add constants */
421 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
425 *name
= assembly_dup_str(assembly
, asmtbl
->Name
);
427 return E_OUTOFMEMORY
;
432 HRESULT
assembly_get_path(ASSEMBLY
*assembly
, LPSTR
*path
)
434 *path
= strdup(assembly
->path
);
436 return E_OUTOFMEMORY
;
441 HRESULT
assembly_get_version(ASSEMBLY
*assembly
, LPSTR
*version
)
444 VS_FIXEDFILEINFO
*ffi
;
448 size
= GetFileVersionInfoSizeA(assembly
->path
, NULL
);
450 return HRESULT_FROM_WIN32(GetLastError());
452 verdata
= HeapAlloc(GetProcessHeap(), 0, size
);
454 return E_OUTOFMEMORY
;
456 if (!GetFileVersionInfoA(assembly
->path
, 0, size
, verdata
))
458 hr
= HRESULT_FROM_WIN32(GetLastError());
462 if (!VerQueryValueA(verdata
, "\\", (LPVOID
*)&ffi
, &size
))
464 hr
= HRESULT_FROM_WIN32(GetLastError());
468 *version
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
);
475 sprintf(*version
, "%d.%d.%d.%d", HIWORD(ffi
->dwFileVersionMS
),
476 LOWORD(ffi
->dwFileVersionMS
), HIWORD(ffi
->dwFileVersionLS
),
477 LOWORD(ffi
->dwFileVersionLS
));
480 HeapFree(GetProcessHeap(), 0, verdata
);
484 HRESULT
assembly_get_architecture(ASSEMBLY
*assembly
, DWORD fixme
)
490 static BYTE
*assembly_get_blob(ASSEMBLY
*assembly
, WORD index
, ULONG
*size
)
492 return GetData(&assembly
->blobs
[index
], size
);
495 static void bytes_to_str(BYTE
*bytes
, DWORD len
, LPSTR str
)
499 static const char hexval
[16] = {
500 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
503 for(i
= 0; i
< len
; i
++)
505 str
[i
* 2] = hexval
[((bytes
[i
] >> 4) & 0xF)];
506 str
[i
* 2 + 1] = hexval
[(bytes
[i
]) & 0x0F];
510 #define BYTES_PER_TOKEN 8
511 #define CHARS_PER_BYTE 2
512 #define TOKEN_LENGTH (BYTES_PER_TOKEN * CHARS_PER_BYTE + 1)
514 HRESULT
assembly_get_pubkey_token(ASSEMBLY
*assembly
, LPSTR
*token
)
516 ASSEMBLYTABLE
*asmtbl
;
517 ULONG i
, offset
, size
;
522 BYTE tokbytes
[BYTES_PER_TOKEN
];
528 offset
= assembly
->tables
[0x20].offset
; /* FIXME: add constants */
532 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
536 pubkey
= assembly_get_blob(assembly
, asmtbl
->PublicKey
, &size
);
538 if (!CryptAcquireContextA(&crypt
, NULL
, NULL
, PROV_RSA_FULL
,
539 CRYPT_VERIFYCONTEXT
))
542 if (!CryptCreateHash(crypt
, CALG_SHA1
, 0, 0, &hash
))
545 if (!CryptHashData(hash
, pubkey
, size
, 0))
549 if (!CryptGetHashParam(hash
, HP_HASHVAL
, NULL
, &size
, 0))
552 hashdata
= HeapAlloc(GetProcessHeap(), 0, size
);
559 if (!CryptGetHashParam(hash
, HP_HASHVAL
, hashdata
, &size
, 0))
562 for (i
= size
- 1; i
>= size
- 8; i
--)
563 tokbytes
[size
- i
- 1] = hashdata
[i
];
565 tok
= HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH
);
572 bytes_to_str(tokbytes
, BYTES_PER_TOKEN
, tok
);
573 tok
[TOKEN_LENGTH
- 1] = '\0';
579 HeapFree(GetProcessHeap(), 0, hashdata
);
580 CryptDestroyHash(hash
);
581 CryptReleaseContext(crypt
, 0);