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.
|
// Write writes the EXE file to the given writer.
|
||||||
func Write(writer io.Writer, code []byte, data []byte) {
|
func Write(writer io.Writer, code []byte, data []byte) {
|
||||||
NumSections := 3
|
NumSections := 2
|
||||||
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||||
codeStart, codePadding := exe.Align(HeaderEnd, config.Align)
|
codeStart, codePadding := exe.Align(HeaderEnd, config.Align)
|
||||||
dataStart, dataPadding := exe.Align(codeStart+len(code), 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)
|
dllAddresses = append(dllAddresses, 0)
|
||||||
importStart, importPadding := exe.Align(dataStart+len(data), config.Align)
|
|
||||||
itblSize := DLLImportSize*len(dlls) + DLLImportSize
|
// Add the address table to the data section
|
||||||
iatblSize := 8 * len(dllAddresses)
|
functionAddressesStart := dataStart + len(data)
|
||||||
itblStart := importStart
|
functionAddressesSize := 8 * len(dllAddresses)
|
||||||
iatblStart := itblStart + itblSize
|
data, err := binary.Append(data, binary.LittleEndian, &dllAddresses)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
dllImports = append(dllImports, DLLImport{
|
dllImports = append(dllImports, DLLImport{
|
||||||
RvaFunctionNameList: uint32(iatblStart),
|
RvaFunctionNameList: uint32(functionAddressesStart),
|
||||||
TimeDateStamp: 0,
|
TimeDateStamp: 0,
|
||||||
ForwarderChain: 0,
|
ForwarderChain: 0,
|
||||||
RvaModuleName: uint32(dataStart + dllName),
|
RvaModuleName: uint32(dataStart + dllName),
|
||||||
RvaFunctionAddressList: uint32(iatblStart),
|
RvaFunctionAddressList: uint32(functionAddressesStart),
|
||||||
})
|
})
|
||||||
|
|
||||||
dllImports = append(dllImports, DLLImport{
|
dllImports = append(dllImports, DLLImport{}) // a zeroed structure marks the end of the list
|
||||||
RvaFunctionNameList: 0,
|
|
||||||
TimeDateStamp: 0,
|
|
||||||
ForwarderChain: 0,
|
|
||||||
RvaModuleName: 0, // must be zero
|
|
||||||
RvaFunctionAddressList: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
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)
|
imageSize, _ = exe.Align(imageSize, config.Align)
|
||||||
|
|
||||||
pe := &EXE{
|
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,
|
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
||||||
},
|
},
|
||||||
OptionalHeader64: OptionalHeader64{
|
OptionalHeader64: OptionalHeader64{
|
||||||
Magic: 0x020B, // PE32+ executable
|
Magic: 0x020B, // PE32+ / 64-bit executable
|
||||||
MajorLinkerVersion: 0x0E,
|
MajorLinkerVersion: 0x0E,
|
||||||
MinorLinkerVersion: 0x16,
|
MinorLinkerVersion: 0x16,
|
||||||
SizeOfCode: uint32(len(code)),
|
SizeOfCode: uint32(len(code)),
|
||||||
@ -133,7 +140,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
NumberOfRvaAndSizes: 16,
|
NumberOfRvaAndSizes: 16,
|
||||||
DataDirectory: [16]DataDirectory{
|
DataDirectory: [16]DataDirectory{
|
||||||
{VirtualAddress: 0, Size: 0},
|
{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},
|
{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: 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},
|
{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),
|
RawAddress: uint32(dataStart),
|
||||||
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
|
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(code)
|
||||||
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||||
writer.Write(data)
|
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
|
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
|
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.
|
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
|
## Links
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user