Vanlin的BLOG

好好学习,天天向上

OllyDbg完全教程 自定义函数描述[Custom function descriptions]
自定义函数描述[Custom function descriptions]

概论[Introduction]

OllyDbg包含(做为内部资源)1900多种标准函数以及400多种标准C函数的名称和参数。分析器[Analyzer] 用这些描述使被调试程序更加易懂。比较下面一个例子,分析器的函数CreateFont:


PUSH OT.00469F2A ; ASCII "Times New Roman"
PUSH 12
PUSH 2
PUSH 0
PUSH 0
PUSH 0
PUSH 0
PUSH 0
MOV EAX,DWORD PTR [49FA70]
PUSH EAX
PUSH 190
PUSH 0

PUSH 0
PUSH 0
PUSH 10
CALL <JMP.&GDI32.CreateFontA>

这是分析后的:


MOV EAX,DWORD PTR [49FA70]
PUSH OT.00469F2A ; ?FaceName = "Times New Roman"
PUSH 12 ; ?PitchAndFamily = VARIABLE_PITCH|FF_ROMAN
PUSH 2 ; ?Quality = PROOF_QUALITY
PUSH 0 ; ?ClipPrecision = CLIP_DEFAULT_PRECIS
PUSH 0 ; ?OutputPrecision = OUT_DEFAULT_PRECIS
PUSH 0 ; ?CharSet = ANSI_CHARSET

PUSH 0 ; ?StrikeOut = FALSE
PUSH 0 ; ?Underline = FALSE
PUSH EAX ; ?Italic => TRUE
PUSH 190 ; ?Weight = FW_NORMAL
PUSH 0 ; ?Orientation = 0
PUSH 0 ; ?Escapement = 0
PUSH 0 ; ?Width = 0
PUSH 10 ; ?Height = 10 (16.)

CALL <JMP.&GDI32.CreateFontA> ; ?CreateFontA

显然,后面的代码更容易理解。API函数CreateFont 有14个参数。分析器标记所有这些参数的名称并解码他们的值。如果寄存器跟踪开启,那么分析器同时会解码参数Italic
的值为地址49FA70处双字长的内容。解码使用参数的真实值,所以如果[49FA70]里的内容改变了,那么参数Italic的值也会随之改变。当EIP指向跳转或调用该函数的命令,或指向入口时,OllyDbg也会在栈中对已知函数的参数进行解码。

OllyDbg可以对像printf()这样参数个数可变的函数进行参数解码:

PUSH EAX ; ?<%.*s>
PUSH E8 ; ?<*> = E8 (232.)
PUSH EBX ; ?<%08X>
PUSH Mymodule.004801D2 ; ?format = "Size %08X (%.*s) bytes"
PUSH ESI ; ?s
CALL Mymodule.sprintf ; ?sprintf

您可以定义自己的函数。每次您打开某个应用程序时,OllyDbg都会重新设置函数参数表并用内嵌描述添充这个表。然后尝试打开文件“<OllyDbg目录>/common.arg”和“<OllyDbg目录>/<应用程序名>.arg”,这里<应用程序名>使用8.3格式(DOS)被调试程序文件名(不带路径和扩展名)。

下面看一个简单的.arg文件实例:


INFO Simple .ARG file that decodes CreateHatchBrush
TYPE HS_X
IF 0 "HS_HORIZONTAL"
IF 1 "HS_VERTICAL"
IF 2 "HS_FDIAGONAL"
IF 3 "HS_BDIAGONAL"
IF 4 "HS_CROSS"
IF 5 "HS_DIAGCROSS"
ELSEINT
END
TYPE COLORREF
IF 0 "<BLACK>"
IF 00FFFFFF "<WHITE>"
OTHERWISE
TEXT "RGB("
FIELD 000000FF
UINT
TEXT ","

FIELD 0000FF00
UINT
TEXT ","
FIELD 00FF0000
UINT
TEXT ")"
END
STDFUNC CreateHatchBrush
"style" HS_X
"colorref" COLORREF
END

标准Windos API函数CreateHatchBrush(int style,int colorref) 有两个参数。第一个必须是阴影风格[hatch style],第二个是常量由红色、绿色、蓝色组成,并用一个32
位整数的低三字节表示。为了解码这些参数,文件定义了两个新的参数类型:HS_X 和 COLORREF。

阴影风格是一个简单的枚举类型,如0表示HS_HORIZONTAL(水平风格)、1表示HS_VERTICAL(垂直风格)。IF关键字比较参数与第一个操作数(注意:其总是十六进制的),如果相同则显示第二个操作数里的文本。但万一匹配失败会如何?关键字ELSEINT 会然OllyDbg会将参数解释为一个整数。

COLORREF 更复杂一些。首先尝试解码两个广泛使用的颜色值:黑(全0组成)与白(全0xFF组成)。如果匹配失败,COLORREF尝试解码颜色为一个结构包含红、绿、蓝的亮度。FIELD会用第一个操作数与参数进行逻辑与操作。然后转换结果为整数,并同时按位右移第一个操作及该整数,直到第一个操作数的二进制个位数字为1,这时整数按位右移的结果以无符号10进制显示出来。这个例子做了三次这样的操作,以分离出每个颜色成份。TEXT关键字用于无条件显示文本。如果参数为00030201,那么
COLORREF将其解码为RGB(1.,2.,3.)。

大多断API函数都会从栈中移除参数并保护寄存器EBX, EBP, ESI 和 EDI。声明这样的函数为STDFUNC,以告诉分析器该函数做了这样的事情。否则请其描述为FUNCTION


万一某个参数由多个域及比特值组成,比如上面提到的fdwPitchAndFamily ,我们该怎么办?请看下面这个例子:


TYPE FF_PITCH
MASK 03
IF 00 "DEFAULT_PITCH"
IF 01 "FIXED_PITCH"
IF 02 "VARIABLE_PITCH"
ELSEHEX
TEXT "|"
MASK 0C
BIT 04 "4|"
BIT 08 "8|"
MASK FFFFFFF0
IF 00 "FF_DONTCARE"
IF 10 "FF_ROMAN"
IF 20 "FF_SWISS"
IF 30 "FF_MODERN"
IF 40 "FF_SCRIPT"
IF 50 "FF_DECORATIVE"
ELSEHEX
END

前两个比特位(第0和等1位)表示倾斜度,必须一起解码。我们使用 MASK 03 来提取这两个比特并通过IF序列来解码。增加了连接符“|”,分别提取第2和第3个比特位,并分别单独解码。最后提取剩余部分并进行解码。

OllyDbg 会移除生成串尾部的连接符“|”、空格、冒号、逗号、分号和等号。

目前版本的分析仅能够解码32位参数。如您不能解码双精度浮点或长双精度浮点的函数参数。


格式描述

自定义解码信息由函数描述和类型描述两部分组成。函数描述部分非常的简单:


FUNCTION|STDFUNC [模块名]函数名
<第一个参数的名称> <第一个参数的类型>
……
<最后一个参数的名称> <最后一个参数的类型>
END

如果函数从栈中移除参数并保护寄存器EBX, EBP, ESI 和 EDI,请使用关键字STDFUNC。大多少函数都遵循这样的规则。其他情况则声明为FUNCTION。模块(EXE 或 DLL)名是可选的。如果模块名被忽略,OllyDbg会对尝试匹配任何模块。模块名不区分大小写。

函数名称总是区分大小写的。有针对UNICODE的函数必须使用后缀 A 或 W 加以区分,比如SetWindowTextA.。

参数的顺序又C风格的参数使用惯例一致。而16位Windows和32位API函数也是按惯例使用。如果参数名由多个字组成,或者包含特殊字符,那么请将其用两个单引号引起来。与在C语言中一样,省略号(叄┦且桓鎏厥獾募锹加糜诒硎静问靠杀洹K匦朐诤枋龅淖詈蟆llyDbg不会尝试解码这样的参数。如果函数的参数为空,则按functionname(void)对待

OllyDbg 仅支持32位的参数。某些参数已经预定义好了:


INT 以十六进制和带符号整数两种格式显示值
UINT 以十六进制和无符号整数两种格式显示值
HEX 以十六进制格式显示值
BOOL TRUE 或 FALSE
CHAR ASCII 字符
WCHAR UNICODE 字符
FLOAT 32位浮点数
ERRCODE 系统错误代码(像由函数GetLastError()报告的)
ADDR, PTR 地址(特殊情况:NULL)
ASCII ASCII 串指针
UNICODE UNICODE 串指针
FORMAT 在类似函数printf()(不包括wscanfW()!)使用的 ASCII 格式串
WFORMAT 类似函数wsprintfW()(不包括scanf()!)使用的 UNICODE 格式串
RECT RECT(矩形)结构指针
MESSAGE MSG(ASCII 窗口消息)结构指针
WMESSAGE MSG(UNICODE 窗口消息)结构指针
HANDLE 句柄(特殊情况:NULL, ERROR_INVALID_HANDLE)
HWND 窗口句柄
HMODULE 模块句柄
RSRC_STRING 带索引的资源串
NULL, DUMMY 有参数,但解码时跳过了
您不能重定义预定义类型。自定义类型允许您将参数分离成几个域并分别解码。类型描述有以下几种格式:


TYPE 类型名
[TEXT "任何文本"]
[<域选择器>]
<域解码>
<域解码>
[TEXT "任何文本"]
[PURGE]
...
<域选择器>
<域解码>
<域解码>
[TEXT "任何文本"]
END

类型名的程度限制在16个字符以内。 OllyDbg会无条件将"任何文本"作为生成的解码。域选择器提取一部分参数用于解码。以下域选择器,可以用于提取域:


MASK 十六进制掩码 - 域等于参数同十六进制掩码按位与(AND)的结果。

FIELD 十六进制掩码 - 参数同十六进制掩码按位与(AND)的数值,然后OllyDbg同时按位右移掩码和计算的数值直到掩码的二进制个位为1,这时数值按位右移的结果就是域的值。例如参数0xC250, FIELD F0,得到的结果是5。

SIGFIELD十六进制掩码 -参数同十六进制掩码按位与(AND)的数值,然后OllyDbg同时按位右移掩码和计算的数值直到掩码的二进制个位为1,这时数值按位右移的结果转成带符号32位数就是域的值。例如参数0xC250 ,SIGFIELD FF00,得到的结果是0xFFFFFFC2。

简单域的解码会一次显示整个域的内容:


HEX - 以十六进制形式显示域内容;

INT - 以带符号十进制形式显示域内容(带小数点);

UINT -以无符号十进制形式显示域内容(带小数点);

CHAR - 以 ASCII 字符形式显示域内容。

域若是一个枚举类型,则可以使用IF序列,如果必要的话还可以在IF序列后跟关键字 TRYxxx 与 ELSExxx:


IF 十六进制值 "文本" - 如果域等于十六进制值,则将文本作为输出字符串;

TRYASCII - 如果域是一个指向ASCII串的指针,则显示这个串;

TRYUNICODE - 如果域是一个指向UNICODE串的指针,则显示这个串;

TRYORDINAL - 如果域是一序号(有16位均为0),则会显示为序号(“#”后跟整数);

OTHERWISE - 如果前面IF语句为真,则停止解码,否则继续解码;


ELSEINT - 如果前面所有的 IF 和 TRYxxx 语句均失败,则以带符号十进制数形式(带小数点)显示这个域;

ELSEHEX -如果前面所有的 IF 和 TRYxxx 语句均为失败,则以十六进制形式显示这个域;

ELSECHAR -如果前面所有的 IF 和 TRYxxx 语句均为失败,则以 ASCII 字符形式显示这个域;

ELSEWCHAR -如果前面所有的 IF 和 TRYxxx 语句均为失败,则以 UNICODE 字符形式显示这个域。

如果域是一个二进制位集,则可以使用BIT序列,如果必要的话可以后面跟关键字 BITZ 与 BITHEX :

BIT 十六进制掩码 "文本" - 如果值与十六进制掩码按位与(AND)的结果不是0,则将文本做为输出串;

BITZ十六进制掩码 "文本" - 如果值与十六进制掩码按位与(AND)的结果是0,则将文本做为输出串;

BITHEX十六进制掩码 - 如果值与十六进制掩码按位与(AND)的结果不是0,则将结果以十六进制形式显示。

特殊关键字 PURGE 会从输出串尾部移除以下几种符号:


空格 ' '
逗号 ','
或 '|'
冒号 ':'
等于 '='
这会让某些解码情况变的简单。关键字END是类型定义结尾标记并会自动运行PURGE命令。


预编译类型

OllyDbg在预编译资源时,已经包含150多种类型描述。以下列出了一部分。您可以在自定义文件中直接使用这些类型:


LANG_X - 操作系统语言ID(0 - 未知、 9 - 语言、 C - 法语,等等)

GENERIC_X - 访问类型(GENERIC_READ, GENERIC_WRITE...)

FILE_SHARE_X - 共享类型(FILE_SHARE_READ, FILE_SHARE_WRITE)

CREATEFILE_X - 文件创建模式(CREATE_NEW, OPEN_EXISTING...)

FILE_ATTRIBUTE_X - 文件属性(READONLY, SYSTEM, DELETE_ON_CLOSE...)

RT_AXX - 资源类型(RT_CURSOR, RT_GROUP_ICON, ASCII string...)

RT_WXX - 资源类型(RT_CURSOR, RT_GROUP_ICON, UNICODE string...)

COORD - 坐标结构 "(X=xxx,Y=yyy)"

STD_IO_X - 标准句柄(STD_INPUT_HANDLE, STD_ERROR_HANDLE...)

GMEM_X - 全局内存类型(GMEM_FIXED, GPTR...)

LMEM_X - 局部内存类型(LMEM_FIXED, LPTR...)

FSEEK_X - 文件查找类型(FILE_BEGIN, FILE_CURRENT...)

OF_X - 文件模式(fOF_READ, OF_SHARE_COMPAT, OF_VERIFY...)

O_X - 文件创建模式(O_RDONLY, O_BINARY, SH_COMPAT...)

SEMAPHORE_X - 信号量类型(SEMAPHORE_ALL_ACCESS, SYNCHRONIZE...)

SLEEP_TIMEOUT - 超时(INFINITE 或时间)

ROP - 一些标准柵格运算标志代码(ROP)(SRCCOPY, MERGEPAINT...)

COLORREF - RGB 颜色值("<WHITE>", "RGB(rr.,gg.,bb.)"...)

WS_X - 窗口风格(WS_OVERLAPPED, WS_POPUP...)

WS_EX_X - 扩展窗口风格(WS_EX_DLGMODALFRAME, WS_EX_TOPMOST...)

MF_X - 菜单标志(MF_BYPOSITION, MF_ENABLED...)

WM_X - ASCII窗口消息类型(WM_CREATE, WM_KILLFOCUS, CB_SETCURSEL...)

WM_W - UNICODE窗口消息类型(WM_CREATE, WM_KILLFOCUS, CB_SETCURSEL...)

VK_X - 虚拟键盘代码(VK_LBUTTON, VK_TAB, VK_F10...)

MB_X - message box style (MB_OK, MB_ICONHAND...)

HKEY_X - 预定义注册表句柄(HKEY_CLASSES_ROOT, HKEY_LOCAL_MACHINE...)

还有更多的预编译类型。如果常量在它文件被定义为ABC_ xxxxxxxx,那么一般就有ABC_X预编译类型。



 
阅读更多
个人分类: 学习人生---破解说
想对作者说点什么? 我来说一句

OllyDbg完全教程OllyDbg完全教程

2010年01月31日 7KB 下载

OllyDbg完全教程

2011年08月01日 242KB 下载

OLLYDBG完全教程

2008年09月23日 266KB 下载

OllyDbg入门完全教程(完美排版)

2018年04月01日 645KB 下载

OllyDbg完全教程.rar

2012年06月14日 165KB 下载

ollydbg完美教程(超强入门级别)

2017年08月03日 1.15MB 下载

没有更多推荐了,返回首页

不良信息举报

OllyDbg完全教程 自定义函数描述[Custom function descriptions]

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭