元始天尊 发表于 2015-1-2 23:47:16

OllyDbg插件深入分析二

OllyDbg插件深入分析一        http://www.0xaa55.com/forum.php?mod=viewthread&tid=1133&extra=


第二章 OllyDbg1输出函数按功能分类

学习Windows编程需要熟悉WindowsAPI,同样地,熟悉OllyDbg插件编程也要熟悉OllyDbg API,下面是我的学习路线。插件函数

intRegisterpluginclass(char *classname,char *iconname,HINSTANCE dllinst,WNDPROCclassproc);
voidUnregisterpluginclass(char *classname);
intPluginwriteinttoini(HINSTANCE dllinst,char *key,int value);
intPluginwritestringtoini(HINSTANCE dllinst,char *key,char *s);
intPluginreadintfromini(HINSTANCE dllinst,char *key,int def);
intPluginreadstringfromini(HINSTANCE dllinst,char *key,char *s,char *def);
intPluginsaverecord(ulong tag,ulong size,void *data);
intPlugingetvalue(int type);
t_statusGetstatus(void);
Registerpluginclass原型:intRegisterpluginclass(char *classname,char *iconname,HINSTANCE dllinst,WNDPROCclassproc)功能:生成唯一的类名并注册为插件窗口。如果iconname为NULL则使用标准插件图标(字母P)
返回:成功时返回0并填充classname,失败时返回1
参数:
      classname 指向大小大于32字符的缓冲区用于接收类名
      iconname 插件DLL中图标资源名
      dllinst 插件实例句柄
      classproc 新类的窗口过程地址
注意:注册后窗口类有8个整数(32字节)的额外空间,插件可以自由使用第2到7个整数空间(偏移8到28用于GetWindowLong和SetWindowLong)。ODBG_Plugininit是执行该函数的最佳位置
Unregisterpluginclass原型:voidUnregisterpluginclass(char *classname)功能:注销之前通过Registerpluginclass注册的窗口类
参数:
      classname 函数Registerpluginclass返回的类名
注意:在ODBG_Plugindestroy中对所有注册的窗口类调用该函数
Pluginwriteinttoini原型:intPluginwriteinttoini(HINSTANCE dllinst,char *key,int value)功能:将整数值绑定的键值对存储在ollydbg.ini的插件自定义区段中
返回:成功时返回1,失败时返回0
参数:
      dllinst 插件实例句柄
      key 整数相关的键名
      value 要存储在ollydbg.ini的整数
Pluginwritestringtoini原型:intPluginwritestringtoini(HINSTANCE dllinst,char *key,char *s)功能:将ASCII字符串绑定的键值对存储在ollydbg.ini的插件自定义区段中
返回:成功时返回1,失败时返回0
参数:
      dllinst 插件实例句柄
      key 字符串相关的键名
      s 要存储在ollydbg.ini的字符串
Pluginreadintfromini原型:intPluginreadintfromini(HINSTANCE dllinst,char *key,int def)功能:将整数值绑定的键值对从ollydbg.ini的插件自定义区段中读取出来
返回:成功时返回目标整数,失败时返回默认值
参数:
      dllinst 插件实例句柄
      key 整数相关的键名
      def 默认值
Pluginreadstringfromini原型:intPluginreadstringfromini(HINSTANCE dllinst,char *key,char *s,char *def)功能:将字符串绑定的键值对从ollydbg.ini的插件自定义区段中读取出来
返回:成功时返回目标字符串,失败时返回默认值
参数:
      dllinst 插件实例句柄
      key 字符串相关的键名
      s 用于接收目标字符串
      def 默认字符串,以零终止符结尾
Pluginsaverecord原型:intPluginsaverecord(ulong tag,ulong size,void *data)功能:将一个记录写入.udd文件
返回:成功时返回1,失败时返回0
参数:
      tag 插件唯一的标签
      size 写入.udd文件的数据大小,最大USERLEN
      data 写入.udd文件的数据缓冲区
注意:只能从ODBG_Pluginsaveudd中调用,否则会崩溃
Plugingetvalue原型:intPlugingetvalue(int type)功能:返回OllyDbg多个设置和变量信息
参数:
      type 要返回的设置或变量信息

type实际类型含义
VAL_HINSTHINST当前OllDbg实例句柄
VAL_HWMAINHWNDOllyDbg主窗口句柄
VAL_HWCLIENTHWNDMDI用户窗口句柄
VAL_NCOLORS 常见颜色数
VAL_COLORSCOLORREF*常见颜色RGB值数组
VAL_BRUSHESHBRUSH*常见颜色画刷句柄数组
VAL_PENSHPEN*常见颜色画笔句柄数组
VAL_NFONTS 常见字体数
VAL_FONTSHFONT*常见字体句柄数组
VAL_FONTNAMESChar**内部字体名称
VAL_FONTWIDTHSint*常见字体平均宽度
VAL_FONTHEIGHTSint*常见字体平均高度
VAL_NFIXFONTS 固定字宽字体数
VAL_DEFFONT 默认字体序号
VAL_NSCHEMES 配色方案数
VAL_SCHEMESt_scheme*配色方案数组
VAL_DEFSCHEME 默认配色方案数组
VAL_DEFHSCROLL 默认水平滚动
VAL_RESTOREWINDOWPOS 从.ini文件恢复窗口位置
VAL_HPROCESSHANDLE被调试进程句柄
VAL_PROCESSID 被调试进程标志ID
VAL_HMAINTHREADHANDLE被调试进程主线程句柄
VAL_MAINTHREADID 被调试进程主线程标志ID
VAL_MAINBASE 被调试进程主模块基址
VAL_PROCESSNAMEchar*被调试进程名
VAL_EXEFILENAMEchar*被调试程序文件名
VAL_CURRENTDIRchar*被调试进程当前目录
VAL_SYSTEDIRchar*系统目录
VAL_DECODEANYIP 不依赖EIP解码寄存器
VAL_PASCALSTRINGS 解码Pascal格式字符串
VAL_ONLYASCII 只解码可打印ASCII字符
VAL_DIACRITICALS 允许字符串有变音符号
VAL_GLOBALSEARCH 从块的开始处搜索
VAL_ALIGNEDSEARCH 逐项搜索
VAL_SEARCHMARGIN 浮点搜索允许误差
VAL_KEEPSELSIZE 保存16进制编辑中选择项数
VAL_MMXDISPLAY 对话框MMX显示模式(0:16进制 1:有符号 2:无符号)
VAL_WINDOWFONT 对话框中使用窗口字体
VAL_TABSTOPS 制表符大小
VAL_MODULESt_table*模块表(包括.EXE和.DLL)
VAL_MEMORYt_table*分配内存块表
VAL_THREADSt_table*活动线程表
VAL_BREAKPOINTSt_table*激活断点表
VAL_REFERENCESt_table*查找到的参考信息表
VAL_SOURCELISTt_table*源文件表
VAL_WATCHESt_table*监视情况表
VAL_CPUFEATURES CPUID返回的CPU特征位
VAL_TRACEFILEFILE*运行跟踪记录文件句柄
VAL_ALIGNDIALOGS 对齐对话框
VAL_CPUDASMt_dump*获取CPU反汇编窗口描述符
VAL_CPUDDUMPt_dump*获取CPU内存窗口描述符
VAL_CPUDSTACKt_dump*获取CPU栈窗口描述符
VAL_APIHELPchar*选择的API帮助文件名
VAL_HARDBP 硬件断点是否激活
VAL_PATCHESt_table*补丁表
VAL_HINTSt_sorted*带分析提示的排序数据

说明:带有VAL_N***的type变量表示获取数量,需要先获取该数量才能知道对应的VAL_***数据数组有多大。例如FONT系列,首先要调用Plugingetvalue(VAL_NFONTS)获取字体个数,之后再调用VAL_FONTNAMES等获取数据数组,数组元素个数就是前一步获取的个数。t_table和t_dump也类似,t_table内含的重要数据是t_sorteddata,而t_sorted结构体自身包含了元素个数,因此读者可根据例1写出输出更完整信息的程序了。返回t_dump类型的函数大部分是窗口数据,从这个意义上插件可以做的和OllyDbg一模一样!Getstatus原型:t_statusGetstatus(void)功能:返回被调试进程的当前状态(STAT_XXX)
返回:

STAT_NONE
未调试进程

STAT_STOPPED
进程挂起

STAT_EVENT
处理调试事件,进程暂停

STAT_RUNNING
进程运行

STAT_FINISHED
进程结束

STAT_CLOSING
调用TerminateProcess()等待结果


例一

#include <windows.h>#include <stdio.h>#include "Plugin.h"#pragma comment(lib,"OllyDbg.lib") char classname;HINSTANCE hinst=NULL; class log//用于实现插件日志记录——单例模式{private:      log()      {               try               {                         if(!AllocConsole())                         {                                  MessageBox(NULL,"无法创建命令行窗口","错误",MB_OK);                                  throw "错误";                         }               }               catch(...)               {                         exit(0);               }      };      ~log()      {               FreeConsole();      } public:      static void v(char* tolog)      {               static log obj;               HANDLEout=GetStdHandle(STD_OUTPUT_HANDLE);               DWORDWriteNum;               WriteConsole(out,tolog,strlen(tolog),&WriteNum,NULL);      }}; BOOL WINAPI DllMain(HINSTANCE hi,DWORD reason,LPVOID reserved){//DLL入口点      if (reason==DLL_PROCESS_ATTACH)      {               hinst=hi;//保存实例句柄供后面使用      }      return 1; } LRESULT CALLBACK WndProc(HWND hw,UINT msg,WPARAM wp,LPARAM lp){      return DefWindowProc(hw,msg,wp,lp);//暂时不用这里,因此只写个空架子} extc int _export cdecl ODBG_Plugininit(int ollydbgversion,HWND hw,ulong *features){      chartemp;      sprintf(temp,"版本号:%d\n",ollydbgversion);      log::v(temp);      if(0 == Registerpluginclass(temp,NULL,hinst,WndProc))      {               log::v("插件注册成功:");               log::v(temp);               log::v("\n");      }      else      {               log::v("插件注册失败\n");      }       return 0;} extc int _export cdecl ODBG_Plugindata(char shortname) {//用于插件菜单中显示插件名      strcpy(shortname,"sample1");         return PLUGIN_VERSION;} extc int _export cdecl ODBG_Pluginshortcut(int origin,int ctrl,int alt,int shift,int key,void *item){//按下I键(代表Information)显示OLLYDBG和进程信息               if (key!='I')                         return 0;               switch(Getstatus())               {                         case STAT_NONE:                                  log::v("——————————————未调试进程——————————————\n");                                  break;                         case STAT_STOPPED:                                  log::v("——————————————进程挂起——————————————\n");                                  break;                         case STAT_EVENT:                                  log::v("——————————————进程暂停,处理调试事件——————————————\n");                                  break;                         case STAT_RUNNING:                                  log::v("——————————————进程运行——————————————\n");                                  break;                         case STAT_FINISHED:                                  log::v("——————————————进程结束——————————————\n");                                  break;                         case STAT_CLOSING:                                  log::v("——————————————进程等待关闭——————————————\n");                                  break;               }                chartemp;               sprintf(temp,"OllyDbg实例句柄:0x%0x\n",Plugingetvalue(VAL_HINST));               log::v(temp);               sprintf(temp,"OllyDbg主窗口句柄:0x%0x\n",Plugingetvalue(VAL_HWMAIN));               log::v(temp);               sprintf(temp,"被调试进程句柄:0x%0x\n",Plugingetvalue(VAL_HPROCESS));               log::v(temp);               sprintf(temp,"被调试进程ID:%d\n",Plugingetvalue(VAL_PROCESSID));               log::v(temp);               sprintf(temp,"被调试进程主线程句柄:0x%0x\n",Plugingetvalue(VAL_HMAINTHREAD));               log::v(temp);               sprintf(temp,"被调试进程主线程ID:%d\n",Plugingetvalue(VAL_MAINTHREADID));               log::v(temp);               sprintf(temp,"被调试进程主模块基址:0x%0x\n",Plugingetvalue(VAL_MAINBASE));               log::v(temp);               sprintf(temp,"被调试进程名:%s\n",Plugingetvalue(VAL_PROCESSNAME));               log::v(temp);               sprintf(temp,"被调试进程文件名:%s\n",Plugingetvalue(VAL_EXEFILENAME));               log::v(temp);               sprintf(temp,"被调试进程当前目录:0x%0x\n",Plugingetvalue(VAL_CURRENTDIR));               log::v(temp);               sprintf(temp,"系统目录:%s\n",Plugingetvalue(VAL_SYSTEMDIR));               log::v(temp);               sprintf(temp,"被调试进程主模块基址:0x%0x\n",Plugingetvalue(VAL_MAINBASE));               log::v(temp);};

说明:如第一章所述,用到的OllyDbg-API有Registerpluginclass,Plugingetvalue,Getstatus都要在Plugin.h重新定义。该代码为Windows DLL项目主文件,插件启动后会出现控制台窗口,在加载了进程后,在OllyDbg窗口激活时按下“I”键,会输出类似下面的数据:
版本号:110
插件注册成功:OT_PLUGIN_0000
——————————————进程挂起——————————————
OllyDbg实例句柄:0x400000
OllyDbg主窗口句柄:0x3f1c14
被调试进程句柄:0x3c0
被调试进程ID:6932
被调试进程主线程句柄:0x758
被调试进程主线程ID:10444
被调试进程主模块基址:0x1000000
被调试进程名:RC
被调试进程文件名:D:\Program Files (x86)\Microsoft Visual Studio\Common\MSDev98\
Bin\RC.EXE
被调试进程当前目录:0x4d5c84
系统目录:C:\windows\system32\
被调试进程主模块基址:0x1000000
file:///C:/Users/lichao/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
本例中提供的log类极为有用,因此需要单独提取出来作为一个文件,后面例子只包含log.h即可,不再赘述

hjie 发表于 2015-4-17 11:17:52

写的很好,帮了很大忙,希望可以继续
页: [1]
查看完整版本: OllyDbg插件深入分析二