Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从IDA动态调试方法到ARM三级流水线的分析到实操

从IDA动态调试方法到ARM三级流水线的分析到实操

作者头像
FB客服
发布于 2021-10-11 07:29:23
发布于 2021-10-11 07:29:23
2.2K00
代码可运行
举报
文章被收录于专栏:FreeBufFreeBuf
运行总次数:0
代码可运行

前言

交互式反汇编器,简称为IDA。是目前最棒的一个静态反编译软件,为众多0day世界的成员和ShellCode安全分析人士不可缺少的利器!此章节让我们熟悉通过IDA修改参数、函数、返回值,同时详细解读标志位的概念,熟悉堆栈及详细解读ARM三级流水线概念和ARM编码编译为二进制的全过程。

一、环境配置

首先配置IDA与安卓联动

IDA动态调用手机apk,请参考:安卓逆向-从环境搭建到动态调试apk IDA部分https://www.freebuf.com/articles/mobile/285861.html

1)加载server

2)端口转发+执行app(javandk1这个测试app)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
adb install E:\IDA7.0\test\javandk1.apk    #安装app
adb shell am start -D -n com.example.javandk1/.MainActivity    #启动app
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
adb forward tcp:23946 tcp:23946    #端口转发

3)打开启动DDMS

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
DDMS

4)打开IDA 32并调试ndk运行

5)并勾选三项调试

6)F9启动+执行jdb调用DDMS

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8600

此时可以看到加载的不是so,而是/arm/base.odex文件,那么此时怎么加载我们需要的so库,分析JNI_onload呢?

问题:解决方法无libjavandk1.so库

1)在Modules查询java:

2)选择libjavacore.so库-在搜索JNI_load选择

那么此时就进入了libjavacore.so的JNI_onload了

3)接下来下一个断点:点击或F2

4)F9运行后跳转到断点截断处,此时回到Modules继续搜索java:

此时就出现需要调试的so库文件:libjavandk1.so库文件

5)那么继续选择进入搜索JNI即可

此时问题就解决了

6)继续来到JNI_onload下断点,开始分析判断传参

二、参数分析

1、第一种方法

这里BLX传入了几个参数?

这里BLX中R3需要跳转,那么R3也是有规定给地址的,所以我们这里的有4个参数R0-R3

R0-R3:4个寄存器->参数寄存器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
R0-R3:用于函数参数及返回值的传递
R4-R6,R8,R10-R11:普通的通用寄存器
R7:栈帧指针(Frame Pointer),指向前一个保存的栈帧(stack frame)和链接寄存器(link register,lr)在栈上的地址。
R9:操作系统保留
R12IP(intra-procedure scratch)
R13:SP(stack pointer) 是栈顶指针
R14LR(link register) 存放函数的返回地址
R15PC (program counter),指向当前指令地址

如果R3作为一个地址的存放,当你把一个函数地址存放在R3里面,根据规定R3已经作为地址存放了,如果这个函数要传参,只能从R0-R2,这个三个寄存器里面进行传参。

注:如果想判断有几个参数,看这个BLX(指令)后面的值(是不是寄存器,如果是,Rn小于4,参数个数就是当前减1;大于等于4,参数寄存器就是R0-R3)

此时回到图中,BLX R3;三个参数,用了R0-R2后,只会依次使用下一个寄存器存放跳转的地址;

BLX R4(三个参数:R0,R1,R2,R3)

现在打开堆栈看看

在BLX R3处打桩,F9运行到下一个断点处

记住此时的栈顶是00000001,这时候SP:FF9ABBE0指向栈顶

这时候单步F7

这时候查看,SP的值还是FF9ABBE0是没有变化的

2、第二种方法

静态调试SO库,按F5查看伪代码

可以查看到伪c代码(int a1,int a2)就是查看参数个数

二、修改寄存器-返回值

我们随便找的几个BLX指令的地方。

BLX R3此时传入几个参数 ?三个

那么BLX R12传入几个参数?四个

按F5进入伪C代码

静态注册参数怎么修改呢?选择你要修改的参数,按Y

如何修改寄存器的值呢

这时候就可以修改寄存器的值了

例如:cmp R0,0,那么就执行BEN,意思就是修改了条件为0后,就不执行改条件,反调试会更深入演示

Y键修改C代码(退出C代码按ESC)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
R0-R3:用于函数参数及返回值的传递
R4-R6,R8,R10-R11:普通的通用寄存器
R7:栈帧指针(Frame Pointer),指向前一个保存的栈帧(stack frame)和链接寄存器(link register,lr)在栈上的地址。
R9:操作系统保留
R12IP(intra-procedure scratch)
R13:SP(stack pointer) 是栈顶指针
R14LR(link register) 存放函数的返回地址
R15PC (program counter),指向当前指令地址

三、修改寄存器-修改函数

1、方法1-修改Hex

如果我要改这条指令

根据三级流水线,需要在前三个代码断点

不想让程序执行怎么办?直接同步下PC寄存器

现在你想在HEX处找的PC的指令,当鼠标放在PC指令处,hex自动选择

然后在Hex View-1处快捷键F2操作,修改,

修改为00 00 00 00后,然后在快捷键F2保存下

这时候指令就没了

2、方法2-修改General

或者直接设置PC(只适合调试时候测试使用)

例如此刻需求是,跳过大红框内容,直接执行MOV R0, #0x10004这条指令,此刻PC在F42AA08C

只需要在General registers处修改PC值为MOV处的指令值即可,那么此时MOV出指令值为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
F42AA0A4

开始修改,双击General registers-PC处,修改为MOV的值:

直接跳转mov处

四、IDA配置堆栈信息

在PC窗口处配置出堆栈指针和Hex View对应的十六进制的值

五、IDA标志位详解

CPSR标志位详解

一边情况下标志位情况

断点后的情况

用最简单的理解,这些到底有什么用

通过图很好了解,例如BLX进行运算是正数还是负数,经过运算后值是不是为零,可以理解为条件标志位,帮我们记录一些状态! 标志位的结果内容可被算数或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。 最重要的是N、Z、C、V、Q、T,那么T是什么意思? T标志位︰该为反应处理器的运行状态。当该位为1时,程序运行于THUMB状态,否则运行于ARM状态。该信号反映在外部引脚TBIT上。在程序中不得修改CPSR中的TBIT位,否则处理器工作状态不能确定。

ARM状态

arm处理器工作于32位指令的状态,所有指令均为32位

thumb状态

arm执行16位指令的状态,即16位状态

六、ARM汇编三级流水线详解

1、什么是三级流水线

前缀

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ARM7处理器采用3级流水线来增加处理器指令流的速度,能提供0.9MIPS/MHz的指令处理速度。
MIPS(Million Instruction Per Second)表示每秒多少百万条指令。比如0.9MIPS,表示每秒九十万条指令。
MIPS/MHz表示CPU在每MHz的运行速度下可以执行多少个MIPS,如0.9MIPS/MHz则表示如果CPU运行在1MHz的频率下,每秒可执行90万条指令。

三级流水线使用3个阶段,因此指令分为3个阶段执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1)取指从存储器装载一条指令
2)译码识别将要被执行的指令
3)执行处理指令并将结果写会寄存器

但是处理实际是这样的:ARM正在执行第一条指令的同时对第二条指令进行译码,并将第三条指令从存储器中取出

所以,ARM7流水线只能在取第4条指令时,第1条指令才算完成执行

无论处理器处于何种状态,程序计数器R15(PC)总是指向”正在取指“的指令,而不是指向”正在执行“的指令或者正在”译码“的指令。

人们一边会习惯性的将正在执行的指令作为参考点,即当前第一条指令,所以,pc总是指向第三条指令

或者说PC总是指向当前正在执行的指令在加2条指令的地址

2、三级流水线详解

处理器处于ARM状态是,每条指令为4个字节,所以PC指令为正在执行的指令地址加8个字节,即是:

PC值=当前程序执行位置+8字节

处理器处于Thumb状态时,每条指令为2字节,所以PC值为正在执行的指令地址加4字节,即是:

PC值=当前程序执行位置+4字节

下面一个列子很好的说明了这个问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
libjavandk1.so:F42AA090 010 00 C0 90 E5 LDR    R12, [R0]    #正在被执行的指令
libjavandk1.so:F42AA094 010 5C C3 9C E5 LDR    R12, [R12,#0x35C]  #正在被编码的指令
libjavandk1.so:F42AA098 010 3C FF 2F E1 BLX    R12   #正在被取指的指令 PC=F42AA098
libjavandk1.so:F42AA09C 010 00 00 50 E3 CMP    R0, #0    #PC+4=F42AA09C

另外补充说明就是根据以上描述,流水线只有被指令填满时才能发挥最大的效能,既每时钟周期完成一条指令的指向(仅单周期指令)

如果程序发送跳转,流水线会被清空,这将需要几个时钟才能使流水线被再次填满。因此,尽量地少使用跳转指令可以提高程序的指令效率

PC代表程序计数器,流水线使用三个阶段,因此指令为分为三个阶段执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、取指(从存储器装载一条指令)
2、译码(识别将要被执行的指令)
3、执行(处理指令并将结果写回寄存器)

而R15(PC)总是指向”正在取指“的指令,而不是指向”正在执行“的指令或者正在”译码“的指令。一般来说,人习惯性约定将”正在执行“的指令作为参考点,称之为第一条指令,因此PC总是指向第三条指令,当ARM状态时,每条指令为4字节长,所以PC始终指向改指令地址加8字节的地址,既:PC值=当前程序执行位置+8;

ARM指令是三级流水线,取指、译指、执行是同时执行的,现在PC指向的是正在取值的地址,那么CPU正在译指的指令地址是PC-4(假设ARM状态下,一个指令占4个字节),cpu正在执行的指令地址是cpu-8,也就是说PC所指向的地址和现在所执行的指令地址相差8。

当突然发生中断的时候,保存的是PC的地址

这样你就知道了,如果返回的时候返回PC,那么中间就有一个指令没有执行,所以用SUB pc lr-irq#4。

这个需要参考《ARM指令》来学习

3、案例-ARM指令转换为机器码

下面我们将一个ARM指令转换为机器码试试

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
00001BD0 BEQ lc04
BEQ lc04;跳转指令,执行条件EQ,即相等跳转到lc04

来计算这条指令

1)首先ARM指令是32位的,因为这里是BEQ的B的跳转指令,32位可以拆分为格式如下

2)前四位:31-28就是cond,这里的意思就是条件码,例如EQ、NE

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0000

3)紧接着3位:27-25(这里由于B指令是101固定的)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0000 101

4)在往下24位:(1或者0,具体判断:带有连接的如果是BL指 令对应的二进制操作数就是1 无条件跳转B指令就是0。)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0000 1010

5)0-23位:偏移地址:目标地址与该指令的相对偏移

偏移的计算公式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(目标跳转的地址-(当前这条指令的地址+8))/4
(1c04-(1bd0+8))/4=1011
1c04:要跳转的地址
1bd0:此指令所在的地址
+8:arm指令有3级流水线的原因,如果执行1c04地址指令,需要加8
/4:因为要做对 其处理

我们拼接一下计算出来的二进制ARM指令机器码,因为0-23位算出来的是1011,

1011对应0-3位置

4-23用0补齐

结果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0000 1010 0000 0000 0000 0000 0000 1011

转换为16进制就是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0A 00 00 0B

因为是小端模式,需要换一下位置结果就是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0B 00 00 0A

我们在IDA中测试一下

将IDA中hex中随便一个地方改为0B 00 00 0A

我们看到指令变为了BEQ loc_F42AA0D4

我们计算利用偏移公式计算F42AA0D4(目标地址)和F42AA0A0(当前地址)结果是不是1011

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(A0D4-(A0A0+8))/4=1011

我们这里就简单了解到了ARM指令如何计算为ARM指令机器码

七、总结

此章节我们详细学习了使用IDA在静态注册和动态注册下分析和修改参数,学习修改返回值、函数,对IDA堆栈功能模块和标志位功能模块进行深入解析,同时了解了ARM中三级流水线并利用案例熟悉ARM指令转换为机器码的案例。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)[转]include <stdio.h>int func(int a, int b, int c, int d, int e,
声明:本文转自Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码),此文干货很多。
用户2930595
2018/08/23
4.3K0
Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)[转]include <stdio.h>int func(int a, int b, int c, int d, int e,
MIPS五级流水线_工业级CPU报价
流水线CPU就是指将一条分解为多步,在同一周期内进行多条指令的同时执行。MIPS五级流水线就是将指令分为:取指(IF),译码(ID),执行(EX),访存(MEM),写回(WB)五个阶段。举个例子:
全栈程序员站长
2022/09/25
1.8K0
MIPS五级流水线_工业级CPU报价
ARM汇编简单学习
ARM汇编语言是针对ARM架构设计的低级编程语言,用于直接操作硬件和编写高效的系统级程序。
cultureSun
2024/03/28
2110
arm和mips架构区别_arm架构详解
1978年12月5日,物理学家赫尔曼·豪泽(Hermann Hauser)和工程师Chris Curry,在英国剑桥创办了CPU公司(Cambridge Processing Unit),主要业务是为当地市场供应电子设备。
全栈程序员站长
2022/11/04
3.4K0
arm汇编指令详解带实例_汇编buf指令
两个 S 用于不同的指令,名称相同,但是在不同的指令结合却有不同的作用
全栈程序员站长
2022/11/04
1.6K0
嵌入式:ARM的流水线技术
在3级流水线的执行过程中,当通过R15寄存器直接访问PC时,必须考虑到此时流水线的执行过程的真实情况
timerring
2022/12/13
1.7K0
嵌入式:ARM的流水线技术
OpenHarmony 内核源码分析(中断切换篇) | 系统因中断活力四射
小帅聊鸿蒙
2025/03/19
980
OpenHarmony 内核源码分析(中断切换篇) | 系统因中断活力四射
嵌入式:ARM转移指令(分支指令)
ARM的转移指令可以从当前指令向前或向后的32MB的地址空间跳转,根据完成的功能它可以分为以下4种 :
timerring
2022/12/25
1.5K0
嵌入式:ARM转移指令(分支指令)
5_LED程序涉及的编程知识
​ 目前IMX6UL是使用Cortex-A7架构,本小节简单介绍一下Cortex-A7架构的基础知识,比如运行模式、寄存器组等。
韦东山
2022/05/05
5950
5_LED程序涉及的编程知识
ARM架构的一次充电
ARM处理器使用精简指令集(RISC),ARM(Advanced RISC Machines)ARM是一家公司的简称,其次ARM指一系列处理器的统称,同时ARM也是一种精简指令集架构。
小道安全
2022/12/18
1.2K0
ARM架构的一次充电
linux内核1-GNU汇编入门_X86-64&ARM
为了阅读Linux内核源代码,是需要一些汇编语言知识的。因为与架构相关的代码基本上都是用汇编语言编写的,所以掌握一些基本的汇编语言语法,能够更好地理解Linux内核源代码,甚至可以对各种架构的差异有一个更深入的理解。
Tupelo
2022/08/10
5.1K0
linux内核1-GNU汇编入门_X86-64&ARM
安卓逆向:这是一篇逆向基础函数在ARM32中的刨根问底。
通过向程序计数器 PC写入跳转地址值,可以实现在 4GB 的地址空间中的任意跳转,在跳转之前结合使用MOV LR,PC
小道安全
2021/01/18
3.7K1
arm(2)| 汇编指令和伪指令
指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。所以指令和伪指令最大区别就是编译完之后会不会生成机器码。
飞哥
2020/07/10
2.8K0
arm(2)| 汇编指令和伪指令
嵌入式软件工程师笔试面试指南-ARM体系与架构
注意:nandflash和norflash的0地址是不冲突的,norflash占用BANK地址,而nandflash不占用BANK地址,它的0地址是内部的。
嵌入式与Linux那些事
2021/04/28
1.8K0
嵌入式软件工程师笔试面试指南-ARM体系与架构
计算机指令的流水线执行与流水线冒险
不要等待计算结果保存到目的寄存器,增加一条额外数据通路,将计算的结果直接传给下一条指令计算的输入
叶茂林
2023/11/19
5350
计算机指令的流水线执行与流水线冒险
Verilog实现MIPS的5级流水线cpu设计(Modelsim仿真)[通俗易懂]
1.1:实验目的 (1)CPU各主要功能部件的实现 (2)CPU的封装 (3)了解提高CPU性能的方法 (4)掌握流水线MIPS微处理器的工作原理 (5)理解并掌握数据冒险、控制冒险的概念以及流水线冲突的解决方法 (6)掌握流水线MIPS微处理器的测试仿真方法 1.2:实验要求 (1)至少实现MIPS中的三类指令,即R类,I内,J类指令 (2)采用5级流水线技术 (3)完成Lw指令的数据冒险的解决 (4)在ID段完成控制冒险的解决
全栈程序员站长
2022/09/24
1.6K0
Verilog实现MIPS的5级流水线cpu设计(Modelsim仿真)[通俗易懂]
R0~R16寄存器作用
诺谦
2018/01/03
1.8K0
ARM指令集
ARM指令的基本格式为: <Opcode> {<Cond>} {S} <Rd>, <Rn> { , <Opcode2> } 其中,<>内的项是必需的,{}内的项是可选的。 1)Opcode项 Opcode是指令助记符,即操作码,说明指令需要执行的操作,在指令中是必需的。 2)Cond项(command) Cond项表明了指令的执行的条件,每一条ARM指令都可以在规定的条件下执行,每条ARM指令包含4位的条件码,位于指令的最高4位[31:28]。 条件码共有16种,每种条件码用2个字符表示,这两个字符可以添加至指令助记符的后面,与指令同时使用。 当指令的执行条件满足时,指令才被执行,否则指令被忽略。如果在指令后不写条件码,则使用默认条件AL(无条件执行)。 指令的条件码 条 件 码 助记符后缀 标 志 含 义 0000 EQ Z置位 相等equal 0001 NE Z清零 不相等not equal 0010 CS C置位 无符号数大于或等于Carry Set 0011 CC C清零 无符号数小于 0100 MI N置位 负数minus 0101 PL N清零 正数或零plus 0110 VS V置位 溢出 0111 VC V清零 没有溢出 1000 HI C置位Z清零 无符号数大于high 1001 LS Z置位C清零 无符号数小于或等于less 1010 GE N等于V 带符号数大于或等于 1011 LT N不等于V 带符号数小于least 1100 GT Z清零且(N等于V) 带符号数大于great 1101 LE Z清零或(N不等于V) 带符号数小于或等于 1110 AL 忽略 无条件执行all 1111 条件码应用举例: 例:比较两个值大小,并进行相应加1处理,C语言代码为: if ( a > b ) a++; else b++; 对应的ARM指令如下(其中R0中保存a 的值,R1中保存b的值): CMP R0, R1 ; R0与R1比较,做R0-R1的操作 ADDHI R0, R0, #1 ;若R0 > R1, 则R0 = R0 + 1 ADDLS R1, R1, #1 ; 若R0 <= R1, 则R1 = R1 + 1 CMP比较指令,用于把一个寄存器的内容和另一个寄存器的内容或一个立即数进行比较,同时更新CPSR中条件标志位的值。指令将第一操作数减去第二操作数,但不存储结果,只更改条件标志位。 CMP R1, R0 ;做R1-R0的操作。 CMP R1,#10 ;做R1-10的操作。 3)S项(sign) S项是条件码设置项,它决定本次指令执行的结果是否影响至CPSR寄存器的相应状态位的值。该项是可选的,使用时影响CPSR,否则不影响CPSR。 4)
全栈程序员站长
2022/07/05
8690
OpenHarmony 内核源码分析 (内核启动篇) | 从汇编到 main ()
这应该是系列篇最难写的一篇,全是汇编代码,需大量的底层知识,涉及协处理器,内核镜像重定位,创建内核映射表,初始化 CPU 模式栈,热启动,到最后熟悉的 main() 。
小帅聊鸿蒙
2025/04/07
2120
OpenHarmony 内核源码分析 (内核启动篇) | 从汇编到 main ()
芯片设计之流水线设计-IC学习笔记(四)
pipeline流水线设计是一种典型的 面积换性能的设计。一方面通过对长功能路径的合理划分,在同一时间内同时并行多个该功能请求,大大提高了某个功能的吞吐率;另一方面由于长功能路径被切割成短路径,可以达到更高的工作频率,如果不需要提高工作频率,多出来的提频空间可以用于降压降功耗。
全栈程序员站长
2022/09/21
3K0
芯片设计之流水线设计-IC学习笔记(四)
推荐阅读
相关推荐
Android逆向之旅---动态方式破解apk进阶篇(IDA调试so源码)[转]include <stdio.h>int func(int a, int b, int c, int d, int e,
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验