iOS逆向工程之Hopper中的ARM指令详解

2020-01-18 15:37:40于丽

1.栈操作---- push 与pop

先简单的聊一下栈的概念,“栈”说白了就是数据结构的一种,栈的数据结构具有LIFO(last in first out) ---- 后进先出的特点。栈在ARM中所指的其实是一块具有栈数据结构特点内存区。栈中主要用来暂存寄存器中的值得,比如R0寄存器正在使呢,可是现在有一个优先级比较高的函数要使用R0, 那么就先把R0的值Push到栈中暂存,然后等R0被优先级更高的函数使用完毕后在从栈中Pop出之前的值。在函数调用时一般会对栈进行操作。

对栈操作的命令就是push和pop了,一般会成对出现,在函数开始时将该函数执行时要使用的寄存器中的值push入栈,然后在函数结束时将之前push到栈中的值在pop到相应的寄存器中。

下方就是push和pop的用法的一个实例。在下方函数开始执行前,将该函数要使用的寄存器r4, r5, r7, lr使用push进行入栈操作,lr是该函数执行后要返回的地址。在函数执行完毕后,使用pop命令将函数执行前入栈的值在pop到相应的寄存器中。有一点需要注意的是将lr寄存器中的值在函数结束后pop到pc (Program Counter)寄存器中,pc寄存器中存储的是将要执行的命令的地址。这样一来,函数执行后就会返回到之前执行的地址上继续执行。

ios,hopper,arm指令,arm逆向工程

2. pc寄存器中的中的标志位

此处我们以32位指令为例,pc寄存器中的后四位是标志位,第28 - 31位分别对应着V (oVerflow),C (Carry),Z (Zero),N (Negative)。下面分别来介绍一下这四种符号所表示的状态。

•N (Negative): 如果结果是负数则置位。

•Z (Zero): 如果结果是零则置位。

•C (Carry): 如果有进位则置位。

•V (Overflow): 在发生溢出的时候置位。

3. 命令操作符

下方是ARM指令集中常用的算术操作:

(1)加法操作

•ADD R0, R1, R2 ; R0 = R1 + R2 •上面的命令就比较简单,就是讲两个数值进行相加。

•ADC R0, R1, R2 ; R0 = R1 + R2 + C (Carry) •带进位的加法,ADC将把两个操作数加起来,并把结果放置到目的寄存器中。ADC使用了C--进位标志,这样就可以做比32位大的加法了。下方就是128位的数字进行加法操作的汇编代码。

•我们现在要对一个128位的数字进行加法操作,因为我们使用的是32位的寄存器,所以要存储一个128位的数字,我们需要4个(128 / 32 = 4)寄存器。所以我们假设R0,R1,R2,R3寄存器中分别由低到高存储着第一个数字,而R4, R5, R6, R7存储着第二个数字。下方就是两个128数字相加操作的ARM汇编指令。我们将结果存储在R8, R9, R10, R11这四个寄存器中。首先我们执行的是将两个数的最低位相加并设置C标志位(ADDS R8, R0, R4),然后在进行下一位的操作,对R1和R5中的值进行相加,在相加后再加上上次操作的进位,然后再设置标志位,以此类推。这样我们最终的值就存储在了R8-R11这四个寄存器中。