Added DLL imports on Windows
This commit is contained in:
parent
0e7c66e44f
commit
07bf488657
11
src/exe/pe/DLLImport.go
Normal file
11
src/exe/pe/DLLImport.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package pe
|
||||||
|
|
||||||
|
const DLLImportSize = 20
|
||||||
|
|
||||||
|
type DLLImport struct {
|
||||||
|
RvaFunctionNameList uint32
|
||||||
|
TimeDateStamp uint32
|
||||||
|
ForwarderChain uint32
|
||||||
|
RvaModuleName uint32
|
||||||
|
RvaFunctionAddressList uint32
|
||||||
|
}
|
@ -17,27 +17,73 @@ type EXE struct {
|
|||||||
Sections []SectionHeader
|
Sections []SectionHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DLL struct {
|
||||||
|
Name string
|
||||||
|
Functions []string
|
||||||
|
}
|
||||||
|
|
||||||
// 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 := 1
|
NumSections := 3
|
||||||
|
|
||||||
if len(data) != 0 {
|
|
||||||
NumSections += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||||
|
codeStart, codePadding := exe.Align(HeaderEnd, config.Align)
|
||||||
|
dataStart, dataPadding := exe.Align(codeStart+len(code), config.Align)
|
||||||
|
|
||||||
var (
|
dlls := []DLL{
|
||||||
codeStart, codePadding = exe.Align(HeaderEnd, config.Align)
|
{
|
||||||
dataStart, dataPadding = exe.Align(codeStart+len(code), config.Align)
|
Name: "kernel32.dll",
|
||||||
)
|
Functions: []string{
|
||||||
|
"ExitProcess",
|
||||||
imageSize := codeStart + len(code)
|
"GetStdHandle",
|
||||||
|
"WriteFile",
|
||||||
if len(data) != 0 {
|
},
|
||||||
imageSize = dataStart + len(data)
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dllAddresses := []uint64{}
|
||||||
|
dllImports := []DLLImport{}
|
||||||
|
|
||||||
|
dllName := len(data)
|
||||||
|
data = append(data, dlls[0].Name...)
|
||||||
|
data = append(data, 0x00)
|
||||||
|
|
||||||
|
for _, f := range dlls[0].Functions {
|
||||||
|
pos := len(data)
|
||||||
|
data = append(data, 0x00, 0x00)
|
||||||
|
data = append(data, f...)
|
||||||
|
data = append(data, 0x00)
|
||||||
|
|
||||||
|
if len(data)&1 != 0 {
|
||||||
|
data = append(data, 0x00) // align the next entry on an even boundary
|
||||||
|
}
|
||||||
|
|
||||||
|
dllAddresses = append(dllAddresses, uint64(dataStart+pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
dllImports = append(dllImports, DLLImport{
|
||||||
|
RvaFunctionNameList: uint32(iatblStart),
|
||||||
|
TimeDateStamp: 0,
|
||||||
|
ForwarderChain: 0,
|
||||||
|
RvaModuleName: uint32(dataStart + dllName),
|
||||||
|
RvaFunctionAddressList: uint32(iatblStart),
|
||||||
|
})
|
||||||
|
|
||||||
|
dllImports = append(dllImports, DLLImport{
|
||||||
|
RvaFunctionNameList: 0,
|
||||||
|
TimeDateStamp: 0,
|
||||||
|
ForwarderChain: 0,
|
||||||
|
RvaModuleName: 0, // must be zero
|
||||||
|
RvaFunctionAddressList: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
imageSize := iatblStart + iatblSize
|
||||||
imageSize, _ = exe.Align(imageSize, config.Align)
|
imageSize, _ = exe.Align(imageSize, config.Align)
|
||||||
|
|
||||||
pe := &EXE{
|
pe := &EXE{
|
||||||
@ -49,6 +95,9 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
Signature: [4]byte{'P', 'E', 0, 0},
|
Signature: [4]byte{'P', 'E', 0, 0},
|
||||||
Machine: IMAGE_FILE_MACHINE_AMD64,
|
Machine: IMAGE_FILE_MACHINE_AMD64,
|
||||||
NumberOfSections: uint16(NumSections),
|
NumberOfSections: uint16(NumSections),
|
||||||
|
TimeDateStamp: 0,
|
||||||
|
PointerToSymbolTable: 0,
|
||||||
|
NumberOfSymbols: 0,
|
||||||
SizeOfOptionalHeader: OptionalHeader64Size,
|
SizeOfOptionalHeader: OptionalHeader64Size,
|
||||||
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
Characteristics: IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE,
|
||||||
},
|
},
|
||||||
@ -57,24 +106,34 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
MajorLinkerVersion: 0x0E,
|
MajorLinkerVersion: 0x0E,
|
||||||
MinorLinkerVersion: 0x16,
|
MinorLinkerVersion: 0x16,
|
||||||
SizeOfCode: uint32(len(code)),
|
SizeOfCode: uint32(len(code)),
|
||||||
|
SizeOfInitializedData: 0,
|
||||||
|
SizeOfUninitializedData: 0,
|
||||||
AddressOfEntryPoint: config.CodeOffset,
|
AddressOfEntryPoint: config.CodeOffset,
|
||||||
BaseOfCode: config.CodeOffset,
|
BaseOfCode: config.CodeOffset,
|
||||||
ImageBase: config.BaseAddress,
|
ImageBase: config.BaseAddress,
|
||||||
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
|
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
|
||||||
FileAlignment: config.Align, // power of 2
|
FileAlignment: config.Align, // power of 2
|
||||||
MajorOperatingSystemVersion: 0x06,
|
MajorOperatingSystemVersion: 0x06,
|
||||||
|
MinorOperatingSystemVersion: 0,
|
||||||
|
MajorImageVersion: 0,
|
||||||
|
MinorImageVersion: 0,
|
||||||
MajorSubsystemVersion: 0x06,
|
MajorSubsystemVersion: 0x06,
|
||||||
|
MinorSubsystemVersion: 0,
|
||||||
|
Win32VersionValue: 0,
|
||||||
SizeOfImage: uint32(imageSize),
|
SizeOfImage: uint32(imageSize),
|
||||||
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
||||||
|
CheckSum: 0,
|
||||||
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI,
|
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI,
|
||||||
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
||||||
SizeOfStackReserve: 0x100000,
|
SizeOfStackReserve: 0x100000,
|
||||||
SizeOfStackCommit: 0x1000,
|
SizeOfStackCommit: 0x1000,
|
||||||
SizeOfHeapReserve: 0x100000,
|
SizeOfHeapReserve: 0x100000,
|
||||||
SizeOfHeapCommit: 0x1000,
|
SizeOfHeapCommit: 0x1000,
|
||||||
|
LoaderFlags: 0,
|
||||||
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: 0, Size: 0},
|
{VirtualAddress: 0, Size: 0},
|
||||||
{VirtualAddress: 0, Size: 0},
|
{VirtualAddress: 0, Size: 0},
|
||||||
{VirtualAddress: 0, Size: 0},
|
{VirtualAddress: 0, Size: 0},
|
||||||
@ -85,8 +144,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: 0, Size: 0},
|
{VirtualAddress: uint32(iatblStart), Size: uint32(iatblSize)}, // 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},
|
{VirtualAddress: 0, Size: 0},
|
||||||
@ -105,23 +163,31 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
|||||||
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
|
Name: [8]byte{'.', 'r', 'd', 'a', 't', 'a'},
|
||||||
VirtualSize: uint32(len(data)),
|
VirtualSize: uint32(len(data)),
|
||||||
VirtualAddress: uint32(dataStart),
|
VirtualAddress: uint32(dataStart),
|
||||||
RawSize: uint32(len(data)), // must be a multiple of FileAlignment
|
RawSize: uint32(len(data)),
|
||||||
RawAddress: uint32(dataStart), // must be a multiple of FileAlignment
|
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,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
|
binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
|
||||||
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
|
binary.Write(writer, binary.LittleEndian, &pe.OptionalHeader64)
|
||||||
binary.Write(writer, binary.LittleEndian, pe.Sections[:NumSections])
|
binary.Write(writer, binary.LittleEndian, &pe.Sections)
|
||||||
|
|
||||||
writer.Write(bytes.Repeat([]byte{0x00}, int(codePadding)))
|
writer.Write(bytes.Repeat([]byte{0x00}, int(codePadding)))
|
||||||
writer.Write(code)
|
writer.Write(code)
|
||||||
|
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||||
if len(data) != 0 {
|
writer.Write(data)
|
||||||
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
writer.Write(bytes.Repeat([]byte{0x00}, int(importPadding)))
|
||||||
writer.Write(data)
|
binary.Write(writer, binary.LittleEndian, &dllImports)
|
||||||
}
|
binary.Write(writer, binary.LittleEndian, &dllAddresses)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package pe
|
|
||||||
|
|
||||||
type ImportDirectory struct {
|
|
||||||
OriginalFirstThunk uint32
|
|
||||||
TimeDateStamp uint32
|
|
||||||
ForwarderChain uint32
|
|
||||||
Name uint32
|
|
||||||
FirstThunk uint32
|
|
||||||
}
|
|
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
Unlike Linux, Windows does not ignore zero-length sections and will fail loading them because they don't exist within the file.
|
Unlike Linux, Windows does not ignore zero-length sections at the end of a file and will
|
||||||
Adding a single byte to the section can fix this problem, but it's easier to just remove the section header entirely.
|
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.
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
|
- https://learn.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||||
- https://learn.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)
|
- https://learn.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)
|
||||||
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail
|
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/february/inside-windows-win32-portable-executable-file-format-in-detail
|
||||||
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
|
- https://learn.microsoft.com/en-us/archive/msdn-magazine/2002/march/inside-windows-an-in-depth-look-into-the-win32-portable-executable-file-format-part-2
|
||||||
|
Loading…
Reference in New Issue
Block a user