-
Notifications
You must be signed in to change notification settings - Fork 34
/
acheron.go
78 lines (66 loc) · 2.18 KB
/
acheron.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package acheron
import (
"fmt"
"github.com/f1zm0/acheron/internal/resolver"
"github.com/f1zm0/acheron/internal/resolver/rvasort"
"github.com/f1zm0/acheron/pkg/hashing"
)
// Acheron is the main struct of the acheron package.
type Acheron struct {
resolver resolver.Resolver
hashFunction hashing.HashFunction
}
// Option is a configuration option to configure the Acheron instance.
type Option func(*options)
type options struct {
hashFunction hashing.HashFunction
}
// stub for asm implementation
func execIndirectSyscall(ssn uint16, gateAddr uintptr, argh ...uintptr) uint32
// New returns a new Acheron instance with the given options, or an error if initialization fails.
func New(opts ...Option) (*Acheron, error) {
options := &options{
hashFunction: hashing.XorDjb2Hash, // default
}
for _, o := range opts {
o(options)
}
if r, err := rvasort.NewResolver(options.hashFunction); err != nil {
return nil, err
} else {
return &Acheron{
resolver: r,
hashFunction: options.hashFunction,
}, nil
}
}
// WithHashFunction returns an Option that sets a custom hashing or obfuscation function.
func WithHashFunction(f hashing.HashFunction) Option {
return func(o *options) {
o.hashFunction = f
}
}
// HashString is a helper function to hash a string which can be used as first arg for Syscall.
func (a *Acheron) HashString(s string) uint64 {
return a.hashFunction([]byte(s))
}
// GetSyscall returns the Syscall struct for the given function hash.
func (a *Acheron) GetSyscall(fnHash uint64) (*resolver.Syscall, error) {
if sys := a.resolver.GetSyscall(fnHash); sys == nil {
return nil, fmt.Errorf("failed with code: 0x%x", ErrSyscallNotFound)
} else {
return sys, nil
}
}
// Syscall makes an indirect syscall with the provided arguments. Returns the status code and an error message if it fails.
func (a *Acheron) Syscall(fnHash uint64, args ...uintptr) (uint32, error) {
sys := a.resolver.GetSyscall(fnHash)
if sys == nil {
return ErrSyscallNotFound, fmt.Errorf("failed with: 0x%x", ErrSyscallNotFound)
}
st := execIndirectSyscall(sys.SSN, sys.TrampolineAddr, args...)
if !NT_SUCCESS(st) {
return st, fmt.Errorf("failed with code: 0x%x", st)
}
return st, nil
}