首页
社区
课程
招聘
[原创]实战IDA脚本编程--用idc实现JumpNotFunction
发表于: 2013-4-23 11:28 23414

[原创]实战IDA脚本编程--用idc实现JumpNotFunction

2013-4-23 11:28
23414
实战IDA脚本编程--用idc实现JumpNotFunction

用IDA反汇编可执行文件时,经常遇到未命名代码片段。对于少量这样的代码片段可以用IDA的Search->not function来定位(快捷键通常为Alt-U),再用Edit->Functoins->Create function...(快捷键为P)创建新函数。如果出现大量这样的代码片段,反复用Alt-U,P操作就很繁琐。于是就想到利用用idc脚本来实现这个功能。查阅了IDA的Help(https://www.hex-rays.com/products/ida/support/idadoc/index.shtml),Search->not function这个功能的名称为JumpNotFunction,但在Help->Index of IDC functions中找不到相对应的函数(快捷键P有对应的MakeFunction)。

用Google搜索 "How to implement JumpNotFunction using idc script in IDA environment" (如何在IDA环境下用idc脚本实现JumpNotFunction),找不到答案。于是决定自己动手解决问题。经过一番学习,找到了主要的可以使用的相关函数:FindCode、GetFunctionName、FindFuncEnd、isCode、GetFlags,摘录如下。

1.
// ea - address to start from
// flag is combination of the following bits:
#define SEARCH_DOWN     0x01            // search forward
#define SEARCH_NEXT     0x02            // search next occurence
#define SEARCH_CASE     0x04            // search case-sensitive
                                        // (only for bin&txt search)
#define SEARCH_REGEX    0x08            // enable regular expressions
#define SEARCH_NOBRK    0x10            // don't test ctrl-break
#define SEARCH_NOSHOW   0x20            // don't display the search progress
//      return BADADDR - not found
long FindCode(long ea,long flag);

2.
// ea - any address belonging to the function
// returns: null string - function doesn't exist otherwise returns function name
string GetFunctionName(long ea);

3.
// ea  - starting address of a new function
// returns:        if a function already exists, then return its end address.
//                 if a function end cannot be determined, then return BADADDR
//                 otherwise return the end address of the new function
long FindFuncEnd(long ea);

4.
#define MS_CLS  0x00000600L             // Mask for typing
#define FF_CODE 0x00000600L             // Code ?
#define FF_DATA 0x00000400L             // Data ?
#define FF_TAIL 0x00000200L             // Tail ?
#define FF_UNK  0x00000000L             // Unknown ?
#define isCode(F)       ((F & MS_CLS) == FF_CODE) // is code byte?

5.
// ea - linear address
// returns: 32-bit value of internal flags. See start of IDC.IDC file for explanations.
long GetFlags(long ea);         // get internal flags for ea

以上函数有关参数的简要说明如下(其中的BADADDR为无效地址):

1. FindCode参数:
输入:
  ea=有效起始地址
  flag=SEARCH_DOWN=向下(地址增加方向)搜索
     (SEARCH_NEXT=搜索下一个;
       SEARCH_CASE=搜索时区分大小写,仅对二进制和文本有效;
       SEARCH_REGEX=允许正则表达式;
       SEARCH_NOBRK=不检测Ctrl-Break按键;
       SEARCH_NOSHOW=不显示搜索进度)
输出:
  返回代码片段起始地址(如果没找到代码片段,则返回BADADDR)。

2. GetFunctionName参数:
输入:
  ea=属于某个函数代码范围内的任何有效地址。
输出:
  返回函数名字符串,如果函数不存在,则返回空字符串。

3. FindFuncEnd参数说明:
输入:
  ea=某个新建函数的起始有效地址。
输出:
  如果函数已经存在,则返回其结束地址;如果函数的结束地址不确定,则返回BADADDR;否则返回新建函数的结束地址。

4. isCode参数说明(isCode实际上为宏定义):
输入:
  F=相对与某个有效地址的标志。
输出:
  逻辑值:1(True)=是代码;0(False)=非代码。

5. GetFlags参数说明:
输入:
  ea=线性有效地址。
输出:
  对应于ea的标志。

有了这些资料就可以动手构建JumpNotFunction了。首先要获取一个有效地址,通常使用ScreenEA获取当前屏幕光标所在地址,然后判断该地址是否为代码,关键在于判断代码是否属于某个函数。也可以用ScreenEA保存当前地址,再用MinEA获取代码段起始地址并对整个代码段进行扫描,然后恢复当前地址。

我们可以用File->IDC Command...(快捷键Shift-F2)把以下代码粘贴到弹出文本窗口测试一下:

  auto ea,name;    // 声明自动类型变量
  ea = ScreenEA(); // 获取当前地址
  ea = FindCode(ea,SEARCH_DOWN); // 找代码片段
  name = GetFunctionName(ea);  // 获取函数名
  Message("ea=%lx   name=%s\n",ea,name); // 显示信息

先找到某个已经定义函数(sub_40xxxx为某个函数的起始地址),运行上述代码,可以到到以下信息:
ea=40xxxx   name=sub_40xxxx

再用Edit->Functions->Delete function删除该函数后运行上述代码,可以到到以下信息:
ea=40xxxx   name=

这说明上述代码有效。

以下是该函数以及利用该函数解决问题的完整代码:

#include <idc.idc>

// 输入:
//   ea=起始有效地址
// 输出:
//   返回未命名代码片段有效地址;如果没找到,则返回BADADDR。
static JumpNotFunction(ea)
{
  auto name;
  do {
    if (!isCode(GetFlags(ea)) || Byte(ea) == 0x90 || Byte(ea) == 0xCC) // 过滤无效代码
      ea = FindCode(ea,SEARCH_DOWN);
    name = GetFunctionName(ea);
    if (name == "" && ea != BADADDR) // 如果找到未定义函数,就跳转到该有效地址
    {
      Jump(ea);
    }
    else
      ea = FindFuncEnd(ea); // 如果是一定义函数,继续查找
  } while(name != "" && ea != BADADDR);
  return ea;
}

// 利用JumpNotFunction解决问题
static main(void)
{
  auto ea0,ea,ea_end,fok;
  ea0 = ScreenEA(); // 记住当前光标位置
  ea=MinEA(); // 从头开始
  ea_end = SegEnd(ea); // 防止地址越界
  Message("ea0=%lx\n",ea);
  do{
    ea = JumpNotFunction(ea); // 调用刚建立的函数
    if (ea != BADADDR)
      fok = MakeFunction(ea,BADADDR);
    if (!fok) {
      ea = FindFuncEnd(ea);
      Jump(ea);
    }
  } while (ea < ea_end && ea != BADADDR);
  Jump(ea0); // 恢复光标位置
}

将以上内容另存为JumpNotFunction.idc文件并复制到idc子文件夹下,就可以用File->IDC file...打开运行了。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
先实验一把 感谢楼主分享
2013-4-23 13:18
0
雪    币: 123
活跃值: (326)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
请问,如何修改函数名?找不到相应的IDC函数,手动可以修改。
2017-3-21 16:10
0
雪    币: 107
活跃值: (12)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
修改函数名,  MakeName  即可.
2017-7-24 14:33
0
游客
登录 | 注册 方可回帖
返回
//