Reduced size of Windows executables
This commit is contained in:
parent
07bf488657
commit
141ec1158d
@ -24,7 +24,7 @@ type DLL struct {
|
||||
|
||||
// Write writes the EXE file to the given writer.
|
||||
func Write(writer io.Writer, code []byte, data []byte) {
|
||||
NumSections := 3
|
||||
NumSections := 2
|
||||
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||
codeStart, codePadding := exe.Align(HeaderEnd, config.Align)
|
||||
dataStart, dataPadding := exe.Align(codeStart+len(code), config.Align)
|
||||
@ -61,29 +61,36 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
}
|
||||
|
||||
dllAddresses = append(dllAddresses, 0)
|
||||
importStart, importPadding := exe.Align(dataStart+len(data), config.Align)
|
||||
itblSize := DLLImportSize*len(dlls) + DLLImportSize
|
||||
iatblSize := 8 * len(dllAddresses)
|
||||
itblStart := importStart
|
||||
iatblStart := itblStart + itblSize
|
||||
|
||||
// Add the address table to the data section
|
||||
functionAddressesStart := dataStart + len(data)
|
||||
functionAddressesSize := 8 * len(dllAddresses)
|
||||
data, err := binary.Append(data, binary.LittleEndian, &dllAddresses)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
dllImports = append(dllImports, DLLImport{
|
||||
RvaFunctionNameList: uint32(iatblStart),
|
||||
RvaFunctionNameList: uint32(functionAddressesStart),
|
||||
TimeDateStamp: 0,
|
||||
ForwarderChain: 0,
|
||||
RvaModuleName: uint32(dataStart + dllName),
|
||||
RvaFunctionAddressList: uint32(iatblStart),
|
||||
RvaFunctionAddressList: uint32(functionAddressesStart),
|
||||
})
|
||||
|
||||
dllImports = append(dllImports, DLLImport{
|
||||
RvaFunctionNameList: 0,
|
||||
TimeDateStamp: 0,
|
||||
ForwarderChain: 0,
|
||||
RvaModuleName: 0, // must be zero
|
||||
RvaFunctionAddressList: 0,
|
||||
})
|
||||
dllImports = append(dllImports, DLLImport{}) // a zeroed structure marks the end of the list
|
||||
|
||||
imageSize := iatblStart + iatblSize
|
||||
// Add imports to the data section
|
||||
importsStart := dataStart + len(data)
|
||||
importsSize := DLLImportSize * len(dllImports)
|
||||
data, err = binary.Append(data, binary.LittleEndian, &dllImports)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
imageSize := functionAddressesStart + functionAddressesSize
|
||||
imageSize, _ = exe.Align(imageSize, config.Align)
|
||||
|
||||
pe := &EXE{
|
||||
@ -102,7 +109,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
||||
},
|
||||
OptionalHeader64: OptionalHeader64{
|
||||
Magic: 0x020B, // PE32+ executable
|
||||
Magic: 0x020B, // PE32+ / 64-bit executable
|
||||
MajorLinkerVersion: 0x0E,
|
||||
MinorLinkerVersion: 0x16,
|
||||
SizeOfCode: uint32(len(code)),
|
||||
@ -133,7 +140,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
NumberOfRvaAndSizes: 16,
|
||||
DataDirectory: [16]DataDirectory{
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: uint32(itblStart), Size: uint32(itblSize)}, // RVA of the imported function table
|
||||
{VirtualAddress: uint32(importsStart), Size: uint32(importsSize)}, // RVA of the imported function table
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
@ -144,7 +151,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: uint32(iatblStart), Size: uint32(iatblSize)}, // RVA of the import address table
|
||||
{VirtualAddress: uint32(functionAddressesStart), Size: uint32(functionAddressesSize)}, // RVA of the import address table
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
{VirtualAddress: 0, Size: 0},
|
||||
@ -167,14 +174,6 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
RawAddress: uint32(dataStart),
|
||||
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
|
||||
},
|
||||
{
|
||||
Name: [8]byte{'.', 'i', 'd', 'a', 't', 'a'},
|
||||
VirtualSize: uint32(iatblSize + itblSize),
|
||||
VirtualAddress: uint32(importStart),
|
||||
RawSize: uint32(iatblSize + itblSize),
|
||||
RawAddress: uint32(importStart),
|
||||
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -187,7 +186,4 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
writer.Write(code)
|
||||
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||
writer.Write(data)
|
||||
writer.Write(bytes.Repeat([]byte{0x00}, int(importPadding)))
|
||||
binary.Write(writer, binary.LittleEndian, &dllImports)
|
||||
binary.Write(writer, binary.LittleEndian, &dllAddresses)
|
||||
}
|
||||
|
@ -5,6 +5,13 @@
|
||||
Unlike Linux, Windows does not ignore zero-length sections at the end of a file and will
|
||||
fail loading them because they don't exist within the file. Adding a single byte to the
|
||||
section can fix this problem, but it's easier to just remove the section header entirely.
|
||||
The solution used here is to guarantee that the data section is never empty by always
|
||||
importing a few core functions from "kernel32.dll".
|
||||
|
||||
## DLL function pointers
|
||||
|
||||
The section where the DLL function pointers are stored does not need to be marked as writable.
|
||||
The Windows executable loader resolves the pointers before they are loaded into memory.
|
||||
|
||||
## Links
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user