什么是汇编
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言,它是最接近与机械语言的编程语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。特定的汇编语言和特定的机器语言指令集是一一对应的,不同平台之间不可直接移植。
什么是寄存器
由于后面的学习,我们会讲到寄存器,所以我就先在这里讲解一下什么是寄存器吧。
寄存器是位于CPU内部的存储空间,每个寄存器都有自己的名字,分别叫作EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI,EIP。这些寄存器都有着各自的用途。如ESP和EBP用管理栈,而EIP指向当前执行的指令。
部分汇编基础指令
和一般编程的语言保留字相比,汇编语言的指令数量多的离谱,因为只有记住将近1000条指令才能编写出像样的程序,难怪相学汇编的人少的可怜。
不过,说实在的,在逆向工程中需要用到的汇编语言知识并没有那么多。正如WIndows程序员美欧必要记住所有的Windows API函数一样,做逆向工程也没有必要记住太多的汇编指令,遇到不会的汇编指令查找一下就可以了,实际上我们需要掌握的指令也就是20~50条左右。(下面就是我看的书中的一些基本的汇编指令)
汇编语言如何实现条件分支
一般来说,对于有一定的编程基础的话,在看到上面的表格基本上会了解部分。然而,在上面的指令中还是有几个需要特别说明一下的,如cmp,test,je和jne这几个,因为这些指令便是在汇编的语言中实现分支的。
在我们一般的编程语言中,都是通过if,switch等一些保留字来实现条件分支的。但是在汇编语言中,则是通过控制标志cmp,test指令,以及根据标志完成分支的跳转类指令来实现的。(对于我们这些初学者而言,例子是必不可少的,所以我们可以对照上面的表格,来大致看懂下面的汇编程序,当然,只是其中的一部分。)
在一般情况下,test指令都会跟着两个相同的寄存器名称,比如test eax,eax,又或者test ecx,ecx。
所以,只要看到带有两个相同的寄存器的test指令,一般就是条件分支,可以简单的理解为“若寄存器值为0,则将ZF置为1”。
汇编语言中,参数存在栈中
在上面提到的eax是参数,而它作为参数,它的值来之哪里?
在上面我们会发现call指令是用来调用子程序的,他的返回值都存在eax中。而在在我们看来可以作为一种惯例,而且在大多数处理器中都是这么做的。(当然,可能会存在一些特殊的情况。)我们在学习汇编的时候也可以这么做,记得要将返回值存放在eax中。
那么,传递给子程序的参数放在哪里?参数要通过push指令存放在栈中。
c语言中的函数调用:
function(1,2,3);
汇编语言中的函数调用:
push 3
push 2
push 1
call function
在汇编语言中,参数是按照从后往前的顺序入栈的,不过这个方面的规则可能会因为CPU和编译器的不同而存在一些差异,不过我们只需要记住“参数是通过栈来传递的”就可以了。