ARM汇编中B、BL、BLX指令的使用?
B:跳转
BL:例如BL{cond} label。带链接的跳转,如果条件cond满足,会首先将当前指令的下一条指令的地址拷贝到R14(即LR)寄存器中,然后跳转到label指定的地址处继续执行。这个指令通常用于调用子程序,在子程序的尾部,通过MOV PC, LR返回到主程序中。
BX:例如BX{cond} Rm。带状态切换的跳转,如果条件cond满足,处理器判断Rm的位[0]是否为1,若为1,目标地址处的代码解释为thumb代码;若为0,则将目标地址处代码解释为ARM代码来执行。
Arm处理器采用3级流水线来增加处理器指令流的速度,也就是说程序计数器R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的,即PC总是指向当前正在执行的指令地址再加2条指令的地址。
ARM参数传入?返回在放在哪个寄存器?
参数:R0-R3这4个寄存器用来传递函数调用第1到第4个参数,超出的参数通过堆栈。
返回值:结果为32位时,通过R0返回;结果为64位时,r0放低32位,r1放高32位。
ARM调用方法时,对于寄存器的压栈保护,调用方法与被调用方法分别对哪些寄存器进行压栈保护?
被调用模块的寄存器使用
1.调用模块和被调用模块通过R0-R3传递参数,因此参数少于四个时可以随意
使用剩余的而不必保存和恢复
2.使用R4-R11之前一定要先在堆栈中保存起来,退出时再恢复
3.可以使用堆栈,但一定要保证堆栈指针(R13)在进入时和退出时相等
4.R14用于保存返回地址,使用前一定要备份
被调用模块的堆栈使用
1.ATPCS规则规定堆栈是满递减(fD)型的,因此使用STMFD/LDMFD指令操作,
2.注意保证进入和退出时堆栈指针相等
简单ATPCS(ARM-Thumb Procedure Call Standard)寄存器的使用规则:
1. 子程序通过寄存器R0~R3来传递参数。这时寄存器可以记作: A0~A3,被调用的子程序在返回前无需恢复寄存器R0~R3的内容。
2. 在子程序中,使用R4~R11来保存局部变量,这时寄存器R4~R11可以记作: V1~V8。如果在子程序中使用到V1~V8的某些寄存器,子程序进入时必须保存这些寄存器的值,在返回前必须恢复这些寄存器的值,对于子程序中没有用到的寄存器则不必执行这些操作。在THUMB程序中,通常只能使用寄存器R4~R7来保存局部变量。
3.寄存器R12用作子程序间内部过程调用寄存器,记作ip;在子程序的连接代码段中经常会有这种使用规则。
4. 寄存器R13用作数据栈指针,记做SP,在子程序中寄存器R13不能用做其他用途。寄存器SP在进入子程序时的值和退出子程序时的值必须相等。
5. 寄存器R14用作连接寄存器,记作LR;它用于保存子程序的返回地址,如果在子程序中保存了返回地址,则R14可用作其它的用途。
6. 寄存器R15是程序计数器,记作PC;它不能用作其他用途。
7. ATPCS中的各寄存器在ARM编译器和汇编器中都是预定义的。
Inline Hook
Inline Hook流程如下所述:
1. 获取被hook函数地址以及新函数地址。函数的地址可以直接通过函数名获得,如下边这段代码即可打印出read函数的地址。
LOGI(“address of read function is %0x”,read);
2. 修改被hook函数所在内存的读写性。获取被hook函数所在内存页的首地址,然后将这页内存修改为可读,写,执行。
3. 判断so文件使用的是arm指令集还是thumb指令集。判断方法是根据第一步中获取的被hook方法的地址,将该地址进行模4操作。如果模4等于1,则说明是thumb指令集,否则就是arm指令集。
4. 备份原方法,在备份原方法时,由于不知道被hook方法的具体长度,所以只备份原方法的一部分,即图2-5中的inst1指令段,这也导致了如果被hook方法非常短,小于inst1指令段的长度,就会导致修改之后程序崩溃。
5. 修改被hook函数的起始的指令。将被hook函数的第一条指令修改为ldr pc,[下一条指令的偏移](ldr为汇编指令,该条指令的意思是将下一条指令的偏移写入到pc中,这样虚拟机在执行完这条指令之后,就会去pc中所存储的地址执行该条指令),然后将新函数地址写到下一条指令。
6. 继续执行原方法,即去执行备份的inst1指令段,此时在执行inst1指令段时,inst1指令段中与pc相关的指令(如bl指令)就会出现问题,因为此时的pc与原本正常流程中的pc不同,所以要调整pc。可以在上述第5步中修改pc的值之前,将原pc的值存储到某个寄存器中,然后在这里执行inst1指令段时将原pc的值修改回来。
7. 在inst1指令段之后添加跳转指令,使得整个程序在执行完inst1指令段之后顺利跳转到inst2指令段从而完成原方法的完整执行。
got表hook和inline hook的区别/优势劣势
Inline hook主要通过直接修改Android应用程序运行过程中的可执行内存,对被hook函数在内存中的指令进行修改来完成对该函数的hook操作。
在使用got表hook时,只能完成对外部符号的hook操作,并且针对不同的so库,需要对每一个so库都进行一次hook操作,但是got表hook的优点在于易实现,只需要修改got表中所存储的偏移地址即可完成对某个外部符号的hook操作。
inline hook有关的问题
1. 了解GOT hook以及Inline hook,说说Inline hook的实现原理?
Inline Hook即内部跳转Hook,通过替换函数开始处的指令为跳转指令,使得原函数跳转到自己的函数,通常还会保留原函数的调用接口。与GOT表Hook相比,Inline Hook具有更广泛的适用性,几乎可以Hook任何函数,不过其实现更为复杂,考虑的情况更多,并且无法对一些太短的函数Hook。
2. Inline hook实现的跳转两条指令是什么?
ARM |
THUMB |
LDR PC, [PC, #‐4] addr |
LDR.W PC, [PC, #0] addr |
为什么第一条要用LDR(从存储器加载数据到寄存器)而不用MOV(将8位的立即数或寄存器的内容传送到目标寄存器中)?
MOV对立即数有要求,只能由一个8bit连续有效位通过偶数此移位得到的数。因为MOV本身就是一个32bit指令,除了指令码本身,不可能再带一个可以表示32bit的数字,所以用了其中的12bit来表示立即数,其中4bit表示移位的位数(循环右移,且数字*2),8bit用来表示要移位的一个基数。如果立即数超过这个范围,就无法用MOV指令给寄存器赋值。
Inline Hook的实现详细参考Android Arm Inline Hook