HW期间,为防范钓鱼,即日起FreeBuf将取消投稿文章的一切外部链接。给您带来的不便,敬请谅解~
关于CallObfuscator
CallObfuscator是一款功能强大的API混淆工具,在该工具的帮助下,广大研究人员可以从静态/动态分析工具中混淆或隐藏PE导入,并使用其他不同的API来混淆特定的Windows API。
比如说,我们假设代码中使用了VirtualProtect,而我想要用Sleep来对其进行混淆处理,那么此时CallObfuscator将会修改IAT,然后让指向VirtualProtect的代码块改为指向Sleep。当我们执行该文件时,Windows加载器将会加载Sleep,而不会加载VirtualProtect,并将执行流转移到入口点,此时执行流将会被重定向至工具之前存储的shellcode,并寻找到VirtualProtect的真实地址,然后用这个地址替换加载器之前分配的Sleep的地址。
CallObfuscator获取
广大研究人员可以使用下列命令将该项目源码克隆至本地:
git clone https://github.com/d35ha/CallObfuscator.git
工具使用
我们可以直接将CallObfuscator以代码库的形式使用,请查看下列代码段,或者直接点击查看项目中的cli.cpp文件:
#include <cobf.hpp> int main() { cobf obf_file = cobf("sample.exe"); obf_file.load_pe(); obf_file.obf_sym("kernel32.dll", "SetLastError", "Beep"); obf_file.obf_sym("kernel32.dll", "GetLastError", "GetACP"); obf_file.generate("sample_obfuscated.exe"); obf_file.unload_pe(); return 0; };
除此之外,CallObfuscator也能够以命令行工具的形式使用,我们只需要提供输入PE路径、输出PE路径和配置文件路径即可。默认配置文件为config.ini:
cobf.exe <input file> <out file> [config file]
配置文件中包含了混淆处理所需的内容(dll和符号等)。下面给出的是配置文件的内容模板:
; Template for the config file: ; * Sections can be written as: ; [dll_name] ; old_sym=new_sym ; * The dll name is case insensitive, but ; the old and the new symbols are not. ; * You can use the wildcard on both the ; dll name and the old symbol. ; * You can use '#' at the start of ; the old or the new symbol to flag ; an ordinal. ; * The new symbol should be exported ; by the dll so the windows loader can resolve it. ; For example: ; * Obfuscating all of the symbols ; imported from user*32.dll with ordinal 1600. [user*32.dll] *=#1600 ; * Obfuscating symbols imported from both ; kernel32.dll and kernelbase.dll with Sleep. [kernel*.dll] *=Sleep ; * Obfuscating fprintf with exit. [*] fprintf=exit
工具使用样例
首先,我们需要构建下列样本代码:
#include <windows.h> #include <stdio.h> int main() { SetLastError(5); printf("Last error is %d\n", GetLastError()); return 0; };
构建完成之后,kernel32导入将如下图所示:
接下来,我们分别使用Beep和GetACP来混淆SetLastError和GetLastError(实际上,任何来自于kernel32的API都支持混淆,即使它们没有被导入)。
使用的配置信息如下:
[kernel32.dll] SetLastError=Beep GetLastError=GetACP
下面是混淆后的输出结果:
我们看看kernel32导入结果:
我们可以看到,其中已经不存在SetLastError或GetLastError了。
但是,我们的程序和文件仍然可以正常运行:
混淆处理效果
IDA HexRays反编译器:
IDA调试器:
Ghidra:
ApiMonitor:
这是因为所有静态分析工具都依赖于在IAT中编写的API名称,该名称可以如图所示进行操作。
对于ApiMonitor,由于使用IAT挂钩,同样的问题也存在。
另一方面,对于x64dbg这样的工具,显示的API名称将只取决于实际调用的内容(而不是IAT中编写的内容)。
注意事项
从内存中转储模糊处理后的PE不会使其失效,因为被修改的IAT是相同的。
此工具的主要目的是搞乱研究人员的分析过程(使其变慢)。
可以将任何导入的符号(按名称或序号)与另一个符号(名称或序号)混淆。
Shellcode会以第一个tls回调执行,并在执行入口点之前处理其他tls回调所需的模糊符号。
Shellcode将作为C代码执行,便于进行编译。
混淆的符号名称是通过哈希而不是直接通过名称来解析的。
该工具将禁用重定位并剥离任何调试符号。
该工具创建一个名为.cobf的新rwx字段,用于保存Shellcode和其他所需的数据。
它可以在同一个模糊处理的PE上使用多次。
工具仅在Windows 10 x64上进行过测试。
项目地址
CallObfuscator:见github。