| 本帖最后由 图钉鱼 于 2025-7-18 04:58 编辑 
 之前看了下,做了一些工作,今天有空发下,我感觉这个样本包不大完整,分析有模糊地带。
 
 
 主程序(hbdsl.exe)加载Language.dll:主程序负责加载DLL并传递配置参数与命令,DLL解析参数执行具体操作。
 
 主程序(hbdsl.exe)细节
 主程序通过LoadLibraryW(L"Language.dll")加载DLL,未指定绝对路径。攻击者可在主程序目录放置同文件名的恶意DLL实现DLL劫持。
 
 
 主程序核心逻辑集中在WinMain函数(地址0x401100):
 1. 路径处理与文件查找
 • 调用GetModuleFileNameW获取自身完整路径(如C:\\hbdsl.exe)
 • 通过PathRemoveFileSpecW提取目录路径(如C:\\*)
 • 使用PathAppendW构建.sim文件搜索路径(如C:\\*\\*.sim)
 • 通过FindFirstFileW和FindNextFileW遍历目录,未找到时使用硬编码路径"C:\\Program files\\CyberLink\\PowerDVD\\PowerDVD.sim"
 
 2. DLL加载与参数传递
 • 通过LoadLibraryW加载Language.dll
 • 使用GetProcAddress获取导出函数LangDLLMain(命令处理)和SetRegPath(注册表配置)
 • 传递注册表配置参数:
 ◦ 定义_DWORD[130]数组v28(地址esp+A7Ch)
 ◦ 初始化前5元素为固定值(7274579, 7602278, 6357111, 6619250, 92),其余置零
 ◦ 调用SetRegPath(v28)传递数组指针(数值对应注册表路径编码,如7274579(0x6F6369)解析为ASCII字符"oci")
 • 通过LangDLLMain(lpCmdLine)传递命令行参数(ANSI字符串)
 ------------------------------------------------------------------------------------------------------------------------
 DLL(Language.dll)细节
 Language.dll是恶意软件的数据处理核心组件,负责解析UTF-16编码的数据,为后续C2命令执行、注册表操作等恶意行为提供可解析的结构化数据。其作用虽不直接实施恶意操作,但却是恶意软件实现复杂功能的必要环节,类似于“数据中转站”。
 将主程序(hbdsl.exe)传递的ANSI命令行参数分为ANSI→UTF16编码转换和UTF16→UTF32代{过}{滤}理对处理两个阶段,并处理代{过}{滤}理对(Surrogate Pair),通过双层编码转换(ANSI→UTF16→UTF32)解析指令。
 • UTF16/UTF32转换规避基于ANSI字符串的检测
 • 参数多重编码降低静态分析可读性 ,强大的免杀能力。
 该组件通过LangDLLMain和sub_10006EB0两个关键函数实现数据转换,所有输入均来自主程序的lpCmdLine参数传递,无需外部文件依赖。
 
 
 1. 注册表配置(SetRegPath函数)
 • 接收v28数组指针,解析注册表路径(如组合为Software\\Malware\\Config)
 • 为后续注册表操作(如持久化)提供路径基础
 
 2. ANSI→UTF-16编码转换(LangDLLMain函数)
 主程序传递的lpCmdLine参数为ANSI字符串,需转换为UTF-16字符串:
 函数原型:int (__cdecl *)(LPSTR lpCmdLine)
 转换逻辑:
 
 复制代码int len = MultiByteToWideChar(CP_ACP, 0, lpCmdLine, -1, NULL, 0);
wchar_t* wCmdLine = (wchar_t*)malloc(len * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, 0, lpCmdLine, -1, wCmdLine, len);   
传递UTF-16字符串至解析函数sub_10006EB0
 
 3. UTF-16→UTF-32代{过}{滤}理对处理(sub_10006EB0函数)
 解析UTF-16字符串中的代{过}{滤}理对(0xD800-0xDFFF):
 函数原型:void (__cdecl *)(__int16 *wCmdLine)
 处理逻辑:
 复制代码while (wCmdLine[i] != L'\0') {  
    wchar_t c = wCmdLine[i];    
    if (c >= 0xD800 && c <= 0xDBFF) {  
        wchar_t c2 = wCmdLine[i+1];    
        if (c2 >= 0xDC00 && c2 <= 0xDFFF) {    
            uint32_t utf32 = ((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000;  
            process_utf32(utf32);   
            i += 2;   
        } else i++;  
    } else {   
        uint32_t utf32 = c;  
        process_utf32(utf32);  
        i++;  
    }  
}  
输出UTF-32字符供后续命令执行使用
 
 DLL函数调用序列
 复制代码_DllMain@12(入口点)  
└─ sub_10008620(参数转发)  
   └─ sub_10008820(数据预处理)  
      ├─ sub_10007DB0(验证a2非空)  
      ├─ sub_10008020(验证a2非空)  
      └─ sub_10008230(启动解析)  
         └─ sub_10008060(复制数据)  
            └─ sub_10006C40(复制a2到v6)  
               └─ sub_10005240(转发v6)  
                  └─ sub_100070F0(解析v6)  
                     └─ sub_10006EB0(解析UTF-16)  
                        └─ sub_10005CA0(检查缓冲区空间)  
                           └─ sub_1001A550(扩展缓冲区)  
                              └─ sub_10005BF0(写入字符)  
 
主程序与DLL交互:
 1. 主程序获取路径并查找.sim文件 (样本包中不存在该文件)
 2. 加载Language.dll并获取导出函数指针
 3. 调用SetRegPath(v28)传递注册表配置
 4. 调用LangDLLMain(lpCmdLine)传递命令
 5. DLL解析注册表路径
 6. DLL转换命令行参数为UTF-16并解析为UTF-32
 7. DLL执行注册表操作或网络指令
 
 自我加解密机制
 DllMain函数0x100043e6处
 
 复制代码memset(Dst, *v17 ^ v16, 1u); // 逐字节XOR解密
Dst:分配的内存区域(来自v69,即v28指向的堆内存);
 *v17:待解密的字节(来自sub_10003AF0函数,推测为加密数据);
 v16:密钥(v70的值,动态计算为“初始值 + 127”);
 1u:每次解密1字节(逐字节处理)。
 
 算法: XOR加密
 密钥: 动态计算值 + 127
 实现逐字节解密到分配的内存区域
 
 需明确lpCmdLine的来源和DLL的输出数据去向才能构成完整攻击链。这部分刚好缺失,或许就藏在Update.xml文件中?
 
 
 
 
 
 
 
 |