1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 #include "rsym.h" 6 #include "rsym64.h" 7 #include "dwarf2.h" 8 9 char DoPrint = 0; 10 ULONG g_ehframep; 11 12 #define DPRINT if(DoPrint) printf 13 14 struct {char *name; char regnt;} regs[] = 15 { {"rax", REG_RAX}, {"rdx", REG_RDX}, {"rcx", REG_RCX}, {"rbx", REG_RBX}, 16 {"rsi", REG_RSI}, {"rdi", REG_RDI}, {"rbp", REG_RBP}, {"rsp", REG_RSP}, 17 {"r8", REG_R8}, {"r9", REG_R9}, {"r10", REG_R10}, {"r11", REG_R11}, 18 {"r12", REG_R12}, {"r13", REG_R13}, {"r14", REG_R14}, {"r15", REG_R15}, 19 {"xmm0", REG_XMM0}, {"xmm1", REG_XMM1}, {"xmm2", REG_XMM2}, {"xmm3", REG_XMM3}, 20 {"xmm4", REG_XMM4}, {"xmm5", REG_XMM5}, {"xmm6", REG_XMM6}, {"xmm7", REG_XMM7}, 21 {"xmm8", REG_XMM8}, {"xmm9", REG_XMM9}, {"xmm10",REG_XMM10},{"xmm11",REG_XMM11}, 22 {"xmm12",REG_XMM12},{"xmm13",REG_XMM13},{"xmm14",REG_XMM14},{"xmm15",REG_XMM15}, 23 // "st0", "st1", "st2", "st3", 24 // "st4", "st5", "st6", "st7", 25 // "mm0", "mm1", "mm2", "mm3", 26 // "mm4", "mm5", "mm6", "mm7" 27 }; 28 29 /** Functions for DWARF2 ******************************************************/ 30 31 unsigned long 32 DwDecodeUleb128(unsigned long *pResult, char *pc) 33 { 34 unsigned long ulResult = 0; 35 unsigned long ulShift = 0; 36 unsigned char current; 37 unsigned long ulSize = 0; 38 39 do 40 { 41 current = pc[ulSize]; 42 ulSize++; 43 ulResult |= (current & 0x7f) << ulShift; 44 ulShift += 7; 45 } 46 while (current & 0x80); 47 48 *pResult = ulResult; 49 return ulSize; 50 } 51 52 unsigned long 53 DwDecodeSleb128(long *pResult, char *pc) 54 { 55 long lResult = 0; 56 unsigned long ulShift = 0; 57 unsigned char current; 58 unsigned long ulSize = 0; 59 60 do 61 { 62 current = pc[ulSize]; 63 ulSize++; 64 lResult |= (current & 0x7f) << ulShift; 65 ulShift += 7; 66 } 67 while (current & 0x80); 68 69 if (current & 0x40) 70 lResult |= - (1 << (ulShift)); 71 72 *pResult = lResult; 73 74 return ulSize; 75 } 76 77 unsigned long 78 DwDecodeCie(PDW2CIE Cie, char *pc) 79 { 80 Cie->Length = *(ULONG*)pc; 81 Cie->Next = pc + 4 + Cie->Length; 82 Cie->CieId = *(ULONG*)(pc + 4); 83 Cie->Version = pc[8]; 84 Cie->AugString = pc + 9; 85 Cie->AugStringLength = strlen(Cie->AugString); 86 pc = Cie->AugString + Cie->AugStringLength + 1; 87 pc += DwDecodeUleb128(&Cie->CodeAlign, pc); 88 pc += DwDecodeSleb128(&Cie->DataAlign, pc); 89 pc += DwDecodeUleb128(&Cie->ReturnAddressRegister, pc); 90 pc += DwDecodeUleb128(&Cie->AugLength, pc); 91 Cie->AugData = pc; 92 pc += Cie->AugLength; 93 Cie->Instructions = pc; 94 95 return Cie->Length + 4; 96 } 97 98 unsigned long 99 DwDecodeFde(PDW2FDE Fde, char *pc) 100 { 101 Fde->Length = *(ULONG*)pc; 102 Fde->Next = pc + 4 + Fde->Length; 103 Fde->CiePointer = pc + 4 - *(ULONG*)(pc + 4); 104 Fde->PcBegin = *(ULONG*)(pc + 8); 105 Fde->PcRange = *(ULONG*)(pc + 12); 106 pc += 16; 107 pc += DwDecodeUleb128(&Fde->AugLength, pc); 108 Fde->AugData = pc; 109 Fde->Instructions = Fde->AugData + Fde->AugLength; 110 111 return Fde->Length + 4; 112 } 113 114 unsigned long 115 DwExecIntruction(PDW2CFSTATE State, char *pc) 116 { 117 unsigned char Code; 118 unsigned long Length; 119 unsigned long PrevFramePtr = State->FramePtr; 120 121 State->Scope = 0; 122 State->IsUwop = 0; 123 State->Code = Code = *pc; 124 Length = 1; 125 if ((Code & 0xc0) == DW_CFA_advance_loc) 126 { 127 State->Code = DW_CFA_advance_loc; 128 State->Location += Code & 0x3f; 129 } 130 else if ((Code & 0xc0) == DW_CFA_offset) 131 { 132 State->Code = DW_CFA_offset; 133 State->Reg = Code & 0x3f; 134 Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + 1); 135 State->Offset *= 8; // fixme data alignment 136 State->IsUwop = 1; 137 } 138 else if ((Code & 0xc0) == DW_CFA_restore) 139 { 140 State->Code = DW_CFA_restore; 141 State->Reg = Code & 0x3f; 142 } 143 else switch (Code) 144 { 145 case DW_CFA_nop: 146 break; 147 case DW_CFA_set_loc: 148 Length = 9; // address 149 State->Location = *(DWORD*)(pc + 1); 150 break; 151 case DW_CFA_advance_loc1: 152 Length = 2; 153 State->Location += pc[1]; 154 break; 155 case DW_CFA_advance_loc2: 156 Length = 3; 157 // printf("Found a DW_CFA_advance_loc2 : 0x%lx ->", *(WORD*)(pc + 1)); 158 State->Location += *(WORD*)(pc + 1); 159 // printf(" 0x%lx\n", State->Location); 160 break; 161 case DW_CFA_advance_loc4: 162 Length = 5; 163 // printf("Found a DW_CFA_advance_loc4 : 0x%lx ->", *(DWORD*)(pc + 1)); 164 State->Location += *(DWORD*)(pc + 1); 165 // printf(" 0x%lx\n", State->Location); 166 break; 167 case DW_CFA_offset_extended: 168 Length += DwDecodeUleb128(&State->Reg, pc + Length); 169 Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + Length); 170 State->IsUwop = 1; 171 break; 172 case DW_CFA_offset_extended_sf: 173 Length += DwDecodeUleb128(&State->Reg, pc + Length); 174 Length += DwDecodeSleb128(&State->Offset, pc + Length); 175 State->IsUwop = 1; 176 break; 177 case DW_CFA_restore_extended: 178 Length += DwDecodeUleb128(&State->Reg, pc + Length); 179 break; 180 case DW_CFA_undefined: 181 Length += DwDecodeUleb128(&State->Reg, pc + Length); 182 break; 183 case DW_CFA_same_value: 184 Length += DwDecodeUleb128(&State->Reg, pc + Length); 185 break; 186 case DW_CFA_register: 187 Length += DwDecodeUleb128(&State->Reg, pc + Length); 188 Length += DwDecodeUleb128(&State->Reg2, pc + Length); 189 break; 190 case DW_CFA_remember_state: 191 break; 192 case DW_CFA_restore_state: 193 break; 194 case DW_CFA_def_cfa: 195 Length += DwDecodeUleb128(&State->Reg, pc + Length); 196 Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length); 197 State->IsUwop = 1; 198 break; 199 case DW_CFA_def_cfa_register: 200 Length += DwDecodeUleb128(&State->Reg, pc + Length); 201 break; 202 case DW_CFA_def_cfa_offset: 203 Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length); 204 State->IsUwop = 1; 205 break; 206 case DW_CFA_def_cfa_sf: 207 Length += DwDecodeUleb128(&State->Reg, pc + Length); 208 Length += DwDecodeSleb128(&State->FramePtr, pc + Length); 209 State->FramePtr *= 8; // data alignment 210 State->IsUwop = 1; 211 break; 212 case DW_CFA_GNU_args_size: 213 { 214 unsigned long argsize; 215 printf("Warning, DW_CFA_GNU_args_size is unimplemented\n"); 216 Length += DwDecodeUleb128(&argsize, pc + Length); 217 break; 218 } 219 /* PSEH */ 220 case 0x21: 221 { 222 unsigned long SehType; 223 224 // printf("found 0x21 at %lx\n", State->Location); 225 Length += DwDecodeUleb128(&SehType, pc + Length); 226 switch (SehType) 227 { 228 case 1: /* Begin Try */ 229 State->TryLevel++; 230 if (State->TryLevel >= 20) 231 { 232 printf("WTF? Trylevel of 20 exceeded...\n"); 233 exit(1); 234 } 235 State->SehBlock[State->TryLevel-1].BeginTry = State->Location; 236 // printf("Found begintry at 0x%lx\n", State->Location); 237 State->Scope = 1; 238 break; 239 240 case 2: /* End Try */ 241 State->SehBlock[State->TryLevel-1].EndTry = State->Location; 242 State->Scope = 2; 243 break; 244 245 case 3: /* Jump target */ 246 State->SehBlock[State->TryLevel-1].Target = State->Location; 247 State->Scope = 3; 248 break; 249 250 case 4: /* SEH End */ 251 if (State->TryLevel == 20) 252 { 253 printf("Ooops, end of SEH with trylevel at 0!\n"); 254 exit(1); 255 } 256 State->SehBlock[State->TryLevel-1].End = State->Location; 257 State->TryLevel--; 258 State->cScopes++; 259 State->Scope = 0; 260 break; 261 262 case 5: /* Constant filter */ 263 { 264 unsigned long value; 265 Length += DwDecodeUleb128(&value, pc + Length); 266 State->SehBlock[State->TryLevel-1].Handler = value; 267 // printf("Found a constant filter at 0x%lx\n", State->Location); 268 break; 269 } 270 271 /* These work differently. We are in a new function. 272 * We have to parse a lea opcode to find the address of 273 * the jump target. This is the reference to find the 274 * appropriate C_SCOPE_TABLE. */ 275 case 6: /* Filter func */ 276 // printf("Found a filter func at 0x%lx\n", State->Location); 277 break; 278 279 case 7: /* Finally func */ 280 { 281 // printf("Found a finally func at 0x%lx\n", State->Location); 282 break; 283 } 284 285 default: 286 printf("Found unknow PSEH code 0x%lx\n", SehType); 287 exit(1); 288 } 289 break; 290 } 291 default: 292 fprintf(stderr, "unknown instruction 0x%x at 0x%p\n", Code, pc); 293 exit(1); 294 } 295 296 State->FramePtrDiff = State->FramePtr - PrevFramePtr; 297 DPRINT("@%p: code=%x, Loc=%lx, offset=%lx, reg=0x%lx:%s\n", 298 (void*)((ULONG)pc - g_ehframep), Code, State->Location, State->Offset, State->Reg, regs[State->Reg].name); 299 return Length; 300 } 301 302 /** Windows unwind data functions *********************************************/ 303 304 ULONG 305 StoreUnwindCodes(PUNWIND_INFO Info, PDW2CFSTATE State, ULONG FunctionStart) 306 { 307 ULONG cCodes = 0; 308 ULONG AllocSize; 309 UNWIND_CODE Code[3]; 310 int i; 311 312 Code[0].CodeOffset = State->Location - FunctionStart; 313 314 switch (State->Code) 315 { 316 case DW_CFA_offset: 317 case DW_CFA_offset_extended: 318 // save register at offset 319 Code[0].OpInfo = regs[State->Reg].regnt; 320 if (State->Offset <= 0x7FFF8) 321 { 322 Code[0].UnwindOp = UWOP_SAVE_NONVOL; 323 Code[1].FrameOffset = State->Offset / 8; 324 cCodes = 2; 325 } 326 else 327 { 328 Code[0].UnwindOp = UWOP_SAVE_NONVOL_FAR; 329 Code[1].FrameOffset = (State->Offset / 8); 330 Code[2].FrameOffset = (State->Offset / 8) >> 16; 331 cCodes = 3; 332 } 333 break; 334 335 case DW_CFA_def_cfa: 336 //case DW_CFA_def_cfa_register: 337 case DW_CFA_def_cfa_offset: 338 case DW_CFA_def_cfa_sf: 339 AllocSize = State->FramePtrDiff; 340 if (AllocSize <= 128) 341 { 342 Code[0].UnwindOp = UWOP_ALLOC_SMALL; 343 Code[0].OpInfo = (AllocSize / 8) - 1; 344 cCodes = 1; 345 } 346 else if (AllocSize <= 0x7FFF8) 347 { 348 Code[0].UnwindOp = UWOP_ALLOC_LARGE; 349 Code[0].OpInfo = 0; 350 Code[1].FrameOffset = AllocSize / 8; 351 cCodes = 2; 352 } 353 else // if (AllocSize > 0x7FFF8) 354 { 355 Code[0].UnwindOp = UWOP_ALLOC_LARGE; 356 Code[0].OpInfo = 1; 357 Code[1].FrameOffset = (USHORT)AllocSize; 358 Code[2].FrameOffset = (USHORT)(AllocSize >> 16); 359 cCodes = 3; 360 } 361 break; 362 } 363 364 if (Info) 365 { 366 /* Move old codes */ 367 for (i = Info->CountOfCodes - 1; i >= 0; i--) 368 { 369 Info->UnwindCode[i + cCodes] = Info->UnwindCode[i]; 370 } 371 372 /* Copy new codes */ 373 for (i = 0; i < cCodes; i++) 374 { 375 Info->UnwindCode[i] = Code[i]; 376 } 377 378 Info->CountOfCodes += cCodes; 379 } 380 381 return cCodes; 382 } 383 384 #define GetxdataSize(cFuncs, cUWOP, cScopes) \ 385 ( cFuncs * (sizeof(UNWIND_INFO) + 2 + 4 + 4) \ 386 + cUWOP * sizeof(UNWIND_CODE) \ 387 + cScopes * sizeof(C_SCOPE_TABLE_ENTRY) ) 388 389 ULONG 390 StoreUnwindInfo(PUNWIND_INFO Info, PDW2FDE pFde, ULONG FunctionStart) 391 { 392 ULONG cbSize; 393 DW2CFSTATE State; 394 char *pInst; 395 ULONG c; 396 DW2CIE Cie; 397 398 cbSize = 4; // sizeof(UNWIND_INFO); 399 Info->Version = 1; 400 Info->Flags = 0; 401 Info->SizeOfProlog = 0; 402 Info->CountOfCodes = 0; 403 Info->FrameRegister = 0; 404 Info->FrameOffset = 0; 405 406 /* Decode the CIE */ 407 DwDecodeCie(&Cie, pFde->CiePointer); 408 409 /* Initialize state */ 410 State.Location = FunctionStart; 411 State.FramePtr = 0; 412 State.TryLevel = 0; 413 State.cScopes = 0; 414 415 /* Parse the CIE's initial instructions */ 416 pInst = Cie.Instructions; 417 while (pInst < Cie.Next) 418 { 419 pInst += DwExecIntruction(&State, pInst); 420 } 421 422 /* Parse the FDE instructions */ 423 pInst = pFde->Instructions; 424 while (pInst < pFde->Next) 425 { 426 pInst += DwExecIntruction(&State, pInst); 427 428 if (State.IsUwop) 429 { 430 c = StoreUnwindCodes(Info, &State, FunctionStart); 431 cbSize += c * sizeof(UNWIND_CODE); 432 Info->SizeOfProlog = State.Location - FunctionStart; 433 } 434 } 435 cbSize = ROUND_UP(cbSize, 4); 436 437 /* Do we have scope table to write? */ 438 if (State.cScopes > 0) 439 { 440 unsigned long i; 441 ULONG *pExceptionHandler; 442 PC_SCOPE_TABLE pScopeTable; 443 444 /* Set flag for exception handler */ 445 Info->Flags |= UNW_FLAG_EHANDLER; 446 447 /* Store address of handler and number of scope tables */ 448 pExceptionHandler = (ULONG*)((char*)Info + cbSize); 449 // HACK for testing purpose 450 *pExceptionHandler = FunctionStart; // _C_specific_handler 451 452 pScopeTable = (PC_SCOPE_TABLE)(pExceptionHandler + 1); 453 pScopeTable->NumEntries = State.cScopes; 454 455 /* Store the scope table entries */ 456 for (i = 0; i < State.cScopes; i++) 457 { 458 pScopeTable->Entry[i].Begin = State.SehBlock[i].BeginTry; 459 pScopeTable->Entry[i].End = State.SehBlock[i].EndTry; 460 pScopeTable->Entry[i].Handler = 1;//State.SehBlock[i].Handler; 461 pScopeTable->Entry[i].Target = State.SehBlock[i].Target; 462 } 463 464 /* Update size */ 465 cbSize += 8 + State.cScopes * sizeof(C_SCOPE_TABLE_ENTRY); 466 } 467 468 return cbSize; 469 } 470 471 void 472 CountUnwindData(PFILE_INFO File) 473 { 474 DW2CIEFDE *p; 475 DW2FDE Fde; 476 char *pInst, *pmax; 477 DW2CFSTATE State; 478 479 File->cFuncs = 0; 480 File->cScopes = 0; 481 File->cUWOP = 0; 482 State.FramePtr = 0; 483 State.TryLevel = 0; 484 485 p = File->eh_frame.p; 486 pmax = (char*)p + File->eh_frame.psh->Misc.VirtualSize; 487 for (; p->Length && (char*)p < pmax; p = NextCIE(p)) 488 { 489 /* Is this an FDE? */ 490 if (p->CiePointer != 0) 491 { 492 File->cFuncs++; 493 DwDecodeFde(&Fde, (char*)p); 494 495 pInst = Fde.Instructions; 496 while (pInst < Fde.Next) 497 { 498 pInst += DwExecIntruction(&State, pInst); 499 File->cUWOP += StoreUnwindCodes(NULL, &State, 0); 500 File->cScopes += State.Scope ? 1 : 0; 501 } 502 } 503 } 504 505 return; 506 } 507 508 int CompFunc(const void *p1, const void *p2) 509 { 510 PRUNTIME_FUNCTION prf1 = (void*)p1, prf2 = (void*)p2; 511 return (prf1->FunctionStart > prf2->FunctionStart ? 1 : -1); 512 } 513 514 void 515 GeneratePData(PFILE_INFO File) 516 { 517 DW2CIEFDE *p; 518 DW2FDE Fde; 519 PIMAGE_DATA_DIRECTORY Dir; 520 ULONG i, Offset; 521 void * eh_frame; 522 PRUNTIME_FUNCTION pdata; 523 ULONG xdata_va; 524 char *xdata_p; 525 ULONG cbSize; 526 PIMAGE_SECTION_HEADER pshp, pshx; 527 ULONG FileAlignment; 528 char *pmax; 529 530 FileAlignment = File->OptionalHeader->FileAlignment; 531 532 /* Get pointer to eh_frame section */ 533 eh_frame = File->eh_frame.p; 534 g_ehframep = (ULONG)eh_frame; 535 536 /* Get sizes */ 537 CountUnwindData(File); 538 // printf("cFuncs = %ld, cUWOPS = %ld, cScopes = %ld\n", 539 // File->cFuncs, File->cUWOP, File->cScopes); 540 541 /* Initialize section header for .pdata */ 542 i = File->pdata.idx = File->UsedSections; 543 pshp = File->pdata.psh = &File->NewSectionHeaders[i]; 544 memcpy(pshp->Name, ".pdata", 7); 545 pshp->Misc.VirtualSize = (File->cFuncs + 1) * sizeof(RUNTIME_FUNCTION); 546 pshp->VirtualAddress = File->NewSectionHeaders[i - 1].VirtualAddress + 547 File->NewSectionHeaders[i - 1].SizeOfRawData; 548 pshp->SizeOfRawData = ROUND_UP(pshp->Misc.VirtualSize, FileAlignment); 549 pshp->PointerToRawData = File->NewSectionHeaders[i - 1].PointerToRawData + 550 File->NewSectionHeaders[i - 1].SizeOfRawData; 551 pshp->PointerToRelocations = 0; 552 pshp->PointerToLinenumbers = 0; 553 pshp->NumberOfRelocations = 0; 554 pshp->NumberOfLinenumbers = 0; 555 pshp->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED | 556 IMAGE_SCN_CNT_INITIALIZED_DATA; 557 558 /* Allocate .pdata buffer */ 559 pdata = File->pdata.p = malloc(pshp->SizeOfRawData); 560 memset(File->pdata.p, 0, pshp->SizeOfRawData); 561 562 /* Init exception data dir */ 563 Dir = &File->OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; 564 Dir->VirtualAddress = pshp->VirtualAddress; 565 Dir->Size = pshp->Misc.VirtualSize; 566 567 /* Initialize section header for .xdata */ 568 File->xdata.idx = File->pdata.idx + 1; 569 pshx = File->xdata.psh = &File->NewSectionHeaders[File->xdata.idx]; 570 memcpy(pshx->Name, ".xdata", 7); 571 pshx->Misc.VirtualSize = GetxdataSize(File->cFuncs, File->cUWOP, File->cScopes); 572 pshx->VirtualAddress = pshp->VirtualAddress + pshp->SizeOfRawData; 573 pshx->SizeOfRawData = ROUND_UP(pshx->Misc.VirtualSize, FileAlignment); 574 pshx->PointerToRawData = pshp->PointerToRawData + pshp->SizeOfRawData; 575 pshx->PointerToRelocations = 0; 576 pshx->PointerToLinenumbers = 0; 577 pshx->NumberOfRelocations = 0; 578 pshx->NumberOfLinenumbers = 0; 579 pshx->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED | 580 IMAGE_SCN_CNT_INITIALIZED_DATA; 581 582 /* Allocate .xdata buffer */ 583 File->xdata.p = malloc(pshx->SizeOfRawData); 584 memset(File->xdata.p, 0, pshx->SizeOfRawData); 585 586 i = 0; 587 Offset = File->eh_frame.psh->VirtualAddress; 588 xdata_va = pshx->VirtualAddress; 589 xdata_p = File->xdata.p; 590 pmax = (char*)eh_frame + File->eh_frame.psh->Misc.VirtualSize - 100; 591 592 for (p = eh_frame; p->Length && (char*)p < pmax; p = NextCIE(p)) 593 { 594 /* Is this an FDE? */ 595 if (p->CiePointer != 0) 596 { 597 DwDecodeFde(&Fde, (char*)p); 598 pdata[i].FunctionStart = Offset + 8 + Fde.PcBegin; 599 pdata[i].FunctionEnd = pdata[i].FunctionStart + Fde.PcRange; 600 pdata[i].UnwindInfo = xdata_va; 601 602 // printf("%ld: RUNTIME_FUNCTION: {0x%lx, 0x%lx, 0x%lx}\n", i, pdata[i].FunctionStart, pdata[i].FunctionEnd, pdata[i].UnwindInfo); 603 604 cbSize = StoreUnwindInfo((void*)xdata_p, &Fde, pdata[i].FunctionStart); 605 xdata_va += cbSize; 606 xdata_p += cbSize; 607 i++; 608 } 609 Offset += 4 + p->Length; 610 } 611 612 /* Sort the RUNTIME_FUNCTIONS */ 613 qsort(pdata, i, sizeof(RUNTIME_FUNCTION), CompFunc); 614 615 } 616 617 /** Functions for COFF ********************************************************/ 618 619 620 WORD 621 CalculateChecksum(DWORD Start, void *pFile, ULONG cbSize) 622 { 623 WORD *Ptr = pFile; 624 DWORD i; 625 DWORD checksum = Start; 626 627 for (i = 0; i < (cbSize + 1) / sizeof(WORD); i++) 628 { 629 checksum += Ptr[i]; 630 checksum = (checksum + (checksum >> 16)) & 0xffff; 631 } 632 633 return checksum ; 634 } 635 636 void 637 WriteOutFile(FILE *handle, PFILE_INFO File) 638 { 639 int ret, Size, Pos = 0; 640 DWORD CheckSum; 641 ULONG i, Alignment; 642 643 Alignment = File->OptionalHeader->FileAlignment; 644 645 /* Update section count */ 646 File->FileHeader->NumberOfSections = File->UsedSections + 2; // FIXME!!! 647 648 /* Update SizeOfImage */ 649 Size = File->xdata.psh->VirtualAddress 650 + File->xdata.psh->SizeOfRawData; 651 File->OptionalHeader->SizeOfImage = Size; 652 653 /* Recalculate checksum */ 654 CheckSum = CalculateChecksum(0, File->FilePtr, File->HeaderSize); 655 for (i = 0; i < File->AllSections; i++) 656 { 657 if (File->UseSection[i]) 658 { 659 Size = File->SectionHeaders[i].SizeOfRawData; 660 if (Size) 661 { 662 void *p; 663 p = File->FilePtr + File->SectionHeaders[i].PointerToRawData; 664 CheckSum = CalculateChecksum(CheckSum, p, Size); 665 } 666 } 667 } 668 Size = File->pdata.psh->Misc.VirtualSize; 669 CheckSum = CalculateChecksum(CheckSum, File->pdata.p, Size); 670 Size = File->xdata.psh->Misc.VirtualSize; 671 CheckSum = CalculateChecksum(CheckSum, File->xdata.p, Size); 672 CheckSum += File->HeaderSize; 673 CheckSum += File->pdata.psh->Misc.VirtualSize; 674 CheckSum += File->xdata.psh->Misc.VirtualSize; 675 File->OptionalHeader->CheckSum = CheckSum; 676 677 /* Write file header */ 678 Size = File->HeaderSize; 679 ret = fwrite(File->DosHeader, 1, Size, handle); 680 Pos = Size; 681 682 /* Write Section headers */ 683 Size = File->NewSectionHeaderSize; 684 ret = fwrite(File->NewSectionHeaders, 1, Size, handle); 685 Pos += Size; 686 687 /* Fill up to next alignement */ 688 Size = ROUND_UP(Pos, Alignment) - Pos; 689 ret = fwrite(File->AlignBuf, 1, Size, handle); 690 Pos += Size; 691 692 /* Write sections */ 693 for (i = 0; i < File->AllSections; i++) 694 { 695 if (File->UseSection[i]) 696 { 697 void *p; 698 Size = File->SectionHeaders[i].SizeOfRawData; 699 if (Size) 700 { 701 p = File->FilePtr + File->SectionHeaders[i].PointerToRawData; 702 ret = fwrite(p, 1, Size, handle); 703 Pos += Size; 704 } 705 } 706 } 707 708 /* Write .pdata section */ 709 Size = File->pdata.psh->SizeOfRawData; 710 ret = fwrite(File->pdata.p, 1, Size, handle); 711 Pos += Size; 712 713 /* Write .xdata section */ 714 Size = File->xdata.psh->SizeOfRawData; 715 ret = fwrite(File->xdata.p, 1, Size, handle); 716 Pos += Size; 717 718 } 719 720 721 int 722 ParsePEHeaders(PFILE_INFO File) 723 { 724 DWORD OldChecksum, Checksum; 725 ULONG Alignment, CurrentPos; 726 int i, j; 727 728 /* Check if MZ header exists */ 729 File->DosHeader = (PIMAGE_DOS_HEADER)File->FilePtr; 730 if ((File->DosHeader->e_magic != IMAGE_DOS_MAGIC) || 731 (File->DosHeader->e_lfanew == 0L)) 732 { 733 perror("Input file is not a PE image.\n"); 734 return -1; 735 } 736 737 /* Locate PE file header */ 738 File->FileHeader = (PIMAGE_FILE_HEADER)(File->FilePtr + 739 File->DosHeader->e_lfanew + sizeof(ULONG)); 740 741 /* Check for x64 image */ 742 if (File->FileHeader->Machine != IMAGE_FILE_MACHINE_AMD64) 743 { 744 perror("Input file is not an x64 image.\n"); 745 return -1; 746 } 747 748 /* Locate optional header */ 749 File->OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)(File->FileHeader + 1); 750 751 /* Check if checksum is correct */ 752 OldChecksum = File->OptionalHeader->CheckSum; 753 File->OptionalHeader->CheckSum = 0; 754 Checksum = CalculateChecksum(0, File->FilePtr, File->cbInFileSize); 755 Checksum += File->cbInFileSize; 756 if ((Checksum & 0xffff) != (OldChecksum & 0xffff)) 757 { 758 fprintf(stderr, "Input file has incorrect PE checksum: 0x%lx (calculated: 0x%lx)\n", 759 OldChecksum, Checksum); 760 // return 0; 761 } 762 763 /* Locate PE section headers */ 764 File->SectionHeaders = (PIMAGE_SECTION_HEADER)((char*)File->OptionalHeader 765 + File->FileHeader->SizeOfOptionalHeader); 766 767 File->HeaderSize = File->DosHeader->e_lfanew 768 + sizeof(ULONG) 769 + sizeof(IMAGE_FILE_HEADER) 770 + File->FileHeader->SizeOfOptionalHeader; 771 772 /* Create some shortcuts */ 773 File->ImageBase = File->OptionalHeader->ImageBase; 774 File->Symbols = File->FilePtr + File->FileHeader->PointerToSymbolTable; 775 File->Strings = (char*)File->Symbols + File->FileHeader->NumberOfSymbols * 18; 776 777 /* Check section names */ 778 File->AllSections = File->FileHeader->NumberOfSections; 779 Alignment = File->OptionalHeader->FileAlignment; 780 File->NewSectionHeaders = malloc((File->AllSections+2) * sizeof(IMAGE_SECTION_HEADER)); 781 File->UsedSections = 0; 782 File->eh_frame.idx = -1; 783 784 /* Allocate array of chars, specifying whether to copy the section */ 785 File->UseSection = malloc(File->AllSections); 786 787 for (i = 0; i < File->AllSections; i++) 788 { 789 char *pName = (char*)File->SectionHeaders[i].Name; 790 File->UseSection[i] = 1; 791 792 /* Check for long name */ 793 if (pName[0] == '/') 794 { 795 unsigned long index = strtoul(pName+1, 0, 10); 796 pName = File->Strings + index; 797 798 // Hack, simply remove all sections with long names 799 File->UseSection[i] = 0; 800 } 801 802 /* Chek if we have the eh_frame section */ 803 if (strcmp(pName, ".eh_frame") == 0) 804 { 805 File->eh_frame.psh = &File->SectionHeaders[i]; 806 File->eh_frame.idx = i; 807 File->eh_frame.p = File->FilePtr + File->eh_frame.psh->PointerToRawData; 808 } 809 810 /* Increase number of used sections */ 811 if (File->UseSection[i]) 812 File->UsedSections = i+1; 813 814 } 815 816 /* This is the actual size of the new section headers */ 817 File->NewSectionHeaderSize = 818 (File->UsedSections+2) * sizeof(IMAGE_SECTION_HEADER); 819 820 /* Calculate the position to start writing the sections to */ 821 CurrentPos = File->HeaderSize + File->NewSectionHeaderSize; 822 CurrentPos = ROUND_UP(CurrentPos, Alignment); 823 824 /* Create new section headers */ 825 for (i = 0, j = 0; i < File->UsedSections; i++) 826 { 827 /* Copy section header */ 828 File->NewSectionHeaders[j] = File->SectionHeaders[i]; 829 830 /* Shall we strip the section? */ 831 if (File->UseSection[i] == 0) 832 { 833 /* Make it a bss section */ 834 File->NewSectionHeaders[j].PointerToRawData = 0; 835 File->NewSectionHeaders[j].SizeOfRawData = 0; 836 File->NewSectionHeaders[j].Characteristics = 0xC0500080; 837 } 838 839 /* Fix Offset into File */ 840 File->NewSectionHeaders[j].PointerToRawData = 841 File->NewSectionHeaders[j].PointerToRawData ? CurrentPos : 0; 842 CurrentPos += File->NewSectionHeaders[j].SizeOfRawData; 843 j++; 844 } 845 846 if (File->eh_frame.idx == -1) 847 { 848 //fprintf(stderr, "No .eh_frame section found\n"); 849 return 0; 850 } 851 852 return 1; 853 } 854 855 int main(int argc, char* argv[]) 856 { 857 char* pszInFile; 858 char* pszOutFile; 859 FILE_INFO File; 860 FILE* outfile; 861 int ret; 862 int arg, argstate = 0; 863 char *SourcePath = NULL; 864 865 for (arg = 1; arg < argc; arg++) 866 { 867 switch (argstate) 868 { 869 default: 870 argstate = -1; 871 break; 872 873 case 0: 874 if (!strcmp(argv[arg], "-s")) 875 { 876 argstate = 1; 877 } 878 else 879 { 880 argstate = 2; 881 pszInFile = convert_path(argv[arg]); 882 } 883 break; 884 885 case 1: 886 free(SourcePath); 887 SourcePath = strdup(argv[arg]); 888 argstate = 0; 889 break; 890 891 case 2: 892 pszOutFile = convert_path(argv[arg]); 893 argstate = 3; 894 break; 895 } 896 } 897 898 if (argstate != 3) 899 { 900 fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n"); 901 exit(1); 902 } 903 904 File.FilePtr = load_file(pszInFile, &File.cbInFileSize); 905 if (!File.FilePtr) 906 { 907 fprintf(stderr, "An error occured loading '%s'\n", pszInFile); 908 exit(1); 909 } 910 911 ret = ParsePEHeaders(&File); 912 if (ret != 1) 913 { 914 free(File.FilePtr); 915 exit(ret == -1 ? 1 : 0); 916 } 917 918 File.AlignBuf = malloc(File.OptionalHeader->FileAlignment); 919 memset(File.AlignBuf, 0, File.OptionalHeader->FileAlignment); 920 921 GeneratePData(&File); 922 923 outfile = fopen(pszOutFile, "wb"); 924 if (outfile == NULL) 925 { 926 perror("Cannot open output file"); 927 free(File.FilePtr); 928 exit(1); 929 } 930 931 WriteOutFile(outfile, &File); 932 933 fclose(outfile); 934 935 return 0; 936 } 937