static int pe_assign_addresses(struct pe_info *pe) { int i, k, o, c; DWORD addr; int *section_order; struct section_info *si; struct section_info *merged_text; struct section_info *merged_data; Section *s; // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); for (o = k = 0 ; k < sec_last; ++k) { for (i = 1; i < pe->s1->nb_sections; ++i) { s = pe->s1->sections[i]; if (k == pe_section_class(s)) { s->sh_addr = pe->imagebase; section_order[o++] = i; } } } pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); addr = pe->imagebase + 1; merged_text = NULL; merged_data = NULL; for (i = 0; i < o; ++i) { k = section_order[i]; s = pe->s1->sections[k]; c = pe_section_class(s); si = &pe->sec_info[pe->sec_count]; #ifdef PE_MERGE_DATA if (c == sec_data && merged_data == NULL) { merged_data = si; } if (c == sec_bss && merged_data != NULL) { // Append .bss to .data s->sh_addr = addr = ((addr - 1) | 15) + 1; addr += s->data_offset; merged_data->sh_size = addr - merged_data->sh_addr; merged_data->last->next = s; merged_data->last = s; continue; } #endif if (c == sec_text) { if (s->unused) continue; if (merged_text) { merged_text->sh_size = align(merged_text->sh_size, s->sh_addralign); s->sh_addr = merged_text->sh_addr + merged_text->sh_size; merged_text->sh_size += s->data_offset; addr = merged_text->sh_addr + merged_text->sh_size; merged_text->last->next = s; merged_text->last = s; continue; } else { merged_text = si; } } strcpy(si->name, c == sec_text ? ".text" : s->name); si->cls = c; si->ord = k; si->sh_addr = s->sh_addr = addr = pe_virtual_align(addr); si->sh_flags = s->sh_flags; si->first = si->last = s; if (c == sec_data && pe->thunk == NULL) { pe->thunk = s; } if (s == pe->thunk) { pe_build_imports(pe); pe_build_exports(pe); } if (c == sec_reloc) { pe_build_reloc(pe); } if (s->data_offset) { si->sh_size = s->data_offset; addr += s->data_offset; pe->sec_count++; } } tcc_free(section_order); return 0; }
ST_FN int pe_assign_addresses (struct pe_info *pe) { int i, k, o, c; DWORD addr; int *section_order; struct section_info *si; Section *s; // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); for (o = k = 0 ; k < sec_last; ++k) { for (i = 1; i < pe->s1->nb_sections; ++i) { s = pe->s1->sections[i]; if (k == pe_section_class(s)) { // printf("%s %d\n", s->name, k); s->sh_addr = pe->imagebase; section_order[o++] = i; } } } pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); addr = pe->imagebase + 1; for (i = 0; i < o; ++i) { k = section_order[i]; s = pe->s1->sections[k]; c = pe_section_class(s); si = &pe->sec_info[pe->sec_count]; #ifdef PE_MERGE_DATA if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { /* append .bss to .data */ s->sh_addr = addr = ((addr-1) | 15) + 1; addr += s->data_offset; si[-1].sh_size = addr - si[-1].sh_addr; continue; } #endif strcpy(si->name, s->name); si->cls = c; si->ord = k; si->sh_addr = s->sh_addr = addr = pe_virtual_align(addr); si->sh_flags = s->sh_flags; if (c == sec_data && NULL == pe->thunk) pe->thunk = s; if (s == pe->thunk) { pe_build_imports(pe); pe_build_exports(pe); } if (c == sec_reloc) pe_build_reloc (pe); if (s->data_offset) { if (s->sh_type != SHT_NOBITS) { si->data = s->data; si->data_size = s->data_offset; } addr += s->data_offset; si->sh_size = s->data_offset; ++pe->sec_count; } // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name); } #if 0 for (i = 1; i < pe->s1->nb_sections; ++i) { Section *s = pe->s1->sections[i]; int type = s->sh_type; int flags = s->sh_flags; printf("section %-16s %-10s %5x %s,%s,%s\n", s->name, type == SHT_PROGBITS ? "progbits" : type == SHT_NOBITS ? "nobits" : type == SHT_SYMTAB ? "symtab" : type == SHT_STRTAB ? "strtab" : type == SHT_REL ? "rel" : "???", s->data_offset, flags & SHF_ALLOC ? "alloc" : "", flags & SHF_WRITE ? "write" : "", flags & SHF_EXECINSTR ? "exec" : "" ); } pe->s1->verbose = 2; #endif tcc_free(section_order); return 0; }
static int pe_write(struct pe_info *pe) { int i; int fd; FILE *op; FILE *stubfile; char *stub; int stub_size; DWORD file_offset, r; Section *s; if (pe->stub) { stubfile = fopen(pe->stub, "rb"); if (stubfile == NULL) { error_noabort("could not read '%s': %s", pe->stub, strerror(errno)); return 1; } fseek(stubfile, 0, SEEK_END); stub_size = ftell(stubfile); fseek(stubfile, 0, SEEK_SET); if (stub_size < sizeof(IMAGE_DOS_HEADER)) { error_noabort("invalid stub (%d bytes): %s", stub_size, pe->stub); return 1; } stub = tcc_malloc(stub_size); if (fread(stub, 1, stub_size, stubfile) != stub_size) { error_noabort("error reading stub '%s': %s", pe->stub, strerror(errno)); return 1; } fclose(stubfile); } else { stub_size = DOSSTUB_SIZE + sizeof(IMAGE_DOS_HEADER); stub = tcc_malloc(stub_size); memcpy(stub, &pe_doshdr, sizeof(IMAGE_DOS_HEADER)); memcpy(stub + sizeof(IMAGE_DOS_HEADER), pe_dosstub, DOSSTUB_SIZE); } ((PIMAGE_DOS_HEADER) stub)->e_lfanew = stub_size; fd = open(pe->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0777); if (fd < 0) { error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); return 1; } op = fdopen(fd, "wb"); pe->sizeofheaders = pe_file_align(pe, stub_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER) + pe->sec_count * sizeof (IMAGE_SECTION_HEADER)); file_offset = pe->sizeofheaders; pe_fpad(op, file_offset, 0); if (verbose == 2) { printf("------------------------------------\n virt file size ord section" "\n"); } for (i = 0; i < pe->sec_count; ++i) { struct section_info *si = pe->sec_info + i; const char *sh_name = si->name; unsigned long addr = si->sh_addr - pe->imagebase; unsigned long size = si->sh_size; IMAGE_SECTION_HEADER *psh = &si->ish; if (verbose == 2) { printf("%6lx %6lx %6lx %4d %s\n", addr, file_offset, size, si->ord, sh_name); } switch (si->cls) { case sec_text: pe_opthdr.BaseOfCode = addr; pe_opthdr.SizeOfCode += size; pe_opthdr.AddressOfEntryPoint = ((Elf32_Sym *) symtab_section->data)[pe->start_sym_index].st_value - pe->imagebase; break; case sec_data: pe_opthdr.BaseOfData = addr; pe_opthdr.SizeOfInitializedData += size; break; case sec_bss: pe_opthdr.SizeOfUninitializedData += size; break; case sec_reloc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); break; case sec_rsrc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); break; case sec_stab: break; } if (pe->thunk == pe->s1->sections[si->ord]) { if (pe->imp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT, pe->imp_offs + addr, pe->imp_size); pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT, pe->iat_offs + addr, pe->iat_size); } if (pe->exp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT, pe->exp_offs + addr, pe->exp_size); } } strcpy((char *) psh->Name, sh_name); psh->Characteristics = pe_sec_flags[si->cls]; psh->VirtualAddress = addr; psh->Misc.VirtualSize = size; pe_opthdr.SizeOfImage = umax(pe_virtual_align(size + addr), pe_opthdr.SizeOfImage); if (si->sh_size) { psh->PointerToRawData = r = file_offset; for (s = si->first; s; s = s->next) { if (s->sh_type != SHT_NOBITS) { file_offset = align(file_offset, s->sh_addralign); pe_fpad(op, file_offset, si->cls == sec_text ? 0x90 : 0x00); fwrite(s->data, 1, s->data_offset, op); file_offset += s->data_offset; } } file_offset = pe_file_align(pe, file_offset); psh->SizeOfRawData = file_offset - r; pe_fpad(op, file_offset, 0); } } pe_filehdr.TimeDateStamp = time(NULL); pe_filehdr.NumberOfSections = pe->sec_count; pe_filehdr.Characteristics = do_debug ? 0x0102 : 0x030E; pe_opthdr.SizeOfHeaders = pe->sizeofheaders; pe_opthdr.ImageBase = pe->imagebase; pe_opthdr.FileAlignment = pe->filealign; if (pe->type == PE_DLL) { pe_filehdr.Characteristics = do_debug ? 0x2102 : 0x230E; } else if (pe->type != PE_GUI) { pe_opthdr.Subsystem = 3; } if (!pe->reloc) pe_filehdr.Characteristics |= 1; if (pe->s1->noshare) pe_filehdr.Characteristics |= 0x4000; fseek(op, 0, SEEK_SET); fwrite(stub, 1, stub_size, op); fwrite(&pe_ntsig, 1, sizeof pe_ntsig, op); fwrite(&pe_filehdr, 1, sizeof pe_filehdr, op); fwrite(&pe_opthdr, 1, sizeof pe_opthdr, op); for (i = 0; i < pe->sec_count; ++i) { fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op); } fclose(op); if (verbose == 2) { printf("------------------------------------\n"); } if (verbose) { printf("<- %s (%lu bytes)\n", pe->filename, file_offset); } tcc_free(stub); return 0; }
/*----------------------------------------------------------------------------*/ ST_FN int pe_write(struct pe_info *pe) { int i; FILE *op; DWORD file_offset, r; op = fopen(pe->filename, "wb"); if (NULL == op) { error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); return 1; } pe->sizeofheaders = pe_file_align( sizeof pe_header + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) ); file_offset = pe->sizeofheaders; pe_fpad(op, file_offset); if (2 == pe->s1->verbose) printf("-------------------------------" "\n virt file size section" "\n"); for (i = 0; i < pe->sec_count; ++i) { struct section_info *si = pe->sec_info + i; const char *sh_name = si->name; unsigned long addr = si->sh_addr - pe->imagebase; unsigned long size = si->sh_size; IMAGE_SECTION_HEADER *psh = &si->ish; if (2 == pe->s1->verbose) printf("%6lx %6lx %6lx %s\n", addr, file_offset, size, sh_name); switch (si->cls) { case sec_text: pe_header.opthdr.BaseOfCode = addr; pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr; break; case sec_data: pe_header.opthdr.BaseOfData = addr; break; case sec_bss: break; case sec_reloc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); break; case sec_rsrc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); break; case sec_stab: break; } if (pe->thunk == pe->s1->sections[si->ord]) { if (pe->imp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT, pe->imp_offs + addr, pe->imp_size); pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT, pe->iat_offs + addr, pe->iat_size); } if (pe->exp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT, pe->exp_offs + addr, pe->exp_size); } } strcpy((char*)psh->Name, sh_name); psh->Characteristics = pe_sec_flags[si->cls]; psh->VirtualAddress = addr; psh->Misc.VirtualSize = size; pe_header.opthdr.SizeOfImage = umax(pe_virtual_align(size + addr), pe_header.opthdr.SizeOfImage); if (si->data_size) { psh->PointerToRawData = r = file_offset; fwrite(si->data, 1, si->data_size, op); file_offset = pe_file_align(file_offset + si->data_size); psh->SizeOfRawData = file_offset - r; pe_fpad(op, file_offset); } } // pe_header.filehdr.TimeDateStamp = time(NULL); pe_header.filehdr.NumberOfSections = pe->sec_count; pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; pe_header.opthdr.ImageBase = pe->imagebase; if (PE_DLL == pe->type) pe_header.filehdr.Characteristics = 0x230E; else if (PE_GUI != pe->type) pe_header.opthdr.Subsystem = 3; fseek(op, SEEK_SET, 0); fwrite(&pe_header, 1, sizeof pe_header, op); for (i = 0; i < pe->sec_count; ++i) fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op); fclose (op); if (2 == pe->s1->verbose) printf("-------------------------------\n"); if (pe->s1->verbose) printf("<- %s (%lu bytes)\n", pe->filename, file_offset); return 0; }