From 6b48ee0a48516003bbe67cd2d5d3bf760dfec545 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Mon, 19 Aug 2024 17:25:51 +0200 Subject: [PATCH] Improved Windows support --- examples/winapi/winapi.q | 10 ++++++++++ lib/mem/alloc_windows.q | 5 +++++ lib/sys/sys_windows.q | 4 ++++ src/arch/x64/AlignStack.go | 6 ++++++ src/asm/Finalize.go | 6 ++++-- src/compiler/Result.go | 4 +--- src/dll/List.go | 15 +++++++++++++-- src/exe/pe/EXE.go | 8 +++++++- 8 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 examples/winapi/winapi.q create mode 100644 lib/mem/alloc_windows.q create mode 100644 src/arch/x64/AlignStack.go diff --git a/examples/winapi/winapi.q b/examples/winapi/winapi.q new file mode 100644 index 0000000..e232a1b --- /dev/null +++ b/examples/winapi/winapi.q @@ -0,0 +1,10 @@ +import mem + +main() { + text := mem.alloc(4) + text[0] = 'H' + text[1] = 'i' + text[2] = '!' + user32.MessageBoxA(0, text, text, 0x00240040) + mem.free(text, 4) +} \ No newline at end of file diff --git a/lib/mem/alloc_windows.q b/lib/mem/alloc_windows.q new file mode 100644 index 0000000..a6fafde --- /dev/null +++ b/lib/mem/alloc_windows.q @@ -0,0 +1,5 @@ +import sys + +alloc(length Int) -> Pointer { + return sys.mmap(0, length, 0x0004, 0x3000) +} \ No newline at end of file diff --git a/lib/sys/sys_windows.q b/lib/sys/sys_windows.q index 0ebf0a6..3c9c82f 100644 --- a/lib/sys/sys_windows.q +++ b/lib/sys/sys_windows.q @@ -8,6 +8,10 @@ mmap(address Int, length Int, protection Int, flags Int) -> Pointer { return kernel32.VirtualAlloc(address, length, flags, protection) } +munmap(address Pointer, length Int) -> Int { + return kernel32.VirtualFree(address, length, 0x4000) +} + exit(code Int) { kernel32.ExitProcess(code) } \ No newline at end of file diff --git a/src/arch/x64/AlignStack.go b/src/arch/x64/AlignStack.go new file mode 100644 index 0000000..d3199e1 --- /dev/null +++ b/src/arch/x64/AlignStack.go @@ -0,0 +1,6 @@ +package x64 + +// AlignStack aligns RSP on a 16-byte boundary. +func AlignStack(code []byte) []byte { + return append(code, 0x48, 0x83, 0xE4, 0xF0) +} diff --git a/src/asm/Finalize.go b/src/asm/Finalize.go index 676eaba..492f722 100644 --- a/src/asm/Finalize.go +++ b/src/asm/Finalize.go @@ -126,11 +126,13 @@ func (a Assembler) Finalize(dlls dll.List) ([]byte, []byte) { case DLLCALL: size := 4 - + // TODO: R15 could be in use. + code = x64.MoveRegisterRegister(code, x64.R15, x64.RSP) + code = x64.AlignStack(code) code = x64.SubRegisterNumber(code, x64.RSP, 32) code = x64.CallAtAddress(code, 0x00_00_00_00) position := len(code) - size - code = x64.AddRegisterNumber(code, x64.RSP, 32) + code = x64.MoveRegisterRegister(code, x64.RSP, x64.R15) label := x.Data.(*Label) pointer := &Pointer{ diff --git a/src/compiler/Result.go b/src/compiler/Result.go index ee73c1c..121d55a 100644 --- a/src/compiler/Result.go +++ b/src/compiler/Result.go @@ -50,7 +50,6 @@ func (r *Result) finalize() ([]byte, []byte, dll.List) { final.RegisterNumber(asm.MOVE, x64.SyscallInputRegisters[1], 0) final.Syscall() case "windows": - final.RegisterNumber(asm.SUB, x64.RSP, 8) final.RegisterNumber(asm.MOVE, windows.X64InputRegisters[0], 0) final.DLLCall("kernel32.ExitProcess") } @@ -83,9 +82,8 @@ func (r *Result) finalize() ([]byte, []byte, dll.List) { final.RegisterNumber(asm.MOVE, x64.SyscallInputRegisters[1], 1) final.Syscall() case "windows": - final.RegisterNumber(asm.SUB, x64.RSP, 8) final.RegisterNumber(asm.MOVE, windows.X64InputRegisters[0], 1) - final.Label(asm.DLLCALL, "kernel32.ExitProcess") + final.DLLCall("kernel32.ExitProcess") } code, data := final.Finalize(dlls) diff --git a/src/dll/List.go b/src/dll/List.go index 236de5f..8b3c3bb 100644 --- a/src/dll/List.go +++ b/src/dll/List.go @@ -5,7 +5,7 @@ type List []DLL // Append adds a function for the given DLL if it doesn't exist yet. func (list List) Append(dllName string, funcName string) List { - for _, dll := range list { + for i, dll := range list { if dll.Name != dllName { continue } @@ -16,13 +16,24 @@ func (list List) Append(dllName string, funcName string) List { } } - dll.Functions = append(dll.Functions, funcName) + list[i].Functions = append(list[i].Functions, funcName) return list } return append(list, DLL{Name: dllName, Functions: []string{funcName}}) } +// Contains returns true if the library exists. +func (list List) Contains(dllName string) bool { + for _, dll := range list { + if dll.Name == dllName { + return true + } + } + + return false +} + // Index returns the position of the given function name. func (list List) Index(dllName string, funcName string) int { index := 0 diff --git a/src/exe/pe/EXE.go b/src/exe/pe/EXE.go index 726fcc4..676f5f0 100644 --- a/src/exe/pe/EXE.go +++ b/src/exe/pe/EXE.go @@ -31,6 +31,12 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { dataStart, dataPadding := exe.Align(codeStart+len(code), config.Align) importsStart, importsPadding := exe.Align(dataStart+len(data), config.Align) + subSystem := IMAGE_SUBSYSTEM_WINDOWS_CUI + + if dlls.Contains("user32") { + subSystem = IMAGE_SUBSYSTEM_WINDOWS_GUI + } + imports := make([]uint64, 0) dllData := make([]byte, 0) dllImports := []DLLImport{} @@ -125,7 +131,7 @@ func Write(writer io.Writer, code []byte, data []byte, dlls dll.List) { SizeOfImage: uint32(imageSize), SizeOfHeaders: config.CodeOffset, // section bodies begin here CheckSum: 0, - Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI, + Subsystem: uint16(subSystem), DllCharacteristics: IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, // IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE SizeOfStackReserve: 0x100000, SizeOfStackCommit: 0x1000,