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