在设计OllyMachine虚拟机时,我感觉到只依靠基本指令是不足以完成一些更高级的操作的,因此,我定义了一系列异常丰富的API供程序员使用,通过它们可以与OllyDbg和用户更好地交互,更有效地实现我们所期望的功能。
就像所有的程序设计教程一样,我先来给大家示范一段Hello World:
// Method 1: lds reg01, "Hello World!" push reg01 msg // Method 2: push "Hello World!" msg // Method 3: invoke msg, "Hello World!"
我设计的API调用方式类似于x86机器,即使用堆栈作为传递参数的“中转站”。就拿上面的Hello World为例:
lds reg01, "Hello World!" push reg01 msg // another way: push "Hello World!" msg
上面这个程序是用来打印经典的“Hello World!”程序的。在这个例子中,msg是一个用来显示字符串的API,它只有一个参数,这个参数必须是一个寄存器,寄存器中储存着字符串的偏移地址;或者是一个由双引号包围起来的字符串。
想必大家已经明白了,调用API时,如果有参数,必须使用push指令把参数按照从右向左的顺序入栈,然后再调用API名字。API运行结束后,堆栈会自动平衡,无需程序员手动调整。
那么什么叫做“从右向左的顺序入栈”呢?我们来看一个例子:
push 16 push 0xFF PrintNum
这个程序的运行结果是弹出一个对话框,显示16进制数0xFF出来。
在这个例子中,我们调用了API函数:PrintNum。
PrintNum有两个参数,它的原型是:
PrintNum 数值,进制
如果是从右向左地把参数入栈的话,那么“进制”就应该是先入栈的,随后就是“数值”。可以看到,在例子中,我们的确是先push了16进去(表示“进制”为16进制),然后才push了0xFF进去(表示“数值”为0xFF),最后调用API的名字,这与我们的API函数调用约定相符合。
从0.11版开始,可以使用invoke宏来调用API,例如:
push 16 push 0xFF PrintNum invoke PrintNum, 0xFF, 16
跟MASM32中的invoke宏一样,是不是更简便了呢?^_^
有的时候,我们需要在API执行完毕后提供一些返回值,以便进行下一步的处理。例如:
lds reg01, "Are you sure?" push reg01 msgyn // another way: push "Are you sure?" msgyn
API函数MsgYN会弹出一个对话框提示用户选择“是/否”,这时我们必须知道用户的选择是什么,才能进行下一步的动作。
在OllyMachine虚拟机中,所有的API函数都遵循这样一个约定:如果该API有返回值,则返回值会储存在reg00中(类似于在Win32系统中,返回值储存在eax中)。因此,程序员在调用完API函数后要注意reg00的值,如果处理不当,可能会造成一些不预期的结果。
在上面的例子中,如果用户输入了“Y”,则reg00的值就会为1(表示成功),如果用户输入了“N”,则reg00的值就会为0(表示失败)。
OllyMachine虚拟机提供了几个输入输出API,以便与用户进行基本的交互:
函数原型:
MSG message
说明:
MSG弹出一个对话框,显示字符串message。
参数:
message : 字符串
返回值:
无
示例:
invoke msg, reg01, "Hello World!"
函数原型:
MSGYN message
说明:
MSGYN弹出一个对话框,显示字符串message,并且要求用户输入Y/N继续。
参数:
message : 字符串
返回值:
成功:1 失败:0
示例:
invoke msgyn, "Are you sure to continue?" cmp reg00, 1 je Continue halt Continue: // ...
函数原型:
PrintNum Value, Base
说明:
PrintNum用Base进制来计算Value的值,并且用一个对话框来显示结果。
参数:
Value : 要显示的数值
Base : 进制
返回值:
无
示例:
invoke PrintNum, 0x100, 16
函数原型:
PrintBuf address, len
说明:
PrintBuf用一个对话框来显示从内存地址address处开始的len个字节。
参数:
address : 开始的内存地址
len : 长度
返回值:
无
示例:
invoke PrintBuf, eip, 10
函数原型:
PrintBufToDump address
说明:
PrintBufToDump把从内存地址address处开始的数据显示到Dump窗口里。
参数:
address : 开始的内存地址
返回值:
成功:1 失败:0
示例:
invoke PrintBufToDump, eip
函数原型:
PrintBufToNewDump title, address, len
说明:
PrintBufToNewDump首先创建一个新的Dump窗口,窗口名为title, 然后把从内存地址address处开始的长度为len的数据显示到新的Dump窗口里。
参数:
title : 窗口名
address : 开始的内存地址
len : 长度
返回值:
成功:新的Dump窗口的句柄(HWND) 失败:0
示例:
invoke PrintBufToNewDump, "New Dump Window", eip, 0x100
函数原型:
UpdateDumpBuf hwnd, address, len
说明:
从address地址开始,取len个字节,然后更新到某个Dump窗口中,该窗口通过hwnd来定位。 一般来说,这个hwnd是由PrintBufToNewDump的返回值来取得的。
参数:
hwnd : dump窗口的句柄
address : 开始的内存地址
len : 长度
返回值:
成功:1 失败:0
示例:
// Create a new dump window: invoke PrintBufToNewDump, "New Dump Window", eip, 0x100 // Save its hwnd: mov reg01, reg00 //... // Update it: invoke UpdateDumpBuf, reg01, eip, 0x200
函数原型:
InputText title
说明:
InputText会弹出一个对话框让用户输入一串字符串,对话框的标题为title中的字符串。 注意:标题的长度不能大于 256 个字节,用户输入的字符串不能大于 4096 个字节。
参数:
title : 对话框的标题
返回值:
成功:1 失败:0(用户按下CANCEL按钮,或者用户输入的字符串大于 4096 个字节) 如果运行成功,用户输入的字符串可以通过FreeBufferReg访问,字符串的长度储存在FreeBufferSizeReg中。
示例:
// ask user's name invoke InputText, "Please input your name" // print user's name invoke msg, FreeBufferReg
函数原型:
InputHexLong value, title
说明:
InputHexLong会弹出一个对话框让用户输入一个16进制数,对话框的标题为title中的字符串,初始值为value。 注意:标题的长度不能大于 256 个字节。
参数:
value : 初始化的值
title : 对话框的标题
返回值:
把用户输入的数值储存在reg00中。 如果用户按了CANCEL,则reg00的值为value原来的值。
示例:
invoke InputHexLong, eip, "Please input EIP" invoke PrintNum, reg00, 16
OllyMachine可以很方便地与内存数据打交道:
函数原型:
ReadMemLong address, len
说明:
ReadMemLong读取在address地址处的len个字节数据,并且储存在寄存器reg00中返回。 len 只能在1~4之间,小于1的话会被设置为1,大于4的话会被设置为4。
参数:
address : 要读取的内存地址
len : 读取的长度
返回值:
成功:读到的数据。 失败:-1
示例:
invoke ReadMemLong, eip, 4
函数原型:
WriteMemLong address, value, len
说明:
WriteMemLong把len个字节长的value值写到address地址处。 len 只能在1~4之间,小于1的话会被设置为1,大于4的话会被设置为4。
参数:
address : 要写入的内存地址
value : 要写入内存的数据
len : 写入的长度
返回值:
成功:1 失败:0
示例:
invoke WriteMemLong, eip, 0x9090, 2
函数原型:
WriteMemHexes address, hexes
说明:
把hexes写到address地址处。
参数:
address : 要写入的内存地址
hexes : 要写入内存的数据
返回值:
成功:1 失败:0
示例:
invoke WriteMemHexes, eip, "e800000000"
函数原型:
ReadFileIntoMem filename, addrbase, filesize
说明:
把文件filename读入内存中,自动分配一段内存给它。 分配的内存的起始地址在addrbase,文件的大小在filesize。 注意!使用完后一定要用VirtualFreeEx来释放这段内存,否则会造成内存泄漏!!!
参数:
filename : [in]传入,文件名
addrbase : [out]返回,内存的起始地址
filesize : [out]返回,文件的大小
返回值:
成功:1 失败:0
示例:
// Read the file into the memory // reg01 = memory starting address // reg02 = filesize invoke ReadFileIntoMem, "test.exe", indexof reg01, indexof reg02 // Print the file contents byte by byte mov reg10, reg01 read_file_contents: invoke ReadMemLong, reg10, 1 invoke PrintNum, reg00, 16 inc reg10 dec reg02 cmp reg02, 0 jne read_file_contents // Remember to free the memory!!! invoke VirtualFreeEx, indexof reg01
函数原型:
DumpMem address, len, filename
说明:
DumpMem把从address地址处的len个字节dump到filename里面去,如果文件已存在,则覆盖。
参数:
address : 开始的地址
len : 字节数
filename : 文件名
返回值:
成功:1 失败:0
示例:
// example1: invoke DumpMem, eip, 10, "c:\test.bin" // example2: invoke InputText, "Please input filename" invoke DumpMem, eip, 10, FreeBufferReg
函数原型:
DumpMemAppend address, len, filename
说明:
DumpMemAppend把从address地址处的len个字节dump到filename里面去,如果文件已存在,则添加数据到文件末尾。
参数:
address : 开始的地址
len : 字节数
filename : 文件名
返回值:
成功:1 失败:0
示例:
// example1: invoke DumpMemAppend, eip, 10, "c:\test.bin" // example2: invoke InputText, "Please input filename" invoke DumpMemAppend, eip, 10, FreeBufferReg
函数原型:
DumpAsPE filename, eip
说明:
DumpAsPE把内存镜像dump成为一个PE文件,该PE文件的Entry Point为eip。
参数:
filename : 文件名
eip : Entry Point
返回值:
成功:1 失败:0
示例:
invoke DumpAsPE, "c:\test.exe", eip
函数原型:
FindOpcode address, opcode
说明:
FindOpcode从address地址处开始往后搜寻opcode,并返回第一个找到的地址。
参数:
address : 开始的地址
opcode : 要搜寻的opcode
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke FindOpcode, eip, 0x90
函数原型:
Find address, code
说明:
Find从address地址处开始往后搜寻code,并返回第一个找到的地址。 支持通配符“??”:一个不确定的字节必须由一个“??”来表示。
参数:
address : 开始的地址
code : 要搜寻的code
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke Find, eip, "e8????????" // find a CALL XXXXXXXX invoke PrintNum, reg00, 16 // find: // CALL XXXXXXXX // PUSH 0 invoke Find, eip, "e8????????6a00" invoke PrintNum, reg00, 16
函数原型:
ReverseFind address, code
说明:
ReverseFind从address地址处开始往前搜寻code,并返回第一个找到的地址。 支持通配符“??”:一个不确定的字节必须由一个“??”来表示。
参数:
address : 开始的地址
code : 要搜寻的code
返回值:
成功:返回找到的地址 失败:-1
示例:
// Reverse find some: PUSHAD, CALL XXXXXXXX invoke ReverseFind, eip, "60e8" invoke PrintNum, reg00, 16 // Reverse find: // CALL XXXXXXXX // PUSH 0 invoke ReverseFind, eip, "e8????????6a00" invoke PrintNum, reg00, 16
函数原型:
Search address, code
说明:
Search从address地址处开始往后搜寻code,并返回第一个找到的地址。 支持通配符“??”:一个不确定的字节必须由一个“??”来表示。 Search与Find的不同之处在于,Search并不会从一个合法的Opcode的起始地址开始搜寻。 例如: 004010DC 55 PUSH EBP 004010DD 8BEC MOV EBP,ESP 004010DF 6A FF PUSH -1 如果用invoke Find, eip, "EC6AFF",那么不会找到,返回-1; 如果用invoke Search, eip, "EC6AFF",那么会返回004010DE。
参数:
address : 开始的地址
code : 要搜寻的code
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke Search, eip, "e8????????" // Search a CALL XXXXXXXX invoke PrintNum, reg00, 16 // Search: // CALL XXXXXXXX // PUSH 0 invoke Search, eip, "e8????????6a00" invoke PrintNum, reg00, 16
函数原型:
ReverseSearch address, code
说明:
ReverseSearch从address地址处开始往前搜寻code,并返回第一个找到的地址。 支持通配符“??”:一个不确定的字节必须由一个“??”来表示。 ReverseSearch与ReverseFind的不同之处在于: ReverseSearch并不会从一个合法的Opcode的起始地址开始搜寻。 例如: 004010DC 55 PUSH EBP 004010DD 8BEC MOV EBP,ESP 004010DF 6A FF PUSH -1 如果用invoke ReverseFind, eip, "EC6AFF",那么不会找到,返回-1; 如果用invoke ReverseSearch, eip, "EC6AFF",那么会返回004010DE。
参数:
address : 开始的地址
code : 要搜寻的code
返回值:
成功:返回找到的地址 失败:-1
示例:
// Reverse search a CALL XXXXXXXX invoke ReverseSearch, eip, "e8????????" invoke PrintNum, reg00, 16 // Reverse search: // CALL XXXXXXXX // PUSH 0 invoke ReverseSearch, eip, "e8????????6a00" invoke PrintNum, reg00, 16
函数原型:
GetPrevOpAddr address, N
说明:
GetPrevOpAddr返回从address地址开始的往前第N条指令的地址。
参数:
address : 开始的地址
N : 第N条指令
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke GetPrevOpAddr, eip, 1 invoke PrintNum, reg00, 16 // Let's see what we got!
函数原型:
GetNextOpAddr address, N
说明:
GetNextOpAddr返回从address地址开始的往后第N条指令的地址。
参数:
address : 开始的地址
N : 第N条指令
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke GetNextOpAddr, eip, 1 invoke PrintNum, reg00, 16 // Let's see what we got!
函数原型:
GetProcAddress funcname, dllname
说明:
GetProcAddress返回在dllname中的funcname的地址。
参数:
funcname : 要查找的函数名
dllname : 函数名所在的dll名
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke GetProcAddress, "MessageBoxA", "user32.dll" invoke PrintNum, reg00, 16 // Let's see what we got!
函数原型:
Fill address, len, value
说明:
Fill把len个字节长的value值写到address地址处。
参数:
address : 要写入的内存地址
len : 要写入数据的长度
value : 要写入内存的数据,Fill函数会只保留value的最低一个字节(例如0x12345678就只写入0x78)
返回值:
成功:1 失败:0
示例:
// fill 10 bytes "NOP" to address starting from EIP invoke Fill, eip, 10, 0x90
函数原型:
ReplaceBytes address, find, repl, len
说明:
ReplaceBytes从address地址处开始往后搜寻字节码find,并且用repl来替换find,一共替换len次。
参数:
address : 开始的地址
find : 要搜寻并替换的字节码
repl : 替换成的字节码
len : 替换的次数
返回值:
成功:返回找到的地址 失败:-1
示例:
invoke ReplaceBytes, eip, 0x90909090, 0x51515151, 1
函数原型:
ReplaceBytesEx address, len, find, repl
说明:
从address地址开始,在len个字节范围内,把find替换成repl。 支持通配符“??”:一个不确定的字节必须由一个“??”来表示。 注意: 1、find和repl的长度必须相同。例如假如find为"60e8??",表示3个字,那么repl也必须是3个字节。 2、在find里面的"??"不会被替换。例如假如find为"60e8??",repl为"123456", 那么替换后将会是"1234??",原来的"??"所表示的那个字节不变。
参数:
address : 开始的地址
len : 范围的长度
find : 要替换的字节码
repl : 替换成的字节码
返回值:
成功:1,表示至少有一个替换。 失败:0,表示没有替换。
示例:
invoke ReplaceBytesEx, eip, 10, "60e8??", "909090"
函数原型:
CopyBytesTo addrsrc, addrdest, len
说明:
把addrsrc地址处开始的len个字节拷贝到addrdest处。
参数:
addrsrc : 源地址
addrdest : 目的地址
len : 字节数
返回值:
成功:1 失败:0
示例:
invoke CopyBytesTo, eip, 0x401000, 10
汇编:
函数原型:
ASM address, command
说明:
ASM函数对字符串command进行汇编,然后写进address地址处。
参数:
address : 要写入的内存地址
command : 待汇编的字符串
返回值:
成功:1 失败:0
示例:
invoke asm, eip, "mov eax, edx"
函数原型:
__asm { }
说明:
内嵌汇编功能,必须使用以下的形式调用: __asm { mov eax, 1 push 0 call ExitProcess } 注意事项: 1、可以使用“//”、“;”作为行注释,“/* */”作为块注释。 2、不允许使用OllyMachine的寄存器。 3、内嵌汇编也是要经过编译的,如果编译后的大小超过2046个字节,则必须把一个大的__asm{}块分开成几个小的块。 例如: __asm { mov eax, 1 // ... // ... mov ecx, 1 } 如果编译器提示内嵌汇编经过编译后的字节数太大的话,则可以把这个大的块分成两个小块: __asm { mov eax, 1 // ... } __asm { // ... mov ecx, 1 } 一直这样分解下去,直到编译器不出错误提示为止。 实际上2046个字节对于大多数情况来说应该已经足够了,如果不够的话我可以增加。
参数:
无
返回值:
无
示例:
__asm { mov eax, 1 push 0 call ExitProcess }
函数原型:
Analyse address
说明:
Analyse函数对address地址处开始的指令进行分析。
参数:
address : 开始的内存地址
返回值:
成功:1 失败:0
示例:
invoke Analyse, eip
通过以下API,可以做到控制OllyDbg运行的目的:
函数原型:
RunToReturn
说明:
RunToReturn会一直运行被调试进程的代码,直到遇到ret指令为止。 运行效果相当于在OllyDbg的主界面按住Ctrl+F9。
参数:
无
返回值:
无
示例:
RunToReturn // 一直运行,直到遇到ret指令为止
函数原型:
RunToUserCode
说明:
有时候,跟踪会运行到很深的系统DLL中,执行RunToUserCode能够很快地返出来, 即运行到第一个不是系统DLL的指令。 运行效果相当于在OllyDbg的主界面按Alt+F9。
参数:
无
返回值:
无
示例:
RunToUserCode
函数原型:
Run
说明:
Run会使被调试进程运行起来。 运行效果相当于在OllyDbg的主界面按F9。
参数:
无
返回值:
无
示例:
Run
函数原型:
AnimateInto
说明:
执行AnimateInto操作。 运行效果相当于在OllyDbg的主界面按Ctrl+F7。
参数:
无
返回值:
无
示例:
AnimateInto
函数原型:
AnimateOver
说明:
执行AnimateOver操作。 运行效果相当于在OllyDbg的主界面按Ctrl+F8。
参数:
无
返回值:
无
示例:
AnimateOver
函数原型:
StepInto
说明:
StepInto会跟踪进当前的call里面去。 运行效果相当于在OllyDbg的主界面按F7。
参数:
无
返回值:
成功:1 失败:0
示例:
StepInto
函数原型:
StepIntoS times
说明:
StepIntoS执行times次StepInto操作。
参数:
times : 次数
返回值:
成功:1 失败:0
示例:
invoke StepIntoS, 3
函数原型:
StepOver
说明:
StepOver会跟踪进当前的call里面去。 运行效果相当于在OllyDbg的主界面按F8。
参数:
无
返回值:
成功:1 失败:0
示例:
StepOver
函数原型:
StepOverS times
说明:
StepOverS执行times次StepOver操作。
参数:
times : 次数
返回值:
成功:1 失败:0
示例:
invoke StepOverS, 3
函数原型:
ESTI
说明:
ESTI运行效果相当于在OllyDbg的主界面按Shift+F7。
参数:
无
返回值:
无
示例:
ESTI
函数原型:
ESTO
说明:
ESTO运行效果相当于在OllyDbg的主界面按Shift+F9。
参数:
无
返回值:
无
示例:
ESTO
函数原型:
GO address
说明:
GO会执行到address地址处。
参数:
address : 要执行到的内存地址
返回值:
成功:1 失败:0
示例:
invoke go, 0x401005
这部分API是跟Trace相关的。
函数原型:
TraceInto
说明:
TraceInto函数执行OllyDbg的“Trace Into”功能。
参数:
无
返回值:
无
示例:
TraceInto
函数原型:
TraceOver
说明:
TraceOver函数执行OllyDbg的“Trace Over”功能。
参数:
无
返回值:
无
示例:
TraceOver
函数原型:
TraceIntoCond condition
说明:
TraceIntoCond函数会Trace Into到call里面,直到condition条件为真才结束。
参数:
condition : 结束条件
返回值:
无
示例:
// Will stop when eip > 0x40100A invoke TraceIntoCond, "eip > 0x40100A"
函数原型:
TraceOverCond condition
说明:
TraceOverCond函数会Trace Over所有的calls,直到condition条件为真才结束。
参数:
condition : 结束条件
返回值:
无
示例:
// Will stop when eip > 0x40100A invoke TraceOverCond, "eip > 0x40100A"
这部分API是跟断点相关的。
函数原型:
BP address
说明:
BP函数在address地址处下无条件(unconditional)断点。
参数:
address : 要下断点的内存地址
返回值:
成功:1 失败:0
示例:
invoke BP, 0x401000 invoke BP, eip
函数原型:
BC address
说明:
BC函数清除在address地址处的无条件(unconditional)断点。
参数:
address : 要清除的断点的内存地址
返回值:
成功:1 失败:0
示例:
invoke BC, 0x401000 invoke BC, eip
函数原型:
BPCND address, condition
说明:
BPCND函数在address地址处下条件(conditional)断点,条件为condition
参数:
address : 要下断点的地址
condition : 条件,为字符串
返回值:
成功:1 失败:0
示例:
invoke BPCND, eip, "ecx==FFFFFFFF"
函数原型:
BPL address, expression
说明:
BPL函数在address地址处下无条件(unconditional)断点,然后把表达式expression显示在log窗口处。
参数:
address : 要下断点的地址
expression : 表达式,为字符串
返回值:
成功:1 失败:0
示例:
// logs the value of eax everytime when EIP's address is passed invoke BPL, eip, "eax"
函数原型:
BPLCND address, expression, condition
说明:
BPLCND函数在address地址处下条件(conditional)断点,然后把表达式expression显示在log窗口处。
参数:
address : 要下断点的地址
expression : 表达式,为字符串
condition : 条件,为字符串
返回值:
成功:1 失败:0
示例:
// logs the value of eax everytime when EIP's address is passed and eax > 1 invoke BPLCND, eip, "eax", "eax > 1"
函数原型:
BPRM address, size
说明:
下内存“读”断点于address地址处,长度为size个字节。
参数:
address : 断点的地址
size : 长度
返回值:
成功:1 失败:0
示例:
invoke BPRM, 0x401000, 0xff
函数原型:
BPWM address, size
说明:
下内存“写”断点于address地址处,长度为size个字节。
参数:
address : 断点的地址
size : 长度
返回值:
成功:1 失败:0
示例:
invoke BPWM, 0x401000, 0xff
函数原型:
BPMC
说明:
清除内存断点。
参数:
无
返回值:
成功:1 失败:0
示例:
BPMC
函数原型:
BPHWS address, mode
说明:
下硬件断点于address地址处,模式可以为“Execute执行”、“Read读”、“Write写”, 由mode来决定:1为“Execute执行”、2为“Read读”、3为“Write写”,其他则会使API返回失败。
参数:
address : 断点的地址
mode : 模式:1为“Execute执行”、2为“Read读”、3为“Write写”
返回值:
成功:1 失败:0
示例:
invoke BPHWS, 0x401000, 1 // mode - "Execute"
函数原型:
BPHWC address
说明:
清除address地址处的硬件断点。
参数:
address : 断点的地址
返回值:
成功:1 失败:0
示例:
invoke BPHWC, 0x401000
函数原型:
EOB label
说明:
EOB的作用是:当OllyMachine运行时遇到了断点,就会跳转到label处继续执行。 EOB是一个比较特殊的API,注意,调用它的时候不是用push的方式来传递参数, 而是直接跟label,例如:EOB LabelName
参数:
label : 遇到断点时跳转到的标号
返回值:
无
示例:
EOB Break // set up jump label invoke bp, 0x40100A // set breakpoint at 0x40100A run // run! will occur breakpoint at 0x40100A halt // ... (some other instructions) Break: // jump to this label when occured breakpoint invoke msg, "Breakpoint occured!"
函数原型:
EOBINT3 label
说明:
EOBINT3的作用是:当OllyMachine运行时遇到了int3断点,就会跳转到label处继续执行。 EOBINT3是一个比较特殊的API,注意,调用它的时候不是用push的方式来传递参数, 而是直接跟label,例如:EOBINT3 LabelName
参数:
label : 遇到断点时跳转到的标号
返回值:
无
示例:
EOBINT3 Break // set up jump label run // run! halt // ... (some other instructions) Break: // jump to this label when occured int3 invoke msg, "Breakpoint occured!"
函数原型:
EOBHW label
说明:
EOBHW的作用是:当OllyMachine运行时遇到了Hardware断点,就会跳转到label处继续执行。 EOBHW是一个比较特殊的API,注意,调用它的时候不是用push的方式来传递参数, 而是直接跟label,例如:EOBHW LabelName
参数:
label : 遇到断点时跳转到的标号
返回值:
无
示例:
EOBHW Break // set up jump label run // run! halt // ... (some other instructions) Break: // jump to this label when occured int3 invoke msg, "Breakpoint occured!"
函数原型:
EOBMEM label
说明:
EOBMEM的作用是:当OllyMachine运行时遇到了memory断点,就会跳转到label处继续执行。 EOBMEM是一个比较特殊的API,注意,调用它的时候不是用push的方式来传递参数, 而是直接跟label,例如:EOBMEM LabelName
参数:
label : 遇到断点时跳转到的标号
返回值:
无
示例:
EOBMEM Break // set up jump label run // run! halt // ... (some other instructions) Break: // jump to this label when occured int3 invoke msg, "Breakpoint occured!"
函数原型:
EOE label
说明:
EOE的作用是:当OllyMachine运行时遇到了异常(exception),就会跳转到label处继续执行。 EOE是一个比较特殊的API,注意,调用它的时候不是用push的方式来传递参数, 而是直接跟label,例如:EOE LabelName
参数:
label : 遇到异常时跳转到的标号
返回值:
无
示例:
EOE exception1 // set up jump label run halt exception1: // if any exceptions occured, jump to here invoke msg, "Exception occured!"
函数原型:
COB
说明:
COB会让脚本在遇到一个断点并处理了该断点后继续回到原位置运行。(清除EOB)
参数:
无
返回值:
无
示例:
EOB Break // set up jump label invoke GetNextOpAddr, eip, 1 invoke bp, reg00 // set breakpoint at next instruction run // run! will occur breakpoint at once! invoke msg, "Continue!" // continue execution here because of COB halt // ... (some other instructions) Break: // jump to this label when occured breakpoint invoke msg, "Breakpoint occured!" COB // removes EOB
函数原型:
COE
说明:
COE会让脚本在遇到一个异常并处理了该异常后继续回到原位置运行。(清除EOE)
参数:
无
返回值:
无
示例:
EOE exception1 // set up jump label run invoke msg, "Continue!" // continue execution here because of COE halt exception1: // if any exceptions occured, jump to here invoke msg, "Exception occured!" COE // removes EOE
这些API与模块(module)有关。
函数原型:
GMI address, info
说明:
GMI返回一个位于address地址处的模块(module)的信息。
参数:
address : 模块所在的地址
info : 信息类型,可以为“MODULEBASE”、“MODULESIZE”、“CODEBASE”、“CODESIZE”、“ENTRYPOINT”
返回值:
成功:相应的地址 失败:-1
示例:
invoke GMI, eip, "ENTRYPOINT" invoke PrintNum, reg00, 16
这些API用来进行注释和标号操作:
函数原型:
Comment address, text
说明:
Comment函数在address地址处写入注释text。
参数:
address : 要写入注释的地址
text : 注释字符串
返回值:
成功:1 失败:0
示例:
invoke Comment, eip, "This is a comment!"
函数原型:
SetLbl address, LabelName
说明:
SetLbl函数在address地址处添加一个LabelName。
参数:
address : 要添加LabelName的地址
LabelName : 标号名称
返回值:
成功:1 失败:0
示例:
invoke SetLbl, eip, "This is a new label!"
这些API用来进行日志操作:
函数原型:
LogText text
说明:
LogText函数把text写到Log窗口。
参数:
text : 要写入log窗口的字符串
返回值:
成功:1 失败:0
示例:
invoke LogText, "This is a log!"
函数原型:
LogLong value
说明:
LogLong函数把long类型的value数值写到Log窗口。 写入的数值以“LOG VALUE: 0xXXXXXXXX”的形式表示。
参数:
value : 要写入log窗口的数值
返回值:
成功:1 失败:0
示例:
invoke LogLong, eip invoke LogLong, 0x12345678
反反调试API,用来对抗反调试技巧:
函数原型:
HideOD
说明:
HideOD改写 fs:[30]+2 处的值为0,使被调试进程无法得知OllyDbg的存在。 Windows XP Sp2 下同样有效。
参数:
无
返回值:
成功:1 失败:0
示例:
HideOD
函数原型:
UnHideOD
说明:
UnHideOD取消HideOD的作用。
参数:
无
返回值:
成功:1 失败:0
示例:
UnHideOD
字符串、缓冲区的API。
函数原型:
malloc size, indexof reg
说明:
malloc分配一块size大小的内存空间给reg。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
size : 要分配的内存区域大小,是(char *)类型。
reg : 分配好的空间传递给哪个寄存器。注意:不得使用reg00!
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01
函数原型:
free indexof reg
说明:
free用来释放通过malloc得到的内存空间。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
reg : 要释放的内存空间所在的寄存器。注意:不得使用reg00!
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01 // ... // now free the space: invoke free, indexof reg01
函数原型:
VirtualAllocEx size, indexof reg
说明:
分配一块size大小的内存空间给reg,该内存的属性为PAGE_EXECUTE_READWRITE。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
size : 要分配的内存区域大小。属性为PAGE_EXECUTE_READWRITE。
reg : 分配好的空间传递给哪个寄存器。注意:不得使用reg00!
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke VirtualAllocEx, 100, indexof reg01
函数原型:
VirtualFreeEx indexof reg
说明:
释放通过VirtualAllocEx得到的内存空间。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
reg : 要释放的内存空间所在的寄存器。注意:不得使用reg00!
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke VirtualAllocEx, 100, indexof reg01 // ... // now free the space: invoke VirtualFreeEx, indexof reg01
函数原型:
strcpy indexof reg, text
说明:
strcpy拷贝text到reg所在的内存空间。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
reg : 目标内存空间所在的寄存器。注意:不得使用reg00!
text : 要拷贝的字符串
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01 invoke strcpy, indexof reg01, "test" // now free the space: invoke free, indexof reg01
函数原型:
strcat indexof reg, text
说明:
strcat把text添加到reg所在的内存空间的末尾。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
reg : 目标内存空间所在的寄存器。注意:不得使用reg00!
text : 要添加的字符串
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01 invoke strcpy, indexof reg01, "test" invoke strcat, indexof reg01, "1234" // now free the space: invoke free, indexof reg01
函数原型:
strlen mode, indexof reg / text
说明:
strlen计算reg所在的内存空间的字符串的长度,或者是text的长度。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
mode : 模式,0表示计算reg所在的内存空间的字符串长度,1表示计算text的长度
text : 字符串
reg : 内存空间所在的寄存器。注意:不得使用reg00!
返回值:
成功:字符串的长度 失败:-1
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01 invoke strcpy, indexof reg01, "test" invoke strlen, 0, indexof reg01 // reg mode invoke PrintNum, reg00, 10 invoke strlen, 1, "1234567890" // text mode invoke PrintNum, reg00, 10 // now free the space: invoke free, indexof reg01
函数原型:
ltoa value, indexof reg, radix
说明:
ltoa把数值value用radix进制转换到reg所在的内存空间去。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
value : 要转换的数值
reg : 内存空间所在的寄存器。注意:不得使用reg00!
radix : 进制
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01 // converts decimal value 874 to string, store in reg01 invoke ltoa, 874, indexof reg01, 10 // what we got? invoke msg, reg01 // now free the space: invoke free, indexof reg01
函数原型:
memcpy indexof reg, buffer, len
说明:
memcpy拷贝buffer到reg所在的内存空间,长度为len。 注意:1、必须使用indexof作为reg的前缀,以便让汇编器知道reg的序号。2、reg不得为reg00!
参数:
reg : 目标内存空间所在的寄存器。注意:不得使用reg00!
buffer : 要拷贝的内容
len : 要拷贝的长度
返回值:
成功:1 失败:0
示例:
// alloc 100 bytes memory to reg01 invoke malloc, 100, indexof reg01 invoke memcpy, indexof reg01, "test", 4 // now free the space: invoke free, indexof reg01
函数原型:
FindProcBegin address
说明:
FindProcBegin返回内存单元address所在的函数体的起始地址。 注意,如果模块没有被分析过(analyze),或者address不在某个函数体内,则会失败。
参数:
address : 在函数体中的地址
返回值:
成功:函数体的起始地址 失败:0
示例:
invoke FindProcBegin, eip
函数原型:
FindProcEnd address
说明:
FindProcEnd返回内存单元address所在的函数体的终止地址。 注意,如果模块没有被分析过(analyze),或者address不在某个函数体内,则会失败。
参数:
address : 在函数体中的地址
返回值:
成功:函数体的终止地址 失败:0
示例:
invoke FindProcEnd, eip
函数原型:
FindPrevProc address
说明:
FindPrevProc返回内存单元address所在的函数体的上一个函数的起始地址。 注意,如果模块没有被分析过(analyze),或者address不在某个函数体内,则会失败。
参数:
address : 在函数体中的地址
返回值:
成功:函数体的起始地址 失败:0
示例:
invoke FindPrevProc, eip
函数原型:
FindNextProc address
说明:
FindNextProc返回内存单元address所在的函数体的下一个函数的起始地址。 注意,如果模块没有被分析过(analyze),或者address不在某个函数体内,则会失败。
参数:
address : 在函数体中的地址
返回值:
成功:函数体的起始地址 失败:0
示例:
invoke FindNextProc, eip
函数原型:
FollowCall address
说明:
FollowCall跳过一系列的jmp指令,直到: 1、某个不是jmp指令为止 2、或者某个指令是在另一个模块中