1、申 请 I D:左岸
2、个人邮箱:hupeng.net@hotmail.com
3、原创技术文章: 软件安全分析相关从业人员暂无公开发表。就地分析一篇。
0x00 前言
刚刚,从 52pojie 的网盘下载 OD,结果报毒,Trojan:Win32/Malgent!MTB, 到底是真是假?为了判定其是误报还是真实威胁,我们利用 IDA
及其相关分析工具对其进行了深度逆向。分析发现,该样本并非传统的二进制病毒,而很可能是一个典型的混淆脚本木马外壳。
原工具下载地址:
https://down.52pojie.cn/Tools/Debuggers/%E5%90%BE%E7%88%B1%E7%A0%B4%E8%A7%A3%E4%B8%93%E7%94%A8%E7%89%88Ollydbg.rar
受影响项目:
- Udd Cleaner.exe Trojan:Win32/Malgent!MTB
- 原版\汉化原版\Ollydbg.exe Trojan:Win32/Malgent
- 原版\英文原版\OLLYDBG.EXE HackTool:Win32/crack
0x01 静态特征分析:合法的“外壳”
废话不多说,直接上 IDA,为了方便大家复现,把程序基地址设置 0x400000,ida 识别 1876 个函数, 先使用 MCP 把所有函数取个有意义的名字。
分析完发现大量 script 开头的函数名:
script_process_wait_close_logic_431516 .text 00431516 0000014C 0000000C R . . . . . B T .
script_process_wait_init_431662 .text 00431662 0000005B 00000000 00000008 R . . . . . . T .
script_process_exists_4316BD .text 004316BD 00000077 0000001C 00000008 R . . . . . B T .
script_process_wait_431734 .text 00431734 00000049 00000008 00000008 R . . . . . . T .
script_process_wait_close_43177D .text 0043177D 0000006C 0000000C 00000008 R . . . . . . T .
script_process_close_4317E9 .text 004317E9 00000250 00000070 00000008 R . . . . . B T .
script_process_get_stats_431A39 .text 00431A39 000002B9 0000006C 00000008 R . . . . . B T .
script_run_431CF2 .text 00431CF2 00000019 00000000 00000008 R . . . . . . T .
script_run_wait_431D0B .text 00431D0B 0000005E 00000008 00000008 R . . . . . . T .
script_run_as_431D69 .text 00431D69 00000013 00000000 00000008 R . . . . . . T .
script_run_as_wait_431D7C .text 00431D7C 0000005A 00000008 00000008 R . . . . . . T .
script_process_spawn_internal_431DD6 .text 00431DD6 00000256 000040A4 00000010 R . . . . . B T .
script_process_spawn_as_internal_43202C .text 0043202C 000004C1 00000248 0000000C R . . . . . B T .
script_shell_execute_4324ED .text 004324ED 00000017 00000000 00000008 R . . . . . . T .
script_shell_execute_wait_432504 .text 00432504 0000005E 00000008 00000008 R . . . . . . T .
script_shell_execute_internal_432562 .text 00432562 0000017E 00000064 00000010 R . . . . . B T .
script_shutdown_4326E0 .text 004326E0 00000028 00000000 00000008 R . . . . . . T .
script_process_set_priority_432708 .text 00432708 000000F6 00000018 00000008 R . . . . . B T .
script_process_list_4327FE .text 004327FE 0000055D 000032F4 00000008 R . . . . . B T .
script_dll_call_432D5B .text 00432D5B 0000021E 00000374 00000008 R . . . . . B T .
dll_call_resolve_symbol_432F79 .text 00432F79 00000141 00000024 00000008 R . . . . . B T .
dll_call_prepare_params_4330BA .text 004330BA 000001C7 0000001C 00000008 R . . . . . B T .
dll_callback_convert_data_4332C2 .text 004332C2 000000C3 0000002C R . . . . . B T .
dll_call_parse_type_signature_4333C6 .text 004333C6 00000114 00000028 00000004 R . . . . . B T .
dll_call_parse_single_type_4334DA .text 004334DA 000005EF 000004AC 00000008 R . . . . . B T .
script_dll_open_433AC9 .text 00433AC9 00000083 0000000C 00000008 R . . . . . B T .
script_dll_close_433B4C .text 00433B4C 00000069 00000008 00000008 R . . . . . . T .
script_dll_callback_register_433BB5 .text 00433BB5 000002A4 0000003C 00000008 R . . . . . B T .
script_dll_callback_free_433E59 .text 00433E59 00000083 00000004 00000008 R . . . . . . T .
script_dll_callback_lookup_internal_433EDC .text 00433EDC 000000CF 00000020 00000008 R . . . . . B T .
script_dll_callback_get_ptr_433FAB .text 00433FAB 00000048 00000004 00000008 R . . . . . . T .
dll_callback_jit_thunk_entry_433FF3 .text 00433FF3 0000000C 00000000 00000004 R . . . . . . . .
dll_callback_internal_dispatcher_433FFF .text 00433FFF 000000EC 00000034 R . . . . . B T .
script_dll_struct_create_4340EB .text 004340EB 0000089E 000002E4 00000008 R . . . . . B T .
script_is_dll_struct_434989 .text 00434989 00000024 00000000 00000008 R . . . . . . T .
script_dll_struct_set_data_4349AD .text 004349AD 00000055 00000010 00000008 R . . . . . B T .
script_dll_struct_get_size_434A02 .text 00434A02 00000056 0000000C 00000008 R . . . . . . T .
script_dll_struct_get_ptr_434A58 .text 00434A58 00000077 00000024 00000008 R . . . . . B T .
dll_struct_resolve_member_434ACF .text 00434ACF 000000BA 0000000C 00000008 R . . . . . B T .
script_dll_struct_get_data_434B89 .text 00434B89 00000052 00000010 00000008 R . . . . . B T .
通过查看几个函数, 通过导入表和字符串分析,我们首先确认了该二进制文件的本质:它是一个功能完整的 AutoIt v3 脚本解释引擎。
好家伙,这程序怎么也要上 AutoIt 引擎?!
- 符号表特征: 样本中保留了大量的 AutoIt 内部函数名,如 engine_execute_next_op(字节码解释器)、script_reg_write(注册表操作)和 script_inet_download(网络下载)。
- 技术手段: 这种手法被称为“利用合法白文件(Living off the Land)”。攻击者通过携带一个经过数字签名的或合法的解释引擎,来运行其自定义的恶意脚本,从而绕过传统的基于文件特征码的检测。
0x02 行为模式分析:隐身与提权
在分析程序入口点 application_entry_401087 时,我们发现了明显的恶意软件行为模式:
- 反调试对抗: 程序启动之初便调用 IsDebuggerPresent(对应函数
sub_445A7A)。一旦检测到分析环境,程序会立即终止或改变执行路径。
- 静默运行指令: 脚本预处理函数 sub_4090D6 负责解析指令。其中包含了
notrayicon(无托盘图标,实现后台隐身)和 #requireadmin(强制触发 UAC 提权请求)。
- 自更新逻辑: 样本通过 ShellExecuteW
实现自我重新执行,配合特定的命令行参数,确保恶意脚本在提权后的环境下运行。
入口函数 c 伪代码
// 应用程序主入口,负责环境检查、脚本加载及引擎启动
int __stdcall application_entry_401087(WCHAR *lpCmdLine)
{
int result;
HWND hForegroundWnd;
const WCHAR *pszParamsTemp;
WCHAR szModulePathBuffer[264]; // 存储当前程序路径
WCHAR szCurrentDirBuffer[264]; // 存储当前工作目录
LPCWSTR pszShellExecParams; // ShellExecute 参数
char bIsScriptLoadedFromDialog = 0; // 标记位:脚本是否通过文件对话框手动选择
char bIsAdminRequired = 0; // 标记位:是否需要管理员权限运行
// 获取初始环境信息
GetCurrentDirectoryW(0x104u, szCurrentDirBuffer);
parse_command_line_4013E8(lpCmdLine); // 解析命令行参数到全局变量
// [关键检测]:反调试对抗
if ( check_debugger_present_445A7A() )
return MessageBoxA(0, "Debugger detected!", "Error", 0x10u);
if ( g_ScriptMode_48A324 ) // 如果处于某种脚本加载模式
{
// [关键加载]:尝试加载内置脚本或外部文件
if ( !(unsigned __int8)load_script_logic_4088C3(&g_ScriptMode_48A324, &bIsScriptLoadedFromDialog) )
{
g_ErrorFlag_4795D4 = 1;
return SetCurrentDirectoryW(szCurrentDirBuffer);
}
g_bIsCompiled_48A328 = g_CompiledFlag_48B470;
bIsAdminRequired = byte_48B471;
GetFullPathNameW(&g_ScriptPath, 0x104u, szModulePathBuffer, &FilePart);
}
else
{
// 处理未定义脚本模式的默认初始化
sub_40827F(1, dword_48A32C, -1);
}
// 语法/完整性验证
if ( validate_script_41B35F(&g_ScriptPath, g_ScriptMode_48A324) )
{
sub_408435();
result = SetCurrentDirectoryW(szCurrentDirBuffer);
g_ErrorFlag_4795D4 = 1;
return result;
}
// [关键行为]:判断是否需要通过 ShellExecuteW 提权或重启动
if ( bIsAdminRequired == 1 && g_AdminCheck_48A2F5 == 1 && !(unsigned __int8)sub_40F69D() )
{
GetModuleFileNameW(0, szModulePathBuffer, 0x104u);
if ( bIsScriptLoadedFromDialog )
{
// 构造提权参数并重新运行自身
sub_40FFD4(asc_46BE10);
ShellExecuteW(GetForegroundWindow(), L"runas", szModulePathBuffer, pszShellExecParams,
szCurrentDirBuffer, 1);
}
else
{
ShellExecuteW(GetForegroundWindow(), L"runas", szModulePathBuffer, lpCmdLine,
szCurrentDirBuffer, 1);
}
}
else
{
// [引擎启动]:初始化 UI 窗口并启动核心解释器循环
register_main_window_class_401292();
create_main_windows_401377();
// 启动 AutoIt 核心字节码解释引擎
engine_main_loop_41B513((int)&g_EngineState_48A548, 1);
}
sub_408435(); // 清理资源
return SetCurrentDirectoryW(szCurrentDirBuffer);
}
0x03 核心载荷分析:加密的脚本资源
木马的真实逻辑隐藏在二进制文件的资源段中。
- 资源定位: 在偏移量 0x46ca60 处,我们定位到了名为 >>>AUTOIT SCRIPT<<< 的特征签名。
- 解密流程: 函数 sub_408E7F 负责加载这些资源,并调用 xor_decode_string_408E20 进行解密。该函数使用简单的异或(XOR)算法,以字符串长度作为 Key,动态还原出真实的 AutoIt 脚本代码。
0x04 可疑远程下载, 以及URL多重混淆隐藏加密
我们分析了网络下载函数 script_inet_download_424196(底层对应 InetGet)。该函数会读取脚本中的加密变量作为 URL。虽然 URL 在静态分析中被混淆,但其具备的从 C2 服务器动态下载后续 Payload 的能力是极其危险的。
为了找出第二阶段负载(Payload)的下载地址,我们需要深入分析被加密/混淆的脚本内容。由于下载行为是由
脚本驱动的,URL 通常以加密字符串的形式存储在脚本的数据段中。
通过之前的分析,我们已知该程序通过以下逻辑处理脚本:
- 资源定位: 在资源段寻找标记为 >>>AUTOIT SCRIPT<<< 的数据。
- 解密逻辑: 使用 buffer_xor_crypt_41533E 和 xor_decode_string_408E20 进行解密。
将通过以下步骤尝试锁定下载地址:
-
查找硬编码的混淆字符串
木马脚本常将 URL 碎片化或使用特定的 XOR Key 加密。我将搜索二进制文件中具有高熵值或特殊格式的字符串。
没有发现 Base64 字符串。接下来重点分析 script_inet_download_424196 的引用。
由于脚本执行是通过分发器实现的,我们可以检查全局状态或变量映射,看是否有预置的下载 URL 模板。
-
分析脚本解密的关键偏移量
脚本的下载 URL 通常紧随 InetGet 的调用之后。在 AutoIt 编译版中,脚本内容(即 TknBlock)会被分片存储。我将通过分析 load_compiled_script_data_408E7F 中涉及的 Block 数据偏移,寻找可能的硬编码域名。
域名字符串也被加密了。在 AutoIt 脚本中,如果使用了 InetGet 或 HttpOpenRequest,这些 API 会被 script_dll_call_41A1B4 或特定的 script_inet_download_424196 调用。
还是没找到,改变分析思路:
- URL 碎片化拼接: 脚本通常会分段定义 URL(如 http:// + domain.top + /payload.exe)。
- 解密函数: sub_408E20 是解密脚本字符串的核心。它使用字符串长度作为 XOR Key。
分析 script_inet_download_424196 的参数处理逻辑,看看它是如何获取 URL 字符串的。 我们来看看它是如何处理 get_variable_value_ptr_412336 的结果的。
分析表明,script_inet_download_424196 获取第一个脚本参数作为 URL。
由于 URL 存储在脚本字节码中,且 load_compiled_script_data_408E7F 负责脚本的解码,我将尝试定位用于存储 URL 等字符串的数据块偏移量。
-
寻找潜在的 IP 地址或域名分段
恶意脚本常将 IP 地址分段定义以绕过简单的静态查杀。我将使用 find_regex 搜索 IP 地址样式的字符串。
只在地址 0x46d034 找到一个 "0.0.0.0" 的IP。
没有发现活跃的 IP。URL 极有可能存储在名为 AUTOIT SCRIPT 的资源块中,并进行了高强度的混淆。
分析结论:下载源的隐藏方式
下载 URL 不直接存在于 PE 文件的字符串表中,而是被锁定在加密的 AutoIt 脚本资源中。
0x05 结论:它有可能不是误报
通过对 Malgent 家族特征的匹配,可以得出以下结论:
- 判定: 该软件很可能是高危木马。
- 理由:
- 它故意隐藏运行轨迹(无图标、后台运行,自动启动)。
- 它包含不必要的权限提升请求。
- 它集成了完整的网络下载、文件操作和远程 DLL
调用能力,且其逻辑核心(脚本)经过了多层加密混淆。
- 威胁等级:
高。它通常作为“滴管”(Dropper)使用,在潜伏进入系统后,根据云端指令下载执行盗号、勒索或后门程序。
前后半小时搞定。
由于时间有限,就没有继续深挖, 如打断点调试,分析脚本的具体内容了。 但从目前的分析来看,这个样本的确具有典型的 Malgent 木马特征,且其核心功能(远程下载执行)被高度隐藏和加密。因此,我倾向于认为它是真实威胁,而非误报。
经验有限,如有错误,欢迎大家指正。