AutoIt 目前最新是v3版本,这是一个使用类似BASIC脚本语言的免费软件,它的设计用于Windows GUI(图形用户界面)中进行自动化操作,利用模拟键盘按键,鼠标移动和窗口/控件的组合来实现自动化任务。而这是其它语言不可能做到或无可靠方法实现的(例如VBScript和SendKeys)。
Autoit3 Decompiler是一款功能强大的AutoIt3反编译工具,可以反编译由AutoIt编译的exe程序,直接反编译出源代码!还带有右键关联功能,非常方便。
在Autoit3 Decompiler中,按“反编译选中”或“反编译当前”按钮,还可以提取exe中的资源(图片、exe等等)到文件夹。
Autoit3 Decompiler 主要功能简介如下:
1. 支持全系列autoit3,包括v3.0.100.0 - v3.3.7.18,后续版本没验证是否支持,理论上是都支持的
2. 支持EXE及A3X文件反编译 ;
3. 支持X86及X64格式反编译 ;
4. 支持ANSI及UNICODE反编译 ;
5. 支持带密码编译,对于3.2.6.0之前版本可以读取原始密码,后续版本无法显示密码但可正常反编译 ;
6. 支持代码混淆,混淆程序反编译后可读性欠佳,但不影响重编译及执行;
7. 支持反编译后文件项信息即时预览 ;
8. 支持反编译后文件内容即时预览 ;
9. 支持批量反编译 ;
10. 支持命令行及图形界面操作 ;
11. 支持鼠标右键菜单集成。
在分析AutoIT编译的恶意软件样本期间,会弹出一个消息框,指示在使用Exe2Aut反编译器时可能执行的样本。这引起了我对反编译程序如何工作以及如何首先编译AutoIt脚本的兴趣。在本文中,我将解释两个最常见的AutoIT反编译程序(Exe2Aut和myAut2Exe)是如何工作的,以及它们是如何被骗去反编译一个诱饵脚本而不是真正的脚本。
什么是“已编译” AutoIT可执行文件?
编译后的AutoIT可执行文件基本上由两部分组成:一个独立的AutoIT解释程序和作为PE文件中资源显示的编译脚本字节码。AutoIT的创建者已经采取了一些措施来防止简单的反编译,并对字节码应用了一种压缩和加密的形式。字节码的解压缩由编译的AutoIT二进制文件执行,然后再解释和执行。
现在,让我们分析一下Exe2Aut反编译程序。
如果要在反编译期间动态分析Exe2Aut,则会注意到以下内容:
1. 将.tmp文件写入%TEMP%文件夹;
2. 目标二进制文件作为Exe2Aut的子进程加载;
3. .tmp文件被注入目标二进制文件中;
4. 目标二进制文件会将反编译的autoIT脚本写入当前工作目录。
因此,我们可以得出结论,Exe2Aut利用嵌入式解释程序对脚本字节码进行解密和解压缩,然后通过将动态链接库(DLL)注入目标二进制文件来提取该字节码。这样就钩住了将执行字节码的函数,并将字节码解码回函数名称,从而使其成为一种动态方法。因此,可以添加代码来检测注入并更改其行为。这样,我们可以欺骗Exe2Aut来反编译诱饵脚本,而不是在运行应用程序时执行的真实脚本。
Exe2Aut注入模块
那MyAut2Exe呢?
与Exe2Aut不同,MyAut2Exe无需嵌入式解释程序就可以提取字节码资源并解压缩和解码。使其成为完整的静态反编译程序,因此没有意外执行任何内容的风险。
MyAut2Exe比Exe2Aut更高级,它支持AutoIT和AutoHotkey编译脚本的多个版本。因此,它具有更多设置来调整已编译脚本代码的提取和解压缩。为了减少正确配置的麻烦,它提供了一个称为“自动化”的功能。该暴力破解将强制反编译程序设置,直到脚本成功反编译为止。当使用“自动”功能时,MyAut2Exe解析可执行文件中的AutoIT魔术字节码签名。一旦找到,它将提取并反编译代码。由于解析和反编译会在魔术字节码序列首次出现时就停止了,因此只要将MyAut2Exe放置在比真实编译脚本资源低的偏移量处,就可以很容易地诱使MyAut2Exe进行反编译。
演示过程
虽然理论知识层面我们已经讲得更清楚了,但是在网络安全领域,概念证明(POC)的价值远远超过任何理论。
这个想法是要使用三个不同的字节码来编译AutoIt可执行文件,一旦被Exe2Aut或MyAut2Exe反编译,其中一个诱饵脚本就会被反编译,而不是真正的代码。
如前所述,MyAut2Exe的诱饵脚本位于真实字节码之前。对于Exe2Aut,诱饵和真实脚本的脚本资源名称将在运行时重命名,以使其反编译错误的代码。
我已经编译了三种不同的AutoIt脚本,并将它们作为资源添加到.rsrc部分。其中两个是诱饵脚本,而第三个是真实的脚本。然后,我将.rsrc部分的权限设置为读取/写入可移植可执行文件(PE)头。
真实和诱骗的脚本资源
接下来,我编写了一个小的程序集shellcode来遍历进程环境块中的PEB_LDR_DATA结构,以检查Exe2Aut注入的DLL是否存在。还可以在磁盘上搜索(UPX压缩)DLL,因为在注入之前,它位于Windows%TEMP%目录下的随机文件名下。我之所以选择这种方法,是因为它更可靠且更难检测。遍历进程环境块以检查所有已加载模块中是否存在节名称为.UPX0的已加载模块,这是一种识别Exe2Aut注入模块的更简便的方法,因为其他所有DLL通常都不会被UPX压缩。这个方法甚至可以检测到各种各样的Exe2Aut版本,而不仅仅是我使用的那个,甚至还有一些自定义的反编译器。
创建了shellcode之后,我需要在准备好的可执行文件中找到一个位置,将我的shellcode注入其中。我在.text部分的末尾找到了一个大约210字节的编解码器,此时我的shellcode可以很容易地放入其中。为了执行我的shellcode,我决定在调用IsDebuggerPresent之后立即跳转到它,并在执行完成后返回正常执行流程。
saveRegisters:
push ecx
push ebx
push edx
checkInjected:
mov ebx, fs:[0x30] ; Get PEB address
mov ebx, [ebx+0xC] ; Get LDR Table address
mov ebx, [ebx+0x14] ; first entry of LDR table. (the first entry is the that of the executable)
mov edx, [ebx+0x10] ; Store the offset in edx
; I need this later to calculate the offsets
; of the resource names
nextModule:
mov ebx, [ebx] ; Get address of next LDR entry
mov ecx, dword ptr ds:[ebx+0x28] ; Pointer of the module name
test ecx, ecx ; If the pointer is OxO it means we have reached
; the end of our LDR table and we want to
je restoreRegisers ; continue normal execution
mov ecx,dword ptr ds:[ebx+0x10] ; Get the modules base offset
mov ecx, dword ptr ds:[ecx+0x178] ; load a dword from the modules base offset+0x178
cmp ecx,0x30585055 ; and check if it is "UPX0"
je swapResouces
jmp nextModule
swapResouces:
mov byte ptr ds:[edx+ 0xc7656], 0x49 ; Replace the '1' for a 'I' in "SCR1PT"
mov byte ptr ds:[edx+ 0xc765e] , 0x35 ; Replace the 'S' for a '5' in "SCRIPT"
restoreRegisers:
pop edx
pop ebx
pop ecx
test eax, eax ; Restore the instructions that were overwritten by
jnz debugerIsPresent ; the jump to the codecave
jmp debugerNotPresent ; Return to the normal program flow
程序集shellcode(70字节)
演示视频可以点击这里,从以上POC中我们可以学到的是,我们不应该总是盲目地相信我们使用的工具。逆向工程师应该意识到他们的工具是如何工作的,以及他们如何可能被欺骗而返回具有误导性的输出结果。虽然这里介绍的技巧可能会误导两个反编译器,但它们不会影响沙箱中的动态分析结果。
参考及来源:https://unit42.paloaltonetworks.com/autoit-compiled-malware/
文章评论