首页
社区
课程
招聘
[原创]堆栈别乱用
2019-12-26 20:47 7738

[原创]堆栈别乱用

2019-12-26 20:47
7738

引言


        在做开发中,可能根据某些特定功能的实现,需要嵌入一段shellcode的汇编代码,当然,前提是你需要有一定的汇编基础,在实际的逆向分析中,理解汇编的指令真的不是很难,无非就是读写、比较、计算数值,操作堆栈、操作寄存器的一系列的操作,如果遇见不会的指令上网查询一下就一目了然了,但是当你真正的去实现一段汇编代码的功能时,你可能会遇见一些让你头疼的坑,当然可能这个坑就是你自己挖的,没办法你挖的你就得负责填上。


异常问题环境相关描述


        实现功能:自写arm汇编指令调用dlopen函数;

        问题手机:经测试vivo/oppo、CPU骁龙660、系统Android 8.1,需要同时符合这三点要求的都会中招;


定位问题点

        最后锁定到问题点在__dl__ZN12LinkerLogger10ResetStateEv函数中的VST1.8 {D16}, [R0@64]!指令,当执行该指令时会出发"SIGBUS"错误信号导致程序崩溃;


分析过程


        首先看一下错误信号"SIGBUS"的含义,通过搜索得知,该错误表示"未对其的访问" ,分析调试代码,第一个想到的就是“dlopen”的第一个参数字符串文件路径,该字符串不是4字节对齐,因此把修改字符串文件路径进行对齐,但是错误继续出现,与此同时在对函数的进一步跟踪发现,出错的__dl__ZN12LinkerLogger10ResetStateEv函数,根本未使用这个字符串文件路径,所以可以肯定是问题点不在这里,失去了线索,一度陷入迷茫中......

带着一份执着,我又调试运行了几次,发现问题每次都出现在VST1.8 {D16}, [R0@64]这条指令上,这不是一条常用指令到底什么意思呢?带着疑问去找到了答案,这是arm汇编里面的VFP浮点指令操作,该条指令的意思是把D16寄存器的值赋值到R0寄存器指向的地址中,(知识点介绍:VFP指令集操作的是高精度的浮点值,所以他的寄存器是按64位8字节方式操作的,即一个“QDWORD”值,关于VFP信息参考连接:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ic/Bcfhdhgd.html )


        从上图我看一下D16寄存器的值的来源,指令为VMOV.I32 D16, #0,从指令中解析出D16寄存器的值等于“0x0000000000000000”,然后在来看一下R0寄存器值的来源,指令MOV R0, R4表示R0寄存器的值是R4寄存赋值过来的,而从指令 ADD R4, SP, #8中获得R4指令是SP+8的地址,由此可见我们R0寄存器实际指向的地址是SP+8,


        从图中我们可以看出R0的地址为0xFFA1660C,那执行VST1.8 {D16}, [R0@64]指令实际上就是吧地址0xFFA1660C、0xFFA16610这两个堆栈地址指向的值置0,分析到这一步,如果是聪明的人应该就知道问题点了,谁让我笨呢!没有看出来,好吧,既然没看出来我没就用笨的方法来吧,只要努力笨鸟也会先飞的,又思考了一下,决定写个demo,正常掉一下对dlopen,在用IDA逆向跟踪一下


        

        通过上面的图看出当前R0寄存器的值为"0xFFA177E8",再仔细看一下出错的时候R0寄存器的值“0xFFA1660C”,再仔细想一下错误提示“未对其的访问“,在想一下VFP浮點指令集是64位操作数的特征,最后再结合一这个图:


        突然茅塞顿开了是吧!就是我们的R0寄存器指向的地址没有对齐导致的“SIGBUS”错误,“0xFFA1660C”地址在64位的操作运算中就是非法的操作,之前我们知道R0的来源是堆栈地址,那接下来就看看我自己编写的汇编代码中操作堆栈的位置:


        追溯起源,从图中可知R0~R7一共是8个dword值,在加上一个LR,一共是9个dword值压入堆栈,就是这里导致后面VST1.8 {D16}, [R0@64]指令执行出错,带着好信的心里,我特意看了一下其他正常函数的堆栈操作,都是按照8字节对齐的。于是乎各种感叹,学艺不精啊!!!!!!~好了问题找到了,那就按8字节对齐的方式去操作堆栈,如图:

       

         由于R0~R3在这里主要的用途就是传参寄存器,其自身就是可变的,所以不考虑这几个寄存器,只把R4寄存器和LR寄存器进行了保存,最后生成项目,重新运行程序,程序没有崩溃正常运行,到这里我们终于解决了问题,仿佛有些感动的泪水,毕竟在查找这个问题的时候所花的时间和经历,对此刻来说都是值得的。


        在前面我说过,只有在vivo/oppo、CPU是骁龙660、系统为Android 8.1的手机才会出现这样的错误,因为在实际中我做过其他机型、其他CPU及其他系统版本的测试都没有问题,个人认为可能是有viov/oppo厂商在定制该种配置手机的ROM的时候可能是添加/未添加某种处理机制产生的现象,当然我们不能说这是人家厂商的问题,我只能说是自己的粗心与马虎给自己造成的问题,但能遇见这样的问题也并不是一件坏的事情,塞翁失马焉知祸福?我温习了旧知识,同时也学习了新知识。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-12-27 11:42 被梨树生果编辑 ,原因: 脱敏处理
收藏
点赞4
打赏
分享
最新回复 (8)
雪    币: 1551
活跃值: (2862)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
zhenwo 1 2019-12-27 18:04
3
0
还没玩过arm的shellcode
雪    币: 12105
活跃值: (15519)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
pureGavin 2 2019-12-27 18:52
4
0
居然让看需的讲师亲自回复,而且还是讲师大哥不懂的领域;LZ 牛批!!!!
雪    币: 614
活跃值: (693)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
eastmaster 2019-12-27 20:02
5
0
牛!
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2019-12-27 21:35
6
0
arm/thumb 64位代码对于内存要求8字节对齐。这一点体现在java层和native层互相调用,传递参数得时候非常明显。特别是8字节长度得参数(浮点类型)。
雪    币: 3579
活跃值: (659)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
梨树生果 2019-12-28 10:01
7
0
zylyy arm/thumb 64位代码对于内存要求8字节对齐。这一点体现在java层和native层互相调用,传递参数得时候非常明显。特别是8字节长度得参数(浮点类型)。
嗯嗯,谢谢您的回复,受教了
雪    币: 3579
活跃值: (659)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
梨树生果 2019-12-28 10:08
8
0
pureGavin 居然让看需的讲师亲自回复,而且还是讲师大哥不懂的领域;LZ 牛批!!!!
谢谢您的夸奖,看雪这个平台的大佬是太多了,我只能算个晚生与后辈,真的感觉碰到的问题不错,仅此想分享一下。
雪    币: 17
活跃值: (205)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
福州-dyh 2020-6-8 14:29
9
0
游客
登录 | 注册 方可回帖
返回