Skip to content

Commit

Permalink
feat: add zw exports parsing logic to resolver
Browse files Browse the repository at this point in the history
  • Loading branch information
f1zm0 committed Apr 9, 2023
1 parent f995154 commit 19f45c7
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 186 deletions.
40 changes: 29 additions & 11 deletions internal/resolver/asm64.s
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ TEXT ·getNtdllBaseAddr(SB),NOSPLIT,$0
RET


// func getModuleEATAddr (moduleBase uintptr) uintptr
TEXT ·getModuleEATAddr(SB),NOSPLIT,$0-8
// func getModuleExportsDirAddr (moduleBase uintptr) uintptr
TEXT ·getModuleExportsDirAddr(SB),NOSPLIT,$0-8
MOVQ moduleBase+0(FP), AX

XORQ R15, R15
Expand All @@ -41,28 +41,28 @@ TEXT ·getModuleEATAddr(SB),NOSPLIT,$0-8
ADDQ $0x88, R15

// AX = ntdll base + IMAGE_DATA_DIRECTORY.VirtualAddress
ADDL 0x0(R15), R14
ADDL (R15), R14
ADDQ R14, AX

MOVQ AX, ret+8(FP)
RET


// func getEATNumberOfFunctions(exportsBase uintptr) uint32
TEXT ·getEATNumberOfFunctions(SB),NOSPLIT,$0-8
// func getExportsNumberOfNames(exportsBase uintptr) uint32
TEXT ·getExportsNumberOfNames(SB),NOSPLIT,$0-8
MOVQ exportsBase+0(FP), AX

XORQ R15, R15

// R15 = exportsBase + IMAGE_EXPORT_DIRECTORY.NumberOfFunctions
MOVL 0x14(AX), R15
// R15 = exportsBase + IMAGE_EXPORT_DIRECTORY.NumberOfNames
MOVL 0x18(AX), R15

MOVL R15, ret+8(FP)
RET


// func getEATAddressOfFunctions(moduleBase,exportsBase uintptr) uintptr
TEXT ·getEATAddressOfFunctions(SB),NOSPLIT,$0-16
// func getExportsAddressOfFunctions(moduleBase,exportsBase uintptr) uintptr
TEXT ·getExportsAddressOfFunctions(SB),NOSPLIT,$0-16
MOVQ moduleBase+0(FP), AX
MOVQ exportsBase+8(FP), R8

Expand All @@ -78,8 +78,8 @@ TEXT ·getEATAddressOfFunctions(SB),NOSPLIT,$0-16
RET


// func getEATAddressOfNames(moduleBase,exportsBase uintptr) uintptr
TEXT ·getEATAddressOfNames(SB),NOSPLIT,$0-16
// func getExportsAddressOfNames(moduleBase,exportsBase uintptr) uintptr
TEXT ·getExportsAddressOfNames(SB),NOSPLIT,$0-16
MOVQ moduleBase+0(FP), AX
MOVQ exportsBase+8(FP), R8

Expand All @@ -93,3 +93,21 @@ TEXT ·getEATAddressOfNames(SB),NOSPLIT,$0-16

MOVQ AX, ret+16(FP)
RET


// func getExportsAddressOfNameOrdinals(moduleBase, exportsBase uintptr) uintptr
TEXT ·getExportsAddressOfNameOrdinals(SB),NOSPLIT,$0-16
MOVQ moduleBase+0(FP), AX
MOVQ exportsBase+8(FP), R8

XORQ SI, SI

// SI = exportsBase + IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
MOVL 0x24(R8), SI

// AX = exportsBase + AddressOfNames offset
ADDQ SI, AX

MOVQ AX, ret+16(FP)
RET

8 changes: 1 addition & 7 deletions internal/resolver/gates.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
package resolver

import (
wt "github.com/f1zm0/acheron/internal/types"
)

const SYSCALL_STUB_SIZE = 0x20

// FindSyscallRetGadgets finds syscall;ret gadgets in ntdll.dll
// that can be "recycled" to ensure syscalls goes through ntdll.
func FindSyscallRetGadgets(hNtdll *wt.PEModule) []uintptr {
func FindSyscallRetGadgets(stubs map[int64]*ZwStub) []uintptr {
// TODO: do implementation
return []uintptr{}
}
40 changes: 0 additions & 40 deletions internal/resolver/ldr.go

This file was deleted.

58 changes: 58 additions & 0 deletions internal/resolver/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package resolver

import (
"github.com/f1zm0/acheron/pkg/hashing"
"github.com/f1zm0/acheron/pkg/memory"
)

type NtModule struct {
BaseAddr uintptr
ExportsBaseAddr uintptr
NumberOfNames uint32
AddressOfFunctions uintptr
AddressOfNames uintptr
AddressOfNameOrdinals uintptr
ZwStubs map[int64]*ZwStub
}

type ZwStub struct {
RVA uint32
VA uintptr
SSN uint16
}

// ParseNtdllModule returns a NtModule struct with the relevant information
// about the in-memory ntdll.dll module.
func ParseNtdllModule(hashFn hashing.Hasher) *NtModule {
var m NtModule

m.BaseAddr = getNtdllBaseAddr()
m.ExportsBaseAddr = getModuleExportsDirAddr(m.BaseAddr)
m.NumberOfNames = getExportsNumberOfNames(m.ExportsBaseAddr)
m.AddressOfFunctions = getExportsAddressOfFunctions(m.BaseAddr, m.ExportsBaseAddr)
m.AddressOfNames = getExportsAddressOfNames(m.BaseAddr, m.ExportsBaseAddr)
m.AddressOfNameOrdinals = getExportsAddressOfNameOrdinals(m.BaseAddr, m.ExportsBaseAddr)

m.ZwStubs = make(
map[int64]*ZwStub,
m.NumberOfNames/4, // Zw* functions are less than ~25% of the total so we can save some memory
)

for i := uint32(0); i < m.NumberOfNames; i++ {
fn := memory.ReadCStringAt(m.BaseAddr, memory.ReadDwordAt(m.AddressOfNames, i*4))
if fn[0] != 'Z' || fn[1] != 'w' {
continue
}
fnHash := hashFn.HashByteString(fn)

nameOrd := memory.ReadWordAt(m.AddressOfNameOrdinals, i*2)
rva := memory.ReadDwordAt(m.AddressOfFunctions, uint32(nameOrd*4))

m.ZwStubs[fnHash] = &ZwStub{
RVA: rva,
VA: memory.RVA2VA(m.BaseAddr, uint32(rva)),
}
}

return &m
}
19 changes: 6 additions & 13 deletions internal/resolver/ssnsort/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"

"github.com/f1zm0/acheron/internal/resolver"
wt "github.com/f1zm0/acheron/internal/types"
"github.com/f1zm0/acheron/pkg/hashing"
)

Expand All @@ -13,7 +12,7 @@ type ssnSortResolver struct {
hasher hashing.Hasher

// map of Zw* InMemProc structs indexed by their name's hash
zwStubs map[int64]wt.InMemProc
zwStubs map[int64]*resolver.ZwStub

// slice with addresses of clean gadgets
safeGates []uintptr
Expand All @@ -22,25 +21,19 @@ type ssnSortResolver struct {
var _ resolver.Resolver = (*ssnSortResolver)(nil)

func NewResolver(h hashing.Hasher) (resolver.Resolver, error) {
r := &ssnSortResolver{}
r := &ssnSortResolver{
hasher: h,
}
if err := r.init(); err != nil {
return nil, err
}
return r, nil
}

func (r *ssnSortResolver) init() error {
// var zwStubs []wt.InMemProc

_, err := resolver.GetNtdllModuleHandle()
if err != nil {
return err
}
ntMod := resolver.ParseNtdllModule(r.hasher)
_ = ntMod

// exports, err := hNtdll.File.Exports()
// if err != nil {
// return err
// }
// for _, exp := range exports {
// memAddr := int64(hNtdll.BaseAddr) + int64(exp.VirtualAddress)
// r.safeGates = resolver.FindSyscallRetGadgets(hNtdll)
Expand Down
15 changes: 6 additions & 9 deletions internal/resolver/stubs.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package resolver

// getNtdllBase signature.
func getNtdllBaseAddr() uintptr

// getModuleEATAddr signature.
func getModuleEATAddr(modBaseAddr uintptr) uintptr
func getModuleExportsDirAddr(modBaseAddr uintptr) uintptr

// getEATNumberOfFunctions signature.
func getEATNumberOfFunctions(exportsBase uintptr) uint32
func getExportsNumberOfNames(exportsBase uintptr) uint32

// getEATAddressOfFunctions signature.
func getEATAddressOfFunctions(moduleBase, exportsBase uintptr) uintptr
func getExportsAddressOfFunctions(moduleBase, exportsBase uintptr) uintptr

// getEATAddressOfNames signature.
func getEATAddressOfNames(moduleBase, exportsBase uintptr) uintptr
func getExportsAddressOfNames(moduleBase, exportsBase uintptr) uintptr

func getExportsAddressOfNameOrdinals(moduleBase, exportsBase uintptr) uintptr
11 changes: 0 additions & 11 deletions internal/types/pe.go

This file was deleted.

32 changes: 0 additions & 32 deletions internal/types/proc.go

This file was deleted.

15 changes: 0 additions & 15 deletions internal/types/unicodestr.go

This file was deleted.

51 changes: 51 additions & 0 deletions pkg/memory/asm64.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "textflag.h"

// func RVA2VA(moduleBase uintptr, rva uint32) uintptr
TEXT ·RVA2VA(SB),NOSPLIT,$0-16
MOVQ moduleBase+0(FP), AX
XORQ DI, DI

MOVL rva+8(FP), DI
ADDQ DI, AX

MOVQ AX, ret+16(FP)
RET


// func ReadDwordAt(start uintptr, offset uint32) uint32
TEXT ·ReadDwordAt(SB),NOSPLIT,$0-16
MOVQ start+0(FP), AX
MOVL offset+8(FP), R8

XORQ DI, DI
ADDQ R8, AX
MOVL (AX), DI

MOVL DI, ret+16(FP)
RET


// func ReadWordAt(start uintptr, offset uint32) uint16
TEXT ·ReadWordAt(SB),NOSPLIT,$0-16
MOVQ start+0(FP), AX
MOVL offset+8(FP), R8

XORQ DI, DI
ADDQ R8, AX
MOVW (AX), DI

MOVW DI, ret+16(FP)
RET


// func ReadByteAt(start uintptr, offset uint32) uint8
TEXT ·ReadByteAt(SB),NOSPLIT,$0-16
MOVQ start+0(FP), AX
MOVL offset+8(FP), R8

XORQ DI, DI
ADDQ R8, AX
MOVB (AX), DI

MOVB DI, ret+16(FP)
RET
15 changes: 15 additions & 0 deletions pkg/memory/cstring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package memory

// ReadCStringAt reads a null-terminated ANSI string from memory.
func ReadCStringAt(start uintptr, offset uint32) []byte {
var buf []byte
for {
ch := ReadByteAt(start, offset)
if ch == 0 {
break
}
buf = append(buf, ch)
offset++
}
return buf
}

0 comments on commit 19f45c7

Please sign in to comment.