Improved Windows support
This commit is contained in:
parent
3fa3ff9227
commit
0db54ff639
@ -8,12 +8,13 @@ import (
|
|||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/arch/x64"
|
"git.akyoto.dev/cli/q/src/arch/x64"
|
||||||
"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/exe"
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
"git.akyoto.dev/cli/q/src/sizeof"
|
"git.akyoto.dev/cli/q/src/sizeof"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Finalize generates the final machine code.
|
// Finalize generates the final machine code.
|
||||||
func (a Assembler) Finalize() ([]byte, []byte) {
|
func (a Assembler) Finalize(dlls dll.List) ([]byte, []byte) {
|
||||||
var (
|
var (
|
||||||
code = make([]byte, 0, len(a.Instructions)*8)
|
code = make([]byte, 0, len(a.Instructions)*8)
|
||||||
data []byte
|
data []byte
|
||||||
@ -21,6 +22,7 @@ func (a Assembler) Finalize() ([]byte, []byte) {
|
|||||||
dataLabels map[string]Address
|
dataLabels map[string]Address
|
||||||
codePointers []*Pointer
|
codePointers []*Pointer
|
||||||
dataPointers []*Pointer
|
dataPointers []*Pointer
|
||||||
|
dllPointers []*Pointer
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, x := range a.Instructions {
|
for _, x := range a.Instructions {
|
||||||
@ -114,7 +116,7 @@ func (a Assembler) Finalize() ([]byte, []byte) {
|
|||||||
case CALL_AT:
|
case CALL_AT:
|
||||||
code = x64.CallAtAddress(code, 0x00_00_00_00)
|
code = x64.CallAtAddress(code, 0x00_00_00_00)
|
||||||
size := 4
|
size := 4
|
||||||
// label := x.Data.(*Label)
|
label := x.Data.(*Label)
|
||||||
|
|
||||||
pointer := &Pointer{
|
pointer := &Pointer{
|
||||||
Position: Address(len(code) - size),
|
Position: Address(len(code) - size),
|
||||||
@ -123,12 +125,11 @@ func (a Assembler) Finalize() ([]byte, []byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pointer.Resolve = func() Address {
|
pointer.Resolve = func() Address {
|
||||||
destination := Address(0x1038)
|
index := dlls.Index("kernel32.dll", label.Name)
|
||||||
distance := destination - (pointer.Position + Address(pointer.Size))
|
return Address(index * 8)
|
||||||
return Address(distance)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
codePointers = append(codePointers, pointer)
|
dllPointers = append(dllPointers, pointer)
|
||||||
|
|
||||||
case COMMENT:
|
case COMMENT:
|
||||||
continue
|
continue
|
||||||
@ -365,5 +366,12 @@ restart:
|
|||||||
binary.LittleEndian.PutUint32(slice, uint32(address))
|
binary.LittleEndian.PutUint32(slice, uint32(address))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, pointer := range dllPointers {
|
||||||
|
destination := Address(0x3000) + pointer.Resolve()
|
||||||
|
address := destination - Address(config.CodeOffset+pointer.Position+Address(pointer.Size))
|
||||||
|
slice := code[pointer.Position : pointer.Position+4]
|
||||||
|
binary.LittleEndian.PutUint32(slice, uint32(address))
|
||||||
|
}
|
||||||
|
|
||||||
return code, data
|
return code, data
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (r *Result) finalize() ([]byte, []byte) {
|
|||||||
final.Label(asm.CALL_AT, "ExitProcess")
|
final.Label(asm.CALL_AT, "ExitProcess")
|
||||||
}
|
}
|
||||||
|
|
||||||
code, data := final.Finalize()
|
code, data := final.Finalize(windows.DLLs)
|
||||||
return code, data
|
return code, data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,24 +154,7 @@ func write(writer io.Writer, code []byte, data []byte) error {
|
|||||||
case "mac":
|
case "mac":
|
||||||
macho.Write(buffer, code, data)
|
macho.Write(buffer, code, data)
|
||||||
case "windows":
|
case "windows":
|
||||||
dlls := []pe.DLL{
|
pe.Write(buffer, code, data, windows.DLLs)
|
||||||
{
|
|
||||||
Name: "kernel32.dll",
|
|
||||||
Functions: []string{
|
|
||||||
"ExitProcess",
|
|
||||||
"GetStdHandle",
|
|
||||||
"WriteFile",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "user32.dll",
|
|
||||||
Functions: []string{
|
|
||||||
"MessageBoxA",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
pe.Write(buffer, code, data, dlls)
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported platform '%s'", config.TargetOS)
|
return fmt.Errorf("unsupported platform '%s'", config.TargetOS)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package pe
|
package dll
|
||||||
|
|
||||||
type DLL struct {
|
type DLL struct {
|
||||||
Name string
|
Name string
|
24
src/dll/List.go
Normal file
24
src/dll/List.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package dll
|
||||||
|
|
||||||
|
// List is a slice of DLLs.
|
||||||
|
type List []DLL
|
||||||
|
|
||||||
|
// Index returns the position of the given function name.
|
||||||
|
func (list List) Index(dllName string, funcName string) int {
|
||||||
|
index := 0
|
||||||
|
|
||||||
|
for _, dll := range list {
|
||||||
|
if dll.Name != dllName {
|
||||||
|
index += len(dll.Functions) + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, fn := range dll.Functions {
|
||||||
|
if fn == funcName {
|
||||||
|
return index + i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1
|
||||||
|
}
|
@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"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/exe"
|
"git.akyoto.dev/cli/q/src/exe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,56 +19,71 @@ 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) {
|
func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) {
|
||||||
NumSections := 2
|
if len(data) == 0 {
|
||||||
|
data = []byte{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumSections := 3
|
||||||
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)
|
||||||
|
importsStart, importsPadding := exe.Align(dataStart+len(data), config.Align)
|
||||||
|
|
||||||
|
imports := make([]uint64, 0)
|
||||||
|
dllData := make([]byte, 0)
|
||||||
dllImports := []DLLImport{}
|
dllImports := []DLLImport{}
|
||||||
|
|
||||||
for _, dll := range dlls {
|
for _, library := range dlls {
|
||||||
dllAddresses := []uint64{}
|
functionsStart := len(imports) * 8
|
||||||
dllNamePos := len(data)
|
dllNamePos := len(dllData)
|
||||||
data = append(data, dll.Name...)
|
dllData = append(dllData, library.Name...)
|
||||||
data = append(data, 0x00)
|
dllData = append(dllData, 0x00)
|
||||||
|
|
||||||
for _, f := range dll.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)
|
|
||||||
|
|
||||||
// Add the address table to the data section
|
|
||||||
functionAddressesStart := dataStart + len(data)
|
|
||||||
data, _ = binary.Append(data, binary.LittleEndian, &dllAddresses)
|
|
||||||
|
|
||||||
dllImports = append(dllImports, DLLImport{
|
dllImports = append(dllImports, DLLImport{
|
||||||
RvaFunctionNameList: uint32(functionAddressesStart),
|
RvaFunctionNameList: uint32(importsStart + functionsStart),
|
||||||
TimeDateStamp: 0,
|
TimeDateStamp: 0,
|
||||||
ForwarderChain: 0,
|
ForwarderChain: 0,
|
||||||
RvaModuleName: uint32(dataStart + dllNamePos),
|
RvaModuleName: uint32(dllNamePos),
|
||||||
RvaFunctionAddressList: uint32(functionAddressesStart),
|
RvaFunctionAddressList: uint32(importsStart + functionsStart),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
for _, fn := range library.Functions {
|
||||||
|
if len(dllData)&1 != 0 {
|
||||||
|
dllData = append(dllData, 0x00) // align the next entry on an even boundary
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := len(dllData)
|
||||||
|
dllData = append(dllData, 0x00, 0x00)
|
||||||
|
dllData = append(dllData, fn...)
|
||||||
|
dllData = append(dllData, 0x00)
|
||||||
|
|
||||||
|
imports = append(imports, uint64(offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
imports = append(imports, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
dllDataStart := importsStart + len(imports)*8
|
||||||
|
|
||||||
|
for i := range imports {
|
||||||
|
if imports[i] == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
imports[i] += uint64(dllDataStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range dllImports {
|
||||||
|
dllImports[i].RvaModuleName += uint32(dllDataStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
dllImports = append(dllImports, DLLImport{}) // a zeroed structure marks the end of the list
|
dllImports = append(dllImports, DLLImport{}) // a zeroed structure marks the end of the list
|
||||||
|
importDirectoryStart := dllDataStart + len(dllData)
|
||||||
|
importDirectorySize := DLLImportSize * len(dllImports)
|
||||||
|
|
||||||
// Add imports to the data section
|
importSectionSize := len(imports)*8 + len(dllData) + importDirectorySize
|
||||||
importsStart := dataStart + len(data)
|
imageSize := importsStart + importSectionSize
|
||||||
importsSize := DLLImportSize * len(dllImports)
|
|
||||||
data, _ = binary.Append(data, binary.LittleEndian, &dllImports)
|
|
||||||
|
|
||||||
imageSize := dataStart + len(data)
|
|
||||||
imageSize, _ = exe.Align(imageSize, config.Align)
|
imageSize, _ = exe.Align(imageSize, config.Align)
|
||||||
|
|
||||||
pe := &EXE{
|
pe := &EXE{
|
||||||
@ -117,8 +133,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls []DLL) {
|
|||||||
NumberOfRvaAndSizes: 16,
|
NumberOfRvaAndSizes: 16,
|
||||||
DataDirectory: [16]DataDirectory{
|
DataDirectory: [16]DataDirectory{
|
||||||
{VirtualAddress: 0, Size: 0},
|
{VirtualAddress: 0, Size: 0},
|
||||||
{VirtualAddress: uint32(importsStart), Size: uint32(importsSize)}, // RVA of the imported function table
|
{VirtualAddress: uint32(importDirectoryStart), Size: uint32(importDirectorySize)}, // 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},
|
{VirtualAddress: 0, Size: 0},
|
||||||
@ -129,6 +144,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls []DLL) {
|
|||||||
{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(importsStart), Size: uint32(len(imports) * 8)}, // 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},
|
||||||
@ -151,6 +167,14 @@ func Write(writer io.Writer, code []byte, data []byte, dlls []DLL) {
|
|||||||
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(importSectionSize),
|
||||||
|
VirtualAddress: uint32(importsStart),
|
||||||
|
RawSize: uint32(importSectionSize),
|
||||||
|
RawAddress: uint32(importsStart),
|
||||||
|
Characteristics: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,4 +187,8 @@ func Write(writer io.Writer, code []byte, data []byte, dlls []DLL) {
|
|||||||
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(importsPadding)))
|
||||||
|
binary.Write(writer, binary.LittleEndian, &imports)
|
||||||
|
binary.Write(writer, binary.LittleEndian, &dllData)
|
||||||
|
binary.Write(writer, binary.LittleEndian, &dllImports)
|
||||||
}
|
}
|
||||||
|
21
src/os/windows/DLLs.go
Normal file
21
src/os/windows/DLLs.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package windows
|
||||||
|
|
||||||
|
import "git.akyoto.dev/cli/q/src/dll"
|
||||||
|
|
||||||
|
// Temporary fix...
|
||||||
|
var DLLs = dll.List{
|
||||||
|
{
|
||||||
|
Name: "kernel32.dll",
|
||||||
|
Functions: []string{
|
||||||
|
"ExitProcess",
|
||||||
|
"GetStdHandle",
|
||||||
|
"WriteFile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "user32.dll",
|
||||||
|
Functions: []string{
|
||||||
|
"MessageBoxA",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user