因为安卓逆向时而需要分析在 .so 文件中定义的 natvie 函数,所以对汇编的指令伪代码也需要进行学习,在《Android软件安全与逆向分析》中的第六章针对部分指令有所讲述,不过例子感觉举的不太充分,下面对部分内容做一个备忘。
Register
R0 ~ R3 :用作传入函数参数,传出函数返回值,比方说 test 函数需要两个参数一个返回值,那么即使用 R0、R1 作为函数的参数,返回值保存在 R0 里。在子程序调用之间,可以将 R0 ~ R3 用于任何用途。 被调用函数在返回之前不必恢复。如果调用函数需要再次使用 R0 ~ R3 的内容,则它必须保留这些内容。
R4 ~ R11 :用作存放函数的局部变量,作用域是单个子程序。如果被调用函数使用了这些寄存器,它在返回之前必须恢复这些寄存器的值。在程序运行过程中,编译器会自动保护R4~R11。
R12:内部调用暂时寄存器 IP。它在过程链接胶合代码(例如,交互操作胶合代码)中用于此角色。 在过程调用之间,可以将它用于任何用途。被调用函数在返回之前不必恢复 R12。
R13:栈指针 SP,不能用于任何其它用途,SP 中存放的值在退出被调用函数时必须与进入时的值相同。 每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式、非异常模式(用户模式和系统模式),都有各自独立的堆栈,用不同的堆栈指针来索引。这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,保证了各种模式下程序的状态的完整性。
R14:链接寄存器 LR,用于保存函数的返回地址。如果其他寄存器保存了函数返回地址,则可以在调用之间将 R14 用于其它用途,程序返回时要恢复。(1)保存子程序返回地址。使用BL或BLX时,跳转指令自动把返回地址放入 R14 中;子程序通过把 R14 复制到PC来实现返回。(2)当异常发生时,异常模式的 R14 用来保存异常返回地址,将 R14 如栈可以处理嵌套中断。
R15:程序计数器 PC,用于指向当前指令地址的指针。它不能用于任何其它用途。
Command
STR:STR{条件} 源寄存器,<存储器地址>
STR R0,[R1],#8 ;将 R0 中的字数据写入以 R1 为地址的存储器中,并将新地址 R1+8 写入 R1 。 STR R0, [R1, #8] ;将 R0 中的字数据写入以 R1+8 为地址的存储器中。
LDR:LDR{条件} 目的寄存器,<存储器地址>
LDR R0,[R1,R2,LSL#2]! ;将存储器地址为 R1+R2×4 的字数据读入寄存器 R0,并将新地址 R1+R2×4 写入 R1。 LDR R0,[R1],R2,LSL#2 ;将存储器地址为 R1 的字数据读入寄存器 R0,幵将新地址 R1+R2×4 写入 R1。 LDR R0,0x12345678 ;将 0x12345678 地址保存的数据放入 R0 LDR{cond} register,=[expr | label-expr] ;伪代码
B 指令向前向后跳转的情况
cond_1: ;A cmp r0, #0 beq cond_1f ; r0==0那么向前跳转到B处执行, f 表示 forward bne cond_1b ; 否则向后跳转到A处执行, b 表示 backward cond_1: ;B
感叹号[!]:可以用来使指令执行后,更新基底位地址。
LDR R0, [R1, #8]! ;[R1+8]->R0 ;R1+8->R1 LDR R0!, {R1-R4} ; R1=[R0], R2=[R0+#4]