首页
社区
课程
招聘
[原创]OD插件编写以及与IDC脚本的配合使用(含OD插件源码及IDC脚本)
发表于: 2010-11-29 15:10 21137

[原创]OD插件编写以及与IDC脚本的配合使用(含OD插件源码及IDC脚本)

2010-11-29 15:10
21137

OD插件编写以及与IDC脚本的配合使用(含OD插件源码及IDC脚本)
                             天易love   2010-11-29      
       用OD调试程序时,有时对其中某一段关键代码比较感兴趣,而你想节省时间也不想为了看那一小段伪代码而用IDA载入那个大家伙,这个时候怎么办呢?由于OD下我们还不能一下子看到伪代码,所以有了这个想法:
1、在OD中选中你感兴趣的代码导出机器码到文件中;
2、在IDA中用IDC脚本打开机器码文件并patch到某个空白处;
3、按F5看伪代码。
   通过实验已经实现,下面具体说一下:
一、关于导出机器码到文件中的OD插件的实现;
    由于本人孤陋寡闻不知道有没有这种插件,所以只好用vc  6.0自己编程实现。网上翻出来一个模板,照猫画虎,竟然也编译成功了。下面奉献自己的一点点经验,告诉大家我是如何从一无所知到写出自己需要的插件的全过程,希望对大家有益。
    我起初的想法是:通过选中一段代码,得到代码的首尾地址,这样就可以把该段内存中的机器码读取并保存到一个指定的文件中。但是这个地址怎么得到呢?读取内存要用什么函数呢?对于写插件我完全是个门外汗,所以我必须先逆向一个类似插件找点感觉。发现了一个插件Asm2Clipboard,它是把汇编代码以某种格式复制到粘贴板,看来可以先拿它开刀。
先静态调试直接看它的Pluginaction伪代码,如下:
int __cdecl ODBG_Pluginaction(int a1, int a2, int a3)
{
  int result; // eax@1
  result = a1;
  if ( a1 )
  {
    if ( a1 == 31 )  //CPU Disassembler窗口调用的?
    {
      result = a2;
      if ( a2 )
      {
        if ( a2 == 1 ) //菜单1?
        {
          sub_100011F0(a3); //关键函数 入口参数是item,可能item中有一些重要信息
          result = sub_100019D0();
        }
      }
      Else   //菜单2?
      {
        sub_100011F0(a3);
        result = sub_10001520();
      }
    }
  }
     查看OllyDbg Plugin API v1.10中有关的ODBG_Pluginaction的解释,才得出上面的注释。
Optional callback function. If present, OllyDbg calls it each time the user selected menu item added to menu by ODBG_Pluginmenu. 简单点就是OD会调用这个函数,当你点你自己的插件菜单时。

void ODBG_Pluginaction(int origin,int action,void *item);
Parameters:
origin - code of window that calls ODBG_Pluginaction. OllyDbg supports following codes:
Code        Cast item to        Who calls ODBG_Pluginmenu
PM_MAIN        item is always NULL        Main window
PM_DUMP        (t_dump *)        Any Dump window
PM_MODULES        (t_module *)        Modules window
PM_MEMORY        (t_memory *)        Memory window
PM_THREADS        (t_thread *)        Threads window
PM_BREAKPOINTS        (t_bpoint *)        Breakpoints window
PM_REFERENCES        (t_ref *)        References window
PM_RTRACE        (int *)        Run trace window
PM_WATCHES        (1-based index)        Watches window
PM_WINDOWS        (t_window *)        Windows window
PM_DISASM        (t_dump *)        CPU Disassembler
PM_CPUDUMP        (t_dump *)        CPU Dump
PM_CPUSTACK        (t_dump *)        CPU Stack
PM_CPUREGS        (t_reg *)        CPU Registers
     //第一个参数是个代码,Asm2Clipboard显然是用的31,那么这个31是哪个呢?在头文件Plugin.h中搜到了#define PM_DISASM  31 这一条,显然首先判断是否是CPU Disassembler这个反汇编窗口调用了Pluginaction函数,其次判断是点了哪个菜单。那么到底该用哪个函数呢?进入sub_100011F0(a3)看看,发现OLLYDBG_101(&v16, v1, 16, 3);它的入口参数就是得到的内存数据buffer,选中汇编代码区域的首地址,将要读取的代码字节长度,读取模式,而返回的机器码就在buffer中了。这个OLLYDBG_101到底是什么函数呢?用lordpe看了下OD原来是ulong Readmemory(void *buf,ulong addr,ulong size,int mode);这样使用的函数就搞定了;接下来就是选中区域的首尾地址该上哪找呢?通过动态调试原来Pluginaction(int a1, int a2, int a3)的第3个参数item是一个t_dump 结构指针。

   

typedef struct t_dump {         // Current status of dump window
  t_table    table;             // Treat dump window as custom table
  int        dimmed;            // Draw in lowcolor if nonzero
  ulong      threadid;          // Use decoding and registers if not 0
  int        dumptype;          // Current dump type, DU_xxx count size
  SPECFUNC   *specdump;         // Decoder of DU_SPEC dump types
  int        menutype;          // Standard menus, MT_xxx

  int        itemwidth;         // Length of displayed item, characters
  int        showstackframes;   // Show stack frames in address dump
  int        showstacklocals;   // Show names of locals in stack
  int        showsource;        // Show source as comment in disassembler
  char       filename[MAXPATH]; // Name of displayed or backup file
  ulong      base;              // Start of memory block or file
  ulong      size;              // Size of memory block or file

  ulong      addr;              // Address of first displayed byte
  ulong      lastaddr;          // Address of last displayed byte   1
  ulong      sel0;              // Address of first selected byte
  ulong      sel1;              // Last selected byte (not included!)
  ulong      startsel;          // Start of last selection
  int        captured;          // Mouse is captured by dump
  ulong      reladdr;           // Addresses relative to this
  char       relname[SHORTLEN]; // Symbol for relative zero address base

  char       *filecopy;         // Copy of the file or NULL
  char       *backup;           // Old backup of memory/file or NULL
  int        runtraceoffset;    // Offset back in run trace
  ulong      reserved[8];       // Reserved for the future extentions
} t_dump;
其中sel0 、sel1成员就是我想要的东西。
ulong      sel0;              // Address of first selected byte
  ulong      sel1;              // Last selected byte (not included!)

这样剩下的就是文件的写操作了。关于调试插件代码,我是用OD调试OD,设个插件用到的断点就可以断到插件的代码段中,动态调试一下以确认自己的判断。

action - identifier of menu item (0..63), as set by ODBG_Pluginmenu;
//第二个参数,判断是点击了哪个菜单
item - pointer either to selected element of sorted data displayed in window or, in case of dump windows, pointer to dump descriptor, or NULL. You may need this element to carry out requested action.//得到选择区域的首尾地址

关键代码如下:
extc int _export cdecl ODBG_Pluginmenu(int origin,char data[4096],void *item)
{
    t_dump *pd;
    if (origin==PM_DISASM) //  Popup menu in Disassembler
    {
        pd = (t_dump *)item;
        if (NULL == pd || 0 == pd->size)  return 0;   // Window empty, don't add
        if (pd->sel1 > pd->sel0) sprintf(data,"0 &Export to C:\\code.txt");//右键弹出菜单文        字
        return 1;
    }
    return 0;
}

extc void _export cdecl ODBG_Pluginaction(int origin,int action,void *item)
{
    const unsigned char table[]="0123456789ABCDEF";
        byte data[512]={0};
    char out[1024]={0x90};
    t_dump *pd;
          ulong start,readbytes,size,i,index;
        FILE *pFile;
         if(PM_DISASM == origin)   
         {
                pd = (t_dump *)item;
                  start=pd->sel0;
                  size= pd->sel1-start;
                  readbytes= Readmemory(data, start, size, MM_RESTORE|MM_SILENT);
                  pFile = fopen("c:\\code.txt", "w");      
                  if ( (pFile !=NULL)  &&  (readbytes=size) )
                  {              
                          for(i=0;i< readbytes;i  )
                          {  
                                        index= data[i]/16;
                                        out[3*i]=table[index];
                                        index= data[i] % 16;
                                        out[3*i 1]=table[index];
                                        out[3*i 2]=' ';             
                          }       
              fwrite(out,sizeof(char),3*readbytes-1,pFile); //去掉最后一个空格         
          fclose(pFile);
                  }
         }
}

   

   

   

       二、在IDA中用IDC脚本打开机器码文件并patch到某个空白处的实现

     用vc  6.0编写了一个body.exe 小程序,里面做了个地址0x401020开头的函数,填充了几百字节的nop指令,用来作为patch的地方,用IDA打开body.idb,G到0x401020处,先在OD中选中一段汇编代码,右键在弹出菜单中选择“export to C:\code.txt”,而后在IDA中执行脚本,在0x401020处按一下P键,如果不出意外的话,再F5一下就可以看到相应的伪C代码了。由于F5是有一定要求的,能否有用和你选择的代码也有一定的关系。脚本代码如下:

#define base_addr 0x401020
#define binaryfile "C:\\code.txt"
static main() {
auto  i,pos, st, st2, f, st_new, addr,b_new;
       for ( i=0; i < 0x200; i=i 1 )
{  
         PatchByte(base_addr i,0x90);   
        }
        f=fopen(binaryfile,"r");
        if (f!=-1)        
         {            
               addr=base_addr;   
               while ((st=readstr(f))!=-1)
              {                 
        //处理1行       
        while (strlen(st)>0)
                    {       
                while (strstr(st," ")==0 & strlen(st)>0)
                        { // 滤去开头的空格
                    st2=substr(st,1,-1);
                              st=st2;
                        }
                               st_new=substr(st,0,2);
                               b_new=xtol(st_new);
                st2=substr(st,2,-1);                                                        st=st2;         
                PatchByte(addr,b_new);
                MakeUnkn(addr,1);
                addr=addr 1;  
                }                     
                        }//while
            } //if
          fclose(f);
          PatchByte(addr,0xc3);
          Jump(base_addr);
          MakeCode(base_addr);   
}


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 7
支持
分享
最新回复 (20)
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好牛啊,学习中
2010-11-29 16:06
0
雪    币: 1432
活跃值: (3072)
能力值: ( LV9,RANK:156 )
在线值:
发帖
回帖
粉丝
3
下载学习   .
2010-11-29 16:36
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
天易的文章与头像一样好
2010-11-29 17:22
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
前些时候,我也正想做个保存选中代码 的字节码的插件

可惜不知道怎么获取当前选中的地方,

还是天易厉害,直接给逆出来个

海风的插件也有保存字节码的功能

我想他老人家肯定特别熟
2010-11-29 17:34
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
要是谁能直接在 OD 插件中实现 IDA 这功能,那就实在太强大了
2010-11-29 17:35
0
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
7
我不知道是不是有人在用,那一定是个非常懒的人。算法很有想象力,不知道有没有这方面的高手给大家上一课。
2010-11-29 17:47
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
8
如果OD能有分析出伪代码的轻量级插件就谢天谢地了,因为本人至今还未触电IDA
2010-11-29 20:11
0
雪    币: 112
活跃值: (51)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
顶,下载学习。
2010-11-29 20:43
0
雪    币: 6790
活跃值: (4446)
能力值: (RANK:600 )
在线值:
发帖
回帖
粉丝
10
向大牛学习这种专研精神.
2010-11-29 21:52
0
雪    币: 1708
活跃值: (586)
能力值: ( LV15,RANK:670 )
在线值:
发帖
回帖
粉丝
11
我还以为是在OD中按F5就给出伪码到文本或记录窗口中
2010-11-29 21:57
0
雪    币: 433
活跃值: (1870)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
12
同感………………
2010-11-30 12:33
0
雪    币: 8835
活跃值: (2404)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
13
同感~。。。。。。。。。。。。。。。。。。。。
2010-11-30 18:58
0
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
14
那你们帮我想个好点的标题?
2010-11-30 19:37
0
雪    币: 29
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
不错。不过用OD的右键菜单中的 备份 =》保存数据到文件
然后用IDA打开保存的文件(内存镜像),指定基址后,直接跳转到对应的地址,按C键反汇编,效果也一样吧。
2010-12-3 03:57
0
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
16
但是我只要右键一下,左键两下,按个P,按个F5,不会超过5秒。
2010-12-3 12:29
0
雪    币: 29
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
呵呵。这倒是。编程对于我来说是个老大难,所以有现成的方法就凑合着用了。
2010-12-4 06:47
0
雪    币: 72
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
学习了 好贴啊
2011-4-17 19:40
0
雪    币: 768
活跃值: (535)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
19
mark一下,刚才打这个贴子找了半天:)
2011-6-16 13:47
0
雪    币: 2015
活跃值: (902)
能力值: ( LV12,RANK:1000 )
在线值:
发帖
回帖
粉丝
20
楼上前辈我是看你的贴子成长起来的,非常感谢!
2011-6-17 12:17
0
雪    币: 768
活跃值: (535)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
21
汗颜呀,还好没误导:)

现在要好好向你学习,互助~:)
2011-6-17 12:49
0
游客
登录 | 注册 方可回帖
返回
//