【免杀】C2免杀技术(五)动态API
一、什么是动态API
在C2免杀领域中,“动态API” 主要指的是绕过静态检测的一种技术手段,其本质是运行时动态解析和调用Windows API函数,而不是在程序编译阶段就明确引用这些API。这种方式可以有效躲避静态分析工具和杀软的签名识别。
为什么使用动态API?
静态杀软和EDR会扫描程序中是否包含可疑API(比如 CreateRemoteThread
、VirtualAllocEx
、WriteProcessMemory
等),一旦在导入表(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下检测
运行测试,正常
三、结尾
免杀效果通常受多方面影响,没有哪一种技术或者手段能够通吃,通常需要多种手段结合才能最终实现免杀;其次,实战中面临的环境也不一样,不同的杀软效果也不一样,具体问题还需具体分析。本系列文章以技术的实现为主,验证时讲究点到为止,以此表达一项技术的有效性。