本帖最后由 元始天尊 于 2015-1-2 23:44 编辑
第一章 初探OllyDbg1插件
官网http://www.ollydbg.de/给出了关于插件开发的信息。OllyDbg1.10的插件开发包在http://www.ollydbg.de/plug11.zip。该压缩包包含以下文件:
│ Bookmark.c OllyDbg书签插件源码,该插件支持调试程序时设置10个书签
│ Cmdexec.c OllyDbg命令行插件,该插件支持输入命令进行调试
│ Cmdline.rtf 命令行插件的帮助文件
│ Command.c
│ Ollydbg.def OllyDbg定义文件,某些编译器用之生成输入链接库ollydbg.lib
│ Plugin.h 插件公共头文件
│ Plugins.hlp 插件编写说明
(Win8.1打不开hlp的解决方法http://www.microsoft.com/zh-cn/download/details.aspx?id=40899)
│
├─Bc55 Borland C++系列编译器工程
│ BOOKMARK.MAK
│ CMDLINE.BPR
│ CMDLINE.CPP
│ CMDLINE.MAK
│ OLLYDBG.LIB
│ SAMPLE.BPR
│ SAMPLE.CPP
│
└─Vc50 Visual C++系列编译器工程,这也是本文所使用的开发环境
BOOKMARK.DSP
BOOKMARK.DSW
BOOKMARK.MAK
CMDLINE.DSP
CMDLINE.DSW
CMDLINE.MAK
OLLYDBG.LIB
一、基本原理
OllyDbgv1.10是OllyDbg1系列的最终版本,作者已停止开发,转而开发v2.0版本,新版本和1.xx版本是不兼容的,插件也是如此。对于1.xx版本,插件大体上通用,这几个版本的改动有:
l t_reg和t_bpoint结构体扩展
l 新选项“总在最前”需要插件窗口特殊支持
l Browsefilename支持保存文件对话框
插件是提供附加功能的DLL文件,位于OllyDbg目录下。OllyDbg启动时会逐个加载所有可用的DLL文件,检查名为_ODBG_Plugindata和_ODBG_Plugininit的入口点(输出函数),如果存在并且插件版本号兼容,OllyDbg会注册插件并在插件子菜单增加相应项。插件可以在反汇编、转储、堆栈、内存、模块、线程、断点、监视、参考、界面窗口、运行跟踪窗口增加菜单项和监视全局/局部快捷键。插件可以是MDI窗口;可以在.udd文件中写入模块相关的自定义数据;可以访问和修改ollydbg.ini的数据结构以描述调试信息。插件使用多个回调函数和OllyDbg通信,可以调用170+个插件API函数。插件接口不是面向对象的。
插件API函数不是线程安全的,没有实现临界区,插件创建的新线程不能调用这些函数,否则可能导致OllyDbg和程序崩溃。
二、编译
请将编译器按如下设置以便插件和OllyDbg通信,plugin.h会检查这些设置:
通过名称输出所有导出函数,而非序数
l 如果使用C++编译器则需要禁用导出函数的名称修饰(使用extern “C”) l 强制所有API函数和导出函数使用C格式调用_cdecl l 强制所有结构体按字节对齐 l 默认字符类型为unsigned型 编译自定义插件会用到plugin.h ollydbg.lib,需要复制到工程目录中。
现在以VS2010为例介绍如何编写无任何功能的插件。首先建立一个Windows动态链接库的空项目,在工程属性中,选C/C++ -> 命令行,右侧“其它选项”加入“/J”。之后向工程添加helloworld.cpp,内容如下:
#include <windows.h> #include "lugin.h" HINSTANCE hinst=NULL; BOOL WINAPIDllEntryPoint(HINSTANCE hi,DWORD reason,LPVOID reserved) {//DLL入口点 if (reason==DLL_PROCESS_ATTACH) hinst=hi; return 1; } extc int _export cdecl ODBG_Plugininit(int ollydbgversion,HWND hw,ulong *features) { MessageBox(NULL,"HelloWorld","HelloWorld",MB_OK); return 0; } extc int _export cdecl ODBG_Plugindata(char shortname[32]) {//用于插件菜单中显示插件名 strcpy(shortname,"HelloWorld"); return PLUGIN_VERSION; }
编译得到的dll放到ollydbg根目录下,启动ollydbg就可以看到弹出对话框,同时插件菜单栏多了一项“Hello Wolrd”。
调用OllyDbg-API:欲调用OllyDbg导出函数(例如FuncA),首先在源文件中包含Plugin.h,并在调用之前增加代码“#pragmacomment(lib,"ollydbg.lib")”,同时将插件开发包Vc50目录下的ollydbg.lib拷贝到工程目录中。此外OllyDbg作者写的Plugin.h不适用于VS系列编译器,由于ollydbg.exe实际导出符号为下划线版本(_FuncA),而plugin.h声明的是无下划线形式,因此直接编译会出现链接问题,而作者仅对ODBG系列函数作出调整而未对OllyDbg-API声明作出相应调整,因此所有用到的OllyDbg-API都需要进行手工调整,先找到Plugin.h中这样的代码段: #define ODBG_Plugindata _ODBG_Plugindata #define ODBG_Plugininit _ODBG_Plugininit #define ODBG_Pluginmainloop _ODBG_Pluginmainloop #define ODBG_Pluginsaveudd _ODBG_Pluginsaveudd #define ODBG_Pluginuddrecord_ODBG_Pluginuddrecord #define ODBG_Pluginmenu _ODBG_Pluginmenu #define ODBG_Pluginaction _ODBG_Pluginaction #define ODBG_Pluginshortcut _ODBG_Pluginshortcut #define ODBG_Pluginreset _ODBG_Pluginreset #define ODBG_Pluginclose _ODBG_Pluginclose #define ODBG_Plugindestroy _ODBG_Plugindestroy #define ODBG_Paused _ODBG_Paused #define ODBG_Pausedex _ODBG_Pausedex #define ODBG_Plugincmd _ODBG_Plugincmd 在其后加入自己的声明,如: #define Plugingetvalue _Plugingetvalue #define Getstatus _Getstatus 这样方可正常编译链接。 生成ollydbg.lib:ollydbg.lib可以由插件根目录存在ollydbg.def文件手动生成,这里会用到VS编译器自带工具lib.exe,命令如下:lib/MACHINE:X86 /DEFllydbg.def 调试:写插件本身具有难度,然而调试OllyDbg运行插件似乎就更难了。然而我却不以为然,将OllyDbg拷贝到生成dll的目录中(前提是该版本OllyDbg读取插件的目录为自身根目录),设置工程属性=>调试=>命令,将拷贝后的OllyDbg文件路径写入该处,调试即可在DLL源码中断下。 三、使用MFC开发OllyDbg1插件
上面介绍的是使用MSVC的Windows DLL工程的情况,而这里介绍如何结合MFC进行插件开发。经我测试,VS2010及之后的MFC,由于内部使用的ATL和/J编译指令冲突,因此无法编译,而VC6版本可以很好地编译。下面是开发步骤,以test为例:
1. 新建名为test的MFC DLL工程 2. 在自动生成的StdAfx.h文件末尾加入 #inclue “Plugin.h” 同时将Plugin.h拷入工程目录 3. 在test.cpp中添加ODBG_***导出函数 4. 在调用OllyDbg导出函数之前,加入#pragma comment(lib,"ollydbg.lib")
四、插件生命周期
OllyDbg所规定的插件输出函数,其实正好反映了插件的生命周期,类似于窗口的生命周期,它与消息机制相关。下面通过实例得到插件生命周期:
#include <windows.h> #include "lugin.h" extc int _export cdecl ODBG_Plugindata(char shortname[32]) {//插件检测 strcpy(shortname,"菜单显示项"); MessageBox(NULL,"ODBG_Plugindata","",MB_OK); return PLUGIN_VERSION; } extc int _export cdecl ODBG_Plugininit(int ollydbgversion,HWND hw,ulong *features) {//插件初始化 MessageBox(NULL,"ODBG_Plugininit","",MB_OK); return 0; } extc int _export cdecl ODBG_Pluginmenu(int origin,char data[4096],void *item) {//初始化菜单项 MessageBox(NULL,"ODBG_Pluginmenu","",MB_OK); return 0; } extc int _export cdecl ODBG_Pluginclose(void) {//用户关闭OllyDbg时触发 MessageBox(NULL,"ODBG_Pluginclose","",MB_OK); return 0; } extc void _export cdecl ODBG_Plugindestroy(void) {//OllyDbg退出时触发 MessageBox(NULL,"ODBG_Plugindestroy","",MB_OK); }
结果为:
ODBG_Plugindata=> ODBG_Plugininit => ODBG_Pluginmenu => ODBG_Pluginclose => ODBG_Plugindestroy |