IDAPython 教程1
Using IDAPython to Make Your Life Easier: Part 1
使用IDAPython简化生活:第1部分
原文:https://unit42.paloaltonetworks.com/using-idapython-to-make-your-life-easier-part-1/
作为一名恶意软件反向工程师,我经常在日常活动中使用IDA Pro。看到IDA Pro是行业标准,这就不足为奇了(尽管Radar2和Hopper之类的替代产品正在受到关注)。我恳请所有逆向工程师使用的IDA的更强大功能之一是Python的附加功能,恰好命名为“ IDAPython”,它公开了大量IDA API调用。当然,用户还可以获得使用Python的额外好处,这使他们可以使用脚本语言提供的丰富功能。
不幸的是,关于IDAPython的教程信息很少。某些例外情况包括:
- 克里斯·伊格尔(Chris Eagle)的“ IDA Pro Book ”
- “ 初学者指南IDAPython ”亚历克斯Hanel
- Magic Lantern的“ IDAPython Wiki ”
为了增加分析人员可以使用的IDAPython教程材料的数量,我提供了一些有趣的用例时编写的代码示例。对于本系列的第1部分,我将介绍一种情况,在这种情况下,我可以编写脚本来阻止恶意软件样本中见证的字符串混淆的多个实例。
背景
在对恶意样本进行反向工程时,我遇到了以下功能:
图1字符串解密功能
根据经验,我怀疑这可能用于解密二进制文件中包含的数据。对此功能的引用数量支持了我的怀疑。
图2对可疑函数的大量引用
如图2所示,有116个实例被调用。在每次调用此函数的情况下,都会通过ESI寄存器将数据的blob作为该函数的参数提供。
图3调用可疑函数(405BF0)的实例
在这一点上,我相信恶意软件正在使用此功能在运行时解密字符串。面对这种情况时,我通常有几种选择:
- 我可以手动解密并重命名这些混淆的字符串
- 我可以动态运行此示例并在遇到字符串时重命名字符串
- 我可以编写一个脚本来解密这些字符串并为我重命名它们
如果在这种情况下,恶意软件总体上只解密了几个字符串,那么我可能会采用第一种或第二种方法。但是,正如我们之前所确定的,此功能已使用了116次,因此脚本编写方法将更加有意义。
IDAPython中的脚本
消除字符串混淆的第一步是识别并复制解密功能。对我们来说幸运的是,这个特定的解密功能非常简单。该函数只是将Blob的第一个字符用作剩余数据的单字节XOR键。
E4 91 96 88 89 8B 8A CA 80 88 88
在上面的示例中,我们将获取0xE4字节并将其与剩余数据进行XOR。这样做将导致字符串“ urlmon.dll”。在Python中,我们可以这样复制解密:
1
2
3
4
5
6
7
8
|
def decrypt(data):
length = len(data)
c = 1
o = ""
while c < length:
o += chr(ord(data[0]) ^ ord(data[c]))
c += 1
return o
|
在测试此代码时,我们得到了预期的结果。
1
2
3
4
|
>>> from binascii import *
>>> d = unhexlify("E4 91 96 88 89 8B 8A CA 80 88 88".replace(" ",''))
>>> decrypt(d)
'urlmon.dll'
|
我们的下一步将是识别引用解密函数的代码,并提取作为参数提供的数据。事实证明,在IDA中标识对函数的引用非常简单,因为XrefsTo()API函数正是这样做的。对于此脚本,我将对解密脚本的地址进行硬编码。以下代码可用于标识解密功能引用的地址。作为测试,我只是要打印出十六进制的地址。
1
2
3
4
5
6
7
8
9
10
11
12
|
for addr in XrefsTo(0x00405BF0, flags=0):
print hex(addr.frm)
Result:
0x401009L
0x40101eL
0x401037L
0x401046L
0x401059L
0x40106cL
0x40107fL
<truncated>
|
将提供的参数用于这些交叉引用并提取原始数据被证明有些棘手,但当然并非不可能。我们要做的第一件事是获取'mov esi,offset unk_ ??'中提供的偏移地址。将调用继续进行到字符串解密函数的指令。为此,对于每个对字符串解密函数的引用,我们将一次向后退一个指令,并查找“ mov esi,offset [addr]”指令。要获取偏移地址的实际地址,我们可以使用GetOperandValue() API函数。
以下代码使我们可以完成此任务:
1
2
3
4
5
6
7
8
9
10
|
def find_function_arg(addr):
while True:
addr = idc.PrevHead(addr)
if GetMnem(addr) == "mov" and "esi" in GetOpnd(addr, 0):
print “We found it at 0x%x” % GetOperandValue(addr, 1)
break
Example Results:
Python>find_function_arg(0x00401009)
We found it at 0x418be0
|
现在,我们只需要从偏移地址中提取字符串即可。通常,我们将使用GetString() API函数,但是,由于所讨论的字符串是原始二进制数据,因此该函数将无法正常工作。相反,我们将逐字节迭代直到到达空终止符。以下代码可用于完成此操作:
1
2
3
4
5
6
7
8
9
|
def get_string(addr):
out = ""
while True:
if Byte(addr) != 0:
out += chr(Byte(addr))
else:
break
addr += 1
return out
|
在这一点上,只需要将我们到目前为止创建的所有内容整合在一起即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
def find_function_arg(addr):
while True:
addr = idc.PrevHead(addr)
if GetMnem(addr) == "mov" and "esi" in GetOpnd(addr, 0):
return GetOperandValue(addr, 1)
return ""
def get_string(addr):
out = ""
while True:
if Byte(addr) != 0:
out += chr(Byte(addr))
else:
break
addr += 1
return out
def decrypt(data):
length = len(data)
c = 1
o = ""
while c < length:
o += chr(ord(data[0]) ^ ord(data[c]))
c += 1
return o
print "[*] Attempting to decrypt strings in malware"
for x in XrefsTo(0x00405BF0, flags=0):
ref = find_function_arg(x.frm)
string = get_string(ref)
dec = decrypt(string)
print "Ref Addr: 0x%x | Decrypted: %s" % (x.frm, dec)
Results:
[*] Attempting to decrypt strings in malware
Ref Addr: 0x401009 | Decrypted: urlmon.dll
Ref Addr: 0x40101e | Decrypted: URLDownloadToFileA
Ref Addr: 0x401037 | Decrypted: wininet.dll
Ref Addr: 0x401046 | Decrypted: InternetOpenA
Ref Addr: 0x401059 | Decrypted: InternetOpenUrlA
Ref Addr: 0x40106c | Decrypted: InternetReadFile
<truncated>
|
我们可以看到恶意软件中所有解密的字符串。尽管我们可以在这一点上停止,但是如果我们下一步在字符串解密参考地址和加密数据的位置提供解密字符串的注释,我们可以很容易地看到正在提供什么数据。为此,我们将使用MakeComm() API函数。在最后一条打印语句之后添加以下两行代码,将添加必要的注释:
1
2
|
MakeComm(x.frm, dec)
MakeComm(ref, dec)
|
添加此额外的步骤可以很好地清理交叉引用视图,如下所示。现在,我们可以轻松地确定引用特定字符串的位置。
图4运行IDAPython脚本后对字符串解密的交叉引用
此外,在浏览反汇编时,我们可以将解密后的字符串视为注释。
图5运行IDAPython脚本后的程序集
结论
使用IDAPython,我们能够执行原本困难的任务,即解密恶意二进制文件中的161个加密字符串实例,并非常容易地破坏二进制文件。如我们所见,IDAPython可以成为反向工程师的强大工具,简化各种任务并节省宝贵的时间。