免杀绕过Windows防火墙
PE文件格式
pics/binary/pe101/pe101.png at master · corkami/pics · GitHub
.text段:代码
.rdata:只读代码
.data:全局变量等
.pdata:
.rsrc: 可以是各种资源文件
.reloc: 重定位,用于加载文件到内存
windows cmd命令查看exe文件
1 | dumpbin /headers C:\windows\system32\calc.exe |
EXE和DLL文件
简单说,exe可以在内存里单独运行,dll不行,dll是给进程提供其调用的函数用的
cmd命令查看dll文件的导出函数
1 | dumpbin /exports implant.dll |
调用dll文件的倒数函数
1 | rundll32 implant.dll,RunME |
恶意程序中的Payload存储位置
droppers:将payload传输到目标机器上的,可以是任何代码,JavaScript、powershell等等
哪里可能拿来存储payloads?.text,.data(创建全局变量存储payload),.rsrc(告诉当前PE文件,某个存储着payload的文件是当前文件需要加载的)
.text段存储payload
需要在进程的内存中申请内存,把payload加载进去,然后执行
这里把申请的内存属性设置为读写而不是读写执行的原因是杀软可能会监视到这种敏感操作,所以分成了两步,先设置为读写,然后设置为读执行
1 |
|
getchar()
的作用是为了x64dbg的时候打断点调试
.data段存储payload
这里是把payload换成了全局变量
1 |
|
.rsrc段存储payload
和前面的区别在于,首先没有定义payload,payload是被加载的
FindResource告诉系统在当前PE文件中找到FAVICON_ICO文件,返回文件句柄,然后使用LoadResource返回另一个句柄
1 |
|
resources.h
1 | #define FAVICON_ICO 100 |
resources.rc
1 | #include "resources.h" |
calc.ico就是弹计算器的shellcode
1 | .rc 文件(资源文件)主要用于定义和管理应用程序的资源,例如图标、菜单、对话框等。resources.rc 文件中定义了一个图标资源 calc.ico,并且通过 FAVICON_ICO 这个宏(其值为 100)来引用它。 |
payload编码和加密
payload在源文件中是加密或者编码存储的,只是在运行或者调用的时候进行解密解码
base64编码
cmd命令
1 | certutil -encode calc.bin calc.b64 |
异或加密
1 |
|
这里的payload是异或加密之后的payload,加载的过程中解密,生成这段加密payload的代码如下(python2)
1 | import sys |
使用方法
1 | python xor.py calc.bin |
AES加密
1 | #include <windows.h> |
AES加密代码
1 | import sys |
函数调用混淆
杀软会分析IAT表,需要把dll文件和外部函数调用进行隐藏
1 | handle = GetModuleHandle("sound.dll") |
在取得函数地址之前要全局变量定义函数,且需要是指针类型,函数原型在Google上搜msdn 函数名,然后强制转换为指针类型
1 | BOOL (WINAPI * pVirtualProtect)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PWORD lpfloldProtect); |
用上述方式在IAT表里找不到VirtualProtect
1 | dumpbin /imports a.exe | findstr /i "virutal" |
但是在字符串里可以找到
1 | strings.exe -n 8 implant.exe | findstr /i "virtual" |
这是因为使用的函数名是明文的,函数名也可以加密(代码附后)
1 | python -i xorencrtypt2.py |
原先的demo
1 |
|
只混淆函数,这种在strings里仍然可以看到,但是在IAT表看不到了
1 |
|
附上异或的操作代码
1 | import sys |
混淆函数名字符串的demo
1 | /* |
后门PE文件
注入恶意代码的位置
1 | code cave:已存在的段的空白处,缺点是空白的大小不定 |
可以结合起来用,比如在text段里找到了code cave,可以在这里加载额外的代码,额外的代码就来源于可写的段或者是resources,这就避免了需要把段设置为可执行的问题
使用PUTTY,32位,然后x32dbg去打开exe文件
在右侧的breakpoint中找到入口点,双击进入
在memory map里找到.text段,往下找到空白的区域
找到code cave,记录下地址,在这里打上断点,在EP的位置跳到code cave,然后在code cave结束的时候再跳回原来的EP
右键这里code cave的地址,copy -> address
把入口点最开始的这几行代码复制下来
右键 assemble 修改汇编代码为 jmp codecaveAddress
在code cave中,首先要使用 pushad和pushfd来保存寄存器状态
选中多行,右键binary edit 将shellcode填入
右键patch,但是这样改无法在执行完弹计算器之后返回正常的putty软件,在每个shellcode的call函数的位置打上断点,来定位到底是在哪个函数的位置退出程序了,最后定位到是在最后一个call的地方这里退出的
把这个位置之前改成jmp到后面的空白区域,然后回复寄存器,执行之前正常程序的流程,再跳回去
payload注入
将shellcodo迁移到别的进程中
木马进程调用AllocateMemory在目标进程中开辟内存,然后CopyShellcode到目标内存中,最后执行shellcode
1 | VirtualAllocEx |
为什么?
1 | 恶意进程可能存活很短 |
shellcode注入
demo
1 |
|
编译之后运行,可以使用process hacker查看进程以及弹出的框属于哪个进程的
点击这个×左边的按钮,可以选中想查看的窗口,而且可以看到RX权限的内存中有shellcode
dll注入
也就在目标进程中是开辟内存,然后将dll路径copy到目标进程的内存中,调用LoadLibrary加载dll
怎么找到LoadLibrary的地址?因为kernel32.dll在不同进程中的加载地址都是一样的,可以在恶意进程中获取LoadLibrary的地址然后拿到目标进程中去用
1 | 调用GetProcAddress获取LoadLibrary的地址 |
需要两个文件,一个是dll,一个是将dll加载到目标进程的exe
implantDLL.cpp
1 |
|
implantDLL.def
1 | LIBRARY "ImplantDLL" |
injectDLL.cpp
1 |
|
当dll文件在目标进程中被加载的时候就会执行shellcode
隐藏控制台
FreeConsole
1 |
|
但是上面的方法还是会短暂的弹出控制台
GuiTrick
就是把程序改成窗口程序而不是控制台程序
1 |
|
Combination
从rsrc提取出加密的shellcode,然后解密shellcode,将shellcode注入到其他进程中,并且避免弹出控制台
使用的shellcoded是弹出个框,先把shellcode进行异或加密
但是resource需要是文件类型,再把异或代码改一下,输出到文件中
1 | ciphertext = xor(plaintext, KEY) |
最终的文件目录结构
resources.h
1 | #define FAVICON_ICO 100 |
resources.rc
1 | #include "resources.h" |
implant.cpp
1 |
|
这里有时候GUI函数(messagebox)在控制台中不能执行,这是正常的
绕过Windows defender
上面的代码如果把进程改成explorer.exe,会被查杀,需要判断是哪个操作触发了wd的检测,是静态检测还是注入代码的时候检测到了
将.exe复制到任意文件夹里,直接报毒了,应该是静态检测的
也就是函数加密那些操作结合起来
1 |
|
这里函数名异或加密的方法