• 当前位置:首页>>编程开发A>>安全防御>>IDASDK对指令操作数的识别
  • IDASDK对指令操作数的识别
  • 创建时间:2005-04-04
    文章属性:整理
    文章提交:san (san_at_xfocus.org)

    整理:san

    创建:2005.03.28

    --[ 1. 相关结构

    IDASDK的ua_ana0函数会调用ph.u_ana并且填充一个类型为insn_t的cmd结构。类insn_t在ua.hpp头文件里定义,通过这个类的结构可以轻松得到指定地址的指令类型和操作数等数据。

    IDAPro支持的指令类型都在allins.hpp里定义,每一种类型的处理器对应一个枚举。通过比较cmd.itype可以判断指定地址的指令类型是什么。

    操作定义在该类里类型为op_t的Operands数组结构,IDASDK允许一条指令最多有6个操作数。类op_t同样在ua.hpp里定义,本文主要要讨论的就是这个结构。类op_t里的type成员非常重要,就在op_t的上面一点定义,下面仔细介绍各种类型:

    o_void

    说明该操作数不可识别。

    o_reg

    说明该操作数只是一个寄存器。寄存器号保存在cmd.Operands[i].reg里面,对于x86的处理器来说,寄存器号可以在intel.hpp头文件里RegNo枚举变量中获取。其它类型的处理器,有些参考module目录下的一些头文件。当然,有很多类型的处理器没有资料。

    o_mem

    说明该操作数是一个引用目标地址的直接内存数据,这个目标虚拟地址保存在cmd.Operands[i].addr里。比如对于指令"mov eax, dword ptr ds:[0x00401000]",第二个操作数的类型是o_mem,用cmd.Operands[1].addr可以取到0x00401000。

    o_phrase

    说明该操作数是一个引用寄存器内容的内存数据。这种操作数可能包含基址寄存器、索引寄存器和缩放系数。当操作数只有一个寄存器的时候,寄存器号保存在cmd.Operands[i].phrase里。当操作数比较复杂的时候就会用到specflag。比如对于指令"lea eax, [ebx+ecx*4]",第二个操作数的类型是o_phrase。以这个指令为例,这时cmd.Operands[1].specflag1=1,cmd.Operands[1].specflag2=0x8B。specflag2的信息按照下面表格拆分表示:

    +-----------------------------------------------+
    |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
    +-----------------------------------------------+
    |  缩放系数 |    索引寄存器   |    基址寄存器   |
    +-----------------------------------------------+

    缩放系数的值是这样对应的:

    0 eq 0
    1 eq 2
    2 eq 4
    3 eq 8

    cmd.Operands[1].specflag2=0x8B拆解为:

    +-----------------------------------------------+
    |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0  |
    +-----------------------------------------------+
    |  1  |  0  |  0  |  0  |  1  |  0  |  1  |  1  |
    +-----------------------------------------------+
    |   2 -> 4  |     1 -> ecx    |     3 -> ebx    |
    +-----------------------------------------------+

    用表达式可以这样取:

    基址寄存器 - specflag2 & 7
    索引寄存器 - (specflag2 >> 3) & 7
    缩放系数   - (specflag2 & 0xC0) >> 6

    对于x86类型处理器,specflag确实是这样操作,但是对于其它类型的处理器,并不是这样,在小节里会提到。

    o_displ

    说明操作数是一个引用寄存器内容并且加偏移的内存数据。偏移值保存在cmd.Operands[i].addr里,其它信息同o_phrase。

    o_imm

    说明操作数是一个立即数。立即数的值保存在cmd.Operands[i].value里。

    o_near

    说明操作数是一个目标地址,通常用于分支跳转和调用指令的地址。目标虚拟地址保存在cmd.Operands[i].addr里。

    o_far

    说明操作数是一个跨段地址的引用。

    --[ 2. 演示代码

    /* oprand.cpp
    *
    *  Oprand demo plugin for IDAPro
    *  Written by san
    *
    *  Compile with:
    *  cl oprand.cpp /I "..\IDAPro\idasdk47\include" /D __NT__ /D __IDP__ /GX /link /dll "..\IDAPro\idasdk47\libvc.w32\ida.lib" /OUT:oprand.plw /export:PLUGIN
    */

    #include <ida.hpp>
    #include <idp.hpp>
    #include <loader.hpp>
    #include <ua.hpp>
    #include <allins.hpp>
    #include <lines.hpp>

    void test()
    {
        int i;
        char ins[256];

        ua_ana0(get_screen_ea());
        generate_disasm_line(cmd.ea, ins, sizeof(ins));
        tag_remove(ins, ins, sizeof(ins));
        
        msg("%08X \"%s\" <==\n  itype: %d\n  size : %d\n  pref : 0x%x\n",
            cmd.ea, ins, cmd.itype, cmd.size, cmd.auxpref);

        for (i=0; i<UA_MAXOP; i++) {
            if (!cmd.Operands[i].type) break;
            msg("  Op%d  : %d\n", i+1, cmd.Operands[i].type);

            switch (cmd.Operands[i].type)
            {
                case o_reg:
                    msg("    reg:%d dtyp:%d\n", cmd.Operands[i].reg, cmd.Operands[i].dtyp);
                    break;
                case o_mem:
                    msg("    mem:0x%x dtyp:%d\n", cmd.Operands[i].addr, cmd.Operands[i].dtyp);
                    break;
                case o_phrase:
                    msg("    phrase:0x%x dtyp:%d specflag1:0x%x specflag2:0x%x",
                        cmd.Operands[i].phrase, cmd.Operands[i].dtyp, cmd.Operands[i].specflag1, cmd.Operands[i].specflag2);
                    if (cmd.Operands[i].specflag1) {
               &nb
  • 上一篇:aa
    下一篇:[AD_LAB-05001] OpenOffice DOC document Heap Overflow