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
34 #include "fusionpriv.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
38 #define TableFromToken(tk) (TypeFromToken(tk) >> 24)
39 #define TokenFromTable(idx) (idx << 24)
41 #define MAX_CLR_TABLES 64
43 #define MD_STRINGS_BIT 0x1
44 #define MD_GUIDS_BIT 0x2
45 #define MD_BLOBS_BIT 0x4
47 typedef struct tagCLRTABLE
61 IMAGE_NT_HEADERS
*nthdr
;
62 IMAGE_COR20_HEADER
*corhdr
;
64 METADATAHDR
*metadatahdr
;
66 METADATATABLESHDR
*tableshdr
;
69 CLRTABLE tables
[MAX_CLR_TABLES
];
79 static DWORD
rva_to_offset(IMAGE_NT_HEADERS
*nthdrs
, DWORD rva
)
81 DWORD offset
= rva
, limit
;
82 IMAGE_SECTION_HEADER
*img
;
85 img
= IMAGE_FIRST_SECTION(nthdrs
);
87 if (rva
< img
->PointerToRawData
)
90 for (i
= 0; i
< nthdrs
->FileHeader
.NumberOfSections
; i
++)
92 if (img
[i
].SizeOfRawData
)
93 limit
= img
[i
].SizeOfRawData
;
95 limit
= img
[i
].Misc
.VirtualSize
;
97 if (rva
>= img
[i
].VirtualAddress
&&
98 rva
< (img
[i
].VirtualAddress
+ limit
))
100 if (img
[i
].PointerToRawData
!= 0)
102 offset
-= img
[i
].VirtualAddress
;
103 offset
+= img
[i
].PointerToRawData
;
113 static BYTE
*GetData(BYTE
*pData
, ULONG
*pLength
)
115 if ((*pData
& 0x80) == 0x00)
117 *pLength
= (*pData
& 0x7f);
121 if ((*pData
& 0xC0) == 0x80)
123 *pLength
= ((*pData
& 0x3f) << 8 | *(pData
+ 1));
127 if ((*pData
& 0xE0) == 0xC0)
129 *pLength
= ((*pData
& 0x1f) << 24 | *(pData
+ 1) << 16 |
130 *(pData
+ 2) << 8 | *(pData
+ 3));
134 *pLength
= (ULONG
)-1;
138 static VOID
*assembly_data_offset(ASSEMBLY
*assembly
, ULONG offset
)
140 return &assembly
->data
[offset
];
143 #define MAX_TABLES_WORD 0xFFFF
144 #define MAX_TABLES_1BIT_ENCODE 32767
145 #define MAX_TABLES_2BIT_ENCODE 16383
146 #define MAX_TABLES_3BIT_ENCODE 8191
147 #define MAX_TABLES_5BIT_ENCODE 2047
149 static inline ULONG
get_table_size(const ASSEMBLY
*assembly
, DWORD index
)
154 switch (TokenFromTable(index
))
158 size
= sizeof(MODULETABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
159 2 * (assembly
->guidsz
- sizeof(WORD
));
164 size
= sizeof(TYPEREFTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
));
166 /* ResolutionScope:ResolutionScope */
167 tables
= max(assembly
->tables
[TableFromToken(mdtModule
)].rows
,
168 assembly
->tables
[TableFromToken(mdtModuleRef
)].rows
);
169 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
);
170 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeRef
)].rows
);
171 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
176 size
= sizeof(TYPEDEFTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
));
178 /* Extends:TypeDefOrRef */
179 tables
= max(assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
,
180 assembly
->tables
[TableFromToken(mdtTypeRef
)].rows
);
181 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeSpec
)].rows
);
182 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
184 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
185 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
186 size
+= (assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
>
187 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
192 size
= sizeof(FIELDTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
193 (assembly
->blobsz
- sizeof(WORD
));
198 size
= sizeof(METHODDEFTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
199 (assembly
->blobsz
- sizeof(WORD
));
201 size
+= (assembly
->tables
[TableFromToken(mdtParamDef
)].rows
>
202 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
207 size
= sizeof(PARAMTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
210 case mdtInterfaceImpl
:
212 size
= sizeof(INTERFACEIMPLTABLE
);
214 /* Interface:TypeDefOrRef */
215 tables
= max(assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
,
216 assembly
->tables
[TableFromToken(mdtTypeRef
)].rows
);
217 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeSpec
)].rows
);
218 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
223 size
= sizeof(MEMBERREFTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
224 (assembly
->blobsz
- sizeof(WORD
));
226 /* Class:MemberRefParent */
227 tables
= max(assembly
->tables
[TableFromToken(mdtTypeRef
)].rows
,
228 assembly
->tables
[TableFromToken(mdtModuleRef
)].rows
);
229 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
);
230 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeSpec
)].rows
);
231 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
);
232 size
+= (tables
> MAX_TABLES_3BIT_ENCODE
) ? sizeof(WORD
) : 0;
235 case 0x0B000000: /* FIXME */
237 size
= sizeof(CONSTANTTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
239 /* Parent:HasConstant */
240 tables
= max(assembly
->tables
[TableFromToken(mdtParamDef
)].rows
,
241 assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
);
242 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtProperty
)].rows
);
243 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
246 case mdtCustomAttribute
:
248 size
= sizeof(CUSTOMATTRIBUTETABLE
) + (assembly
->blobsz
- sizeof(WORD
));
250 /* Parent:HasCustomAttribute */
251 tables
= max(assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
,
252 assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
);
253 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeRef
)].rows
);
254 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
);
255 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtParamDef
)].rows
);
256 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtInterfaceImpl
)].rows
);
257 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtMemberRef
)].rows
);
258 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtPermission
)].rows
);
259 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtProperty
)].rows
);
260 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtEvent
)].rows
);
261 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtSignature
)].rows
);
262 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtModuleRef
)].rows
);
263 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeSpec
)].rows
);
264 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtAssembly
)].rows
);
265 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtFile
)].rows
);
266 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtExportedType
)].rows
);
267 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtManifestResource
)].rows
);
268 size
+= (tables
> MAX_TABLES_5BIT_ENCODE
) ? sizeof(WORD
) : 0;
270 /* Type:CustomAttributeType */
271 tables
= max(assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
,
272 assembly
->tables
[TableFromToken(mdtMemberRef
)].rows
);
273 size
+= (tables
> MAX_TABLES_3BIT_ENCODE
) ? sizeof(WORD
) : 0;
276 case 0x0D000000: /* FIXME */
278 size
= sizeof(FIELDMARSHALTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
280 /* Parent:HasFieldMarshal */
281 tables
= max(assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
,
282 assembly
->tables
[TableFromToken(mdtParamDef
)].rows
);
283 size
+= (tables
> MAX_TABLES_1BIT_ENCODE
) ? sizeof(WORD
) : 0;
288 size
= sizeof(DECLSECURITYTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
290 /* Parent:HasDeclSecurity */
291 tables
= max(assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
,
292 assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
);
293 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtAssembly
)].rows
);
294 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
297 case 0x0F000000: /* FIXME */
299 size
= sizeof(CLASSLAYOUTTABLE
);
300 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
301 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
304 case 0x10000000: /* FIXME */
306 size
= sizeof(FIELDLAYOUTTABLE
);
307 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
308 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
313 size
= sizeof(STANDALONESIGTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
316 case 0x12000000: /* FIXME */
318 size
= sizeof(EVENTMAPTABLE
);
319 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
320 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
321 size
+= (assembly
->tables
[TableFromToken(mdtEvent
)].rows
>
322 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
327 size
= sizeof(EVENTTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
329 /* EventType:TypeDefOrRef */
330 tables
= max(assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
,
331 assembly
->tables
[TableFromToken(mdtTypeRef
)].rows
);
332 tables
= max(tables
, assembly
->tables
[TableFromToken(mdtTypeSpec
)].rows
);
333 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
336 case 0x15000000:/* FIXME */
338 size
= sizeof(PROPERTYMAPTABLE
);
339 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
340 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
341 size
+= (assembly
->tables
[TableFromToken(mdtProperty
)].rows
>
342 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
347 size
= sizeof(PROPERTYTABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
348 (assembly
->blobsz
- sizeof(WORD
));
351 case 0x18000000: /* FIXME */
353 size
= sizeof(METHODSEMANTICSTABLE
);
355 /* Association:HasSemantics */
356 tables
= max(assembly
->tables
[TableFromToken(mdtEvent
)].rows
,
357 assembly
->tables
[TableFromToken(mdtProperty
)].rows
);
358 size
+= (tables
> MAX_TABLES_1BIT_ENCODE
) ? sizeof(WORD
) : 0;
360 size
+= (assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
>
361 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
364 case 0x19000000: /* FIXME */
366 size
= sizeof(METHODIMPLTABLE
);
368 /* MethodBody:MethodDefOrRef, MethodDeclaration:MethodDefOrRef */
369 tables
= max(assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
,
370 assembly
->tables
[TableFromToken(mdtMemberRef
)].rows
);
371 size
+= (tables
> MAX_TABLES_1BIT_ENCODE
) ? 2 * sizeof(WORD
) : 0;
373 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
374 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
379 size
= sizeof(MODULEREFTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
384 size
= sizeof(TYPESPECTABLE
) + (assembly
->blobsz
- sizeof(WORD
));
387 case 0x1C000000: /* FIXME */
389 size
= sizeof(IMPLMAPTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
391 /* MemberForwarded:MemberForwarded */
392 tables
= max(assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
,
393 assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
);
394 size
+= (tables
> MAX_TABLES_1BIT_ENCODE
) ? sizeof(WORD
) : 0;
396 size
+= (assembly
->tables
[TableFromToken(mdtModuleRef
)].rows
>
397 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
400 case 0x1D000000: /* FIXME */
402 size
= sizeof(FIELDRVATABLE
);
403 size
+= (assembly
->tables
[TableFromToken(mdtFieldDef
)].rows
>
404 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
409 size
= sizeof(ASSEMBLYTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
)) +
410 (assembly
->blobsz
- sizeof(WORD
));
413 case 0x20000001: /* FIXME */
415 size
= sizeof(ASSEMBLYPROCESSORTABLE
);
418 case 0x22000000: /* FIXME */
420 size
= sizeof(ASSEMBLYOSTABLE
);
425 size
= sizeof(ASSEMBLYREFTABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
)) +
426 2 * (assembly
->blobsz
- sizeof(WORD
));
429 case 0x24000000: /* FIXME */
431 size
= sizeof(ASSEMBLYREFPROCESSORTABLE
);
432 size
+= (assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
>
433 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
436 case 0x25000000: /* FIXME */
438 size
= sizeof(ASSEMBLYREFOSTABLE
);
439 size
+= (assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
>
440 MAX_TABLES_WORD
) ? sizeof(WORD
) : 0;
445 size
= sizeof(FILETABLE
) + (assembly
->stringsz
- sizeof(WORD
)) +
446 (assembly
->blobsz
- sizeof(WORD
));
449 case mdtExportedType
:
451 size
= sizeof(EXPORTEDTYPETABLE
) + 2 * (assembly
->stringsz
- sizeof(WORD
));
453 /* Implementation:Implementation */
454 tables
= max(assembly
->tables
[TableFromToken(mdtFile
)].rows
,
455 assembly
->tables
[TableFromToken(mdtMethodDef
)].rows
);
456 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
459 case mdtManifestResource
:
461 size
= sizeof(MANIFESTRESTABLE
) + (assembly
->stringsz
- sizeof(WORD
));
463 /* Implementation:Implementation */
464 tables
= max(assembly
->tables
[TableFromToken(mdtFile
)].rows
,
465 assembly
->tables
[TableFromToken(mdtAssemblyRef
)].rows
);
466 size
+= (tables
> MAX_TABLES_2BIT_ENCODE
) ? sizeof(WORD
) : 0;
469 case 0x29000000: /* FIXME */
471 size
= sizeof(NESTEDCLASSTABLE
);
472 size
+= (assembly
->tables
[TableFromToken(mdtTypeDef
)].rows
>
473 MAX_TABLES_WORD
) ? 2 * sizeof(WORD
) : 0;
483 static HRESULT
parse_clr_tables(ASSEMBLY
*assembly
, ULONG offset
)
485 DWORD i
, previ
, offidx
;
489 assembly
->tableshdr
= assembly_data_offset(assembly
, currofs
);
490 if (!assembly
->tableshdr
)
493 assembly
->stringsz
= (assembly
->tableshdr
->HeapOffsetSizes
& MD_STRINGS_BIT
) ?
494 sizeof(DWORD
) : sizeof(WORD
);
495 assembly
->guidsz
= (assembly
->tableshdr
->HeapOffsetSizes
& MD_GUIDS_BIT
) ?
496 sizeof(DWORD
) : sizeof(WORD
);
497 assembly
->blobsz
= (assembly
->tableshdr
->HeapOffsetSizes
& MD_BLOBS_BIT
) ?
498 sizeof(DWORD
) : sizeof(WORD
);
500 currofs
+= sizeof(METADATATABLESHDR
);
501 assembly
->numrows
= assembly_data_offset(assembly
, currofs
);
502 if (!assembly
->numrows
)
505 assembly
->numtables
= 0;
506 for (i
= 0; i
< MAX_CLR_TABLES
; i
++)
508 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.u
.LowPart
>> i
) & 1) ||
509 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.u
.HighPart
>> i
) & 1))
511 assembly
->numtables
++;
515 currofs
+= assembly
->numtables
* sizeof(DWORD
);
516 memset(assembly
->tables
, -1, MAX_CLR_TABLES
* sizeof(CLRTABLE
));
518 if (assembly
->tableshdr
->MaskValid
.u
.LowPart
& 1)
519 assembly
->tables
[0].offset
= currofs
;
522 for (i
= 0; i
< MAX_CLR_TABLES
; i
++)
524 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.u
.LowPart
>> i
) & 1) ||
525 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.u
.HighPart
>> i
) & 1))
527 assembly
->tables
[i
].rows
= assembly
->numrows
[offidx
];
534 for (i
= 1; i
< MAX_CLR_TABLES
; i
++)
536 if ((i
< 32 && (assembly
->tableshdr
->MaskValid
.u
.LowPart
>> i
) & 1) ||
537 (i
>= 32 && (assembly
->tableshdr
->MaskValid
.u
.HighPart
>> i
) & 1))
539 currofs
+= get_table_size(assembly
, previ
) * assembly
->numrows
[offidx
- 1];
540 assembly
->tables
[i
].offset
= currofs
;
549 static HRESULT
parse_metadata_header(ASSEMBLY
*assembly
, DWORD
*hdrsz
)
551 METADATAHDR
*metadatahdr
;
556 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
557 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
, rva
, NULL
);
561 metadatahdr
= (METADATAHDR
*)ptr
;
563 assembly
->metadatahdr
= HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR
));
564 if (!assembly
->metadatahdr
)
565 return E_OUTOFMEMORY
;
567 size
= FIELD_OFFSET(METADATAHDR
, Version
);
568 memcpy(assembly
->metadatahdr
, metadatahdr
, size
);
570 assembly
->metadatahdr
->Version
= (LPSTR
)&metadatahdr
->Version
;
572 ofs
= FIELD_OFFSET(METADATAHDR
, Flags
);
573 ptr
+= FIELD_OFFSET(METADATAHDR
, Version
) + metadatahdr
->VersionLength
+ 1;
574 dest
= (BYTE
*)assembly
->metadatahdr
+ ofs
;
575 memcpy(dest
, ptr
, sizeof(METADATAHDR
) - ofs
);
577 *hdrsz
= sizeof(METADATAHDR
) - sizeof(LPSTR
) + metadatahdr
->VersionLength
+ 1;
582 static HRESULT
parse_clr_metadata(ASSEMBLY
*assembly
)
584 METADATASTREAMHDR
*streamhdr
;
591 hr
= parse_metadata_header(assembly
, &hdrsz
);
595 rva
= assembly
->corhdr
->MetaData
.VirtualAddress
;
596 ptr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
, rva
+ hdrsz
, NULL
);
600 for (i
= 0; i
< assembly
->metadatahdr
->Streams
; i
++)
602 streamhdr
= (METADATASTREAMHDR
*)ptr
;
603 ofs
= rva_to_offset(assembly
->nthdr
, rva
+ streamhdr
->Offset
);
605 ptr
+= sizeof(METADATASTREAMHDR
);
608 if (!lstrcmpA(stream
, "#~"))
610 hr
= parse_clr_tables(assembly
, ofs
);
614 else if (!lstrcmpA(stream
, "#Strings") || !lstrcmpA(stream
, "Strings"))
615 assembly
->strings
= assembly_data_offset(assembly
, ofs
);
616 else if (!lstrcmpA(stream
, "#Blob") || !lstrcmpA(stream
, "Blob"))
617 assembly
->blobs
= assembly_data_offset(assembly
, ofs
);
619 ptr
+= lstrlenA(stream
) + 1;
620 ptr
= (BYTE
*)(((UINT_PTR
)ptr
+ 3) & ~3); /* align on DWORD boundary */
626 static HRESULT
parse_pe_header(ASSEMBLY
*assembly
)
628 IMAGE_DATA_DIRECTORY
*datadirs
;
630 assembly
->nthdr
= ImageNtHeader(assembly
->data
);
631 if (!assembly
->nthdr
)
634 if (assembly
->nthdr
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
636 IMAGE_OPTIONAL_HEADER64
*opthdr
=
637 (IMAGE_OPTIONAL_HEADER64
*)&assembly
->nthdr
->OptionalHeader
;
638 datadirs
= opthdr
->DataDirectory
;
642 IMAGE_OPTIONAL_HEADER32
*opthdr
=
643 (IMAGE_OPTIONAL_HEADER32
*)&assembly
->nthdr
->OptionalHeader
;
644 datadirs
= opthdr
->DataDirectory
;
650 if (!datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
||
651 !datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].Size
)
656 assembly
->corhdr
= ImageRvaToVa(assembly
->nthdr
, assembly
->data
,
657 datadirs
[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
].VirtualAddress
, NULL
);
658 if (!assembly
->corhdr
)
664 HRESULT
assembly_create(ASSEMBLY
**out
, LPCWSTR file
)
671 assembly
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ASSEMBLY
));
673 return E_OUTOFMEMORY
;
675 assembly
->path
= strdupW(file
);
682 assembly
->hfile
= CreateFileW(file
, GENERIC_READ
, FILE_SHARE_READ
,
683 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
684 if (assembly
->hfile
== INVALID_HANDLE_VALUE
)
686 hr
= HRESULT_FROM_WIN32(GetLastError());
690 assembly
->hmap
= CreateFileMappingW(assembly
->hfile
, NULL
, PAGE_READONLY
,
694 hr
= HRESULT_FROM_WIN32(GetLastError());
698 assembly
->data
= MapViewOfFile(assembly
->hmap
, FILE_MAP_READ
, 0, 0, 0);
701 hr
= HRESULT_FROM_WIN32(GetLastError());
705 hr
= parse_pe_header(assembly
);
706 if (FAILED(hr
)) goto failed
;
708 hr
= parse_clr_metadata(assembly
);
709 if (FAILED(hr
)) goto failed
;
715 assembly_release(assembly
);
719 HRESULT
assembly_release(ASSEMBLY
*assembly
)
724 HeapFree(GetProcessHeap(), 0, assembly
->metadatahdr
);
725 HeapFree(GetProcessHeap(), 0, assembly
->path
);
726 UnmapViewOfFile(assembly
->data
);
727 CloseHandle(assembly
->hmap
);
728 CloseHandle(assembly
->hfile
);
729 HeapFree(GetProcessHeap(), 0, assembly
);
734 static LPWSTR
assembly_dup_str(const ASSEMBLY
*assembly
, DWORD index
)
738 LPCSTR str
= (LPCSTR
)&assembly
->strings
[index
];
740 len
= MultiByteToWideChar(CP_ACP
, 0, str
, -1, NULL
, 0);
742 if ((cpy
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
))))
743 MultiByteToWideChar(CP_ACP
, 0, str
, -1, cpy
, len
);
748 HRESULT
assembly_get_name(ASSEMBLY
*assembly
, LPWSTR
*name
)
754 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
758 ptr
= assembly_data_offset(assembly
, offset
);
762 ptr
+= FIELD_OFFSET(ASSEMBLYTABLE
, PublicKey
) + assembly
->blobsz
;
763 if (assembly
->stringsz
== sizeof(DWORD
))
764 stridx
= *(DWORD
*)ptr
;
766 stridx
= *(WORD
*)ptr
;
768 *name
= assembly_dup_str(assembly
, stridx
);
770 return E_OUTOFMEMORY
;
775 HRESULT
assembly_get_path(const ASSEMBLY
*assembly
, LPWSTR
*path
)
777 LPWSTR cpy
= HeapAlloc(GetProcessHeap(), 0, (strlenW(assembly
->path
) + 1) * sizeof(WCHAR
));
780 strcpyW(cpy
, assembly
->path
);
782 return E_OUTOFMEMORY
;
787 HRESULT
assembly_get_version(ASSEMBLY
*assembly
, LPWSTR
*version
)
789 static const WCHAR format
[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
791 ASSEMBLYTABLE
*asmtbl
;
796 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
800 asmtbl
= assembly_data_offset(assembly
, offset
);
804 *version
= HeapAlloc(GetProcessHeap(), 0, sizeof(format
) + 4 * strlen("65535") * sizeof(WCHAR
));
806 return E_OUTOFMEMORY
;
808 sprintfW(*version
, format
, asmtbl
->MajorVersion
, asmtbl
->MinorVersion
,
809 asmtbl
->BuildNumber
, asmtbl
->RevisionNumber
);
814 PEKIND
assembly_get_architecture(ASSEMBLY
*assembly
)
816 if ((assembly
->corhdr
->MajorRuntimeVersion
== 2) && (assembly
->corhdr
->MinorRuntimeVersion
== 0))
817 return peNone
; /* .NET 1.x assembly */
819 if (assembly
->nthdr
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
820 return peAMD64
; /* AMD64/IA64 assembly */
822 if ((assembly
->corhdr
->Flags
& COMIMAGE_FLAGS_ILONLY
) && !(assembly
->corhdr
->Flags
& COMIMAGE_FLAGS_32BITREQUIRED
))
823 return peMSIL
; /* MSIL assembly */
825 return peI386
; /* x86 assembly */
828 static BYTE
*assembly_get_blob(ASSEMBLY
*assembly
, DWORD index
, ULONG
*size
)
830 return GetData(&assembly
->blobs
[index
], size
);
833 HRESULT
assembly_get_pubkey_token(ASSEMBLY
*assembly
, LPWSTR
*token
)
837 BYTE
*hashdata
, *pubkey
, *ptr
;
840 BYTE tokbytes
[BYTES_PER_TOKEN
];
847 offset
= assembly
->tables
[TableFromToken(mdtAssembly
)].offset
;
851 ptr
= assembly_data_offset(assembly
, offset
);
855 ptr
+= FIELD_OFFSET(ASSEMBLYTABLE
, PublicKey
);
856 if (assembly
->blobsz
== sizeof(DWORD
))
861 pubkey
= assembly_get_blob(assembly
, idx
, &size
);
863 if (!CryptAcquireContextA(&crypt
, NULL
, NULL
, PROV_RSA_FULL
,
864 CRYPT_VERIFYCONTEXT
))
867 if (!CryptCreateHash(crypt
, CALG_SHA1
, 0, 0, &hash
))
870 if (!CryptHashData(hash
, pubkey
, size
, 0))
874 if (!CryptGetHashParam(hash
, HP_HASHVAL
, NULL
, &size
, 0))
877 hashdata
= HeapAlloc(GetProcessHeap(), 0, size
);
884 if (!CryptGetHashParam(hash
, HP_HASHVAL
, hashdata
, &size
, 0))
887 for (i
= size
- 1; i
>= size
- 8; i
--)
888 tokbytes
[size
- i
- 1] = hashdata
[i
];
890 tok
= HeapAlloc(GetProcessHeap(), 0, (TOKEN_LENGTH
+ 1) * sizeof(WCHAR
));
897 token_to_str(tokbytes
, tok
);
903 HeapFree(GetProcessHeap(), 0, hashdata
);
904 CryptDestroyHash(hash
);
905 CryptReleaseContext(crypt
, 0);
910 HRESULT
assembly_get_runtime_version(ASSEMBLY
*assembly
, LPSTR
*version
)
912 *version
= assembly
->metadatahdr
->Version
;
916 HRESULT
assembly_get_external_files(ASSEMBLY
*assembly
, LPWSTR
**files
, DWORD
*count
)
926 offset
= assembly
->tables
[TableFromToken(mdtFile
)].offset
;
930 ptr
= assembly_data_offset(assembly
, offset
);
934 num_rows
= assembly
->tables
[TableFromToken(mdtFile
)].rows
;
938 ret
= HeapAlloc(GetProcessHeap(), 0, num_rows
* sizeof(WCHAR
*));
940 return E_OUTOFMEMORY
;
942 for (i
= 0; i
< num_rows
; i
++)
944 ptr
+= sizeof(DWORD
); /* skip Flags field */
945 if (assembly
->stringsz
== sizeof(DWORD
))
950 ret
[i
] = assembly_dup_str(assembly
, idx
);
953 for (; i
>= 0; i
--) HeapFree(GetProcessHeap(), 0, ret
[i
]);
954 HeapFree(GetProcessHeap(), 0, ret
);
955 return E_OUTOFMEMORY
;
957 ptr
+= assembly
->stringsz
; /* skip Name field */
958 ptr
+= assembly
->blobsz
; /* skip Hash field */