免杀学习--shellcode加载免杀
前言
这段时间测试了不少免杀的手法,但是对一些加载器的实现原理还没有完全理清,所以本文主要是学习总结原理和姿势,不测试实际免杀效果。
目前来看分离免杀仍然是主流的一种免杀方式,我们可以将shellcode比作子弹,那么枪也就是我们所说的加载器。在这种情况下对于杀软来说,单纯的枪或者说子弹,都有可能绕过杀软。
python加载器
核心代码:
1 | #!/usr/bin/python |
代码不是很长,可以看到主要调用的就是ctypes这个库。
1 | ctypes 是 Python 的外部函数库。它提供了与 C 兼容的数据类型,并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。 |
主要流程
- 调用VirtualAlloc函数,来申请一块可读可写可执行的动态内存区域。
- 调用RtlMoveMemory函数,此函数从指定内存中复制内容至另一内存里。
- 调用CreateThread函数,在主线程的基础上创建一个新线程。
- 调用WaitForSingleObject函数,等待创建的线程运行结束。
当然目前来说这种比较原始的方式杀软已经杀很严了,所以之后更多要有混淆加密的操作。
常见的有Hex加密、AES加密、XOR加密、base64等等,或者可以自己写加密和解密,免杀效果会更好
加载器
HEX加密
1 | #scrun by k8gege |
base64加密
1 | #scrun by k8gege |
C++加载器
对于C/C++来说,常用的加载方式有函数指针执行、内联汇编指令、伪指令等方式.
函数指针执行
简单的C代码:
1 | char shellcode[] = ""; |
(void(*)() shellcode 将shellcode转换为函数指针,指向void形式的函数,然后再通过一个*对指针进行取值,之后通过()双括号调用函数进而执行shell从而执行shellocde。
动态内存加载
1 |
|
原理和上面python实现类似。
内联汇编指令
汇编指令相关的知识可以看这里:
免杀、汇编指令大全_K的专栏-程序员宅基地 - 程序员宅基地 (cxyzjd.com)
1 | include <stdio.h> |
其他的写法:
1 | void RunShellCode() |
MOV EAX, offset shellcode
此指令意为将 shellcode 放入到寄存器 EAX 中
JMP EAX
无条件跳转到EAX
伪指令
伪指令(Pseudo Instruction)是用于对汇编过程进行控制的指令,该类指令并不是可执行指令,没有机器代码,只用于汇编过程中为汇编程序提供汇编信息。 例如,提供如下信息:哪些是指令、哪些是数据及数据的字长、程序的起始地址和结束地址等。
1 | void RunShellCode_5() |
go加载器
动态内存加载
核心代码如下:
1 | package main |
其实原理与上面python或者C/C++类似。
通过声明匿名函数,然后指向读入的ShellCode字节数据的那片内存,并将内存设置为可读可写可执行,之后调用函数就将ShellCode运行起来了。
内联C加载
核心代码如下:
1 | package main |
总结
shellcode既然是一段二进制代码,那加载器的功能其实就是想办法将二进制写到内存中,并将这段内存设置为可执行。在这个过程中,为了逃避杀软,所以要更多采用加密混淆等操作。