Synchronize with trunk r58457.
[reactos.git] / dll / win32 / fusion / assembly.c
1 /*
2 * assembly parser
3 *
4 * Copyright 2008 James Hawkins
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #define WIN32_NO_STATUS
22 #define _INC_WINDOWS
23 #define COM_NO_WINDOWS_H
24
25 #include <stdarg.h>
26 //#include <stdio.h>
27
28 #include <windef.h>
29 #include <winbase.h>
30 //#include "winuser.h"
31 #include <winver.h>
32 #include <wincrypt.h>
33 #include <dbghelp.h>
34 #include <ole2.h>
35 #include <fusion.h>
36 #include <corhdr.h>
37
38 #include "fusionpriv.h"
39 #include <wine/debug.h>
40 #include <wine/unicode.h>
41
42 #define TableFromToken(tk) (TypeFromToken(tk) >> 24)
43 #define TokenFromTable(idx) (idx << 24)
44
45 #define MAX_CLR_TABLES 64
46
47 #define MD_STRINGS_BIT 0x1
48 #define MD_GUIDS_BIT 0x2
49 #define MD_BLOBS_BIT 0x4
50
51 typedef struct tagCLRTABLE
52 {
53 INT rows;
54 DWORD offset;
55 } CLRTABLE;
56
57 struct tagASSEMBLY
58 {
59 LPWSTR path;
60
61 HANDLE hfile;
62 HANDLE hmap;
63 BYTE *data;
64
65 IMAGE_NT_HEADERS *nthdr;
66 IMAGE_COR20_HEADER *corhdr;
67
68 METADATAHDR *metadatahdr;
69
70 METADATATABLESHDR *tableshdr;
71 DWORD numtables;
72 DWORD *numrows;
73 CLRTABLE tables[MAX_CLR_TABLES];
74
75 DWORD stringsz;
76 DWORD guidsz;
77 DWORD blobsz;
78
79 BYTE *strings;
80 BYTE *blobs;
81 };
82
83 static DWORD rva_to_offset(IMAGE_NT_HEADERS *nthdrs, DWORD rva)
84 {
85 DWORD offset = rva, limit;
86 IMAGE_SECTION_HEADER *img;
87 WORD i;
88
89 img = IMAGE_FIRST_SECTION(nthdrs);
90
91 if (rva < img->PointerToRawData)
92 return rva;
93
94 for (i = 0; i < nthdrs->FileHeader.NumberOfSections; i++)
95 {
96 if (img[i].SizeOfRawData)
97 limit = img[i].SizeOfRawData;
98 else
99 limit = img[i].Misc.VirtualSize;
100
101 if (rva >= img[i].VirtualAddress &&
102 rva < (img[i].VirtualAddress + limit))
103 {
104 if (img[i].PointerToRawData != 0)
105 {
106 offset -= img[i].VirtualAddress;
107 offset += img[i].PointerToRawData;
108 }
109
110 return offset;
111 }
112 }
113
114 return 0;
115 }
116
117 static BYTE *GetData(BYTE *pData, ULONG *pLength)
118 {
119 if ((*pData & 0x80) == 0x00)
120 {
121 *pLength = (*pData & 0x7f);
122 return pData + 1;
123 }
124
125 if ((*pData & 0xC0) == 0x80)
126 {
127 *pLength = ((*pData & 0x3f) << 8 | *(pData + 1));
128 return pData + 2;
129 }
130
131 if ((*pData & 0xE0) == 0xC0)
132 {
133 *pLength = ((*pData & 0x1f) << 24 | *(pData + 1) << 16 |
134 *(pData + 2) << 8 | *(pData + 3));
135 return pData + 4;
136 }
137
138 *pLength = (ULONG)-1;
139 return 0;
140 }
141
142 static VOID *assembly_data_offset(ASSEMBLY *assembly, ULONG offset)
143 {
144 return &assembly->data[offset];
145 }
146
147 #define MAX_TABLES_WORD 0xFFFF
148 #define MAX_TABLES_1BIT_ENCODE 32767
149 #define MAX_TABLES_2BIT_ENCODE 16383
150 #define MAX_TABLES_3BIT_ENCODE 8191
151 #define MAX_TABLES_5BIT_ENCODE 2047
152
153 static inline ULONG get_table_size(const ASSEMBLY *assembly, DWORD index)
154 {
155 DWORD size;
156 INT tables;
157
158 switch (TokenFromTable(index))
159 {
160 case mdtModule:
161 {
162 size = sizeof(MODULETABLE) + (assembly->stringsz - sizeof(WORD)) +
163 2 * (assembly->guidsz - sizeof(WORD));
164 break;
165 }
166 case mdtTypeRef:
167 {
168 size = sizeof(TYPEREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
169
170 /* ResolutionScope:ResolutionScope */
171 tables = max(assembly->tables[TableFromToken(mdtModule)].rows,
172 assembly->tables[TableFromToken(mdtModuleRef)].rows);
173 tables = max(tables, assembly->tables[TableFromToken(mdtAssemblyRef)].rows);
174 tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows);
175 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
176 break;
177 }
178 case mdtTypeDef:
179 {
180 size = sizeof(TYPEDEFTABLE) + 2 * (assembly->stringsz - sizeof(WORD));
181
182 /* Extends:TypeDefOrRef */
183 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
184 assembly->tables[TableFromToken(mdtTypeRef)].rows);
185 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
186 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
187
188 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
189 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
190 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
191 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
192 break;
193 }
194 case mdtFieldDef:
195 {
196 size = sizeof(FIELDTABLE) + (assembly->stringsz - sizeof(WORD)) +
197 (assembly->blobsz - sizeof(WORD));
198 break;
199 }
200 case mdtMethodDef:
201 {
202 size = sizeof(METHODDEFTABLE) + (assembly->stringsz - sizeof(WORD)) +
203 (assembly->blobsz - sizeof(WORD));
204
205 size += (assembly->tables[TableFromToken(mdtParamDef)].rows >
206 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
207 break;
208 }
209 case mdtParamDef:
210 {
211 size = sizeof(PARAMTABLE) + (assembly->stringsz - sizeof(WORD));
212 break;
213 }
214 case mdtInterfaceImpl:
215 {
216 size = sizeof(INTERFACEIMPLTABLE);
217
218 /* Interface:TypeDefOrRef */
219 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
220 assembly->tables[TableFromToken(mdtTypeRef)].rows);
221 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
222 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
223 break;
224 }
225 case mdtMemberRef:
226 {
227 size = sizeof(MEMBERREFTABLE) + (assembly->stringsz - sizeof(WORD)) +
228 (assembly->blobsz - sizeof(WORD));
229
230 /* Class:MemberRefParent */
231 tables = max(assembly->tables[TableFromToken(mdtTypeRef)].rows,
232 assembly->tables[TableFromToken(mdtModuleRef)].rows);
233 tables = max(tables, assembly->tables[TableFromToken(mdtMethodDef)].rows);
234 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
235 tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows);
236 size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0;
237 break;
238 }
239 case 0x0B000000: /* FIXME */
240 {
241 size = sizeof(CONSTANTTABLE) + (assembly->blobsz - sizeof(WORD));
242
243 /* Parent:HasConstant */
244 tables = max(assembly->tables[TableFromToken(mdtParamDef)].rows,
245 assembly->tables[TableFromToken(mdtFieldDef)].rows);
246 tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows);
247 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
248 break;
249 }
250 case mdtCustomAttribute:
251 {
252 size = sizeof(CUSTOMATTRIBUTETABLE) + (assembly->blobsz - sizeof(WORD));
253
254 /* Parent:HasCustomAttribute */
255 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
256 assembly->tables[TableFromToken(mdtFieldDef)].rows);
257 tables = max(tables, assembly->tables[TableFromToken(mdtTypeRef)].rows);
258 tables = max(tables, assembly->tables[TableFromToken(mdtTypeDef)].rows);
259 tables = max(tables, assembly->tables[TableFromToken(mdtParamDef)].rows);
260 tables = max(tables, assembly->tables[TableFromToken(mdtInterfaceImpl)].rows);
261 tables = max(tables, assembly->tables[TableFromToken(mdtMemberRef)].rows);
262 tables = max(tables, assembly->tables[TableFromToken(mdtPermission)].rows);
263 tables = max(tables, assembly->tables[TableFromToken(mdtProperty)].rows);
264 tables = max(tables, assembly->tables[TableFromToken(mdtEvent)].rows);
265 tables = max(tables, assembly->tables[TableFromToken(mdtSignature)].rows);
266 tables = max(tables, assembly->tables[TableFromToken(mdtModuleRef)].rows);
267 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
268 tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows);
269 tables = max(tables, assembly->tables[TableFromToken(mdtFile)].rows);
270 tables = max(tables, assembly->tables[TableFromToken(mdtExportedType)].rows);
271 tables = max(tables, assembly->tables[TableFromToken(mdtManifestResource)].rows);
272 size += (tables > MAX_TABLES_5BIT_ENCODE) ? sizeof(WORD) : 0;
273
274 /* Type:CustomAttributeType */
275 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
276 assembly->tables[TableFromToken(mdtMemberRef)].rows);
277 size += (tables > MAX_TABLES_3BIT_ENCODE) ? sizeof(WORD) : 0;
278 break;
279 }
280 case 0x0D000000: /* FIXME */
281 {
282 size = sizeof(FIELDMARSHALTABLE) + (assembly->blobsz - sizeof(WORD));
283
284 /* Parent:HasFieldMarshal */
285 tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows,
286 assembly->tables[TableFromToken(mdtParamDef)].rows);
287 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
288 break;
289 }
290 case mdtPermission:
291 {
292 size = sizeof(DECLSECURITYTABLE) + (assembly->blobsz - sizeof(WORD));
293
294 /* Parent:HasDeclSecurity */
295 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
296 assembly->tables[TableFromToken(mdtMethodDef)].rows);
297 tables = max(tables, assembly->tables[TableFromToken(mdtAssembly)].rows);
298 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
299 break;
300 }
301 case 0x0F000000: /* FIXME */
302 {
303 size = sizeof(CLASSLAYOUTTABLE);
304 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
305 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
306 break;
307 }
308 case 0x10000000: /* FIXME */
309 {
310 size = sizeof(FIELDLAYOUTTABLE);
311 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
312 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
313 break;
314 }
315 case mdtSignature:
316 {
317 size = sizeof(STANDALONESIGTABLE) + (assembly->blobsz - sizeof(WORD));
318 break;
319 }
320 case 0x12000000: /* FIXME */
321 {
322 size = sizeof(EVENTMAPTABLE);
323 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
324 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
325 size += (assembly->tables[TableFromToken(mdtEvent)].rows >
326 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
327 break;
328 }
329 case mdtEvent:
330 {
331 size = sizeof(EVENTTABLE) + (assembly->stringsz - sizeof(WORD));
332
333 /* EventType:TypeDefOrRef */
334 tables = max(assembly->tables[TableFromToken(mdtTypeDef)].rows,
335 assembly->tables[TableFromToken(mdtTypeRef)].rows);
336 tables = max(tables, assembly->tables[TableFromToken(mdtTypeSpec)].rows);
337 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
338 break;
339 }
340 case 0x15000000:/* FIXME */
341 {
342 size = sizeof(PROPERTYMAPTABLE);
343 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
344 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
345 size += (assembly->tables[TableFromToken(mdtProperty)].rows >
346 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
347 break;
348 }
349 case mdtProperty:
350 {
351 size = sizeof(PROPERTYTABLE) + (assembly->stringsz - sizeof(WORD)) +
352 (assembly->blobsz - sizeof(WORD));
353 break;
354 }
355 case 0x18000000: /* FIXME */
356 {
357 size = sizeof(METHODSEMANTICSTABLE);
358
359 /* Association:HasSemantics */
360 tables = max(assembly->tables[TableFromToken(mdtEvent)].rows,
361 assembly->tables[TableFromToken(mdtProperty)].rows);
362 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
363
364 size += (assembly->tables[TableFromToken(mdtMethodDef)].rows >
365 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
366 break;
367 }
368 case 0x19000000: /* FIXME */
369 {
370 size = sizeof(METHODIMPLTABLE);
371
372 /* MethodBody:MethodDefOrRef, MethodDeclaration:MethodDefOrRef */
373 tables = max(assembly->tables[TableFromToken(mdtMethodDef)].rows,
374 assembly->tables[TableFromToken(mdtMemberRef)].rows);
375 size += (tables > MAX_TABLES_1BIT_ENCODE) ? 2 * sizeof(WORD) : 0;
376
377 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
378 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
379 break;
380 }
381 case mdtModuleRef:
382 {
383 size = sizeof(MODULEREFTABLE) + (assembly->stringsz - sizeof(WORD));
384 break;
385 }
386 case mdtTypeSpec:
387 {
388 size = sizeof(TYPESPECTABLE) + (assembly->blobsz - sizeof(WORD));
389 break;
390 }
391 case 0x1C000000: /* FIXME */
392 {
393 size = sizeof(IMPLMAPTABLE) + (assembly->stringsz - sizeof(WORD));
394
395 /* MemberForwarded:MemberForwarded */
396 tables = max(assembly->tables[TableFromToken(mdtFieldDef)].rows,
397 assembly->tables[TableFromToken(mdtMethodDef)].rows);
398 size += (tables > MAX_TABLES_1BIT_ENCODE) ? sizeof(WORD) : 0;
399
400 size += (assembly->tables[TableFromToken(mdtModuleRef)].rows >
401 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
402 break;
403 }
404 case 0x1D000000: /* FIXME */
405 {
406 size = sizeof(FIELDRVATABLE);
407 size += (assembly->tables[TableFromToken(mdtFieldDef)].rows >
408 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
409 break;
410 }
411 case mdtAssembly:
412 {
413 size = sizeof(ASSEMBLYTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
414 (assembly->blobsz - sizeof(WORD));
415 break;
416 }
417 case 0x20000001: /* FIXME */
418 {
419 size = sizeof(ASSEMBLYPROCESSORTABLE);
420 break;
421 }
422 case 0x22000000: /* FIXME */
423 {
424 size = sizeof(ASSEMBLYOSTABLE);
425 break;
426 }
427 case mdtAssemblyRef:
428 {
429 size = sizeof(ASSEMBLYREFTABLE) + 2 * (assembly->stringsz - sizeof(WORD)) +
430 2 * (assembly->blobsz - sizeof(WORD));
431 break;
432 }
433 case 0x24000000: /* FIXME */
434 {
435 size = sizeof(ASSEMBLYREFPROCESSORTABLE);
436 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
437 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
438 break;
439 }
440 case 0x25000000: /* FIXME */
441 {
442 size = sizeof(ASSEMBLYREFOSTABLE);
443 size += (assembly->tables[TableFromToken(mdtAssemblyRef)].rows >
444 MAX_TABLES_WORD) ? sizeof(WORD) : 0;
445 break;
446 }
447 case mdtFile:
448 {
449 size = sizeof(FILETABLE) + (assembly->stringsz - sizeof(WORD)) +
450 (assembly->blobsz - sizeof(WORD));
451 break;
452 }
453 case mdtExportedType:
454 {
455 size = sizeof(EXPORTEDTYPETABLE) + 2 * (assembly->stringsz - sizeof(WORD));
456
457 /* Implementation:Implementation */
458 tables = max(assembly->tables[TableFromToken(mdtFile)].rows,
459 assembly->tables[TableFromToken(mdtMethodDef)].rows);
460 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
461 break;
462 }
463 case mdtManifestResource:
464 {
465 size = sizeof(MANIFESTRESTABLE) + (assembly->stringsz - sizeof(WORD));
466
467 /* Implementation:Implementation */
468 tables = max(assembly->tables[TableFromToken(mdtFile)].rows,
469 assembly->tables[TableFromToken(mdtAssemblyRef)].rows);
470 size += (tables > MAX_TABLES_2BIT_ENCODE) ? sizeof(WORD) : 0;
471 break;
472 }
473 case 0x29000000: /* FIXME */
474 {
475 size = sizeof(NESTEDCLASSTABLE);
476 size += (assembly->tables[TableFromToken(mdtTypeDef)].rows >
477 MAX_TABLES_WORD) ? 2 * sizeof(WORD) : 0;
478 break;
479 }
480 default:
481 return 0;
482 }
483
484 return size;
485 }
486
487 static HRESULT parse_clr_tables(ASSEMBLY *assembly, ULONG offset)
488 {
489 DWORD i, previ, offidx;
490 ULONG currofs;
491
492 currofs = offset;
493 assembly->tableshdr = assembly_data_offset(assembly, currofs);
494 if (!assembly->tableshdr)
495 return E_FAIL;
496
497 assembly->stringsz = (assembly->tableshdr->HeapOffsetSizes & MD_STRINGS_BIT) ?
498 sizeof(DWORD) : sizeof(WORD);
499 assembly->guidsz = (assembly->tableshdr->HeapOffsetSizes & MD_GUIDS_BIT) ?
500 sizeof(DWORD) : sizeof(WORD);
501 assembly->blobsz = (assembly->tableshdr->HeapOffsetSizes & MD_BLOBS_BIT) ?
502 sizeof(DWORD) : sizeof(WORD);
503
504 currofs += sizeof(METADATATABLESHDR);
505 assembly->numrows = assembly_data_offset(assembly, currofs);
506 if (!assembly->numrows)
507 return E_FAIL;
508
509 assembly->numtables = 0;
510 for (i = 0; i < MAX_CLR_TABLES; i++)
511 {
512 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
513 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
514 {
515 assembly->numtables++;
516 }
517 }
518
519 currofs += assembly->numtables * sizeof(DWORD);
520 memset(assembly->tables, -1, MAX_CLR_TABLES * sizeof(CLRTABLE));
521
522 if (assembly->tableshdr->MaskValid.u.LowPart & 1)
523 assembly->tables[0].offset = currofs;
524
525 offidx = 0;
526 for (i = 0; i < MAX_CLR_TABLES; i++)
527 {
528 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
529 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
530 {
531 assembly->tables[i].rows = assembly->numrows[offidx];
532 offidx++;
533 }
534 }
535
536 previ = 0;
537 offidx = 1;
538 for (i = 1; i < MAX_CLR_TABLES; i++)
539 {
540 if ((i < 32 && (assembly->tableshdr->MaskValid.u.LowPart >> i) & 1) ||
541 (i >= 32 && (assembly->tableshdr->MaskValid.u.HighPart >> i) & 1))
542 {
543 currofs += get_table_size(assembly, previ) * assembly->numrows[offidx - 1];
544 assembly->tables[i].offset = currofs;
545 offidx++;
546 previ = i;
547 }
548 }
549
550 return S_OK;
551 }
552
553 static HRESULT parse_metadata_header(ASSEMBLY *assembly, DWORD *hdrsz)
554 {
555 METADATAHDR *metadatahdr;
556 BYTE *ptr, *dest;
557 DWORD size, ofs;
558 ULONG rva;
559
560 rva = assembly->corhdr->MetaData.VirtualAddress;
561 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva, NULL);
562 if (!ptr)
563 return E_FAIL;
564
565 metadatahdr = (METADATAHDR *)ptr;
566
567 assembly->metadatahdr = HeapAlloc(GetProcessHeap(), 0, sizeof(METADATAHDR));
568 if (!assembly->metadatahdr)
569 return E_OUTOFMEMORY;
570
571 size = FIELD_OFFSET(METADATAHDR, Version);
572 memcpy(assembly->metadatahdr, metadatahdr, size);
573
574 /* we don't care about the version string */
575
576 ofs = FIELD_OFFSET(METADATAHDR, Flags);
577 ptr += FIELD_OFFSET(METADATAHDR, Version) + metadatahdr->VersionLength + 1;
578 dest = (BYTE *)assembly->metadatahdr + ofs;
579 memcpy(dest, ptr, sizeof(METADATAHDR) - ofs);
580
581 *hdrsz = sizeof(METADATAHDR) - sizeof(LPSTR) + metadatahdr->VersionLength + 1;
582
583 return S_OK;
584 }
585
586 static HRESULT parse_clr_metadata(ASSEMBLY *assembly)
587 {
588 METADATASTREAMHDR *streamhdr;
589 ULONG rva, i, ofs;
590 LPSTR stream;
591 HRESULT hr;
592 DWORD hdrsz;
593 BYTE *ptr;
594
595 hr = parse_metadata_header(assembly, &hdrsz);
596 if (FAILED(hr))
597 return hr;
598
599 rva = assembly->corhdr->MetaData.VirtualAddress;
600 ptr = ImageRvaToVa(assembly->nthdr, assembly->data, rva + hdrsz, NULL);
601 if (!ptr)
602 return E_FAIL;
603
604 for (i = 0; i < assembly->metadatahdr->Streams; i++)
605 {
606 streamhdr = (METADATASTREAMHDR *)ptr;
607 ofs = rva_to_offset(assembly->nthdr, rva + streamhdr->Offset);
608
609 ptr += sizeof(METADATASTREAMHDR);
610 stream = (LPSTR)ptr;
611
612 if (!lstrcmpA(stream, "#~"))
613 {
614 hr = parse_clr_tables(assembly, ofs);
615 if (FAILED(hr))
616 return hr;
617 }
618 else if (!lstrcmpA(stream, "#Strings") || !lstrcmpA(stream, "Strings"))
619 assembly->strings = assembly_data_offset(assembly, ofs);
620 else if (!lstrcmpA(stream, "#Blob") || !lstrcmpA(stream, "Blob"))
621 assembly->blobs = assembly_data_offset(assembly, ofs);
622
623 ptr += lstrlenA(stream) + 1;
624 ptr = (BYTE *)(((UINT_PTR)ptr + 3) & ~3); /* align on DWORD boundary */
625 }
626
627 return S_OK;
628 }
629
630 static HRESULT parse_pe_header(ASSEMBLY *assembly)
631 {
632 IMAGE_DATA_DIRECTORY *datadirs;
633
634 assembly->nthdr = ImageNtHeader(assembly->data);
635 if (!assembly->nthdr)
636 return E_FAIL;
637
638 if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
639 {
640 IMAGE_OPTIONAL_HEADER64 *opthdr =
641 (IMAGE_OPTIONAL_HEADER64 *)&assembly->nthdr->OptionalHeader;
642 datadirs = opthdr->DataDirectory;
643 }
644 else
645 {
646 IMAGE_OPTIONAL_HEADER32 *opthdr =
647 (IMAGE_OPTIONAL_HEADER32 *)&assembly->nthdr->OptionalHeader;
648 datadirs = opthdr->DataDirectory;
649 }
650
651 if (!datadirs)
652 return E_FAIL;
653
654 if (!datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress ||
655 !datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size)
656 {
657 return E_FAIL;
658 }
659
660 assembly->corhdr = ImageRvaToVa(assembly->nthdr, assembly->data,
661 datadirs[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress, NULL);
662 if (!assembly->corhdr)
663 return E_FAIL;
664
665 return S_OK;
666 }
667
668 HRESULT assembly_create(ASSEMBLY **out, LPCWSTR file)
669 {
670 ASSEMBLY *assembly;
671 HRESULT hr;
672
673 *out = NULL;
674
675 assembly = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASSEMBLY));
676 if (!assembly)
677 return E_OUTOFMEMORY;
678
679 assembly->path = strdupW(file);
680 if (!assembly->path)
681 {
682 hr = E_OUTOFMEMORY;
683 goto failed;
684 }
685
686 assembly->hfile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ,
687 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
688 if (assembly->hfile == INVALID_HANDLE_VALUE)
689 {
690 hr = HRESULT_FROM_WIN32(GetLastError());
691 goto failed;
692 }
693
694 assembly->hmap = CreateFileMappingW(assembly->hfile, NULL, PAGE_READONLY,
695 0, 0, NULL);
696 if (!assembly->hmap)
697 {
698 hr = HRESULT_FROM_WIN32(GetLastError());
699 goto failed;
700 }
701
702 assembly->data = MapViewOfFile(assembly->hmap, FILE_MAP_READ, 0, 0, 0);
703 if (!assembly->data)
704 {
705 hr = HRESULT_FROM_WIN32(GetLastError());
706 goto failed;
707 }
708
709 hr = parse_pe_header(assembly);
710 if (FAILED(hr)) goto failed;
711
712 hr = parse_clr_metadata(assembly);
713 if (FAILED(hr)) goto failed;
714
715 *out = assembly;
716 return S_OK;
717
718 failed:
719 assembly_release(assembly);
720 return hr;
721 }
722
723 HRESULT assembly_release(ASSEMBLY *assembly)
724 {
725 if (!assembly)
726 return S_OK;
727
728 HeapFree(GetProcessHeap(), 0, assembly->metadatahdr);
729 HeapFree(GetProcessHeap(), 0, assembly->path);
730 UnmapViewOfFile(assembly->data);
731 CloseHandle(assembly->hmap);
732 CloseHandle(assembly->hfile);
733 HeapFree(GetProcessHeap(), 0, assembly);
734
735 return S_OK;
736 }
737
738 static LPWSTR assembly_dup_str(const ASSEMBLY *assembly, DWORD index)
739 {
740 int len;
741 LPWSTR cpy;
742 LPCSTR str = (LPCSTR)&assembly->strings[index];
743
744 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
745
746 if ((cpy = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
747 MultiByteToWideChar(CP_ACP, 0, str, -1, cpy, len);
748
749 return cpy;
750 }
751
752 HRESULT assembly_get_name(ASSEMBLY *assembly, LPWSTR *name)
753 {
754 BYTE *ptr;
755 LONG offset;
756 DWORD stridx;
757
758 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
759 if (offset == -1)
760 return E_FAIL;
761
762 ptr = assembly_data_offset(assembly, offset);
763 if (!ptr)
764 return E_FAIL;
765
766 ptr += FIELD_OFFSET(ASSEMBLYTABLE, PublicKey) + assembly->blobsz;
767 if (assembly->stringsz == sizeof(DWORD))
768 stridx = *((DWORD *)ptr);
769 else
770 stridx = *((WORD *)ptr);
771
772 *name = assembly_dup_str(assembly, stridx);
773 if (!*name)
774 return E_OUTOFMEMORY;
775
776 return S_OK;
777 }
778
779 HRESULT assembly_get_path(const ASSEMBLY *assembly, LPWSTR *path)
780 {
781 LPWSTR cpy = HeapAlloc(GetProcessHeap(), 0, (strlenW(assembly->path) + 1) * sizeof(WCHAR));
782 *path = cpy;
783 if (cpy)
784 strcpyW(cpy, assembly->path);
785 else
786 return E_OUTOFMEMORY;
787
788 return S_OK;
789 }
790
791 HRESULT assembly_get_version(ASSEMBLY *assembly, LPWSTR *version)
792 {
793 static const WCHAR format[] = {'%','u','.','%','u','.','%','u','.','%','u',0};
794
795 ASSEMBLYTABLE *asmtbl;
796 LONG offset;
797
798 *version = NULL;
799
800 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
801 if (offset == -1)
802 return E_FAIL;
803
804 asmtbl = assembly_data_offset(assembly, offset);
805 if (!asmtbl)
806 return E_FAIL;
807
808 *version = HeapAlloc(GetProcessHeap(), 0, sizeof(format) + 4 * strlen("65535") * sizeof(WCHAR));
809 if (!*version)
810 return E_OUTOFMEMORY;
811
812 sprintfW(*version, format, asmtbl->MajorVersion, asmtbl->MinorVersion,
813 asmtbl->BuildNumber, asmtbl->RevisionNumber);
814
815 return S_OK;
816 }
817
818 BYTE assembly_get_architecture(ASSEMBLY *assembly)
819 {
820 if ((assembly->corhdr->MajorRuntimeVersion == 2) && (assembly->corhdr->MinorRuntimeVersion == 0))
821 return 0; /* .NET 1.x assembly */
822
823 if (assembly->nthdr->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
824 return peAMD64; /* AMD64/IA64 assembly */
825
826 if ((assembly->corhdr->Flags & COMIMAGE_FLAGS_ILONLY) && !(assembly->corhdr->Flags & COMIMAGE_FLAGS_32BITREQUIRED))
827 return peMSIL; /* MSIL assembly */
828
829 return peI386; /* x86 assembly */
830 }
831
832 static BYTE *assembly_get_blob(ASSEMBLY *assembly, WORD index, ULONG *size)
833 {
834 return GetData(&assembly->blobs[index], size);
835 }
836
837 HRESULT assembly_get_pubkey_token(ASSEMBLY *assembly, LPWSTR *token)
838 {
839 ASSEMBLYTABLE *asmtbl;
840 ULONG i, size;
841 LONG offset;
842 BYTE *hashdata;
843 HCRYPTPROV crypt;
844 HCRYPTHASH hash;
845 BYTE *pubkey;
846 BYTE tokbytes[BYTES_PER_TOKEN];
847 HRESULT hr = E_FAIL;
848 LPWSTR tok;
849
850 *token = NULL;
851
852 offset = assembly->tables[TableFromToken(mdtAssembly)].offset;
853 if (offset == -1)
854 return E_FAIL;
855
856 asmtbl = assembly_data_offset(assembly, offset);
857 if (!asmtbl)
858 return E_FAIL;
859
860 pubkey = assembly_get_blob(assembly, asmtbl->PublicKey, &size);
861
862 if (!CryptAcquireContextA(&crypt, NULL, NULL, PROV_RSA_FULL,
863 CRYPT_VERIFYCONTEXT))
864 return E_FAIL;
865
866 if (!CryptCreateHash(crypt, CALG_SHA1, 0, 0, &hash))
867 return E_FAIL;
868
869 if (!CryptHashData(hash, pubkey, size, 0))
870 return E_FAIL;
871
872 size = 0;
873 if (!CryptGetHashParam(hash, HP_HASHVAL, NULL, &size, 0))
874 return E_FAIL;
875
876 hashdata = HeapAlloc(GetProcessHeap(), 0, size);
877 if (!hashdata)
878 {
879 hr = E_OUTOFMEMORY;
880 goto done;
881 }
882
883 if (!CryptGetHashParam(hash, HP_HASHVAL, hashdata, &size, 0))
884 goto done;
885
886 for (i = size - 1; i >= size - 8; i--)
887 tokbytes[size - i - 1] = hashdata[i];
888
889 tok = HeapAlloc(GetProcessHeap(), 0, (TOKEN_LENGTH + 1) * sizeof(WCHAR));
890 if (!tok)
891 {
892 hr = E_OUTOFMEMORY;
893 goto done;
894 }
895
896 token_to_str(tokbytes, tok);
897
898 *token = tok;
899 hr = S_OK;
900
901 done:
902 HeapFree(GetProcessHeap(), 0, hashdata);
903 CryptDestroyHash(hash);
904 CryptReleaseContext(crypt, 0);
905
906 return hr;
907 }