idapython修复全局变量段未识别指针

idapython修复全局变量段未识别指针

    在逆向的过程中,经常会遇到虚表或者指针数组的实现,这种时候在回溯一些危险函数调用的时候,经常找不到交叉引用,这里记录一下,下次就不去翻idapython的文档了。

 

    这是一个IoT设备的cgi,这部分的逻辑是根据不同的路由名称,调用不同的函数指针进行http请求的处理。这个action_table是一个结构体数组,这个结构体里面有函数指针和字符串指针,在ida中定位到action_table处,发现在全局变量段,没有正确识别变量类型,本来指针应该识别为dword类型的变量,但是识别成byte类型。也没有把整型识别成指针,这就导致大量的函数找不到交叉引用,非常影响后续分析。

  当然这种情况,可以手动一个一个去恢复,但是遗憾的是,今天遇到的这个结构体数组出奇得大,手动确实太笨拙了,所以我们需要idapython来自动化实现这个过程。idapython的话,至少需要两个api,一个把byte识别成dword,一个api去把全局变量标记成指针。然后开始google+idapython的文档,花了点时间,在官方文档和一些论坛上找到了对应的函数,最后贴出小脚本:

import idc,idaapi

for seg in idautils.Segments():
    if(idc.get_segm_name(seg)) == ".data":
        data_start_addr = idc.get_segm_start(seg)
        data_end_addr = idc.get_segm_end(seg)
        print("data segment start address: %s"%hex(data_start_addr))
        print("data segment end address: %s"%hex(data_end_addr))

# 识别变量类型的api: ida_bytes.create_*(),这里先识别为dword类型
# mark a global variable as an offset using IDAPython: idc_offset.op_offset(ea,0,idc.REF_OFF32)
ea = data_start_addr
while ea != data_end_addr:
    ida_bytes.create_dword(ea,4)
    value = idaapi.get_dword(ea)
    if value > 0xff:                                    # 结构体的字段中,存在非指针的整型变量,这里做个区分,避免ida里面出现非法地址引用了
        ida_offset.op_offset(ea,0,idc.REF_OFF32)
    ea += 4

   修复一下,就可以正常进行后续分析了,不用担心找不到交叉引用了。

    但是在这次的逆向工作中,我觉得可以不仅仅止步于此。前面提到过,这个函数指针实现的功能,是根据路由名称,调用不同的函数来处理http请求,还可以顺带着重命名一下函数名称方便后续分析。

  下面是我恢复过的结构体:

 

   结构体中一个成员变量是路由名称的字符串指针,这个用来调用不同结构体中的函数指针,一个结构体中有两个函数指针,一个是post请求会调用的,一个是get请求会调用的,然后还有一个成员变量用来判断是否是post请求,最后完善一下脚本。

import idc,idaapi,idautils

callaction_struct_size = 24
callaction_start_addr = 0x0097468
data_start_addr,data_end_addr = 0,0
end_addr = 0x00098444

def search_data_base():
    global data_start_addr,data_end_addr
    for seg in idautils.Segments():
        if(idc.get_segm_name(seg)) == ".data":
            data_start_addr = idc.get_segm_start(seg)
            data_end_addr = idc.get_segm_end(seg)
            print("data segment start address: %s"%hex(data_start_addr))
            print("data segment end address: %s"%hex(data_end_addr))

def fix_dataSeg_funcptr():
    ea,sz = data_start_addr,0
    data_end_addr = end_addr
    print(hex(ea))
    while ea <= data_end_addr:
        ida_bytes.create_dword(ea,4)
        value = idaapi.get_dword(ea)
        if value > 0xff:                                    # 结构体的字段中,存在非指针的整型变量,这里做个区分,避免ida里面出现非法地址引用了
            ida_offset.op_offset(ea,0,idc.REF_OFF32)

        if(ea >= callaction_start_addr):
            if(sz % callaction_struct_size == 0):
                action_name = idc.get_strlit_contents(idaapi.get_dword(ea)).decode()
                post_func_addr = idaapi.get_dword(ea + 4)
                get_func_addr = idaapi.get_dword(ea + 8)
                #idc.SetType(ea,"callaction")
                print("action name: %s"%action_name)
                if post_func_addr != 0:
                    idc.set_name(post_func_addr,(action_name + "_post"))
                if get_func_addr != 0:
                    idc.set_name(get_func_addr,(action_name + "_get"))
            sz += 4
        ea += 4
        
def main():
    search_data_base()
    fix_dataSeg_funcptr()

if __name__ == "__main__":
    main()

    恢复结果如下。如果全局变量段将变量类型设置成结构体的话,反而会找不到交叉引用,所以我只重命名了函数,把设置结构体那一行注释掉了。

 

 

 

 

 

posted @ 2022-10-27 23:21  Riv4ille  阅读(283)  评论(0编辑  收藏  举报