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 LPSTR str
= (LPSTR
)&assembly
->strings
[index
];
410 LPSTR cpy
= HeapAlloc(GetProcessHeap(), 0, strlen(str
)+1);
416 HRESULT
assembly_get_name(ASSEMBLY
*assembly
, LPSTR
*name
)
418 ASSEMBLYTABLE
*asmtbl
;
421 offset
= assembly
->tables
[0x20].offset
; /* FIXME: add constants */
425 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
429 *name
= assembly_dup_str(assembly
, asmtbl
->Name
);
431 return E_OUTOFMEMORY
;
436 HRESULT
assembly_get_path(ASSEMBLY
*assembly
, LPSTR
*path
)
438 LPSTR cpy
= HeapAlloc(GetProcessHeap(), 0, strlen(assembly
->path
)+1);
441 strcpy(cpy
, assembly
->path
);
443 return E_OUTOFMEMORY
;
448 HRESULT
assembly_get_version(ASSEMBLY
*assembly
, LPSTR
*version
)
451 VS_FIXEDFILEINFO
*ffi
;
455 size
= GetFileVersionInfoSizeA(assembly
->path
, NULL
);
457 return HRESULT_FROM_WIN32(GetLastError());
459 verdata
= HeapAlloc(GetProcessHeap(), 0, size
);
461 return E_OUTOFMEMORY
;
463 if (!GetFileVersionInfoA(assembly
->path
, 0, size
, verdata
))
465 hr
= HRESULT_FROM_WIN32(GetLastError());
469 if (!VerQueryValueA(verdata
, "\\", (LPVOID
*)&ffi
, &size
))
471 hr
= HRESULT_FROM_WIN32(GetLastError());
475 *version
= HeapAlloc(GetProcessHeap(), 0, MAX_PATH
);
482 sprintf(*version
, "%d.%d.%d.%d", HIWORD(ffi
->dwFileVersionMS
),
483 LOWORD(ffi
->dwFileVersionMS
), HIWORD(ffi
->dwFileVersionLS
),
484 LOWORD(ffi
->dwFileVersionLS
));
487 HeapFree(GetProcessHeap(), 0, verdata
);
491 HRESULT
assembly_get_architecture(ASSEMBLY
*assembly
, DWORD fixme
)
497 static BYTE
*assembly_get_blob(ASSEMBLY
*assembly
, WORD index
, ULONG
*size
)
499 return GetData(&assembly
->blobs
[index
], size
);
502 static void bytes_to_str(BYTE
*bytes
, DWORD len
, LPSTR str
)
506 static const char hexval
[16] = {
507 '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
510 for(i
= 0; i
< len
; i
++)
512 str
[i
* 2] = hexval
[((bytes
[i
] >> 4) & 0xF)];
513 str
[i
* 2 + 1] = hexval
[(bytes
[i
]) & 0x0F];
517 #define BYTES_PER_TOKEN 8
518 #define CHARS_PER_BYTE 2
519 #define TOKEN_LENGTH (BYTES_PER_TOKEN * CHARS_PER_BYTE + 1)
521 HRESULT
assembly_get_pubkey_token(ASSEMBLY
*assembly
, LPSTR
*token
)
523 ASSEMBLYTABLE
*asmtbl
;
524 ULONG i
, offset
, size
;
529 BYTE tokbytes
[BYTES_PER_TOKEN
];
535 offset
= assembly
->tables
[0x20].offset
; /* FIXME: add constants */
539 asmtbl
= (ASSEMBLYTABLE
*)assembly_data_offset(assembly
, offset
);
543 pubkey
= assembly_get_blob(assembly
, asmtbl
->PublicKey
, &size
);
545 if (!CryptAcquireContextA(&crypt
, NULL
, NULL
, PROV_RSA_FULL
,
546 CRYPT_VERIFYCONTEXT
))
549 if (!CryptCreateHash(crypt
, CALG_SHA1
, 0, 0, &hash
))
552 if (!CryptHashData(hash
, pubkey
, size
, 0))
556 if (!CryptGetHashParam(hash
, HP_HASHVAL
, NULL
, &size
, 0))
559 hashdata
= HeapAlloc(GetProcessHeap(), 0, size
);
566 if (!CryptGetHashParam(hash
, HP_HASHVAL
, hashdata
, &size
, 0))
569 for (i
= size
- 1; i
>= size
- 8; i
--)
570 tokbytes
[size
- i
- 1] = hashdata
[i
];
572 tok
= HeapAlloc(GetProcessHeap(), 0, TOKEN_LENGTH
);
579 bytes_to_str(tokbytes
, BYTES_PER_TOKEN
, tok
);
580 tok
[TOKEN_LENGTH
- 1] = '\0';
586 HeapFree(GetProcessHeap(), 0, hashdata
);
587 CryptDestroyHash(hash
);
588 CryptReleaseContext(crypt
, 0);