第二章

OllyMachine体系

2.1  核心

OllyMachine由一个汇编器(Assembler)和一个32位虚拟机(Virtual Machine)所组成。其核心为寄存器虚拟机(Register-Machine),拥有堆栈、寄存器结构以及相关的寻址方式,与x86 CPU比较相似。

2.1.1  寻址空间

OllyMachine是32位虚拟机,因此,它的有效寻址空间为:

但是,在实际中可能达不到这么大的寻址空间(例如,现在大部分的机器的物理内存只有512MB),因此这只是一个理论值。

2.1.2  寄存器

在OllyMachine虚拟机中,有83个通用寄存器以及3个隐含的寄存器。其中:

reg00、reg01、reg02 ... reg64、FreeBufferReg、FreeBufferSizeReg

以上这67个寄存器可以供用户自由使用。FreeBufferReg和FreeBufferSizeReg有其特殊用途,留待后面再说。

以及9个寄存器为:

eax、ecx、edx、ebx、esp、ebp、esi、edi、eip

这9个寄存器比较特殊,它们是我在设计OllyMachine时,为了方便程序员与OllyDbg进行交互而定义的特殊寄存器,对它们的操作将直接反映到OllyDbg的当前被调试进程上。

还有7个标志位寄存器:

CF、PF、AF、ZF、SF、DF、OF

这7个标志位寄存器对应着OllyDbg里面的相应的标志位,举例如下:

not cf
mov zf, 0
mov pf, 1

另外,OllyMachine中还有2个隐含的寄存器,它们是:eip和esp。eip为指令指针寄存器,用来存放代码段中的偏移地址;esp为堆栈指针寄存器,用来指示栈顶的偏移地址。

注意!这2个隐含的寄存器必须区分于上面提到的那9个寄存器中的同名寄存器。主要的区别在于:上面那9个寄存器其实是引用自OllyDbg的当前被调试进程,程序员可以直接操纵它们,其结果相当于在OllyDbg中直接操纵对应的寄存器;而这2个隐含的寄存器则是属于OllyMachine CPU内部的,不能被程序员直接访问,我给它们取名为eip和esp只是由于我对x86 CPU体系的个人喜好。

2.1.3  标志位

OllyMachine CPU内部,还有一个隐含的EFlags寄存器,它是标志位寄存器。标志位往往用来作为后续条件转移指令的转移控制条件,所以称为条件码。在OllyMachine CPU内部,有以下2位标志位:

2.2  工作流程

OllyMachine拥有自己的一套指令集(opcode),它与用户的接口是一套被称为OllyMachine Script的汇编语言,用户通过编写汇编语言与OllyMachine打交道。

在运行前,OllyMachine会首先通过内置的Assembler把汇编语言源代码编译成字节码(byte codes),其工作流程如下图所示:

图 1:  Assembler工作流程

通过Assembler生成字节码后,字节码即可送进虚拟机内部进行执行。

因此,实际上OllyMachine的工作流程是分成两个独立的步骤:

我们也可以事先执行好汇编的步骤,即把源代码编译成一个字节码文件并保存起来,以后就可以直接用OllyMachine载入这个字节码文件而无需再次汇编,达到节省时间的目的。

2.3  编译期错误

OllyMachine有一个内置的汇编器,它是一个两遍扫描的LL(1)语法驱动汇编器。如果源程序中有词法、语法错误,会在编译期间被检测出来,并提示出错文件、行、单词以及出错类型给程序员,方便程序员进行debug。

请看下面这个例子程序:

mov reg00, reg73    // Error: "reg73" is invalid
inc reg00
inc reg00, 1        // Error: "inc" doesn't need second operand

exit:               // Warning: unreferenced label

OllyMachine的汇编器会报错:

图 2:  编译期错误示例

2.4  运行期异常

OllyMachine在运行期如产生异常,会被捕捉(例如除0异常等),并且会给出导致异常的指令名称,以及dump出所有的字节码,供程序员进行debug。

请看下面这个例子程序:

mov reg00, 9
mov reg01, 3
sub reg01, 3        // now reg01 is 0
div reg00, reg01    // oh shit!

由于程序员的粗心产生了除0错误,于是就会导致OllyMachine捕获这个异常(依次显示下面的两个报错对话框):

图 3:  运行期异常示例1

图 4:  运行期异常示例2