识别 ida.dll 导出函数为可读形式

作者: 一块三毛钱
邮箱: zhongts@163.com
日期: 2005.10.17

  逆向 Ida Pro 插件的时候会发现调用的插件函数都是通过序号导入的,函数名字都是 ida_123 的样子,从名字看不出来函数的作用。如果能够把函数名字都替换成有意义的名字会方便很多,比如 callui 肯定比 ida_169 要容易理解。本文就通过 idc 脚本语言来完成函数名替换的功能,首先通过 dumpbin /exports ida.lib >ida.lib_480.txt 命令生成函数序号和函数名对照关系的文件,ida.lib 是 sdk 中带的 vc32 格式的链接库。然后运行如下脚本实现替换。代码

#include <idc.idc>

static _GetImportSeg()
{
    auto    ea, name;
    ea = FirstSeg();
    while (ea != -1)
    {
        name = SegName(ea);
        if (substr(name, 0, 6 ) == ".idata") break;
        ea = NextSeg(ea);
    }
    return ea;
}

static _Process(fp, ea, szFuncName)
{
    auto    szFuncOrd;
    auto    szLine, szName;
    auto    iStart, iEnd;

    if (substr(szFuncName, 0, 4) == "ida_" || substr(szFuncName, 0, 4) == "IDA_")
    {
        szFuncOrd = substr(szFuncName, 4, -1);
        szFuncOrd = " " + szFuncOrd + " ";

        fseek(fp, 0, 0);
        szLine = readstr(fp);
        while (szLine != -1)
        {
            if (strstr(szLine, szFuncOrd) != -1)
            {
                iStart = strstr(szLine, "_");
                iEnd = strstr(szLine, "@");
                if (iEnd == -1)
                    iEnd = strlen(szLine) - 1;  //去掉最后的换行符
                szName = substr(szLine, iStart, iEnd);
                MakeName(ea, szName);
                Message("%s -> %s\n", szFuncName, szName);
                return;
            }
            szLine = readstr(fp);
        }
    }
    return;
}

static main()
{
    auto    szFile, fp;
    auto    ea, szFuncName;
    auto    BytePtr, EndImports;

    szFile = AskFile(0, "*.txt", "select a dumpbin's file...");
    fp = fopen(szFile, "r");
    if (fp == 0)
    {
        Message("Open File %s Failed!\n", szFile);
        return;
    }

    /* 处理函数名 */
    Message("ida.lib by zhongts (2005.10.17)\nProcess Function ...\n");
    ea = NextFunction(0);
    while (ea != -1)
    {
        szFuncName = GetFunctionName(ea);
        _Process(fp, ea, szFuncName);
        ea = NextFunction(ea);
    }

    /* 处理输入表 */
    BytePtr = SegStart(_GetImportSeg());
    EndImports = SegEnd(BytePtr);
    Message("Process Import Table ... (%X - %X)\n", BytePtr, EndImports);
    while (BytePtr < EndImports && BytePtr != -1)
    {
        _Process(fp, BytePtr, Name(BytePtr));
        BytePtr = NextAddr(BytePtr);
    }

    fclose(fp);
    Message(" OK!\n");

    return;
}

  分别处理函数形式和导入表中的形式是因为有些导入函数会被编译成 call/jmp 的函数形式,而有些会被编译成 mov eax,xxx/call eax 的形式。通过比较函数名(或者导入函数名)是否具有 ida_xxx 的形式来判断是否需要被替换,如果需要则取出函数名后面的序号 xxx,把 "xxx" 转换成 " xxx "是为了和文本文件中的序号匹配,然后通过查找对照文件把对应序号的函数名提取出来,替换原来的函数名。