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
|
||||
}
|
||||
|
||||
type DLL struct {
|
||||
Name string
|
||||
Functions []string
|
||||
}
|
||||
|
||||
// Write writes the EXE file to the given writer.
|
||||
func Write(writer io.Writer, code []byte, data []byte) {
|
||||
NumSections := 1
|
||||
|
||||
if len(data) != 0 {
|
||||
NumSections += 1
|
||||
}
|
||||
|
||||
NumSections := 3
|
||||
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
|
||||
codeStart, codePadding := exe.Align(HeaderEnd, config.Align)
|
||||
dataStart, dataPadding := exe.Align(codeStart+len(code), config.Align)
|
||||
|
||||
var (
|
||||
codeStart, codePadding = exe.Align(HeaderEnd, config.Align)
|
||||
dataStart, dataPadding = exe.Align(codeStart+len(code), config.Align)
|
||||
)
|
||||
|
||||
imageSize := codeStart + len(code)
|
||||
|
||||
if len(data) != 0 {
|
||||
imageSize = dataStart + len(data)
|
||||
dlls := []DLL{
|
||||
{
|
||||
Name: "kernel32.dll",
|
||||
Functions: []string{
|
||||
"ExitProcess",
|
||||
"GetStdHandle",
|
||||
"WriteFile",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
pe := &EXE{
|
||||
@ -49,6 +95,9 @@ func Write(writer io.Writer, code []byte, data []byte) {
|
||||
Signature: [4]byte{'P', 'E', 0, 0},
|
||||
Machine: IMAGE_FILE_MACHINE_AMD64,
|
||||
NumberOfSections: uint16(NumSections),
|
||||
TimeDateStamp: 0,
|
||||
PointerToSymbolTable: 0,
|
||||
NumberOfSymbols: 0,
|
||||
SizeOfOptionalHeader: OptionalHeader64Size,
|
||||
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,
|
||||
MinorLinkerVersion: 0x16,
|
||||
SizeOfCode: uint32(len(code)),
|
||||
SizeOfInitializedData: 0,
|
||||
SizeOfUninitializedData: 0,
|
||||
AddressOfEntryPoint: config.CodeOffset,
|
||||
BaseOfCode: config.CodeOffset,
|
||||
ImageBase: config.BaseAddress,
|
||||
SectionAlignment: config.Align, // power of 2, must be greater than or equal to FileAlignment
|
||||
FileAlignment: config.Align, // power of 2
|
||||
MajorOperatingSystemVersion: 0x06,
|
||||
MinorOperatingSystemVersion: 0,
|
||||
MajorImageVersion: 0,
|
||||
MinorImageVersion: 0,
|
||||
MajorSubsystemVersion: 0x06,
|
||||
MinorSubsystemVersion: 0,
|
||||
Win32VersionValue: 0,
|
||||
SizeOfImage: uint32(imageSize),
|
||||
SizeOfHeaders: config.CodeOffset, // section bodies begin here
|
||||
CheckSum: 0,
|
||||
Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI,
|
||||
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE,
|
||||
SizeOfStackReserve: 0x100000,
|
||||
SizeOfStackCommit: 0x1000,
|
||||
SizeOfHeapReserve: 0x100000,
|
||||
SizeOfHeapCommit: 0x1000,
|
||||
LoaderFlags: 0,
|
||||
NumberOfRvaAndSizes: 16,
|
||||
DataDirectory: [16]DataDirectory{
|
||||
{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},
|
||||
@ -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: uint32(iatblStart), Size: uint32(iatblSize)}, // RVA of the import address table
|
||||
{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'},
|
||||
VirtualSize: uint32(len(data)),
|
||||
VirtualAddress: uint32(dataStart),
|
||||
RawSize: uint32(len(data)), // must be a multiple of FileAlignment
|
||||
RawAddress: uint32(dataStart), // must be a multiple of FileAlignment
|
||||
RawSize: uint32(len(data)),
|
||||
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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
binary.Write(writer, binary.LittleEndian, &pe.DOSHeader)
|
||||
binary.Write(writer, binary.LittleEndian, &pe.NTHeader)
|
||||
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(code)
|
||||
|
||||
if len(data) != 0 {
|
||||
writer.Write(bytes.Repeat([]byte{0x00}, int(dataPadding)))
|
||||
writer.Write(data)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
package pe
|
||||
|
||||
type ImportDirectory struct {
|
||||
OriginalFirstThunk uint32
|
||||
TimeDateStamp uint32
|
||||
ForwarderChain uint32
|
||||
Name uint32
|
||||
FirstThunk uint32
|
||||
}
|
@ -2,11 +2,13 @@
|
||||
|
||||
## Notes
|
||||
|
||||
Unlike Linux, Windows does not ignore zero-length sections 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.
|
||||
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.
|
||||
|
||||
## 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/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
|
||||
|
Loading…
Reference in New Issue
Block a user