-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add lib entrypoint and indirect syscall asm
- Loading branch information
Showing
4 changed files
with
147 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package acheron | ||
|
||
import ( | ||
"github.com/f1zm0/acheron/internal/resolver" | ||
"github.com/f1zm0/acheron/internal/resolver/ssnsort" | ||
"github.com/f1zm0/acheron/pkg/hashing" | ||
) | ||
|
||
type Acheron struct { | ||
resolver resolver.Resolver | ||
} | ||
|
||
// New returns a new Acheron instance that can be used as a proxy to perform | ||
// indirect syscalls for native api functions, or an error if the initialization fails. | ||
func New(opts ...Option) (*Acheron, error) { | ||
options := &options{ | ||
hasher: hashing.NewDjb2(), | ||
} | ||
for _, o := range opts { | ||
o(options) | ||
} | ||
|
||
if r, err := ssnsort.NewResolver(options.hasher); err != nil { | ||
return nil, err | ||
} else { | ||
return &Acheron{ | ||
resolver: r, | ||
}, nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// syscall implementation is a mix of: | ||
// - https://golang.org/src/runtime/sys_windows_amd64.s | ||
// - https://github.com/C-Sto/BananaPhone/blob/master/pkg/BananaPhone/asm_x64.s#L96 | ||
// with added support for indirect syscall inspired by: | ||
// - https://github.com/thefLink/RecycledGate | ||
|
||
// func execSyscall(ssn uint16, gateAddr uintptr, argh ...uintptr) (errcode uint32) | ||
#define maxargs 16 | ||
TEXT ·execIndirectSyscall(SB), $0-56 | ||
XORQ AX,AX | ||
MOVW ssn+0(FP), AX | ||
PUSHQ CX | ||
|
||
XORQ BX,BX | ||
MOVQ gateAddr+8(FP),BX | ||
|
||
//put variadic pointer into SI | ||
MOVQ argh_base+16(FP),SI | ||
//put variadic size into CX | ||
MOVQ argh_len+24(FP),CX | ||
|
||
// SetLastError(0). | ||
MOVQ 0x30(GS), DI | ||
MOVL $0, 0x68(DI) | ||
SUBQ $(maxargs*8), SP // room for args | ||
|
||
// Fast version, do not store args on the stack. | ||
CMPL CX, $4 | ||
JLE loadregs | ||
|
||
// Check we have enough room for args. | ||
CMPL CX, $maxargs | ||
JLE 2(PC) | ||
INT $3 // not enough room -> crash | ||
|
||
// Copy args to the stack. | ||
MOVQ SP, DI | ||
CLD | ||
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 | ||
MOVQ 8(SI), DX | ||
MOVQ 16(SI), R8 | ||
MOVQ 24(SI), R9 | ||
|
||
// Floating point arguments are passed in the XMM | ||
MOVQ CX, X0 | ||
MOVQ DX, X1 | ||
MOVQ R8, X2 | ||
MOVQ R9, X3 | ||
|
||
MOVQ CX, R10 | ||
|
||
// jump to gate instead of direct syscall | ||
CALL BX | ||
|
||
ADDQ $((maxargs+1)*8), SP | ||
|
||
// Return result. | ||
POPQ CX | ||
MOVL AX, errcode+32(FP) | ||
RET |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package acheron | ||
|
||
import ( | ||
"github.com/f1zm0/acheron/pkg/hashing" | ||
) | ||
|
||
// Option is a configuration option which can be used within a | ||
// call to the formatter constructor. | ||
type ( | ||
Option func(*options) | ||
Options []Option | ||
) | ||
|
||
type options struct { | ||
hasher hashing.Hasher | ||
} | ||
|
||
// WithHashFunction returns an Option that sets a custom hashing (or obfuscation) | ||
// function that will be used when resolving native api procedures by hash. | ||
func WithHashFunction(f hashing.Hasher) Option { | ||
return func(o *options) { | ||
o.hasher = f | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package acheron | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
// Syscall executes a syscall with the given function hash and arguments. | ||
// Returns the error code and an error if the syscall failed. | ||
func (a *Acheron) Syscall(fnHash int64, args ...uintptr) error { | ||
ssn, err := a.resolver.GetSyscallSSN(fnHash) | ||
if err != nil { | ||
return err | ||
} | ||
gateAddr := a.resolver.GetSafeGate() | ||
|
||
if errCode := execIndirectSyscall(ssn, gateAddr, args...); errCode != 0 { | ||
return errors.New(fmt.Sprintf("syscall failed with error code %d", errCode)) | ||
} | ||
return nil | ||
} | ||
|
||
// execIndirectSyscall function signature for go-asm impelementation. | ||
// returns 0 if the syscall was successful or an error code if the operation failed. | ||
func execIndirectSyscall(ssn uint16, gateAddr uintptr, argh ...uintptr) (errcode uint32) |