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