最近网上看到某免杀exe生成工具存在后门
找到样本来学习一下看看
下载好后有2个文件
LoaderMaker.exe
这是用来生成免杀文件的,后门在该文件中
ShellcodeLoader.exe
这是一个模板
这次不学习这东西怎么免杀的
就是看看后门是藏在哪里的
先看一下LoaderMaker.exe的导出函数有哪些
看到这个函数就感觉有点问题了
这是用来列进程的函数,一个免杀工具好端端的为啥要去列进程
参考了一下大佬的文章,是逆着推的,后面慢慢说
首先找到主函数
运行文件后会打印title
主函数位置为sub_004019A0
打印下面还有2个函数
网上说是用来反沙箱的,找了半天找不到特别有用的信息,好像是一个处理字符串的函数
可以看到从ntdll里面找PfxInitialize函数,然后对比输出结果是否为0x200
去dbg里面跟了一下
发出了疑惑的声音,这不是在硬编码中写死的吗
后来又去ReactOS看了下
可以看到函数内部执行了UNIMPLEMENTED,再过去看看
可以看到是个宏定义,如果满足上面的条件则调用Dbgprint,反之为空
Dbgprint是内核的打印函数,可以不用去管
这里简单的猜测一下,PfxInitialize的返回值应该是在编译ntdll的时候决定的
返回值和CPU架构有关,勉强可以说是反沙箱的函数,只是不是动态确定的就是了
上面是一些简单的猜测,如果有问题欢迎大佬指出
这函数就是用来直接提权的,里面不细究了之前的文章有写过,开启debug特权,开不起就算了
所以你一个免杀工具为啥要debug特权???
后面的就是混淆shellcode的一些东西了,这脚本的免杀怎么实现的就不在这里说了
毕竟这文章主要是来看后门的
这里跟着大佬的脚步逆着推
先找到调用CreateToolhelp32Snapshot的函数
sub_401560
毫不掩饰的遍历进程,通过进程名找到PID再用a1传回去
再往上找到sub_401710,这里函数太长了截图不完
可以看到sub_401560执行完后如果找到PID就会去执行sub_401290
再看下面的函数之前先去看看到底找了什么进程吧
看上图有一堆不知道什么的变量,还有循环
到这里看伪代码就会有点不清楚了,可以选择直接去看汇编
1 | .text:00401710 var_54 = dword ptr -54h |
上面这些都是参数在栈中对应的位置,稍微把参数对应的位置改一下
先贴一张后面要用到的
这里能看到byte_41ADC4对应的字符串
shellcodeLoader.exe
1 | .text:00401799 mov edx, [ebp-4] |
这么看了之后就很明了了
上面v1-v12的变量去byte_41ADC4找到对应位置的字符就可以了
其实这里动态调试可以马上看到
这里看着还有点不对
再往下看看ida中还有这句
LOWORD(v14) = 112;
这里就明确了找的是资源管理器的PID
虽然动态可以直接看到不过有些程序不能调试,所以静态也是必要的技能
好了可以接着看下面的函数了
去找了某dll的句柄
这里取字符串的方式和上面的一样,不过取的位置在byte_41AE20
byte_41AE20=[A-Za-z]
这里取出的来的字符串为Kernel
加上v23 = 0x320033;
完整的字符串就是Kernel32
得到Kernel32的句柄
然后用OpenProcess得到资源管理器的句柄
然后使用GetProcAddress得到需要调用的函数地址
这里有些区别
先提取出dword_41A9E4的数字然后再从byte_41AE20找到指定字符
这里提取出来的函数是VirtullAllocEx
下面还有GetProcAddress
和上面的一样
这里的函数是WriteProcessMemory
先判断系统的位数,如果是64位则注入shellcode,反之就不动
然后开一块堆内存用来解密shellcode
关于解密shellcode这块可以写脚本解密,这次偷懒就直接用x64dbg运行了
解密了之后可以看到这就是一个普通cs的shellcode,甚至无混淆,直接可以看到域名和端口
端口: 0x827=2087
不过看到FC48就可以知道这是一段x64位的shellcode,不过这个后门程序是32位的该怎么去动64位的程序的还需要看下去
后面的代码调用了前面提取出来的函数
就是在explorer.exe开内存然后把shellcode写入explorer.exe的内存中
调用sub_401230开一块内存将sub_41A8B0数据段内的数据复制进去
然后执行这段内存
下面看看这段内存是啥用的
这项技术早有耳闻
以前一直没有研究,没想到在这里碰到了
下面简单说一下这技术,这次先不深入学习了以后再专门的文章
该技术可以在32位的进程里面执行64位的汇编指令
其实32位程序会载入32位和64位的ntdll.dll,可以用ProcessHacker看到
由64位的ntdll模拟一个环境让32位的程序可以正常执行
用来区别执行什么位数的指令用的是段寄存器cs
如果cs为0x23则指令为32位,为0x33则为64位
在ida找到数据段按C可以转为汇编代码
可以看到call了sub_41A933函数
sub_41A933函数push 0x33和eax,这里eax的是call sub_41A933的下一行指令
不过这已经不重要了,因为IDA和dbg都看不清了,到这里已经转成64位的指令了
这里可以用PE-bear简单的查看一下
可以把机器码转为不同位数的指令
前面说了rerf指针会回到call sub_41A933的下一行指令,就是这位置
不要在意上面的指令为啥不是call,因为这里位数已经改变了
看一下下面的汇编0x60,0x18,这种就是在找PEB里面的dll链表了
因为之前文章有说过这里就不展开了
这块指令就是用来找64位ntdll的地址,然后找里面的某个函数调用
这里可以把机器码全部复制下来然后用x64dbg调试
1 |
|
这段代码找函数的方法和cs类似输入一个特征然后去遍历字符串这样的
0x5E3980FA这就是特征,找到的函数为ZwCreateThreadEx
这就是该段代码的作用。,找到64位的ZwCreateThreadEx执行之前写入explorer.exe的shellcode
至于参数是从栈里面传过来的,因为实在不好调试所以就不调了
总结一下就是
找到explorer.exe的pid->开辟内存->写入x64的shellcode->找到x64的ZwCreateThreadEx函数执行shellcdoe
最后的问题就是这个后门是在哪里触发的
找到是谁调用了sub_401710
这里有个计数器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
不要看有这么一串调用栈,其实这些函数里面基本就是类似的,如下
1 | int __cdecl sub_401930(int a1) |
就直接调用
有可能和编译器有关系
最后会发现这是用来打印的函数
上面打印了5次
如果参数不够在if的代码块里置零,这样后面的四次打印就不会触发后门
参数正确的话会在最后打印output时候触发后门
意思就是在如果不生成就不会被上线
生成了就上线
为了确认文章的准确性特意去调了一下那段shellcode,发现了有意思的东西*
如果下载到的样本是未被修改的话
这段shellcode无法上线
在调试的时候发现InternetOpenA需要调用的参数全是空
说明shellcode到这里就崩溃了
去附参数的位置看看发现已经全部都置零了
找了文章发现提取出来的shellcode是一样的
去看了一下沙箱的信息,虽然说提取到了恶意的url不过好像也无可疑的http请求
再去看了一下聊天记录的截图好像连接的也不是提取到的地址
所以可能这东西真的不能上线..只是作者逗着玩的
https://citrusice.github.io/posts/shellcode-loader-backdoor-analysis/