最近在实习面试,频繁被问到简历上写的“了解windows免杀技术”,遂趁着有空,笔者打算将之前所学整理出来。由于之后不打算深耕免杀这个领域,所以这篇文写的不深入,仅入门。
0 CS木马
生成木马的工具有很多,笔者比较熟悉的是CS,包括之前打hw,团队里的师傅也是基于CS生成的木马去作的免杀。
简单介绍一下Cobalt Strike,是一款内网渗透测试框架,可以生成多语言木马。它是C/S架构,服务端一个,客户端可以有多个。当不使用的时候,一定要关闭CS,避免被威胁情报标记为C2 ip。
服务端最好部署在Linux上,默认端口50050,建议修改默认端口,改teamserver文件。对外不能暴露真实监听端口,如果知道端口,用nmap脚本grab_beacon_config.nse
能够扫出C2信息
在CS里还有个很重要的概念——Beacon。这是一种攻击payload,让服务端和肉鸡进行通信,支持http、https、dns、smb协议。通信方式有两种:
- 异步通信:Beacon回连服务器,下载任务,休眠
- 交互通信:实时发生
exe可以分为两种,有阶段Staged和无阶段Stageless【生成的exe体积、上线流程不同】:
- 有阶段:小马拉大马,小的和服务端建立初始连接,再去下载大的
- 无阶段:payload一次执行,减少与服务端的交互,不过体积不能太大
修改服务端特征:
- 修改默认端口
- 替换默认证书(keytool生成伪造的;国外云服务商的真证书,无需实名备案的)
- 设置混淆配置文件,伪装流量。将命令下发结果回传进行包装,从流量上看像是在访问网页
隐藏C2:域前置(有点像CDN)
一般先静态后动态
静态查杀:基于样本特征码的查杀,使用病毒特征库,识别特定代码段,独特字符串等。
- 反编译看Windows API函数
- 匹配样本库里的md5值
- 加解密行为显得很可疑
- 数字签名
- 资源文件,比如图标信息、产品名称、产品版本等
动态查杀:放到云沙箱中
- 监控计算机行为:服务、注册表、防火墙、敏感程序cmd、添加用户的行为
- 监控网络方面:ip、域名、流量内容
1 shellcode+loader
shellcode:一组用于执行特定任务的机器码指令,可能以十六进制字符串的形式出现,然后被解析成二进制数据。
loader:将shellcode字符串载入内存
loader工作流程:
- 申请内存
- 将shellcode放到这块内存中
- 执行shellcode
shellcode的处理
- 加密:异或加密、base64、AES加密、sgn工具
- 变形:通用唯一标识符uuid、mac地址(6字节)、ipv4
- 和loader分离:
- 本地直接加载
- 远程加载(这里会有网络请求)
- 隐藏在图片中(有点像隐写)
loader
- 加载方式:
- 申请可读可写可操作的内存然后复制进去:
VirtualAlloc
,RtlMoveMemory
- 内存本身可读可写,为了避免敏感函数,可以在默认的基础属性上,修改为可执行:
VirtualProtect
- 创建具有执行权限的堆,在堆中分配内存:
HeapCreate
、HeapAlloc
- 将shellcode当成资源文件导入:
IDR_CXX
标识资源文件,然后在代码里用FindResource
查找,最后LoadResource
加载到内存
- 申请可读可写可操作的内存然后复制进去:
- 运行方式:
- 内联汇编:在c++代码中直接嵌入汇编代码,这种方式只能加载32位的shellcode
- 函数指针:将buf的地址转换成一个函数指针,然后调用这个指针所指向的函数
- 创建线程:
CreateThread
- 创建线程池:将shellcode地址作为回调函数传递给我们在线程池中新建的等待对象
SetThreadpoolWait
,当满足特定条件的时候(事件对象CreateEvent
有信号)就调用关联的回调函数,从而执行shellcode。 - 创建纤程运行:
ConvertThreadToFiber
将当前线程转换为纤程,CreateFiber
创建一个纤程对象,切换SwitchToFiber
。【资源消耗小,轻量级线程】 - 利用回调函数特性,将shellcode作为参数传递给回调函数,回调函数是正常功能调用,从而躲避免杀:如
EnumFontsW
是Windows API,用于枚举系统中所有可用字体
2 exe的处理
- 添加数字签名
- 模拟正常程序添加签名,该签名是无效的
- 添加自签名证书,该签名是无法验证的
- 添加资源:在编译的时候添加图片资源
- 加壳:upx,不过加壳就杀
- 降低文件的熵值:熵值越大,混乱程度越高,越容易被认为是恶意文件
- 增大木马体积来降低熵
- 给exe加上图标资源
- 对shellcode进行加密增长
3 反沙箱
反沙箱是木马免杀中极为重要的一个步骤。大部分杀软本地都会有一个内置的沙箱/或者云上沙箱,运行一个exe都会在沙箱中模拟运行,进行检测。
思考沙箱和真实环境的差异
- 检测中文
GetUserDefaultUILanguage
- 当前环境开机时间
GetTickCount
- 检测虚拟机进程:vmware、vbox等【不太准】
- cpu核心数【敏感,慎用】、系统用户名、显卡显存大小
- 桌面上文件数量,有没有微信QQ等
- 系统内文档文件word、excel、ppt数量
4 白加黑
白:有效的数字签名exe文件 黑:恶意代码所在的文件,通常是dll文件 上线原理:exe执行——>dll——>dllmain/导出函数——>执行loader代码,加载shellcode
dll文件目录结构:
- framework.h:项目中要用的头文件
- pch.h:常用头文件预编译版本
- dllmain.cpp:程序入口点
DllMain
函数 - pch.cpp:存放导出函数
导出函数:存储在DLL文件中的公共函数,这些函数可以被其他程序调用。
- 当其他程序加载一个DLL文件(静态链接或者动态链接调用
LoadLibrary
等函数),操作系统会调用DllMain
函数。DllMain
函数可以执行一些初始化工作,比如初始化全局变量或者创建线程。 - 导出函数的声明:
dllmain.cpp
可以声明和定义一些导出函数。这些函数可以由其他程序调用。 - 主入口点:
dllmain.cpp
中的DllMain
函数是DLL的主入口点。其他导出函数可以通过DllMain
进行调用或者初始化。
查看导出函数:
dumpbin
,是 vs 自带的一款工具,可以查看 obj 文件、lib 库、dll 库、exe 执行文件。# 查看 dll 库中包含哪些函数 dumpbin /exports a.dll
Dependencies
,图像化工具,更方便,下载地址
白+黑dll劫持:大部分程序在运行时,都会调用相应需要的dll链接库,我们可以替换这个dll文件,来执行我们自己的代码,这就是DLL劫持
。白exe+黑dll。当exe需要调用dll时,系统会去搜索dll的位置,优先级最高的是应用程序所在的目录,所以将黑dll放在此处。
dll劫持,启动!
- 寻找白exe,可以手工可以工具:将exe复制到单独的目录里,点击看缺少哪些dll,只找缺少一个dll的(否则需要制作多个dll),拿来当白文件
- 制作黑dll:将导出函数的定义复制到dllmain.cpp中,在其中写入loader代码
- dllmain中执行shellcode可以通过进程注入的方式:比如通过 CreateProcess 创建一个 rundll32 进程并在其内存中分配内存写入shellcode,并通过修改其程序计数器 Rip 指向写入的 shellcode 地址,然后恢复线程执行shellcode。