#include #include #include #include "rsym.h" #include "rsym64.h" #include "dwarf2.h" char DoPrint = 0; ULONG g_ehframep; #define DPRINT if(DoPrint) printf struct {char *name; char regnt;} regs[] = { {"rax", REG_RAX}, {"rdx", REG_RDX}, {"rcx", REG_RCX}, {"rbx", REG_RBX}, {"rsi", REG_RSI}, {"rdi", REG_RDI}, {"rbp", REG_RBP}, {"rsp", REG_RSP}, {"r8", REG_R8}, {"r9", REG_R9}, {"r10", REG_R10}, {"r11", REG_R11}, {"r12", REG_R12}, {"r13", REG_R13}, {"r14", REG_R14}, {"r15", REG_R15}, {"xmm0", REG_XMM0}, {"xmm1", REG_XMM1}, {"xmm2", REG_XMM2}, {"xmm3", REG_XMM3}, {"xmm4", REG_XMM4}, {"xmm5", REG_XMM5}, {"xmm6", REG_XMM6}, {"xmm7", REG_XMM7}, {"xmm8", REG_XMM8}, {"xmm9", REG_XMM9}, {"xmm10",REG_XMM10},{"xmm11",REG_XMM11}, {"xmm12",REG_XMM12},{"xmm13",REG_XMM13},{"xmm14",REG_XMM14},{"xmm15",REG_XMM15}, // "st0", "st1", "st2", "st3", // "st4", "st5", "st6", "st7", // "mm0", "mm1", "mm2", "mm3", // "mm4", "mm5", "mm6", "mm7" }; /** Functions for DWARF2 ******************************************************/ unsigned long DwDecodeUleb128(unsigned long *pResult, char *pc) { unsigned long ulResult = 0; unsigned long ulShift = 0; unsigned char current; unsigned long ulSize = 0; do { current = pc[ulSize]; ulSize++; ulResult |= (current & 0x7f) << ulShift; ulShift += 7; } while (current & 0x80); *pResult = ulResult; return ulSize; } unsigned long DwDecodeSleb128(long *pResult, char *pc) { long lResult = 0; unsigned long ulShift = 0; unsigned char current; unsigned long ulSize = 0; do { current = pc[ulSize]; ulSize++; lResult |= (current & 0x7f) << ulShift; ulShift += 7; } while (current & 0x80); if (current & 0x40) lResult |= - (1 << (ulShift)); *pResult = lResult; return ulSize; } unsigned long DwDecodeCie(PDW2CIE Cie, char *pc) { Cie->Length = *(ULONG*)pc; Cie->Next = pc + 4 + Cie->Length; Cie->CieId = *(ULONG*)(pc + 4); Cie->Version = pc[8]; Cie->AugString = pc + 9; Cie->AugStringLength = strlen(Cie->AugString); pc = Cie->AugString + Cie->AugStringLength + 1; pc += DwDecodeUleb128(&Cie->CodeAlign, pc); pc += DwDecodeSleb128(&Cie->DataAlign, pc); pc += DwDecodeUleb128(&Cie->ReturnAddressRegister, pc); pc += DwDecodeUleb128(&Cie->AugLength, pc); Cie->AugData = pc; pc += Cie->AugLength; Cie->Instructions = pc; return Cie->Length + 4; } unsigned long DwDecodeFde(PDW2FDE Fde, char *pc) { Fde->Length = *(ULONG*)pc; Fde->Next = pc + 4 + Fde->Length; Fde->CiePointer = pc + 4 - *(ULONG*)(pc + 4); Fde->PcBegin = *(ULONG*)(pc + 8); Fde->PcRange = *(ULONG*)(pc + 12); pc += 16; pc += DwDecodeUleb128(&Fde->AugLength, pc); Fde->AugData = pc; Fde->Instructions = Fde->AugData + Fde->AugLength; return Fde->Length + 4; } unsigned long DwExecIntruction(PDW2CFSTATE State, char *pc) { unsigned char Code; unsigned long Length; unsigned long PrevFramePtr = State->FramePtr; State->Scope = 0; State->IsUwop = 0; State->Code = Code = *pc; Length = 1; if ((Code & 0xc0) == DW_CFA_advance_loc) { State->Code = DW_CFA_advance_loc; State->Location += Code & 0x3f; } else if ((Code & 0xc0) == DW_CFA_offset) { State->Code = DW_CFA_offset; State->Reg = Code & 0x3f; Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + 1); State->Offset *= 8; // fixme data alignment State->IsUwop = 1; } else if ((Code & 0xc0) == DW_CFA_restore) { State->Code = DW_CFA_restore; State->Reg = Code & 0x3f; } else switch (Code) { case DW_CFA_nop: break; case DW_CFA_set_loc: Length = 9; // address State->Location = *(DWORD*)(pc + 1); break; case DW_CFA_advance_loc1: Length = 2; State->Location += pc[1]; break; case DW_CFA_advance_loc2: Length = 3; // printf("Found a DW_CFA_advance_loc2 : 0x%lx ->", *(WORD*)(pc + 1)); State->Location += *(WORD*)(pc + 1); // printf(" 0x%lx\n", State->Location); break; case DW_CFA_advance_loc4: Length = 5; // printf("Found a DW_CFA_advance_loc4 : 0x%lx ->", *(DWORD*)(pc + 1)); State->Location += *(DWORD*)(pc + 1); // printf(" 0x%lx\n", State->Location); break; case DW_CFA_offset_extended: Length += DwDecodeUleb128(&State->Reg, pc + Length); Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + Length); State->IsUwop = 1; break; case DW_CFA_offset_extended_sf: Length += DwDecodeUleb128(&State->Reg, pc + Length); Length += DwDecodeSleb128(&State->Offset, pc + Length); State->IsUwop = 1; break; case DW_CFA_restore_extended: Length += DwDecodeUleb128(&State->Reg, pc + Length); break; case DW_CFA_undefined: Length += DwDecodeUleb128(&State->Reg, pc + Length); break; case DW_CFA_same_value: Length += DwDecodeUleb128(&State->Reg, pc + Length); break; case DW_CFA_register: Length += DwDecodeUleb128(&State->Reg, pc + Length); Length += DwDecodeUleb128(&State->Reg2, pc + Length); break; case DW_CFA_remember_state: break; case DW_CFA_restore_state: break; case DW_CFA_def_cfa: Length += DwDecodeUleb128(&State->Reg, pc + Length); Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length); State->IsUwop = 1; break; case DW_CFA_def_cfa_register: Length += DwDecodeUleb128(&State->Reg, pc + Length); break; case DW_CFA_def_cfa_offset: Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length); State->IsUwop = 1; break; case DW_CFA_def_cfa_sf: Length += DwDecodeUleb128(&State->Reg, pc + Length); Length += DwDecodeSleb128(&State->FramePtr, pc + Length); State->FramePtr *= 8; // data alignment State->IsUwop = 1; break; case DW_CFA_GNU_args_size: { unsigned long argsize; printf("Warning, DW_CFA_GNU_args_size is unimplemented\n"); Length += DwDecodeUleb128(&argsize, pc + Length); break; } /* PSEH */ case 0x21: { unsigned long SehType; // printf("found 0x21 at %lx\n", State->Location); Length += DwDecodeUleb128(&SehType, pc + Length); switch (SehType) { case 1: /* Begin Try */ State->TryLevel++; if (State->TryLevel >= 20) { printf("WTF? Trylevel of 20 exceeded...\n"); exit(1); } State->SehBlock[State->TryLevel-1].BeginTry = State->Location; // printf("Found begintry at 0x%lx\n", State->Location); State->Scope = 1; break; case 2: /* End Try */ State->SehBlock[State->TryLevel-1].EndTry = State->Location; State->Scope = 2; break; case 3: /* Jump target */ State->SehBlock[State->TryLevel-1].Target = State->Location; State->Scope = 3; break; case 4: /* SEH End */ if (State->TryLevel == 20) { printf("Ooops, end of SEH with trylevel at 0!\n"); exit(1); } State->SehBlock[State->TryLevel-1].End = State->Location; State->TryLevel--; State->cScopes++; State->Scope = 0; break; case 5: /* Constant filter */ { unsigned long value; Length += DwDecodeUleb128(&value, pc + Length); State->SehBlock[State->TryLevel-1].Handler = value; // printf("Found a constant filter at 0x%lx\n", State->Location); break; } /* These work differently. We are in a new function. * We have to parse a lea opcode to find the address of * the jump target. This is the reference to find the * appropriate C_SCOPE_TABLE. */ case 6: /* Filter func */ // printf("Found a filter func at 0x%lx\n", State->Location); break; case 7: /* Finally func */ { // printf("Found a finally func at 0x%lx\n", State->Location); break; } default: printf("Found unknow PSEH code 0x%lx\n", SehType); exit(1); } break; } default: fprintf(stderr, "unknown instruction 0x%x at 0x%p\n", Code, pc); exit(1); } State->FramePtrDiff = State->FramePtr - PrevFramePtr; DPRINT("@%p: code=%x, Loc=%lx, offset=%lx, reg=0x%lx:%s\n", (void*)((ULONG)pc - g_ehframep), Code, State->Location, State->Offset, State->Reg, regs[State->Reg].name); return Length; } /** Windows unwind data functions *********************************************/ ULONG StoreUnwindCodes(PUNWIND_INFO Info, PDW2CFSTATE State, ULONG FunctionStart) { ULONG cCodes = 0; ULONG AllocSize; UNWIND_CODE Code[3]; int i; Code[0].CodeOffset = State->Location - FunctionStart; switch (State->Code) { case DW_CFA_offset: case DW_CFA_offset_extended: // save register at offset Code[0].OpInfo = regs[State->Reg].regnt; if (State->Offset <= 0x7FFF8) { Code[0].UnwindOp = UWOP_SAVE_NONVOL; Code[1].FrameOffset = State->Offset / 8; cCodes = 2; } else { Code[0].UnwindOp = UWOP_SAVE_NONVOL_FAR; Code[1].FrameOffset = (State->Offset / 8); Code[2].FrameOffset = (State->Offset / 8) >> 16; cCodes = 3; } break; case DW_CFA_def_cfa: //case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: case DW_CFA_def_cfa_sf: AllocSize = State->FramePtrDiff; if (AllocSize <= 128) { Code[0].UnwindOp = UWOP_ALLOC_SMALL; Code[0].OpInfo = (AllocSize / 8) - 1; cCodes = 1; } else if (AllocSize <= 0x7FFF8) { Code[0].UnwindOp = UWOP_ALLOC_LARGE; Code[0].OpInfo = 0; Code[1].FrameOffset = AllocSize / 8; cCodes = 2; } else // if (AllocSize > 0x7FFF8) { Code[0].UnwindOp = UWOP_ALLOC_LARGE; Code[0].OpInfo = 1; Code[1].FrameOffset = (USHORT)AllocSize; Code[2].FrameOffset = (USHORT)(AllocSize >> 16); cCodes = 3; } break; } if (Info) { /* Move old codes */ for (i = Info->CountOfCodes - 1; i >= 0; i--) { Info->UnwindCode[i + cCodes] = Info->UnwindCode[i]; } /* Copy new codes */ for (i = 0; i < cCodes; i++) { Info->UnwindCode[i] = Code[i]; } Info->CountOfCodes += cCodes; } return cCodes; } #define GetxdataSize(cFuncs, cUWOP, cScopes) \ ( cFuncs * (sizeof(UNWIND_INFO) + 2 + 4 + 4) \ + cUWOP * sizeof(UNWIND_CODE) \ + cScopes * sizeof(C_SCOPE_TABLE_ENTRY) ) ULONG StoreUnwindInfo(PUNWIND_INFO Info, PDW2FDE pFde, ULONG FunctionStart) { ULONG cbSize; DW2CFSTATE State; char *pInst; ULONG c; DW2CIE Cie; cbSize = 4; // sizeof(UNWIND_INFO); Info->Version = 1; Info->Flags = 0; Info->SizeOfProlog = 0; Info->CountOfCodes = 0; Info->FrameRegister = 0; Info->FrameOffset = 0; /* Decode the CIE */ DwDecodeCie(&Cie, pFde->CiePointer); /* Initialize state */ State.Location = FunctionStart; State.FramePtr = 0; State.TryLevel = 0; State.cScopes = 0; /* Parse the CIE's initial instructions */ pInst = Cie.Instructions; while (pInst < Cie.Next) { pInst += DwExecIntruction(&State, pInst); } /* Parse the FDE instructions */ pInst = pFde->Instructions; while (pInst < pFde->Next) { pInst += DwExecIntruction(&State, pInst); if (State.IsUwop) { c = StoreUnwindCodes(Info, &State, FunctionStart); cbSize += c * sizeof(UNWIND_CODE); Info->SizeOfProlog = State.Location - FunctionStart; } } cbSize = ROUND_UP(cbSize, 4); /* Do we have scope table to write? */ if (State.cScopes > 0) { unsigned long i; ULONG *pExceptionHandler; PC_SCOPE_TABLE pScopeTable; /* Set flag for exception handler */ Info->Flags |= UNW_FLAG_EHANDLER; /* Store address of handler and number of scope tables */ pExceptionHandler = (ULONG*)((char*)Info + cbSize); // HACK for testing purpose *pExceptionHandler = FunctionStart; // _C_specific_handler pScopeTable = (PC_SCOPE_TABLE)(pExceptionHandler + 1); pScopeTable->NumEntries = State.cScopes; /* Store the scope table entries */ for (i = 0; i < State.cScopes; i++) { pScopeTable->Entry[i].Begin = State.SehBlock[i].BeginTry; pScopeTable->Entry[i].End = State.SehBlock[i].EndTry; pScopeTable->Entry[i].Handler = 1;//State.SehBlock[i].Handler; pScopeTable->Entry[i].Target = State.SehBlock[i].Target; } /* Update size */ cbSize += 8 + State.cScopes * sizeof(C_SCOPE_TABLE_ENTRY); } return cbSize; } void CountUnwindData(PFILE_INFO File) { DW2CIEFDE *p; DW2FDE Fde; char *pInst, *pmax; DW2CFSTATE State; File->cFuncs = 0; File->cScopes = 0; File->cUWOP = 0; State.FramePtr = 0; State.TryLevel = 0; p = File->eh_frame.p; pmax = (char*)p + File->eh_frame.psh->Misc.VirtualSize; for (; p->Length && (char*)p < pmax; p = NextCIE(p)) { /* Is this an FDE? */ if (p->CiePointer != 0) { File->cFuncs++; DwDecodeFde(&Fde, (char*)p); pInst = Fde.Instructions; while (pInst < Fde.Next) { pInst += DwExecIntruction(&State, pInst); File->cUWOP += StoreUnwindCodes(NULL, &State, 0); File->cScopes += State.Scope ? 1 : 0; } } } return; } int CompFunc(const void *p1, const void *p2) { PRUNTIME_FUNCTION prf1 = (void*)p1, prf2 = (void*)p2; return (prf1->FunctionStart > prf2->FunctionStart ? 1 : -1); } void GeneratePData(PFILE_INFO File) { DW2CIEFDE *p; DW2FDE Fde; PIMAGE_DATA_DIRECTORY Dir; ULONG i, Offset; void * eh_frame; PRUNTIME_FUNCTION pdata; ULONG xdata_va; char *xdata_p; ULONG cbSize; PIMAGE_SECTION_HEADER pshp, pshx; ULONG FileAlignment; char *pmax; FileAlignment = File->OptionalHeader->FileAlignment; /* Get pointer to eh_frame section */ eh_frame = File->eh_frame.p; g_ehframep = (ULONG)eh_frame; /* Get sizes */ CountUnwindData(File); // printf("cFuncs = %ld, cUWOPS = %ld, cScopes = %ld\n", // File->cFuncs, File->cUWOP, File->cScopes); /* Initialize section header for .pdata */ i = File->pdata.idx = File->UsedSections; pshp = File->pdata.psh = &File->NewSectionHeaders[i]; memcpy(pshp->Name, ".pdata", 7); pshp->Misc.VirtualSize = (File->cFuncs + 1) * sizeof(RUNTIME_FUNCTION); pshp->VirtualAddress = File->NewSectionHeaders[i - 1].VirtualAddress + File->NewSectionHeaders[i - 1].SizeOfRawData; pshp->SizeOfRawData = ROUND_UP(pshp->Misc.VirtualSize, FileAlignment); pshp->PointerToRawData = File->NewSectionHeaders[i - 1].PointerToRawData + File->NewSectionHeaders[i - 1].SizeOfRawData; pshp->PointerToRelocations = 0; pshp->PointerToLinenumbers = 0; pshp->NumberOfRelocations = 0; pshp->NumberOfLinenumbers = 0; pshp->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED | IMAGE_SCN_CNT_INITIALIZED_DATA; /* Allocate .pdata buffer */ pdata = File->pdata.p = malloc(pshp->SizeOfRawData); memset(File->pdata.p, 0, pshp->SizeOfRawData); /* Init exception data dir */ Dir = &File->OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; Dir->VirtualAddress = pshp->VirtualAddress; Dir->Size = pshp->Misc.VirtualSize; /* Initialize section header for .xdata */ File->xdata.idx = File->pdata.idx + 1; pshx = File->xdata.psh = &File->NewSectionHeaders[File->xdata.idx]; memcpy(pshx->Name, ".xdata", 7); pshx->Misc.VirtualSize = GetxdataSize(File->cFuncs, File->cUWOP, File->cScopes); pshx->VirtualAddress = pshp->VirtualAddress + pshp->SizeOfRawData; pshx->SizeOfRawData = ROUND_UP(pshx->Misc.VirtualSize, FileAlignment); pshx->PointerToRawData = pshp->PointerToRawData + pshp->SizeOfRawData; pshx->PointerToRelocations = 0; pshx->PointerToLinenumbers = 0; pshx->NumberOfRelocations = 0; pshx->NumberOfLinenumbers = 0; pshx->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED | IMAGE_SCN_CNT_INITIALIZED_DATA; /* Allocate .xdata buffer */ File->xdata.p = malloc(pshx->SizeOfRawData); memset(File->xdata.p, 0, pshx->SizeOfRawData); i = 0; Offset = File->eh_frame.psh->VirtualAddress; xdata_va = pshx->VirtualAddress; xdata_p = File->xdata.p; pmax = (char*)eh_frame + File->eh_frame.psh->Misc.VirtualSize - 100; for (p = eh_frame; p->Length && (char*)p < pmax; p = NextCIE(p)) { /* Is this an FDE? */ if (p->CiePointer != 0) { DwDecodeFde(&Fde, (char*)p); pdata[i].FunctionStart = Offset + 8 + Fde.PcBegin; pdata[i].FunctionEnd = pdata[i].FunctionStart + Fde.PcRange; pdata[i].UnwindInfo = xdata_va; // printf("%ld: RUNTIME_FUNCTION: {0x%lx, 0x%lx, 0x%lx}\n", i, pdata[i].FunctionStart, pdata[i].FunctionEnd, pdata[i].UnwindInfo); cbSize = StoreUnwindInfo((void*)xdata_p, &Fde, pdata[i].FunctionStart); xdata_va += cbSize; xdata_p += cbSize; i++; } Offset += 4 + p->Length; } /* Sort the RUNTIME_FUNCTIONS */ qsort(pdata, i, sizeof(RUNTIME_FUNCTION), CompFunc); } /** Functions for COFF ********************************************************/ WORD CalculateChecksum(DWORD Start, void *pFile, ULONG cbSize) { WORD *Ptr = pFile; DWORD i; DWORD checksum = Start; for (i = 0; i < (cbSize + 1) / sizeof(WORD); i++) { checksum += Ptr[i]; checksum = (checksum + (checksum >> 16)) & 0xffff; } return checksum ; } void WriteOutFile(FILE *handle, PFILE_INFO File) { int ret, Size, Pos = 0; DWORD CheckSum; ULONG i, Alignment; Alignment = File->OptionalHeader->FileAlignment; /* Update section count */ File->FileHeader->NumberOfSections = File->UsedSections + 2; // FIXME!!! /* Update SizeOfImage */ Size = File->xdata.psh->VirtualAddress + File->xdata.psh->SizeOfRawData; File->OptionalHeader->SizeOfImage = Size; /* Recalculate checksum */ CheckSum = CalculateChecksum(0, File->FilePtr, File->HeaderSize); for (i = 0; i < File->AllSections; i++) { if (File->UseSection[i]) { Size = File->SectionHeaders[i].SizeOfRawData; if (Size) { void *p; p = File->FilePtr + File->SectionHeaders[i].PointerToRawData; CheckSum = CalculateChecksum(CheckSum, p, Size); } } } Size = File->pdata.psh->Misc.VirtualSize; CheckSum = CalculateChecksum(CheckSum, File->pdata.p, Size); Size = File->xdata.psh->Misc.VirtualSize; CheckSum = CalculateChecksum(CheckSum, File->xdata.p, Size); CheckSum += File->HeaderSize; CheckSum += File->pdata.psh->Misc.VirtualSize; CheckSum += File->xdata.psh->Misc.VirtualSize; File->OptionalHeader->CheckSum = CheckSum; /* Write file header */ Size = File->HeaderSize; ret = fwrite(File->DosHeader, 1, Size, handle); Pos = Size; /* Write Section headers */ Size = File->NewSectionHeaderSize; ret = fwrite(File->NewSectionHeaders, 1, Size, handle); Pos += Size; /* Fill up to next alignement */ Size = ROUND_UP(Pos, Alignment) - Pos; ret = fwrite(File->AlignBuf, 1, Size, handle); Pos += Size; /* Write sections */ for (i = 0; i < File->AllSections; i++) { if (File->UseSection[i]) { void *p; Size = File->SectionHeaders[i].SizeOfRawData; if (Size) { p = File->FilePtr + File->SectionHeaders[i].PointerToRawData; ret = fwrite(p, 1, Size, handle); Pos += Size; } } } /* Write .pdata section */ Size = File->pdata.psh->SizeOfRawData; ret = fwrite(File->pdata.p, 1, Size, handle); Pos += Size; /* Write .xdata section */ Size = File->xdata.psh->SizeOfRawData; ret = fwrite(File->xdata.p, 1, Size, handle); Pos += Size; } int ParsePEHeaders(PFILE_INFO File) { DWORD OldChecksum, Checksum; ULONG Alignment, CurrentPos; int i, j; /* Check if MZ header exists */ File->DosHeader = (PIMAGE_DOS_HEADER)File->FilePtr; if ((File->DosHeader->e_magic != IMAGE_DOS_MAGIC) || (File->DosHeader->e_lfanew == 0L)) { perror("Input file is not a PE image.\n"); return -1; } /* Locate PE file header */ File->FileHeader = (PIMAGE_FILE_HEADER)(File->FilePtr + File->DosHeader->e_lfanew + sizeof(ULONG)); /* Check for x64 image */ if (File->FileHeader->Machine != IMAGE_FILE_MACHINE_AMD64) { perror("Input file is not an x64 image.\n"); return -1; } /* Locate optional header */ File->OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)(File->FileHeader + 1); /* Check if checksum is correct */ OldChecksum = File->OptionalHeader->CheckSum; File->OptionalHeader->CheckSum = 0; Checksum = CalculateChecksum(0, File->FilePtr, File->cbInFileSize); Checksum += File->cbInFileSize; if ((Checksum & 0xffff) != (OldChecksum & 0xffff)) { fprintf(stderr, "Input file has incorrect PE checksum: 0x%lx (calculated: 0x%lx)\n", OldChecksum, Checksum); // return 0; } /* Locate PE section headers */ File->SectionHeaders = (PIMAGE_SECTION_HEADER)((char*)File->OptionalHeader + File->FileHeader->SizeOfOptionalHeader); File->HeaderSize = File->DosHeader->e_lfanew + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) + File->FileHeader->SizeOfOptionalHeader; /* Create some shortcuts */ File->ImageBase = File->OptionalHeader->ImageBase; File->Symbols = File->FilePtr + File->FileHeader->PointerToSymbolTable; File->Strings = (char*)File->Symbols + File->FileHeader->NumberOfSymbols * 18; /* Check section names */ File->AllSections = File->FileHeader->NumberOfSections; Alignment = File->OptionalHeader->FileAlignment; File->NewSectionHeaders = malloc((File->AllSections+2) * sizeof(IMAGE_SECTION_HEADER)); File->UsedSections = 0; File->eh_frame.idx = -1; /* Allocate array of chars, specifying whether to copy the section */ File->UseSection = malloc(File->AllSections); for (i = 0; i < File->AllSections; i++) { char *pName = (char*)File->SectionHeaders[i].Name; File->UseSection[i] = 1; /* Check for long name */ if (pName[0] == '/') { unsigned long index = strtoul(pName+1, 0, 10); pName = File->Strings + index; // Hack, simply remove all sections with long names File->UseSection[i] = 0; } /* Chek if we have the eh_frame section */ if (strcmp(pName, ".eh_frame") == 0) { File->eh_frame.psh = &File->SectionHeaders[i]; File->eh_frame.idx = i; File->eh_frame.p = File->FilePtr + File->eh_frame.psh->PointerToRawData; } /* Increase number of used sections */ if (File->UseSection[i]) File->UsedSections = i+1; } /* This is the actual size of the new section headers */ File->NewSectionHeaderSize = (File->UsedSections+2) * sizeof(IMAGE_SECTION_HEADER); /* Calculate the position to start writing the sections to */ CurrentPos = File->HeaderSize + File->NewSectionHeaderSize; CurrentPos = ROUND_UP(CurrentPos, Alignment); /* Create new section headers */ for (i = 0, j = 0; i < File->UsedSections; i++) { /* Copy section header */ File->NewSectionHeaders[j] = File->SectionHeaders[i]; /* Shall we strip the section? */ if (File->UseSection[i] == 0) { /* Make it a bss section */ File->NewSectionHeaders[j].PointerToRawData = 0; File->NewSectionHeaders[j].SizeOfRawData = 0; File->NewSectionHeaders[j].Characteristics = 0xC0500080; } /* Fix Offset into File */ File->NewSectionHeaders[j].PointerToRawData = File->NewSectionHeaders[j].PointerToRawData ? CurrentPos : 0; CurrentPos += File->NewSectionHeaders[j].SizeOfRawData; j++; } if (File->eh_frame.idx == -1) { //fprintf(stderr, "No .eh_frame section found\n"); return 0; } return 1; } int main(int argc, char* argv[]) { char* pszInFile; char* pszOutFile; FILE_INFO File; FILE* outfile; int ret; int arg, argstate = 0; char *SourcePath = NULL; for (arg = 1; arg < argc; arg++) { switch (argstate) { default: argstate = -1; break; case 0: if (!strcmp(argv[arg], "-s")) { argstate = 1; } else { argstate = 2; pszInFile = convert_path(argv[arg]); } break; case 1: free(SourcePath); SourcePath = strdup(argv[arg]); argstate = 0; break; case 2: pszOutFile = convert_path(argv[arg]); argstate = 3; break; } } if (argstate != 3) { fprintf(stderr, "Usage: rsym [-s ] \n"); exit(1); } File.FilePtr = load_file(pszInFile, &File.cbInFileSize); if (!File.FilePtr) { fprintf(stderr, "An error occured loading '%s'\n", pszInFile); exit(1); } ret = ParsePEHeaders(&File); if (ret != 1) { free(File.FilePtr); exit(ret == -1 ? 1 : 0); } File.AlignBuf = malloc(File.OptionalHeader->FileAlignment); memset(File.AlignBuf, 0, File.OptionalHeader->FileAlignment); GeneratePData(&File); outfile = fopen(pszOutFile, "wb"); if (outfile == NULL) { perror("Cannot open output file"); free(File.FilePtr); exit(1); } WriteOutFile(outfile, &File); fclose(outfile); return 0; }