Windows免杀总结

最近在实习面试,频繁被问到简历上写的“了解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的处理

  1. 加密:异或加密、base64、AES加密、sgn工具
  2. 变形:通用唯一标识符uuid、mac地址(6字节)、ipv4
  3. 和loader分离:
    1. 本地直接加载
    2. 远程加载(这里会有网络请求)
    3. 隐藏在图片中(有点像隐写)

loader

  1. 加载方式:
    1. 申请可读可写可操作的内存然后复制进去:VirtualAllocRtlMoveMemory
    2. 内存本身可读可写,为了避免敏感函数,可以在默认的基础属性上,修改为可执行:VirtualProtect
    3. 创建具有执行权限的堆,在堆中分配内存:HeapCreateHeapAlloc
    4. 将shellcode当成资源文件导入:IDR_CXX标识资源文件,然后在代码里用FindResource查找,最后LoadResource加载到内存
  2. 运行方式:
    1. 内联汇编:在c++代码中直接嵌入汇编代码,这种方式只能加载32位的shellcode
    2. 函数指针:将buf的地址转换成一个函数指针,然后调用这个指针所指向的函数
    3. 创建线程:CreateThread
    4. 创建线程池:将shellcode地址作为回调函数传递给我们在线程池中新建的等待对象SetThreadpoolWait,当满足特定条件的时候(事件对象CreateEvent有信号)就调用关联的回调函数,从而执行shellcode。
    5. 创建纤程运行:ConvertThreadToFiber将当前线程转换为纤程,CreateFiber创建一个纤程对象,切换SwitchToFiber。【资源消耗小,轻量级线程】
    6. 利用回调函数特性,将shellcode作为参数传递给回调函数,回调函数是正常功能调用,从而躲避免杀:如EnumFontsW是Windows API,用于枚举系统中所有可用字体

2 exe的处理

  1. 添加数字签名
    1. 模拟正常程序添加签名,该签名是无效的
    2. 添加自签名证书,该签名是无法验证的
  2. 添加资源:在编译的时候添加图片资源
  3. 加壳:upx,不过加壳就杀
  4. 降低文件的熵值:熵值越大,混乱程度越高,越容易被认为是恶意文件
    1. 增大木马体积来降低熵
    2. 给exe加上图标资源
    3. 对shellcode进行加密增长

3 反沙箱

反沙箱是木马免杀中极为重要的一个步骤。大部分杀软本地都会有一个内置的沙箱/或者云上沙箱,运行一个exe都会在沙箱中模拟运行,进行检测。

思考沙箱和真实环境的差异

  1. 检测中文GetUserDefaultUILanguage
  2. 当前环境开机时间GetTickCount
  3. 检测虚拟机进程:vmware、vbox等【不太准】
  4. cpu核心数【敏感,慎用】、系统用户名、显卡显存大小
  5. 桌面上文件数量,有没有微信QQ等
  6. 系统内文档文件word、excel、ppt数量

4 白加黑

白:有效的数字签名exe文件 黑:恶意代码所在的文件,通常是dll文件 上线原理:exe执行——>dll——>dllmain/导出函数——>执行loader代码,加载shellcode

dll文件目录结构:

  • framework.h:项目中要用的头文件
  • pch.h:常用头文件预编译版本
  • dllmain.cpp:程序入口点DllMain函数
  • pch.cpp:存放导出函数

导出函数:存储在DLL文件中的公共函数,这些函数可以被其他程序调用。

  1. 当其他程序加载一个DLL文件(静态链接或者动态链接调用 LoadLibrary 等函数),操作系统会调用 DllMain 函数。 DllMain 函数可以执行一些初始化工作,比如初始化全局变量或者创建线程。
  2. 导出函数的声明:dllmain.cpp 可以声明和定义一些导出函数。这些函数可以由其他程序调用。
  3. 主入口点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。
Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计
本博客已稳定运行