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