及与其字节码间的关系。一般来说,该方法更有效,但是我们必须要能够得到程序的所有文
件。

该方法能够对付除了操作码重映射之外的所有混淆技术。下一节我们将讨论如何在操作
码重映射中获得有用的字节码。
3.对付操作码重映射
当使用了操作码重映射后,co_code对象与磁盘上的文件内容一样被混淆了。虽然我们
已经可以分析内存中的对象了,但是这并不能给我们很大的帮组,因为我们仍然无法知道字
节码中的真正操作码。为了能够将这种字节码反汇编为源码,我们需要一种更复杂的方法。
在Python 2.6.4中,一共定义了119中操作码。为了成功地反汇编重映射后的字节码,
我们需要推断出每个重映射后的操作码的真实值。由于我们已经能够获得修改后的Python
运行环境的控制权,我们可以用其来协助解码工作。
经过操作码重映射处理后的运行环境仍然携带了该应用程序所依赖于的Python标准库
文件以及其他可能的文件。当这些文件从.py编译成.pyc,其也使用了相同的混淆技术。有
这些文件的好处是,这些代码来源于我们已知的源代码。这就意味着,如果将相同的源码编
译成两份字节码,一份正常的和一份混淆后的,我们可以对比两份字节码来找出操作码的对
应关系。当然,单个模块不可能包含所有的Python操作码,因此我们需要分析多个模块知道
我们找到了所有的操作码或者我们已经分析完了所有的标准库模块。
如果应用程序仅使用了这一种混淆技术,那么我们就可以直接从磁盘上静态地分析.pyc
文件。但是如果该程序还使用了其他的混淆技术,那么我们就只能动态地来进行分析。
对由相同源码编译成的两份字节码进行对比分析是很简单的,下述简化的方法必须被执
行两次,一次在标准运行环境中以及另一次在修改后的运行环境:
1. 导入标准库模块。
2. 通过dir()函数获得一个包含函数/方法/的有序链表/generator。
3. 对每个函数的co_code中导出字节码。
4. 根据dir() list中的顺序将函数的字节码连在一起。
为了与正常文件区分,我们将上述连接在一起而形成的函数字节码存入.pyb文件。
一旦我们两个.pyb都有了,我们就可以简单地一个字节一个字节的对比。由于该软件仅
将操作码的值重映射了,如果我们发现两个字节相同,我们可以认为这两个字节是某个操作
码的参数。如果两个字节不同,我们可以认为这是一个操作数的重映射。图3是一个简单的
例子来解释这个。一个需要注意的问题是如果仅对一个子集的操作码进行了重映射,那么某
些操作码在标准模块和混淆后的模块中有相同的值。在现实中,我们可以很容易地解决该问
题。
一旦一个新的操作码值的映射被创建了,我们就创建一个新的opcode.py文件。我们现
在就可以反汇编Co_code对象中混淆后的字节码了。
以如下Python表达式为例:
print “bugs”
在标准Python中,该表达式被编译为如下的Python 汇编指令:
0 LOAD_CONST 0 (‘bugs’)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 1 (None)
8 RETURN_VALUE
这些指令依次变为如下字节码:
0x64, 0x0, 0x0, 0x47, 0x48, 0x64, 0x1, 0x0, 0x53
使用操作码重映射技术后编译得到的字节码为:
0x28, 0x0, 0x0, 0x19, 0x2e, 0x28, 0x1, 0x0, 0x12
现在对这两个字节流逐字节的对比,我们可以发现操作码本身是不一样的,
但是操作码的参数是一样的:
LOAD_CONST 0x64 -> 0x28
[ARG] 0x0
[ARG] 0x0
PRINT_ITEM 0x47 -> 0x19
PRINT_NEWLINE 0x48 -> 0x2e
LOAD_CONST 0x64 -> 0x28
[ARG] 0x1
[ARG] 0x0
RETURN_VALUE 0x53 -> 0x12
云中逆向工程
近年来,软件即服务的模式已经越来越流行。名词“云”也越来越多地被用来描述大量
系统和服务来提供该软件。本文仅讨论这种模式对于逆向工程的影响,而不会涉及其原理等。 |