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; }