82d72daa76
git-svn-id: svn://kolibrios.org@7597 a494cfbc-eb01-0410-851d-a64ba20cac60
733 lines
24 KiB
Plaintext
733 lines
24 KiB
Plaintext
(*
|
|
BSD 2-Clause License
|
|
|
|
Copyright (c) 2018, 2019, Anton Krotov
|
|
All rights reserved.
|
|
*)
|
|
|
|
MODULE PE32;
|
|
|
|
IMPORT BIN, LISTS, UTILS, WR := WRITER, mConst := CONSTANTS, CHL := CHUNKLISTS;
|
|
|
|
|
|
CONST
|
|
|
|
SIZE_OF_DWORD = 4;
|
|
SIZE_OF_WORD = 2;
|
|
|
|
SIZE_OF_IMAGE_EXPORT_DIRECTORY = 40;
|
|
|
|
IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
|
|
|
|
IMAGE_SIZEOF_SHORT_NAME = 8;
|
|
|
|
SIZE_OF_IMAGE_FILE_HEADER* = 20;
|
|
|
|
SIZE_OF_IMAGE_SECTION_HEADER* = 40;
|
|
|
|
(* SectionHeader.Characteristics *)
|
|
|
|
SHC_text = 060000020H;
|
|
SHC_data = 0C0000040H;
|
|
SHC_bss = 0C00000C0H;
|
|
|
|
SectionAlignment = 1000H;
|
|
FileAlignment = 200H;
|
|
|
|
|
|
TYPE
|
|
|
|
WORD = WCHAR;
|
|
DWORD = INTEGER;
|
|
|
|
NAME* = ARRAY IMAGE_SIZEOF_SHORT_NAME OF CHAR;
|
|
|
|
|
|
IMAGE_DATA_DIRECTORY = RECORD
|
|
|
|
VirtualAddress: DWORD;
|
|
Size: DWORD
|
|
|
|
END;
|
|
|
|
|
|
IMAGE_OPTIONAL_HEADER = RECORD
|
|
|
|
Magic: WORD;
|
|
MajorLinkerVersion: BYTE;
|
|
MinorLinkerVersion: BYTE;
|
|
SizeOfCode: DWORD;
|
|
SizeOfInitializedData: DWORD;
|
|
SizeOfUninitializedData: DWORD;
|
|
AddressOfEntryPoint: DWORD;
|
|
BaseOfCode: DWORD;
|
|
BaseOfData: DWORD;
|
|
ImageBase: DWORD;
|
|
SectionAlignment: DWORD;
|
|
FileAlignment: DWORD;
|
|
MajorOperatingSystemVersion: WORD;
|
|
MinorOperatingSystemVersion: WORD;
|
|
MajorImageVersion: WORD;
|
|
MinorImageVersion: WORD;
|
|
MajorSubsystemVersion: WORD;
|
|
MinorSubsystemVersion: WORD;
|
|
Win32VersionValue: DWORD;
|
|
SizeOfImage: DWORD;
|
|
SizeOfHeaders: DWORD;
|
|
CheckSum: DWORD;
|
|
Subsystem: WORD;
|
|
DllCharacteristics: WORD;
|
|
SizeOfStackReserve: DWORD;
|
|
SizeOfStackCommit: DWORD;
|
|
SizeOfHeapReserve: DWORD;
|
|
SizeOfHeapCommit: DWORD;
|
|
LoaderFlags: DWORD;
|
|
NumberOfRvaAndSizes: DWORD;
|
|
|
|
DataDirectory: ARRAY IMAGE_NUMBEROF_DIRECTORY_ENTRIES OF IMAGE_DATA_DIRECTORY
|
|
|
|
END;
|
|
|
|
|
|
IMAGE_FILE_HEADER* = RECORD
|
|
|
|
Machine*: WORD;
|
|
NumberOfSections*: WORD;
|
|
TimeDateStamp*: DWORD;
|
|
PointerToSymbolTable*: DWORD;
|
|
NumberOfSymbols*: DWORD;
|
|
SizeOfOptionalHeader*: WORD;
|
|
Characteristics*: WORD
|
|
|
|
END;
|
|
|
|
|
|
IMAGE_NT_HEADERS = RECORD
|
|
|
|
Signature: ARRAY 4 OF BYTE;
|
|
FileHeader: IMAGE_FILE_HEADER;
|
|
OptionalHeader: IMAGE_OPTIONAL_HEADER
|
|
|
|
END;
|
|
|
|
|
|
IMAGE_SECTION_HEADER* = RECORD
|
|
|
|
Name*: NAME;
|
|
|
|
VirtualSize*,
|
|
VirtualAddress*,
|
|
SizeOfRawData*,
|
|
PointerToRawData*,
|
|
PointerToRelocations*,
|
|
PointerToLinenumbers*: DWORD;
|
|
|
|
NumberOfRelocations*,
|
|
NumberOfLinenumbers*: WORD;
|
|
|
|
Characteristics*: DWORD
|
|
|
|
END;
|
|
|
|
|
|
IMAGE_EXPORT_DIRECTORY = RECORD
|
|
|
|
Characteristics: DWORD;
|
|
TimeDateStamp: DWORD;
|
|
MajorVersion: WORD;
|
|
MinorVersion: WORD;
|
|
Name,
|
|
Base,
|
|
NumberOfFunctions,
|
|
NumberOfNames,
|
|
AddressOfFunctions,
|
|
AddressOfNames,
|
|
AddressOfNameOrdinals: DWORD
|
|
|
|
END;
|
|
|
|
|
|
VIRTUAL_ADDR = RECORD
|
|
|
|
Code, Data, Bss, Import: INTEGER
|
|
|
|
END;
|
|
|
|
|
|
FILE = WR.FILE;
|
|
|
|
|
|
VAR
|
|
|
|
msdos: ARRAY 128 OF BYTE;
|
|
PEHeader: IMAGE_NT_HEADERS;
|
|
SectionHeaders: ARRAY 16 OF IMAGE_SECTION_HEADER;
|
|
Relocations: LISTS.LIST;
|
|
bit64: BOOLEAN;
|
|
libcnt: INTEGER;
|
|
|
|
|
|
PROCEDURE SIZE (): INTEGER;
|
|
RETURN SIZE_OF_DWORD * (ORD(bit64) + 1)
|
|
END SIZE;
|
|
|
|
|
|
PROCEDURE Export (program: BIN.PROGRAM; DataRVA: INTEGER; VAR ExportDir: IMAGE_EXPORT_DIRECTORY): INTEGER;
|
|
BEGIN
|
|
|
|
ExportDir.Characteristics := 0;
|
|
ExportDir.TimeDateStamp := PEHeader.FileHeader.TimeDateStamp;
|
|
ExportDir.MajorVersion := 0X;
|
|
ExportDir.MinorVersion := 0X;
|
|
ExportDir.Name := program.modname + DataRVA;
|
|
ExportDir.Base := 0;
|
|
ExportDir.NumberOfFunctions := LISTS.count(program.exp_list);
|
|
ExportDir.NumberOfNames := ExportDir.NumberOfFunctions;
|
|
ExportDir.AddressOfFunctions := SIZE_OF_IMAGE_EXPORT_DIRECTORY;
|
|
ExportDir.AddressOfNames := ExportDir.AddressOfFunctions + ExportDir.NumberOfFunctions * SIZE_OF_DWORD;
|
|
ExportDir.AddressOfNameOrdinals := ExportDir.AddressOfNames + ExportDir.NumberOfFunctions * SIZE_OF_DWORD
|
|
|
|
RETURN SIZE_OF_IMAGE_EXPORT_DIRECTORY + ExportDir.NumberOfFunctions * (2 * SIZE_OF_DWORD + SIZE_OF_WORD)
|
|
END Export;
|
|
|
|
|
|
PROCEDURE align (n, _align: INTEGER): INTEGER;
|
|
BEGIN
|
|
IF n MOD _align # 0 THEN
|
|
n := n + _align - (n MOD _align)
|
|
END
|
|
|
|
RETURN n
|
|
END align;
|
|
|
|
|
|
PROCEDURE GetProcCount (lib: BIN.IMPRT): INTEGER;
|
|
VAR
|
|
import: BIN.IMPRT;
|
|
res: INTEGER;
|
|
|
|
BEGIN
|
|
res := 0;
|
|
import := lib.next(BIN.IMPRT);
|
|
WHILE (import # NIL) & (import.label # 0) DO
|
|
INC(res);
|
|
import := import.next(BIN.IMPRT)
|
|
END
|
|
|
|
RETURN res
|
|
END GetProcCount;
|
|
|
|
|
|
PROCEDURE GetImportSize (imp_list: LISTS.LIST): INTEGER;
|
|
VAR
|
|
import: BIN.IMPRT;
|
|
proccnt: INTEGER;
|
|
procoffs: INTEGER;
|
|
OriginalCurrentThunk,
|
|
CurrentThunk: INTEGER;
|
|
|
|
BEGIN
|
|
libcnt := 0;
|
|
proccnt := 0;
|
|
import := imp_list.first(BIN.IMPRT);
|
|
WHILE import # NIL DO
|
|
IF import.label = 0 THEN
|
|
INC(libcnt)
|
|
ELSE
|
|
INC(proccnt)
|
|
END;
|
|
import := import.next(BIN.IMPRT)
|
|
END;
|
|
|
|
procoffs := 0;
|
|
|
|
import := imp_list.first(BIN.IMPRT);
|
|
WHILE import # NIL DO
|
|
IF import.label = 0 THEN
|
|
import.OriginalFirstThunk := procoffs;
|
|
import.FirstThunk := procoffs + (GetProcCount(import) + 1);
|
|
OriginalCurrentThunk := import.OriginalFirstThunk;
|
|
CurrentThunk := import.FirstThunk;
|
|
procoffs := procoffs + (GetProcCount(import) + 1) * 2
|
|
ELSE
|
|
import.OriginalFirstThunk := OriginalCurrentThunk;
|
|
import.FirstThunk := CurrentThunk;
|
|
INC(OriginalCurrentThunk);
|
|
INC(CurrentThunk)
|
|
END;
|
|
import := import.next(BIN.IMPRT)
|
|
END
|
|
|
|
RETURN (libcnt + 1) * 5 * SIZE_OF_DWORD + (proccnt + libcnt) * 2 * SIZE()
|
|
END GetImportSize;
|
|
|
|
|
|
PROCEDURE fixup (program: BIN.PROGRAM; Address: VIRTUAL_ADDR);
|
|
VAR
|
|
reloc: BIN.RELOC;
|
|
iproc: BIN.IMPRT;
|
|
L: INTEGER;
|
|
delta: INTEGER;
|
|
AdrImp: INTEGER;
|
|
|
|
BEGIN
|
|
AdrImp := Address.Import + (libcnt + 1) * 5 * SIZE_OF_DWORD;
|
|
|
|
reloc := program.rel_list.first(BIN.RELOC);
|
|
WHILE reloc # NIL DO
|
|
|
|
L := BIN.get32le(program.code, reloc.offset);
|
|
delta := 3 - reloc.offset - Address.Code - 7 * ORD(bit64);
|
|
|
|
CASE reloc.opcode OF
|
|
|
|
|BIN.PICDATA:
|
|
BIN.put32le(program.code, reloc.offset, L + Address.Data + delta)
|
|
|
|
|BIN.PICCODE:
|
|
BIN.put32le(program.code, reloc.offset, BIN.GetLabel(program, L) + Address.Code + delta)
|
|
|
|
|BIN.PICBSS:
|
|
BIN.put32le(program.code, reloc.offset, L + Address.Bss + delta)
|
|
|
|
|BIN.PICIMP:
|
|
iproc := BIN.GetIProc(program, L);
|
|
BIN.put32le(program.code, reloc.offset, iproc.FirstThunk * SIZE() + AdrImp + delta)
|
|
|
|
END;
|
|
|
|
reloc := reloc.next(BIN.RELOC)
|
|
END
|
|
END fixup;
|
|
|
|
|
|
PROCEDURE WriteWord (file: FILE; w: WORD);
|
|
BEGIN
|
|
WR.Write16LE(file, ORD(w))
|
|
END WriteWord;
|
|
|
|
|
|
PROCEDURE WriteName* (File: FILE; name: NAME);
|
|
VAR
|
|
i, nameLen: INTEGER;
|
|
|
|
BEGIN
|
|
nameLen := LENGTH(name);
|
|
|
|
FOR i := 0 TO nameLen - 1 DO
|
|
WR.WriteByte(File, ORD(name[i]))
|
|
END;
|
|
|
|
i := LEN(name) - nameLen;
|
|
WHILE i > 0 DO
|
|
WR.WriteByte(File, 0);
|
|
DEC(i)
|
|
END
|
|
|
|
END WriteName;
|
|
|
|
|
|
PROCEDURE WriteSectionHeader* (file: FILE; h: IMAGE_SECTION_HEADER);
|
|
VAR
|
|
i, nameLen: INTEGER;
|
|
|
|
BEGIN
|
|
nameLen := LENGTH(h.Name);
|
|
|
|
FOR i := 0 TO nameLen - 1 DO
|
|
WR.WriteByte(file, ORD(h.Name[i]))
|
|
END;
|
|
|
|
i := LEN(h.Name) - nameLen;
|
|
WHILE i > 0 DO
|
|
WR.WriteByte(file, 0);
|
|
DEC(i)
|
|
END;
|
|
|
|
WR.Write32LE(file, h.VirtualSize);
|
|
WR.Write32LE(file, h.VirtualAddress);
|
|
WR.Write32LE(file, h.SizeOfRawData);
|
|
WR.Write32LE(file, h.PointerToRawData);
|
|
WR.Write32LE(file, h.PointerToRelocations);
|
|
WR.Write32LE(file, h.PointerToLinenumbers);
|
|
|
|
WriteWord(file, h.NumberOfRelocations);
|
|
WriteWord(file, h.NumberOfLinenumbers);
|
|
|
|
WR.Write32LE(file, h.Characteristics)
|
|
END WriteSectionHeader;
|
|
|
|
|
|
PROCEDURE WriteFileHeader* (file: FILE; h: IMAGE_FILE_HEADER);
|
|
BEGIN
|
|
WriteWord(file, h.Machine);
|
|
WriteWord(file, h.NumberOfSections);
|
|
|
|
WR.Write32LE(file, h.TimeDateStamp);
|
|
WR.Write32LE(file, h.PointerToSymbolTable);
|
|
WR.Write32LE(file, h.NumberOfSymbols);
|
|
|
|
WriteWord(file, h.SizeOfOptionalHeader);
|
|
WriteWord(file, h.Characteristics)
|
|
END WriteFileHeader;
|
|
|
|
|
|
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; BaseAddress: INTEGER; console, dll, amd64: BOOLEAN);
|
|
VAR
|
|
i, n: INTEGER;
|
|
|
|
Size: RECORD
|
|
|
|
Code, Data, Bss, Stack, Import, Reloc, Export: INTEGER
|
|
|
|
END;
|
|
|
|
Address: VIRTUAL_ADDR;
|
|
|
|
File: FILE;
|
|
|
|
import: BIN.IMPRT;
|
|
ImportTable: CHL.INTLIST;
|
|
|
|
ExportDir: IMAGE_EXPORT_DIRECTORY;
|
|
export: BIN.EXPRT;
|
|
|
|
|
|
PROCEDURE WriteExportDir (file: FILE; e: IMAGE_EXPORT_DIRECTORY);
|
|
BEGIN
|
|
WR.Write32LE(file, e.Characteristics);
|
|
WR.Write32LE(file, e.TimeDateStamp);
|
|
|
|
WriteWord(file, e.MajorVersion);
|
|
WriteWord(file, e.MinorVersion);
|
|
|
|
WR.Write32LE(file, e.Name);
|
|
WR.Write32LE(file, e.Base);
|
|
WR.Write32LE(file, e.NumberOfFunctions);
|
|
WR.Write32LE(file, e.NumberOfNames);
|
|
WR.Write32LE(file, e.AddressOfFunctions);
|
|
WR.Write32LE(file, e.AddressOfNames);
|
|
WR.Write32LE(file, e.AddressOfNameOrdinals)
|
|
END WriteExportDir;
|
|
|
|
|
|
PROCEDURE WriteOptHeader (file: FILE; h: IMAGE_OPTIONAL_HEADER);
|
|
VAR
|
|
i: INTEGER;
|
|
|
|
BEGIN
|
|
|
|
WriteWord(file, h.Magic);
|
|
|
|
WR.WriteByte(file, h.MajorLinkerVersion);
|
|
WR.WriteByte(file, h.MinorLinkerVersion);
|
|
|
|
WR.Write32LE(file, h.SizeOfCode);
|
|
WR.Write32LE(file, h.SizeOfInitializedData);
|
|
WR.Write32LE(file, h.SizeOfUninitializedData);
|
|
WR.Write32LE(file, h.AddressOfEntryPoint);
|
|
WR.Write32LE(file, h.BaseOfCode);
|
|
|
|
IF bit64 THEN
|
|
WR.Write64LE(file, h.ImageBase)
|
|
ELSE
|
|
WR.Write32LE(file, h.BaseOfData);
|
|
WR.Write32LE(file, h.ImageBase)
|
|
END;
|
|
|
|
WR.Write32LE(file, h.SectionAlignment);
|
|
WR.Write32LE(file, h.FileAlignment);
|
|
|
|
WriteWord(file, h.MajorOperatingSystemVersion);
|
|
WriteWord(file, h.MinorOperatingSystemVersion);
|
|
WriteWord(file, h.MajorImageVersion);
|
|
WriteWord(file, h.MinorImageVersion);
|
|
WriteWord(file, h.MajorSubsystemVersion);
|
|
WriteWord(file, h.MinorSubsystemVersion);
|
|
|
|
WR.Write32LE(file, h.Win32VersionValue);
|
|
WR.Write32LE(file, h.SizeOfImage);
|
|
WR.Write32LE(file, h.SizeOfHeaders);
|
|
WR.Write32LE(file, h.CheckSum);
|
|
|
|
WriteWord(file, h.Subsystem);
|
|
WriteWord(file, h.DllCharacteristics);
|
|
|
|
IF bit64 THEN
|
|
WR.Write64LE(file, h.SizeOfStackReserve);
|
|
WR.Write64LE(file, h.SizeOfStackCommit);
|
|
WR.Write64LE(file, h.SizeOfHeapReserve);
|
|
WR.Write64LE(file, h.SizeOfHeapCommit)
|
|
ELSE
|
|
WR.Write32LE(file, h.SizeOfStackReserve);
|
|
WR.Write32LE(file, h.SizeOfStackCommit);
|
|
WR.Write32LE(file, h.SizeOfHeapReserve);
|
|
WR.Write32LE(file, h.SizeOfHeapCommit)
|
|
END;
|
|
|
|
WR.Write32LE(file, h.LoaderFlags);
|
|
WR.Write32LE(file, h.NumberOfRvaAndSizes);
|
|
|
|
FOR i := 0 TO LEN(h.DataDirectory) - 1 DO
|
|
WR.Write32LE(file, h.DataDirectory[i].VirtualAddress);
|
|
WR.Write32LE(file, h.DataDirectory[i].Size)
|
|
END
|
|
|
|
END WriteOptHeader;
|
|
|
|
|
|
PROCEDURE WritePEHeader (file: FILE; h: IMAGE_NT_HEADERS);
|
|
BEGIN
|
|
WR.Write(file, h.Signature, LEN(h.Signature));
|
|
WriteFileHeader(file, h.FileHeader);
|
|
WriteOptHeader(file, h.OptionalHeader)
|
|
END WritePEHeader;
|
|
|
|
|
|
PROCEDURE InitSection (VAR section: IMAGE_SECTION_HEADER; Name: NAME; Characteristics: DWORD);
|
|
BEGIN
|
|
section.Name := Name;
|
|
section.PointerToRelocations := 0;
|
|
section.PointerToLinenumbers := 0;
|
|
section.NumberOfRelocations := 0X;
|
|
section.NumberOfLinenumbers := 0X;
|
|
section.Characteristics := Characteristics
|
|
END InitSection;
|
|
|
|
|
|
BEGIN
|
|
bit64 := amd64;
|
|
Relocations := LISTS.create(NIL);
|
|
|
|
Size.Code := CHL.Length(program.code);
|
|
Size.Data := CHL.Length(program.data);
|
|
Size.Bss := program.bss;
|
|
Size.Stack := program.stack;
|
|
|
|
PEHeader.Signature[0] := 50H;
|
|
PEHeader.Signature[1] := 45H;
|
|
PEHeader.Signature[2] := 0;
|
|
PEHeader.Signature[3] := 0;
|
|
|
|
IF amd64 THEN
|
|
PEHeader.FileHeader.Machine := 08664X
|
|
ELSE
|
|
PEHeader.FileHeader.Machine := 014CX
|
|
END;
|
|
|
|
PEHeader.FileHeader.NumberOfSections := WCHR(4 + ORD(dll));
|
|
|
|
PEHeader.FileHeader.TimeDateStamp := UTILS.UnixTime();
|
|
PEHeader.FileHeader.PointerToSymbolTable := 0H;
|
|
PEHeader.FileHeader.NumberOfSymbols := 0H;
|
|
PEHeader.FileHeader.SizeOfOptionalHeader := WCHR(0E0H + 10H * ORD(amd64));
|
|
PEHeader.FileHeader.Characteristics := WCHR(010EH + (20H - 100H) * ORD(amd64) + 2000H * ORD(dll));
|
|
|
|
PEHeader.OptionalHeader.Magic := WCHR(010BH + 100H * ORD(amd64));
|
|
PEHeader.OptionalHeader.MajorLinkerVersion := mConst.vMajor;
|
|
PEHeader.OptionalHeader.MinorLinkerVersion := mConst.vMinor;
|
|
PEHeader.OptionalHeader.SizeOfCode := align(Size.Code, FileAlignment);
|
|
PEHeader.OptionalHeader.SizeOfInitializedData := 0;
|
|
PEHeader.OptionalHeader.SizeOfUninitializedData := 0;
|
|
PEHeader.OptionalHeader.AddressOfEntryPoint := SectionAlignment;
|
|
PEHeader.OptionalHeader.BaseOfCode := SectionAlignment;
|
|
PEHeader.OptionalHeader.BaseOfData := PEHeader.OptionalHeader.BaseOfCode + align(Size.Code, SectionAlignment);
|
|
PEHeader.OptionalHeader.ImageBase := BaseAddress;
|
|
PEHeader.OptionalHeader.SectionAlignment := SectionAlignment;
|
|
PEHeader.OptionalHeader.FileAlignment := FileAlignment;
|
|
PEHeader.OptionalHeader.MajorOperatingSystemVersion := 1X;
|
|
PEHeader.OptionalHeader.MinorOperatingSystemVersion := 0X;
|
|
PEHeader.OptionalHeader.MajorImageVersion := 0X;
|
|
PEHeader.OptionalHeader.MinorImageVersion := 0X;
|
|
PEHeader.OptionalHeader.MajorSubsystemVersion := 4X;
|
|
PEHeader.OptionalHeader.MinorSubsystemVersion := 0X;
|
|
PEHeader.OptionalHeader.Win32VersionValue := 0H;
|
|
PEHeader.OptionalHeader.SizeOfImage := SectionAlignment;
|
|
PEHeader.OptionalHeader.SizeOfHeaders := 400H;
|
|
PEHeader.OptionalHeader.CheckSum := 0;
|
|
PEHeader.OptionalHeader.Subsystem := WCHR((2 + ORD(console)) * ORD(~dll));
|
|
PEHeader.OptionalHeader.DllCharacteristics := 0040X;
|
|
PEHeader.OptionalHeader.SizeOfStackReserve := Size.Stack;
|
|
PEHeader.OptionalHeader.SizeOfStackCommit := Size.Stack DIV 16;
|
|
PEHeader.OptionalHeader.SizeOfHeapReserve := 100000H;
|
|
PEHeader.OptionalHeader.SizeOfHeapCommit := 10000H;
|
|
PEHeader.OptionalHeader.LoaderFlags := 0;
|
|
PEHeader.OptionalHeader.NumberOfRvaAndSizes := IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
|
|
|
|
InitSection(SectionHeaders[0], ".text", SHC_text);
|
|
SectionHeaders[0].VirtualSize := Size.Code;
|
|
SectionHeaders[0].VirtualAddress := 1000H;
|
|
SectionHeaders[0].SizeOfRawData := align(Size.Code, FileAlignment);
|
|
SectionHeaders[0].PointerToRawData := PEHeader.OptionalHeader.SizeOfHeaders;
|
|
|
|
InitSection(SectionHeaders[1], ".data", SHC_data);
|
|
SectionHeaders[1].VirtualSize := Size.Data;
|
|
SectionHeaders[1].VirtualAddress := align(SectionHeaders[0].VirtualAddress + SectionHeaders[0].VirtualSize, SectionAlignment);
|
|
SectionHeaders[1].SizeOfRawData := align(Size.Data, FileAlignment);
|
|
SectionHeaders[1].PointerToRawData := SectionHeaders[0].PointerToRawData + SectionHeaders[0].SizeOfRawData;
|
|
|
|
InitSection(SectionHeaders[2], ".bss", SHC_bss);
|
|
SectionHeaders[2].VirtualSize := Size.Bss;
|
|
SectionHeaders[2].VirtualAddress := align(SectionHeaders[1].VirtualAddress + SectionHeaders[1].VirtualSize, SectionAlignment);
|
|
SectionHeaders[2].SizeOfRawData := 0;
|
|
SectionHeaders[2].PointerToRawData := SectionHeaders[1].PointerToRawData + SectionHeaders[1].SizeOfRawData;
|
|
|
|
Size.Import := GetImportSize(program.imp_list);
|
|
|
|
InitSection(SectionHeaders[3], ".idata", SHC_data);
|
|
SectionHeaders[3].VirtualSize := Size.Import + CHL.Length(program.import);
|
|
SectionHeaders[3].VirtualAddress := align(SectionHeaders[2].VirtualAddress + SectionHeaders[2].VirtualSize, SectionAlignment);
|
|
SectionHeaders[3].SizeOfRawData := align(SectionHeaders[3].VirtualSize, FileAlignment);
|
|
SectionHeaders[3].PointerToRawData := SectionHeaders[2].PointerToRawData + SectionHeaders[2].SizeOfRawData;
|
|
|
|
Address.Code := SectionHeaders[0].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
|
|
Address.Data := SectionHeaders[1].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
|
|
Address.Bss := SectionHeaders[2].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
|
|
Address.Import := SectionHeaders[3].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
|
|
|
|
fixup(program, Address);
|
|
|
|
IF dll THEN
|
|
Size.Export := Export(program, SectionHeaders[1].VirtualAddress, ExportDir);
|
|
|
|
InitSection(SectionHeaders[4], ".edata", SHC_data);
|
|
SectionHeaders[4].VirtualSize := Size.Export + CHL.Length(program.export);
|
|
SectionHeaders[4].VirtualAddress := align(SectionHeaders[3].VirtualAddress + SectionHeaders[3].VirtualSize, SectionAlignment);
|
|
SectionHeaders[4].SizeOfRawData := align(SectionHeaders[4].VirtualSize, FileAlignment);
|
|
SectionHeaders[4].PointerToRawData := SectionHeaders[3].PointerToRawData + SectionHeaders[3].SizeOfRawData;
|
|
END;
|
|
|
|
FOR i := 0 TO IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 DO
|
|
PEHeader.OptionalHeader.DataDirectory[i].VirtualAddress := 0;
|
|
PEHeader.OptionalHeader.DataDirectory[i].Size := 0
|
|
END;
|
|
|
|
IF dll THEN
|
|
PEHeader.OptionalHeader.DataDirectory[0].VirtualAddress := SectionHeaders[4].VirtualAddress;
|
|
PEHeader.OptionalHeader.DataDirectory[0].Size := SectionHeaders[4].VirtualSize
|
|
END;
|
|
|
|
PEHeader.OptionalHeader.DataDirectory[1].VirtualAddress := SectionHeaders[3].VirtualAddress;
|
|
PEHeader.OptionalHeader.DataDirectory[1].Size := SectionHeaders[3].VirtualSize;
|
|
|
|
FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
|
|
INC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[i].SizeOfRawData)
|
|
END;
|
|
|
|
DEC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[0].SizeOfRawData);
|
|
DEC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[2].SizeOfRawData);
|
|
|
|
PEHeader.OptionalHeader.SizeOfUninitializedData := align(SectionHeaders[2].VirtualSize, FileAlignment);
|
|
|
|
FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
|
|
INC(PEHeader.OptionalHeader.SizeOfImage, align(SectionHeaders[i].VirtualSize, SectionAlignment))
|
|
END;
|
|
|
|
n := 0;
|
|
BIN.InitArray(msdos, n, "4D5A80000100000004001000FFFF000040010000000000004000000000000000");
|
|
BIN.InitArray(msdos, n, "0000000000000000000000000000000000000000000000000000000080000000");
|
|
BIN.InitArray(msdos, n, "0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F");
|
|
BIN.InitArray(msdos, n, "742062652072756E20696E20444F53206D6F64652E0D0A240000000000000000");
|
|
|
|
File := WR.Create(FileName);
|
|
|
|
WR.Write(File, msdos, LEN(msdos));
|
|
|
|
WritePEHeader(File, PEHeader);
|
|
|
|
FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
|
|
WriteSectionHeader(File, SectionHeaders[i])
|
|
END;
|
|
|
|
WR.Padding(File, FileAlignment);
|
|
|
|
CHL.WriteToFile(File, program.code);
|
|
WR.Padding(File, FileAlignment);
|
|
|
|
CHL.WriteToFile(File, program.data);
|
|
WR.Padding(File, FileAlignment);
|
|
|
|
n := (libcnt + 1) * 5;
|
|
ImportTable := CHL.CreateIntList();
|
|
|
|
FOR i := 0 TO (Size.Import - n * SIZE_OF_DWORD) DIV SIZE() + n - 1 DO
|
|
CHL.PushInt(ImportTable, 0)
|
|
END;
|
|
|
|
i := 0;
|
|
import := program.imp_list.first(BIN.IMPRT);
|
|
WHILE import # NIL DO
|
|
IF import.label = 0 THEN
|
|
CHL.SetInt(ImportTable, i + 0, import.OriginalFirstThunk * SIZE() + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
|
|
CHL.SetInt(ImportTable, i + 1, 0);
|
|
CHL.SetInt(ImportTable, i + 2, 0);
|
|
CHL.SetInt(ImportTable, i + 3, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress);
|
|
CHL.SetInt(ImportTable, i + 4, import.FirstThunk * SIZE() + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
|
|
i := i + 5
|
|
END;
|
|
import := import.next(BIN.IMPRT)
|
|
END;
|
|
|
|
CHL.SetInt(ImportTable, i + 0, 0);
|
|
CHL.SetInt(ImportTable, i + 1, 0);
|
|
CHL.SetInt(ImportTable, i + 2, 0);
|
|
CHL.SetInt(ImportTable, i + 3, 0);
|
|
CHL.SetInt(ImportTable, i + 4, 0);
|
|
|
|
import := program.imp_list.first(BIN.IMPRT);
|
|
WHILE import # NIL DO
|
|
IF import.label # 0 THEN
|
|
CHL.SetInt(ImportTable, import.OriginalFirstThunk + n, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2);
|
|
CHL.SetInt(ImportTable, import.FirstThunk + n, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2)
|
|
END;
|
|
import := import.next(BIN.IMPRT)
|
|
END;
|
|
|
|
FOR i := 0 TO n - 1 DO
|
|
WR.Write32LE(File, CHL.GetInt(ImportTable, i))
|
|
END;
|
|
|
|
FOR i := n TO CHL.Length(ImportTable) - 1 DO
|
|
IF amd64 THEN
|
|
WR.Write64LE(File, CHL.GetInt(ImportTable, i))
|
|
ELSE
|
|
WR.Write32LE(File, CHL.GetInt(ImportTable, i))
|
|
END
|
|
END;
|
|
|
|
CHL.WriteToFile(File, program.import);
|
|
WR.Padding(File, FileAlignment);
|
|
|
|
IF dll THEN
|
|
|
|
INC(ExportDir.AddressOfFunctions, SectionHeaders[4].VirtualAddress);
|
|
INC(ExportDir.AddressOfNames, SectionHeaders[4].VirtualAddress);
|
|
INC(ExportDir.AddressOfNameOrdinals, SectionHeaders[4].VirtualAddress);
|
|
|
|
WriteExportDir(File, ExportDir);
|
|
|
|
export := program.exp_list.first(BIN.EXPRT);
|
|
WHILE export # NIL DO
|
|
WR.Write32LE(File, export.label + SectionHeaders[0].VirtualAddress);
|
|
export := export.next(BIN.EXPRT)
|
|
END;
|
|
|
|
export := program.exp_list.first(BIN.EXPRT);
|
|
WHILE export # NIL DO
|
|
WR.Write32LE(File, export.nameoffs + Size.Export + SectionHeaders[4].VirtualAddress);
|
|
export := export.next(BIN.EXPRT)
|
|
END;
|
|
|
|
FOR i := 0 TO ExportDir.NumberOfFunctions - 1 DO
|
|
WriteWord(File, WCHR(i))
|
|
END;
|
|
|
|
CHL.WriteToFile(File, program.export);
|
|
WR.Padding(File, FileAlignment)
|
|
END;
|
|
|
|
WR.Close(File)
|
|
END write;
|
|
|
|
|
|
END PE32. |