Improved section offset calculation

This commit is contained in:
Eduard Urbach 2025-01-20 13:51:47 +01:00
parent e2a6a31d8e
commit 4b7c9f387d
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
7 changed files with 56 additions and 38 deletions

2
go.mod
View File

@ -7,4 +7,4 @@ require (
git.akyoto.dev/go/color v0.1.1 git.akyoto.dev/go/color v0.1.1
) )
require golang.org/x/sys v0.24.0 // indirect require golang.org/x/sys v0.29.0 // indirect

4
go.sum
View File

@ -2,5 +2,5 @@ git.akyoto.dev/go/assert v0.1.3 h1:QwCUbmG4aZYsNk/OuRBz1zWVKmGlDUHhOnnDBfn8Qw8=
git.akyoto.dev/go/assert v0.1.3/go.mod h1:0GzMaM0eURuDwtGkJJkCsI7r2aUKr+5GmWNTFPgDocM= git.akyoto.dev/go/assert v0.1.3/go.mod h1:0GzMaM0eURuDwtGkJJkCsI7r2aUKr+5GmWNTFPgDocM=
git.akyoto.dev/go/color v0.1.1 h1:mMAoMIwLBPNy7ocRSxdsCFs7onPC3GfDEiJErCneqRE= git.akyoto.dev/go/color v0.1.1 h1:mMAoMIwLBPNy7ocRSxdsCFs7onPC3GfDEiJErCneqRE=
git.akyoto.dev/go/color v0.1.1/go.mod h1:ywOjoD0O0sk6bIn92uAJf7mErlEFCuQInL84y4Lqi3Q= git.akyoto.dev/go/color v0.1.1/go.mod h1:ywOjoD0O0sk6bIn92uAJf7mErlEFCuQInL84y4Lqi3Q=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

View File

@ -8,7 +8,10 @@ import (
"git.akyoto.dev/cli/q/src/config" "git.akyoto.dev/cli/q/src/config"
"git.akyoto.dev/cli/q/src/dll" "git.akyoto.dev/cli/q/src/dll"
"git.akyoto.dev/cli/q/src/elf"
"git.akyoto.dev/cli/q/src/fs" "git.akyoto.dev/cli/q/src/fs"
"git.akyoto.dev/cli/q/src/macho"
"git.akyoto.dev/cli/q/src/pe"
"git.akyoto.dev/cli/q/src/sizeof" "git.akyoto.dev/cli/q/src/sizeof"
"git.akyoto.dev/cli/q/src/x64" "git.akyoto.dev/cli/q/src/x64"
) )
@ -370,21 +373,40 @@ restart:
} }
} }
headerEnd := Address(0)
switch config.TargetOS {
case "linux":
headerEnd = elf.HeaderEnd
case "macos":
headerEnd = macho.HeaderEnd
case "windows":
headerEnd = pe.HeaderEnd
}
codeStart, _ := fs.Align(headerEnd, config.Align)
dataStart, _ := fs.Align(codeStart+Address(len(code)), config.Align)
data, dataLabels = a.Data.Finalize() data, dataLabels = a.Data.Finalize()
dataStart := config.BaseAddress + config.CodeOffset + len(code)
dataStart, _ = fs.Align(dataStart, config.Align)
for _, pointer := range dataPointers { for _, pointer := range dataPointers {
address := Address(dataStart) + pointer.Resolve() address := config.BaseAddress + Address(dataStart) + pointer.Resolve()
slice := code[pointer.Position : pointer.Position+4] slice := code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(address)) binary.LittleEndian.PutUint32(slice, uint32(address))
} }
for _, pointer := range dllPointers { if config.TargetOS == "windows" {
destination := Address(0x3000) + pointer.Resolve() if len(data) == 0 {
address := destination - Address(config.CodeOffset+pointer.Position+Address(pointer.Size)) data = []byte{0}
slice := code[pointer.Position : pointer.Position+4] }
binary.LittleEndian.PutUint32(slice, uint32(address))
importsStart, _ := fs.Align(dataStart+Address(len(data)), config.Align)
for _, pointer := range dllPointers {
destination := Address(importsStart) + pointer.Resolve()
delta := destination - Address(codeStart+pointer.Position+Address(pointer.Size))
slice := code[pointer.Position : pointer.Position+4]
binary.LittleEndian.PutUint32(slice, uint32(delta))
}
} }
return code, data return code, data

View File

@ -9,11 +9,8 @@ const (
// The base address is the virtual address for our ELF file. // The base address is the virtual address for our ELF file.
BaseAddress = 0x40 * MinAddress BaseAddress = 0x40 * MinAddress
// Align decides the alignment of the sections and it must be a multiple of the page size. // Align is the alignment of the sections and it must be a multiple of the page size.
Align = 0x1000 Align = 0x1000
// The code offset is the offset of the executable machine code within the file.
CodeOffset = Align
) )
var ( var (

View File

@ -9,6 +9,8 @@ import (
"git.akyoto.dev/cli/q/src/fs" "git.akyoto.dev/cli/q/src/fs"
) )
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
// ELF represents an ELF file. // ELF represents an ELF file.
type ELF struct { type ELF struct {
Header Header
@ -18,8 +20,6 @@ type ELF struct {
// Write writes the ELF64 format to the given writer. // Write writes the ELF64 format to the given writer.
func Write(writer io.Writer, code []byte, data []byte) { func Write(writer io.Writer, code []byte, data []byte) {
const HeaderEnd = HeaderSize + ProgramHeaderSize*2
var ( var (
codeStart, codePadding = fs.Align(HeaderEnd, config.Align) codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
@ -36,7 +36,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
Type: TypeExecutable, Type: TypeExecutable,
Architecture: ArchitectureAMD64, Architecture: ArchitectureAMD64,
FileVersion: 1, FileVersion: 1,
EntryPointInMemory: config.BaseAddress + config.CodeOffset, EntryPointInMemory: int64(config.BaseAddress + codeStart),
ProgramHeaderOffset: HeaderSize, ProgramHeaderOffset: HeaderSize,
SectionHeaderOffset: 0, SectionHeaderOffset: 0,
Flags: 0, Flags: 0,
@ -50,9 +50,9 @@ func Write(writer io.Writer, code []byte, data []byte) {
CodeHeader: ProgramHeader{ CodeHeader: ProgramHeader{
Type: ProgramTypeLOAD, Type: ProgramTypeLOAD,
Flags: ProgramFlagsExecutable | ProgramFlagsReadable, Flags: ProgramFlagsExecutable | ProgramFlagsReadable,
Offset: config.CodeOffset, Offset: int64(codeStart),
VirtualAddress: config.BaseAddress + config.CodeOffset, VirtualAddress: int64(config.BaseAddress + codeStart),
PhysicalAddress: config.BaseAddress + config.CodeOffset, PhysicalAddress: int64(config.BaseAddress + codeStart),
SizeInFile: int64(len(code)), SizeInFile: int64(len(code)),
SizeInMemory: int64(len(code)), SizeInMemory: int64(len(code)),
Align: config.Align, Align: config.Align,

View File

@ -9,6 +9,11 @@ import (
"git.akyoto.dev/cli/q/src/fs" "git.akyoto.dev/cli/q/src/fs"
) )
const (
SizeCommands = Segment64Size*3 + ThreadSize
HeaderEnd = HeaderSize + SizeCommands
)
// MachO is the executable format used on MacOS. // MachO is the executable format used on MacOS.
type MachO struct { type MachO struct {
Header Header
@ -20,11 +25,6 @@ type MachO struct {
// Write writes the Mach-O format to the given writer. // Write writes the Mach-O format to the given writer.
func Write(writer io.Writer, code []byte, data []byte) { func Write(writer io.Writer, code []byte, data []byte) {
const (
SizeCommands = Segment64Size*3 + ThreadSize
HeaderEnd = HeaderSize + SizeCommands
)
var ( var (
codeStart, codePadding = fs.Align(HeaderEnd, config.Align) codeStart, codePadding = fs.Align(HeaderEnd, config.Align)
dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align) dataStart, dataPadding = fs.Align(codeStart+len(code), config.Align)
@ -102,7 +102,7 @@ func Write(writer io.Writer, code []byte, data []byte) {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
config.BaseAddress + config.CodeOffset, 0, uint32(config.BaseAddress + codeStart), 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,

View File

@ -10,6 +10,11 @@ import (
"git.akyoto.dev/cli/q/src/fs" "git.akyoto.dev/cli/q/src/fs"
) )
const (
NumSections = 3
HeaderEnd = DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
)
// EXE is the portable executable format used on Windows. // EXE is the portable executable format used on Windows.
type EXE struct { type EXE struct {
DOSHeader DOSHeader
@ -20,12 +25,6 @@ type EXE 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, dlls dll.List) { func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
if len(data) == 0 {
data = []byte{0}
}
NumSections := 3
HeaderEnd := DOSHeaderSize + NTHeaderSize + OptionalHeader64Size + SectionHeaderSize*NumSections
codeStart, codePadding := fs.Align(HeaderEnd, config.Align) codeStart, codePadding := fs.Align(HeaderEnd, config.Align)
dataStart, dataPadding := fs.Align(codeStart+len(code), config.Align) dataStart, dataPadding := fs.Align(codeStart+len(code), config.Align)
importsStart, importsPadding := fs.Align(dataStart+len(data), config.Align) importsStart, importsPadding := fs.Align(dataStart+len(data), config.Align)
@ -115,8 +114,8 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
SizeOfCode: uint32(len(code)), SizeOfCode: uint32(len(code)),
SizeOfInitializedData: 0, SizeOfInitializedData: 0,
SizeOfUninitializedData: 0, SizeOfUninitializedData: 0,
AddressOfEntryPoint: config.CodeOffset, AddressOfEntryPoint: uint32(codeStart),
BaseOfCode: config.CodeOffset, BaseOfCode: uint32(codeStart),
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
@ -128,7 +127,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
MinorSubsystemVersion: 0, MinorSubsystemVersion: 0,
Win32VersionValue: 0, Win32VersionValue: 0,
SizeOfImage: uint32(imageSize), SizeOfImage: uint32(imageSize),
SizeOfHeaders: config.CodeOffset, // section bodies begin here SizeOfHeaders: uint32(codeStart), // section bodies begin here
CheckSum: 0, CheckSum: 0,
Subsystem: uint16(subSystem), Subsystem: uint16(subSystem),
DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
@ -161,9 +160,9 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
{ {
Name: [8]byte{'.', 't', 'e', 'x', 't'}, Name: [8]byte{'.', 't', 'e', 'x', 't'},
VirtualSize: uint32(len(code)), VirtualSize: uint32(len(code)),
VirtualAddress: config.CodeOffset, VirtualAddress: uint32(codeStart),
RawSize: uint32(len(code)), // must be a multiple of FileAlignment RawSize: uint32(len(code)), // must be a multiple of FileAlignment
RawAddress: config.CodeOffset, // must be a multiple of FileAlignment RawAddress: uint32(codeStart), // must be a multiple of FileAlignment
Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ, Characteristics: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ,
}, },
{ {