当前位置: 首页 > news >正文

【免杀】C2免杀技术(五)动态API

一、什么是动态API

在C2免杀领域中,“动态API” 主要指的是绕过静态检测的一种技术手段,其本质是运行时动态解析和调用Windows API函数,而不是在程序编译阶段就明确引用这些API。这种方式可以有效躲避静态分析工具和杀软的签名识别。

为什么使用动态API?

静态杀软和EDR会扫描程序中是否包含可疑API(比如 CreateRemoteThreadVirtualAllocExWriteProcessMemory 等),一旦在导入表(IAT)或代码段中发现这些函数,就可能被标记为恶意。通过动态API调用,这些函数不会直接出现在导入表中,也不会以明文字符串形式出现,提高了免杀能力。

什么是IAT导入表?

在Windows可执行文件(如 .exe.dll)中,导入表(IAT,Import Address Table) 是PE结构中的一个关键部分,它告诉操作系统这个程序运行时需要哪些外部模块(DLL)和函数(API),并在加载时将它们的地址填入到程序中可调用的位置。一句话定义:IAT 是Windows程序用于调用外部DLL函数的一张“函数地址表”,由操作系统在加载时填充。 

举个直观的例子,假设你的程序要使用 Windows 的 MessageBoxA 函数,它位于 user32.dll 中。编译后 (静态导入),在PE文件头的导入表中,会列出DLL名、函数名;加载时操作系统的PE加载器会加载user32.dll,查找MessageBoxA函数的内存地址,并把这个地址写入到你的程序的IAT表项。然后你的代码中对MessageBoxA的调用,实际上是跳转到这个表项。

因此,杀软和EDR能直接查看IAT,看你的程序调用了哪些函数(如上图),一旦发现这些敏感API,程序可能立即被标记为恶意; 通过动态API可以绕过IAT暴露。

二、免杀效果展示

这里用C++写一个简单的喝水提醒的程序,代码如下:

#include <windows.h>
#include <iostream>
#include <thread>
#include <chrono>void remindToDrinkWater() {while (true) {// 等待1小时(3600秒)//std::this_thread::sleep_for(std::chrono::hours(1));std::this_thread::sleep_for(std::chrono::seconds(10));// 弹出消息框提醒喝水MessageBoxA(NULL, "该喝水了!", "喝水提醒", MB_OK | MB_ICONINFORMATION);}
}int main() {// 启动提醒喝水的线程std::thread reminderThread(remindToDrinkWater);// 主线程保持运行reminderThread.join();return 0;
}

运行测试,功能正常

再复制一份,加上动态API解析和调用代码

#include <windows.h>
#include <thread>
#include <chrono>
#include <iostream>typedef int (WINAPI* MessageBoxAFunc)(HWND, LPCSTR, LPCSTR, UINT);void remindToDrinkWater() {// 获取 user32.dll 的模块句柄HMODULE hUser32 = LoadLibraryA("user32.dll");if (!hUser32) {std::cerr << "无法加载 user32.dll" << std::endl;return;}// 动态获取 MessageBoxA 函数地址MessageBoxAFunc pMessageBoxA = (MessageBoxAFunc)GetProcAddress(hUser32, "MessageBoxA");if (!pMessageBoxA) {std::cerr << "无法获取 MessageBoxA 函数地址" << std::endl;return;}while (true) {std::this_thread::sleep_for(std::chrono::seconds(10)); // 测试用:每10秒提醒一次pMessageBoxA(NULL, "该喝水了!", "喝水提醒", MB_OK | MB_ICONINFORMATION);}
}int main() {std::thread reminder(remindToDrinkWater);reminder.join();  // 等待线程结束(实际永远运行)return 0;
}

运行测试,功能正常

将两个程序均编译出来

使用StudyPE+对比一下两者的导入表,发现右边使用动态API技术的程序比左边少了user32.dll,所以IAT不可能存在MessageBoxA函数

放到360下检测

运行测试,正常

三、结尾

免杀效果通常受多方面影响,没有哪一种技术或者手段能够通吃,通常需要多种手段结合才能最终实现免杀;其次,实战中面临的环境也不一样,不同的杀软效果也不一样,具体问题还需具体分析。本系列文章以技术的实现为主,验证时讲究点到为止,以此表达一项技术的有效性。 

http://www.xdnf.cn/news/520381.html

相关文章:

  • C2S-Scale方法解读
  • [Android] 青木扫描全能文档3.0,支持自动扫描功能
  • 机器学习入门之朴素叶贝斯和决策树分类(四)
  • 【VMware】开启「共享文件夹」
  • 计算机系统的工作原理
  • 2.2.5
  • 进程间通信--信号量【Linux操作系统】
  • leetcode解题思路分析(一百六十四)1418 - 1424 题
  • [论文品鉴] DeepSeek V3 最新论文 之 MHA、MQA、GQA、MLA
  • 进程状态并详解S和D状态
  • C++学习:六个月从基础到就业——C++17:结构化绑定
  • 什么是dom?作用是什么
  • 产品周围的几面墙
  • C++高级用法--绑定器和函数对象
  • 垂直智能体:企业AI落地的正确打开方式
  • [人月神话_6] 另外一面 | 一页流程图 | 没有银弹
  • 三:操作系统线程管理之用户级线程与内核级线程
  • 大模型应用开发工程师
  • 从逻辑学视角探析证据学的理论框架与应用体系;《证据学》大纲参考
  • Java学习手册:服务熔断与降级
  • 朴素贝叶斯
  • 做什么, what to do?
  • 面试题总结二
  • atcoder C - ~
  • EmuEdit
  • 网页 H5 微应用接入钉钉自动登录
  • python29
  • 【从基础到模型网络】深度学习-语义分割-ROI
  • C++ - 网络编程之初始连接(Winsock2 概述、初始连接案例、初始连接案例解读)
  • 封装、继承、多态的理解