使用idapython脚本解码样本中的字符串

@lzeroyuee  July 9, 2020

0x00 背景

在一次样本分析过程中,碰到了如下函数,此函数功能为解码字符串。
img1.png
按照平常的思路一般都是动态调试出字符串,然后在ida上打上注释。
如果此时同类型的样本量非常大,显然一个个的调试是不现实的。
这时便可以使用idapython辅助我们来对字符串进行解码。
此篇记下学习idapython脚本的过程。

0x01 确定解码过程

根据ida F5的结果来看,是将每个字节数据减去13
img2.png
我们很容易能编写出GenerateStr函数,如下:

def GenerateStr(data):
    str_len = len(data)
    decode_str = ""
    if str_len != 0:
        index = 0
        while index < str_len:
            decode_str += chr(ord(data[index]) - 13)
            index += 1
    return decode_str

0x02 确定调用GenerateStr的地址

在ida中,可以查找GenerateStr的引用来确定哪些地方调用了此函数
img3.png
同样,在idapython中也提供了接口

XrefsTo(func_addr, flags = 0)

0x03 获取GenerateStr的参数

通过观察,我们发现每次调用GenerateStr函数时,传入参数都是esi,则我们可以定位call GenerateStr,然后向上找mov esi, xxx,直到找到此指令时,xxx就是我们需要的参数地址
idapython脚本如下:

def find_function_arg(addr):
    while True:
        # 获取上一条指令地址
        addr = idc.PrevHead(addr)
        # 判断当前指令的操作码为mov,且第一个操作数为esi
        if GetMnem(addr) == "mov" and "esi" in GetOpnd(addr, 0):
            # print "[+]Found it at 0x%x" % GetOperandValue(addr, 1)
            break
     # 返回第二个操作数       
    return GetOperandValue(addr, 1)

得到参数地址之后,我们要获取参数的内容,可以循环读直到空字符

def get_string(addr):
    output = ""
    while Byte(addr) != 0:
        output += chr(Byte(addr))
        addr += 1
    return output

0x04 完整代码

def find_function_arg(addr):
    while True:
        addr = idc.PrevHead(addr)
        if GetMnem(addr) == "mov" and "esi" in GetOpnd(addr, 0):
            # print "[+]Found it at 0x%x" % GetOperandValue(addr, 1)
            break
    return GetOperandValue(addr, 1)
            
def get_string(addr):
    output = ""
    while Byte(addr) != 0:
        output += chr(Byte(addr))
        addr += 1
    return output
            
def GenerateStr(data):
    str_len = len(data)
    decode_str = ""
    if str_len != 0:
        index = 0
        while index < str_len:
            decode_str += chr(ord(data[index]) - 13)
            index += 1
    return decode_str
    

if __name__ == '__main__':
    func_addr = 0x00402F30
    result = {}
    for addr in XrefsTo(func_addr, flags = 0):
        arg_addr = find_function_arg(addr.frm)
        result[addr.frm] = (arg_addr, GenerateStr(get_string(arg_addr)))
    # print result
    
    for addr, (arg_addr, comm) in result.items():
        # print "[+]CallFunc: ", hex(addr), "\tArgAddr: ", hex(arg_addr), "\tComm: ", comm
        MakeComm(int(addr), comm)        # 添加注释
        MakeComm(int(arg_addr), comm)    # 添加注释
    
    print "done..."

添加新评论