首页 > 编程知识 正文

arm寄存器组有几个寄存器,arm处理器有几个寄存器

时间:2023-05-06 16:00:11 阅读:126874 作者:738

i春秋作家: v4ever

研究了近期几种开源朴素层hook方案的实现方式,并在此基础上梳理了ARM装配层中容易出现问题的部分,供后人从中获得并应用于现实问题。 当然,本文的很多介绍都是借鉴了很多零散的文章,本文侧重于相关概念的整理收集,并以比较合理的顺序引出对后面文章hook技术中一些难点的解读。

安卓平台大多采用ARM架构的CPU,但ARM是RISC,具有与X86架构的处理器不同的特点。 本文介绍了ARM难以理解的ARM寄存器的各种问题,包括ARM流水线、面向PC寄存器的问题、ARM和Thumb指令的区分以及相关概念在朴素层hook中的应用问题。

1.ARM寄存器介绍

ARM微处理器有37个32位寄存器,其中31个是通用寄存器,6个是状态寄存器。 但是,这些寄存器不能同时访问。 具体哪个寄存器可以访问取决于ARM处理器的工作状态和具体的工作模式。 但是,通用寄存器R14~R0、程序计数器PC、1个状态寄存器可以随时访问。

简而言之,在用户模式下ARM可以识别的寄存器有16个32位寄存器(r0~R15 )和当前的程序状态寄存器CPSR。 其中,r15是程序计数器PC,R14是子程序的返回地址LR,R13是用于存储堆栈顶层SP的寄存器。

本文重点介绍R15寄存器,即PC寄存器。 理论上,PC寄存器应该指向即将执行的下一个指令的地址,但在实际应用中发现PC寄存器并不总是这样。 从资料上看,发现这个问题是由ARM中存在的指令流水线引起的。

2.ARM管线介绍

流水线技术通过多个功能部件并行运行,缩短了程序运行时间,提高了处理器内核的效率和吞吐量,成为微处理器设计中最重要的技术之一。 也就是说,通过划分指令执行中的不同阶段并并行执行,提高指令的执行效率。 ARM7处理器采用fetch、decode、execute三级流水线结构。

3.PC寄存器方向问题

如上图所示,当执行add r0、r1、#5指令时,第二个指令处于解码阶段,第三个指令处于指阶段。 执行第一条指令时,PC寄存器应指向第三条指令。 也就是说,处理器为三级流水线结构时,PC寄存器始终指向以下第三条指令。

当处理器处于ARM状态时,PC寄存器的值是当前指令地址8字节,因为每个ARM指令为4字节。 当处理器处于Thumb状态时,每个Thumb指令为2字节,因此PC寄存器的值为当前指令地址4字节。 另外,在ARM9中,采用了在ARM7的三级流水线结构之后追加了两个新工艺的五级流水线结构。 因此,指令的执行过程和提取过程仍然是分隔解码过程的,所以PC是指当前指令之后的第三个指令。

此外,应该注意的是,当用指令STR或STM存储R15时,所存储的是当前指令地址加8或者是当前指令地址加12。 具体是加8还是加12取决于处理器的设计。 但是,同一芯片只能是某一个方案,即正8或正12。

您可以通过以下代码查看处理器是如何工作的:

SUB R1、PC、#4; R1中保存STR指令的地址

STR PC,[R0]; 用STR指令将PC保存在R0所指的地址单元中。 PC=STR指令地址偏移(偏移为8或12 )。

LDR R0,[R0]; 读取STR指令地址偏移的值

SUB R0、R0、R1; 从STR命令的地址偏移值中减去STR命令的地址,得到偏移值(8或12 )。

4 .区分4. ARM/Thumb命令

已知ARM体系结构包括ARM状态、Thumb状态和Thumb-2状态。 ARM状态时执行32位长的字对齐的ARM命令,Thumb状态时执行16位长的半字对齐的Thumb命令。

Thumb指令集和ARM指令的区别一般在于以下方面:

转移指令程序的相对转移,特别是条件转移与用ARM码的转移相比,在范围上有很多限制,向子程序的转移是无条件的转移。

数据处理指令数据处理指令是操作通用寄存器的指令,在很多情况下,操作的结果需要放入其中一个操作数寄存器而不是第三个寄存器。 数据处理动作比ARM状态少,访问寄存器R8~R15有一定的限制。 除了MOV和ADD命令存取器R8~R15以外,其他数据处理命令总是更新CPSR中ALU状态标志,访问寄存器R8~R15的Thumb数据处理命令不能更新CPSR中的ALU状态标志.

在单寄存器加载存储指令Thumb状态下,单寄存器加载存储指令只能访问寄存器R0~R7

批量寄存器加载&; 存储指令LDM和STM指令可以加载或存储R0~R7的寄存器的任意范围的子集。

PUSH 和 POP 指令使用堆栈指令 R13 作为基址实现满递减堆栈.除 R0~R7 外,PUSH 指令还可以存储链接寄存器 R14,并且 POP 指令可以加载程序指令PC

     而程序在执行过程中,是如何区分ARM状态和Thumb状态的呢?在逆向分析过程中,经常会看到许多函数调用过程为形如BX sub_84C0 + 1,即函数地址为奇数。在ARM运行过程中,函数调用的地址最后一位为1时,表示目标函数为Thumb指令;否则为ARM指令。然而,不管是ARM和Thumb状态指令,均是偶数字节对齐的,即函数地址最后一位肯定为0。因此,可以用最后一位判断目标函数是否为Thumb和ARM状态。

        综上,程序状态切换可以用如下方式实现:

从ARM切换到Thumb:

        LDR R0, =label + 1

        BX R0

从Thumb切换到ARM:

        LDR R0, = label

        BX R0

    上文中,label为符号的地址,因为字节对齐缘故,最后一位肯定为0。

5.native层hook技术解析
        以上 问题均是我在分析开源hook框架adbi源码时遇到的问题的解答,下面我将介绍一下上述几个问题在hook中的应用。

        在adbi源文件中,hijack.c文件中的sc数组用于存储在对目标函数前几个字节的指令修改过程中的相关指令和寄存器值。

        第一条指令为ldr r0, [pc, #64],即将pc + 64位置处的内存的4个字节读到r0寄存器中。经过上面几个章节的介绍,且此处看出指令均为4个字节即ARM指令,可知读取的位置为当前位置 + 8 + 64 位置处的内容,即sc[18]处的内容,也即addr of libname的内容,即将函数调用时第一个参数R0设置为动态库的字符串名。

        第二条指令将r1寄存器,即函数的第二个参数设置为0。

        第三条指令将pc的值赋值给lr寄存器,即将随后函数调用后的返回地址设置为559行的那条指令,即第五条指令。

        第四条指令将pc + 56位置处存储的值赋值给pc寄存器,即当前位置 + 8 + 56位置处的值,也即sc[16]处的值,即被hook的dlopen函数的地址。

        随后函数调转到目标函数执行,并在返回后执行559行的执行,从此开始恢复寄存器环境。也即通过这种方式完成了对目标函数的hook劫持过程。

        在hook.c文件中,实现了对目标函数的查找及指令替换功能,详情如下图所示。图中,通过对find_name函数的调用,得到了目标so库中的函数funcname的地址并存储于addr中。在代码编译过程中,编译为Thumb指令的函数,通过函数名得到的目标函数地址最后一位为1,用于表示目标函数为Thumb指令集。在adbi代码中,即根据该方法判断需要hook的目标函数是Thumb指令集还是ARM指令集。ARM指令集由于是4字节对齐的,因此最后2位总是为0,据此判断是否是ARM指令。根据不同的指令集实现不同的指令替换,并完成hook功能。 

        以上即是我在研究adbi源码过程中碰到的需要深入了解的一些基本概念及其具体应用,了解这些能对hook的实现原理能有较为深刻的理解,并据此编写自己的简易的hook方案。

6.总结
        在ARM处理器架构中,PC寄存器通常是指向当前指令后的第三条指令地址,即在ARM指令是+8,Thumb指令时+4。 

        ARM/Thumb状态切换是根据目标函数地址最后一位是否为0来进行判断,并用BX指令实现。

参考链接
https://blog.csdn.net/Sandeldeng/article/details/52954781

https://blog.csdn.net/zhi_yong_chen/article/details/51314377

http://www.eepw.com.cn/article/201611/318735.htm

有问题大家可以留言哦,也欢迎大家到春秋论坛中来耍一耍  >>>点击跳转

转载于:https://www.cnblogs.com/ichunqiu/p/9056630.html

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。