1 前言

最近博主在学习Android逆向的时候,参照吾爱破解论坛的《教我兄弟学Android逆向系列课程》学习的时候,学到第8章《教我兄弟学Android逆向08 IDA爆破签名验证》的时候,开始上手 ida pro 反汇编 so 库,在动手修改 so 库指令的时候遇到了困难,经过一番研究,终于搞懂了在 ida pro 中修改 so 库中 arm 汇编指令的方法,并完成了课后习题:

爆破李华Demo中的用户名和密码 要求输入任意用户名和密码 会提示登陆成功

于是写下这篇博客记录研究过程,并把被作者一笔带过的最核心问题如何修改so库讲清楚。
附上原吾爱破解教程地址:

《教我兄弟学Android逆向系列课程+附件导航帖》
《教我兄弟学Android逆向08 IDA爆破签名验证》

2 准备

(1) 下载 ida pro 7.0

原贴中使用的是ida pro 6.6,博主使用的是 ida pro 7.0,这一版是免安装的绿色版,下载地址:

IDA Pro 7.0 绿色版

(2) 下载 Android Killer

AndroidKiller_v1.3.1.zip

(3) 下载夜神模拟器

如果有真机也可以使用真机,这里我们使用夜神模拟器:

夜神模拟器官网

(4) 下载demo

原贴中的demo:黑宝宝.apk 下载地址:

链接:https://pan.baidu.com/s/1h6pX2ARE3qtiKiYbcnJ-3g 密码:duv5

(5) 下载 jni.h

下载链接:https://pan.baidu.com/s/1n16NEx67zLHfGtVpU-CKAA 密码:7xg6

(6) Arm指令手册

https://download.csdn.net/download/fuchaosz/12243691

(7) arm指令转换网站

Arm汇编指令转机器码网站:http://armconverter.com/

3 SO库的选择

首先把 黑宝宝.apk 拖进 Android Killer 中反编译,我们可以看到在 lib 中有三个 libJniTes.so :

armeabi     : 32位 arm cpu 库,几乎所有手机都支持
armeabi-v7a : 64位 arm cpu 库,现在我们买的手机基本上都是64位的cpu了
x86         : 在电脑上运行的模拟器或者基于Intel x86的平板电脑上用的

这里要说一下历史,在电脑CPU芯片领域,Intel独霸天下,x86代表32位cpu,x86_64代表64位的cpu,cpu位数增加不仅意味着运算速度更快,同时还代表着可以使用的内存更大,例如32位系统最大只能使用4G内存,所以windos xp上装8G内存条完全是浪费;但在手机领域arm才是龙头老大,可以说垄断了市场,因为arm制定了标准,所以,我们经常听说的高通骁龙芯片,虽然芯片是高通生产的,但却是arm的架构和指令集,因为我们的app到底层最终都被翻译成了arm指令。
这次,我们选择 armeabi 目录下的 libJniTes.so

因为这是几乎所有手机都支持的,而且网上资料是最多的,并且这三个版本的库在指令上有很多差别,例如:在 armeabi 中跳转指令是 BNE:

但在 armeabi-v7a 中跳转指令却是 CBNZ:

在 x86 中跳转指令则是 jnz:


所以,作为初学者,我们选择 armeabi 下的 libJniTest.so 库作为研究对象,便于在网上查找资料。
另外,值得一提的是,以前很多 app 只提供 armeabi 版本的 so 库,所以在安卓模拟器上很多app运行不了,尤其是很多游戏无法在模拟器上运行,好在现在主流安卓模拟器已经可以运行 armeabi 库了,例如夜神模拟器,所以,这次我们修改后的 armeabi 下的 libJniTest.so 是可以运行在夜神模拟器上的。

4 引出问题

参照 《教我兄弟学Android逆向08 IDA爆破签名验证》 这篇文章一步一步来,先将 黑宝宝.apk 拖入 Android Killer 中反编译,然后再将 armeabi 目录下的 libJniTest.so 用 ida pro 7.0 打开,接着在 Export 窗口中搜索 check 函数,接着导入 jni.h,接着替换 _JniEnvenv 两个参数,然后就到了关键的地方,在函数流程图中,作者要改变函数流程,要将 BNE 改为 BEQ,如下图:


看关键的代码:

cmp R0,#0
BNE loc_F62

cmp 是比较两个数是否相等
loc_F62 代表的函数是 “签名不一致,退出程序”
BNE 指不相等的时候跳转(branch not equal)
BEQ 指相等的时候跳转(branch equal)

结合反汇编后的C代码和函数流程图,我们可以很明显的知道这段代码的含义就是:如果签名不相等,则跳转到loc_F62,即直接退出程序。很明显我们回编译后的apk签名和作者预设的签名是绝对不可能一致的,所以会直接退出程序。

搞清楚了逻辑,那么爆破这个apk的签名其实就是把 BNE loc_F62 改为 BEQ loc_F62,即签名一致则跳转到 loc_F62退出程序,我们的签名和作者签名一定不同,所以程序不会直接退出,爆破成功。

接下来就是核心的地方:如何将 BNE 改为 BEQ ?

参照原贴方法,鼠标点击BNE那一行,然后View->Open subviews->Hex dump 查看那一行指令对应的机器码:



10 D1上点右键Edit,修改为10 D0:

接着右键apply changes:

再回到函数流程图,可以看到 BNE已经变为BEQ


那么问题来了:为什么要这样改?

我们可以看到上图第2个BEQ loc_F74命令对应的机器码是09 D0:

铺垫结束,问题来了:我们要修改操作码而不是操作数,为什么是把10 D1改为10 D0,而不是改为09 D1?

这个问题是最核心的问题,但是原帖里面作者一带而过了,加入现在我要把BNE指令改为无条件跳转指令 B 又该怎么改呢?

博主在这里卡了一天,最后经过实践得出了结论,所以写了这篇博客。下面我们来深入探讨这个问题。

5 深入问题

先来回顾一下《汇编》和《计算机组成原理》的内容,计算机只认识0和1,所有的操作听歌、看视频、打游戏等等,归根结底都是对0和1进行操作,在Intel x86架构中,一条指令是32位,因为32位CPU一次必须读入32位,不多不少,这一次读入的32个0或1就是一条指令,那么一秒钟可以读多少次呢,这就是cpu的主频决定的,所以理论上,cpu主频越高,一秒钟执行的指令越多,性能越高。接着思考,cpu是如何知道这32个数字(一条指令)中哪些数字代表操作,哪些数字代表被操作的数据呢,这就是指令格式,x86指令格式如下:

一条指令(32位) = 操作码(前16位):操作数(后16位)

操作码代表做哪些运算,例如:ADD、MOV、B 等等
操作数就代表被操作的数据,即可以是数据也可以是地址。

前面16位操作码排列组合起来就是指令集,每家厂商对指令集是不同,arm指令集也是同理,这就是汇编指令和机器码的关系。当然,实际指令格式不一定是这样平分的,但都是由操作码和操作数两部分组成的。

回到正题,我们梳理一下:

BNE loc_F62  对应机器码 10 D1 对应二进制 0001 0000 1101  0001
BEQ loc_F74  对应机器码 09 D0 对应二进制 0000 1001 1101  0000

根据上面的知识,我们要改的是操作码,所以应该是把 操作码 10 改为 09 才对呀,即改为 09 D1 而不是 10 D0,博主被这个问题深深的卡住了,于是查阅资料,搜到了arm的官方指令手册,查看了官方给的机器码表,结果更懵逼了。

打开arm指令手册,并没有BNE、BEQ指令,再看B指令的解释,翻到A6-3.1:


对照下面的条件码表:

通过官方手册和条件码表,我们组合起来就得到BNE指令的机器码:

1101 + 0001 + 8_bit_signed_offset

可是ida pro里面 BNE loc_F62 对应的正确的机器码明明是:

0001 0000 1101 0001

这就把博主整崩溃了,经过一天的谷歌百度,再经过反复实践,博主得出以下结论(敲黑板、划重点、记笔记),该结论没有找到确切资料,但抓住老鼠就是好猫。

6 结论

ida pro 反汇编 Android SO库(armeabi版本) ,一条汇编指令如果由4个十六进制数组成的,则前面2个(十六进制数)是操作数,后面2个(十六进制数)才是操作码,即so库的指令格式如下:

一条SO的汇编指令(16位) = 操作数(前8位) :操作码(后8位)

划重点:
1、一条指令是4个十六进制数
2、前面2个是操作数,后面2个才是操作码
3、如果你发现一条指令是8个十六进制数(例如BL),那么以上结论不适用
4、SO库的字节数是不能变的,我们只能替换,不能增删

注意:4位十六进制机器码的指令都遵循上述规律,但是8位十六进制的指令规律还没有总结出来,如果你知道了,欢迎给我留言。

7 解决问题

根据以上结论,我们很容易就能理解为什么要把 D1 改为 D0 了,因为操作码是后面两位,根据arm手册和条件码表,我们很容易组合出来BNE的操作码是D1BEQ 的操作码是 D0,所以,正确的操作是把 10 D1 改为 10 D0 ,问题解决。

如果我们每次修改指令都要去查arm手册的话,那是very dan疼的,那英文太酸爽,arm生怕多写几句浪费纸,所以,我们在实际操作中有以下两种方法来修改指令:

(1) 方法一:照葫芦画瓢

既然我们已经知道改指令就是改后面2个数,那就so easy了,我们只要在ida pro里面查看目标指令的机器码后面2个数,然后照着改就可以了,例如:我们接着要把BEQ loc_F62 改为 B loc_F62 呢,B指令是无条件跳转指令,首先鼠标点击到其他 B 指令上,View->Open subviews->Hex dump 查看机器码为14 E0



接着我们将 10 D0 改为 10 E0,这样 BEQ loc_F62 就又被改为了 B loc_F62


改动成功,成功应用了我们总结的知识,这里只是个演示,改动完后记得还原。

(2) 方法二:在线转换机器码

我们还可以打开以下网站:

http://armconverter.com/

直接输入我们想要的指令,直接转换为机器码,一个小技巧,如果需要操作数的话可以用#0,例如我们想知道B指令的机器码,则可以构造一条语句 B #0 就可以了

从这个网站我们也可以发现一点,就是ida pro反编译SO库用的是 Thumb-2 指令集,这个指令集是 arm 指令集的子集,标准arm指令集是操作码后跟操作数,这个thumb-2指令集反过来了,坑啊,关键是网上还查不到资料。

8 完成课后练习

理论知识学习完了,接着我们来完成课后习题:

爆破李华Demo中的用户名和密码 要求输入任意用户名和密码 会提示登陆成功

通过第4节的C语言代码我们可以看到,check这个函数很简单,除了检验签名外,就是当你输入用户名koudai和密码black后显示登陆成功,只要一个输入不对,就登陆失败,博主看了网上很多破解教程,都是把原来等于koudai 和 等于black的判断逻辑改为不等于,这样有个很明显的问题,虽然输入其他用户名密码可以登陆成功,但当我们用户名输入koudai 或 密码输入 black就会登陆失败,不符合题意:要求输入任意用户名和密码 会提示登陆成功。

所以,这里我们要改函数调用逻辑,要求不管输入什么,都要跳转到正确的函数中,还记得上节提到的B指令吗,这就是无条件跳转指令,下面开始。

首先解决输入任意用户名调到正确的函数,先看流程图:

很明显不管输入什么,最后必须无条件跳转到loc_F74所在的函数,那就简单了,直接BEQ loc_F74改为B loc_F74,还记得怎么改为B指令吗,这里把09 D0改为09 E0

改完后我们发现,无论输入什么都会进入校验密码的函数模块,那么用户名输入问题解决,下面处理密码输入。

仔细看上面的流程图,校验密码的函数有个函数首地址loc_F74,但是登陆成功的函数块没有首地址,反而是登陆失败的函数有首地址loc_F8C,所以照葫芦画瓢行不通了,怎么办呢?

博主在这里也卡了一下,后来想了一下,BNE loc_F8C这条指令真是多余,要是没有这条指令不就可以直接进入登陆成功的函数块了吗,那么问题又来了:怎么清除一条指令?

前面说了,so库只能替换,不能增删,网上搜了一下,说是有个nop指令用于清除目标指令,就是00 00,于是直接把这条指令的4个数全部改为0,即04 D1改为00 00,然后就可以了,看改完后的流程图:


看流程图,不管用户名和密码输入什么,都会显示登陆成功,至此,作业完成,接着把ida pro中的改动保存到so文件:


关闭ida pro,将修改后的libJniTest.so文件替换掉原来armeabi目录下的so文件,接着删除armeabi-v7a和x86目录,再回编译后安装到夜神模拟器,输入任意字符串都可以提示登陆成功:



9 总结

通过本篇文章的学习,我们掌握了4个十六进制数指令的格式和修改方法,同时我们学会了修改 B系列 跳转指令,并且明白了为什么要这样改,以后就可以随心所欲的修改函数的流程了,所以,很多高级语言的语法和保护措施在底层都失效了,这就是无法无天的底层,也是搞底层的乐趣。

当然,8个十六进制数的指令(例如BL指令)我们还没有弄清楚规律,但是目前已经够用了,所以,以后再来研究,如果你弄清楚了,欢迎在下方给我留言。

10 补充

如果你在实践中遇到了 ida pro 7.0 无法显示中文的问题,请参照下面这篇博客解决:

ida pro 7.0 无法显示中文的问题解决方法

如果你在用 Android Killer 回编译的时候遇到错误导致回编译失败,请参照下面这篇文章解决:

Android Killer反编译失败:No resource identifier found for attribute 问题解决方法

11 转载请注明来自“梧桐那时雨”的博客:https://blog.csdn.net/fuchaosz/article/details/104804026

Tips:
如果觉得这篇博客对你有帮助或者喜欢博主的写作风格,就关注一下博主或者给博主留个言呗,鼓励博主创作出更多优质博客,Thank you.

ida pro 反汇编 Android so 库后修改 arm 汇编指令的方法总结相关推荐

  1. [系统安全] 三.IDA Pro反汇编工具初识及逆向工程解密实战

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  2. linux 搜狗输入法 太慢,【分享】ibus使用搜狗输入法词库后,反应慢的解决方法...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 ibus确实是个不错的输入法,但是有个缺点就是词库太小,导致中文输入时,效率一直上不去,于是就有了添加词库的方法,添加完词库后,确实好多了,但是由于数据库 ...

  3. IDA Pro 反汇编窗口基本操作

    反汇编窗口也叫IDA-View窗口. 反汇编窗口有两种显示格式:默认的基于图形的视图,面向文本的列表视图. 在打开的反汇编窗口中,可以使用空格键在图形视图与列表视图之间切换. 图形视图将一个函数分解成 ...

  4. Ubuntu安装搜狗输入法后修改默认英文输入状态的方法

    ubuntu安装搜狗输入法后如果把其他输入法都删除,只留下搜狗输入法则默认是中文输入,在打开命令行时一般是输入英文,默认中文的确很麻烦,而且linux系统使用英语的情况更多谢. 如果ubuntu默认安 ...

  5. Excel数据筛选出来后修改再粘贴进去的方法

    1.近期处理excel数据时,遇到要把数据筛选出来,修改之后再粘贴回去的问题. 网上百度了一个方法,比较好用,记录一下,方便回看.https://jingyan.baidu.com/article/7 ...

  6. realarm Android系统编译后内核无法启动的解决方法

    由于之前版本使用的内核并非uImage格式,而在编译时使用的是非uImage格式编译,所以照成无法启动. 解决方法是,在编译内核时使用make uImage方式编译. 修改根目录下的build_rea ...

  7. Android kernel Crash后,定位出错点的方法

    1. 将/prebuild/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-gdb 拷贝到/usr/loca ...

  8. Android 拍摄照片后返回缩略图的两种方法详解

    博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家,

  9. Android逆向基础笔记—Android中的常用ARM汇编指令

    一  ARM寄存器 1.通用寄存器 1).未分组寄存器:R0~R7 2).分组寄存器:R8~812 R13:SP,常用作堆栈指针,始终指向堆栈的顶部,当一个数据(32位)推入堆栈时,SP(R13的值减 ...

最新文章

  1. 分享一张SQLSERVER执行流程的图片
  2. 1044 火星数字 (20 分)(c++)
  3. Python 3.10 正式发布,新增模式匹配,同事用了直呼真香
  4. linux的基础知识——网络套接字函数
  5. ZooKeeper(二) idea中使用Java操作zookeeper
  6. 【转】Linux C动态内存泄漏追踪方法
  7. android百度地图单点定位_Android百度地图实现搜索和定位及自定义图标绘制并点击时弹出泡泡...
  8. 数字信号处理--7.3--FFT算法
  9. linux 定位 踩内存_运维常见问题故障定位,这里总结全了!
  10. 软件过程— 螺旋模型
  11. 物料编码是计算机识别和检索物料的( ),物料编码是计算机识别和检索物料的
  12. 差分进化算法_差分进化变体-JADE
  13. NGS 分析流程 (一)
  14. 微商怎么通过QQ引流?微商如何利用QQ加人?微商QQ引流技巧
  15. 如何用计算机计算平均温差,传热平均温差的计算
  16. wan状态dns服务器,路由器的wan口dns和dhcp区别是什么?
  17. matlab曲线已知y求x,已知X、Y用MATLAB绘制曲线
  18. Adblock Plus 3.2 Chrome插件下载
  19. 成人教育有什么用处?
  20. 【go语言】在线小词典

热门文章

  1. c++语言打开文件对话框,C++采用openfilename打开文件对话框用法实例
  2. Java小程序木叶村_恋爱球滚动的天空
  3. H3C AC:无线探针配置
  4. Docker下载安装运行Nginx服务
  5. SpringBoot项目中自动加载datasourceConfig配置导致启动失败
  6. 二十岁的男人(应该需要做什么)
  7. 离线部署NFS文件系统
  8. 数字藏品以虚强实,赋能实体经济发展
  9. 【职场篇】游戏开发社招求职面试指南③——面试总结
  10. Unity的Package了解(2020.3)