首页 > 代码库 > 加壳学习笔记(二)-汇编基础

加壳学习笔记(二)-汇编基础

7.简单的汇编语法:
  堆栈平衡  
PUSH,POP
功能: 把操作数压入或取出堆栈
语法: PUSH 操作数 POP 操作数
格式: PUSH r PUSH M PUSH data POP r POP m

PUSHF,POPF,PUSHA,POPA
功能: 堆栈指令群
格式: PUSHF POPF PUSHA POPA

ADD,ADC
功能: 加法指令
语法: ADD OP1,OP2 ADC OP1,OP2
格式: ADD r1,r2 ADD r,m ADD m,r ADD r,data
影响标志: C,P,A,Z,S,O

SUB,SBB
功能:减法指令
语法: SUB OP1,OP2 SBB OP1,OP2
格式: SUB r1,r2 SUB r,m SUB m,r SUB r,data SUB m,data
影响标志: C,P,A,Z,S,O

INC,DEC
功能: 把OP的值加一或减一
语法: INC OP DEC OP
格式: INC r/m DEC r/m
影响标志: P,A,Z,S,O

MUL,IMUL
功能: 乘法指令
语法: MUL OP IMUL OP
格式: MUL r/m IMUL r/m
影响标志: C,P,A,Z,S,O(仅IMUL会影响S标志)

DIV,IDIV
功能:除法指令
语法: DIV OP IDIV OP
格式: DIV r/m IDIV r/m

CBW,CWD
功能: 有符号数扩展指令
语法: CBW CWD
AAA,AAS,AAM,AAD
功能: 非压BCD码运算调整指令
语法: AAA AAS AAM AAD
影响标志: A,C(AAA,AAS) S,Z,P(AAM,AAD)

DAA,DAS
功能: 压缩BCD码调整指令
语法: DAA DAS
影响标志: C,P,A,Z,S

SHR,SHL,SAR,SAL
功能: 移位指令
语法: SHR r/m,data/CL SHL r/m,data/CL SAR r/m,data/CL SAL r/m,data/CL
影响标志: C,P,Z,S,O
ROR,ROL,RCR,RCL
功能: 循环移位指令

所有跳转语句:

Jxx - Jump Instructions Table
        Mnemonic              Meaning                    Jump Condition
          JA     Jump if Above                         CF=0 and ZF=0
          JAE    Jump if Above or Equal                CF=0
          JB     Jump if Below                         CF=1
          JBE    Jump if Below or Equal                CF=1 or ZF=1
          JC     Jump if Carry                         CF=1
          JCXZ   Jump if CX Zero                       CX=0
          JE     Jump if Equal                         ZF=1
          JG     Jump if Greater (signed)              ZF=0 and SF=OF
          JGE    Jump if Greater or Equal (signed)     SF=OF
          JL     Jump if Less (signed)                 SF != OF
          JLE    Jump if Less or Equal (signed)        ZF=1 or SF != OF
          JMP    Unconditional Jump                    unconditional
          JNA    Jump if Not Above                     CF=1 or ZF=1
          JNAE   Jump if Not Above or Equal            CF=1
          JNB    Jump if Not Below                     CF=0
          JNBE   Jump if Not Below or Equal            CF=0 and ZF=0
          JNC    Jump if Not Carry                     CF=0
          JNE    Jump if Not Equal                     ZF=0
          JNG    Jump if Not Greater (signed)          ZF=1 or SF != OF
          JNGE   Jump if Not Greater or Equal (signed) SF != OF
          JNL    Jump if Not Less (signed)             SF=OF
          JNLE   Jump if Not Less or Equal (signed)    ZF=0 and SF=OF
          JNO    Jump if Not Overflow (signed)         OF=0
          JNP    Jump if No Parity                     PF=0
          JNS    Jump if Not Signed (signed)           SF=0
          JNZ    Jump if Not Zero                      ZF=0
          JO     Jump if Overflow (signed)             OF=1
          JP     Jump if Parity                        PF=1
          JPE    Jump if Parity Even                   PF=1
          JPO    Jump if Parity Odd                    PF=0
          JS     Jump if Signed (signed)               SF=1
          JZ     Jump if Zero                          ZF=1
                                 Clocks                 Size
        Operands         808x  286   386   486          Bytes
        Jx: jump          16   7+m   7+m    3             2
            no jump        4    3     3     1
        Jx  near-label     -    -    7+m    3             4
            no jump        -    -     3     1
        - It‘s a good programming practice to organize code so the
          expected case is executed without a jump since the actual
          jump takes longer to execute than falling through the test.
        - see   JCXZ  and  JMP  for their respective timings

JCXZ/JECXZ - Jump if Register (E)CX is Zero
        Usage:  JCXZ    label
                JECXZ   label  (386+)
        Modifies flags: None
        Causes execution to branch to "label" if register CX is zero.  Uses
        unsigned comparision.
                                 Clocks                 Size
        Operands         808x  286   386   486          Bytes
        label:  jump      18   8+m   9+m    8             2
                no jump    6    4     5     5
JMP - Unconditional Jump

2.简单的call函数过程
 1.参数入栈,返回地址入栈。在一个栈帧里,call function的完整过程应该是这样的,call调用的过程要经历两个过程,一个是首先把调用函数之前的指令的下一条指令地址压入栈中(push ebp),作为返回地址,也就是保存旧栈地址,接着会跳转到被调函数的地址入口。呵呵,现在就是借此来恶补汇编哈。

 2.代码区跳转。在执行被调函数的时候,为函数重新开辟栈帧,(mov ebp,esp)这句的意思是将旧栈顶换为新栈的底,这里的新栈一般是由函数专属的哈, 下面就是用sub esp, xx 抬高栈顶,这个过程也就是被调函数局部变量从右向左依次入栈的过程,执行函数体的代码段,

 3.栈帧调整。第一步是:保存当前栈的状态值,就是push ebp,我的理解就是这里实际上是入的系统栈,之所以要先使ebp入栈是要为了分割栈帧,告诉系统要截断旧栈帧,建立新栈帧。第二步:将栈顶装入新的栈底,mov ebp,esp ,准备栈帧转换了,使用这句话的目的是建立新的空栈;第三步:sub esp,xx 就是抬高栈顶,sub是减嘛,就是向低地址扩展噻,栈顶的地址减小,用__stdcall约定的话,如果有三个参数1,2,3
 则这里的入栈顺序为  push 3 ;push 2 ;push 1;这样依次参数入栈,完成函数体入栈(就是将原来的栈顶作为新栈的栈底存在寄存器里,一般就是在系统栈上往上加,开辟完之后,首先call指令会跳转到该函数的入口地址,执行函数体,即将函数的变量依次压入栈中,再依次弹栈,最后返回调用该函数之前的栈地址,也就是上一次的栈顶,这里再进行栈顶的弹栈,正好就是上次调用的函数的调用点)。

 4.跳转。当函数执行完成后首先是保存返回值,通常将函数的返回值保存的EAX寄存器中,然后将当前的栈帧的数据一个个的弹出,直到栈底,实际的具体过程是在esp上加上当前栈帧的大小,降低栈顶,回收当前栈帧的空间,然后当前栈底的保存的前一个栈帧的ebp弹入ebp寄存器,恢复上一个栈帧,将函数返回地址弹给EIP寄存器,下一步按照函数返回地址(不太明白)继续执行母函数中函数调用点的下一个指令的操作:具体代码是:
 add esp,xxx   //降低栈顶
 pop ebp       //弹出栈底
 retn    //这条代码有两个作用,1.弹出当前栈顶元素,这时候已经是到了旧栈帧了,也就是弹出之前的保存指令位置的返回地址,到这里栈帧恢复工作完成啦,然后让处理器取指令的跳转到原来的返回地址恢复调用前的代码区