更为详细的叙述,可以参看"Fun and Games with Mac OS X and IPhone Payloads"。作者就是曾在Pwn2Own上攻破Safari和IE8的Charlie Miller。
直接注入代码很明显是不可能了,ROP大显伸手的时候到了。ROP的基本思想用x86更容易解释一些:当覆盖返回值或其他方式控制了栈时,返回时我们让eip指向类似如下的指令序列:XXX; ret这样就执行了一个XXX(也许就是简单的改变一个寄存器的值)操作,然后就ret了。ret会从栈上取出下一条指令的地址,然后跳转过去,同样这次我们选取的指令仍为XXX;ret的格式,每次使用的指令最后都以ret结尾,利用栈来控制指令执行流程,这就是ROP了。
而现在我们面对的是RISC的ARM指令,就稍微有些区别了。ARM体系下,包含r0-r13,sp,lr,pc等多个寄存器,没有ret指令,但指令指针PC是我们可以直接操作的,每条指令都是四字节(thumb指令为两字节,thumb-2里面四字节和两字节指令混合)。函数的参数传递规则是,前四个参数使用r0-r3传递,更多的参数才使用栈。通常函数返回使用 pop {r7,pc}或bx lr等方式(bx,b类似jmp为跳转指令,但bx可以指定跳转区域究竟为thumb还是arm指令)。
我们的目标是溢出后执行下面的操作
为了搜索这条指令,我把dyld库从IPAD中复制到主机(使用winscp,需要在IPAD上安装openssh),用IDA反汇编分析。但IDA似乎没有类似OD那种即时汇编指令为机器码的功能。因此只能查ARM手册自己将需要的汇编代码转为机器码字节了(这样才能搜索)。我把需要的汇编代码内联汇编写到first_ipad_view程序(也就是刚刚编写的存在漏洞的程序)中,然后用gdb(使用cydia安装到IPAD,一定要更新到最新版本6.3.50,否则指令解析有问题。然后用putty通过ssh连接到IPAD,这就是开篇无线路由器的用意。我本想用Xcode带的调试器调程序,但却总是提示Program not being run,另外用gdbserver+IDA或IPhone_server+IDA也一直没能连接成功,所以只能ssh+gdb调了。记得要用cydia安装cmd以及其相关的各种指令包,比如ps命令)察看那些代码的机器码(很麻烦很笨~我也没办法,哪位有快速获得ARM指令机器码的方法麻烦告诉我吧~)。找到机器码序列后,在IDA中用Alt+B搜索,定位位置后再到gdb中察看改指令的地址。比如上述指令的地址就是0x30cc05d0。
通过IDA分析只能搜索dyld库的指令,还有其他可执行映像中的指令搜索其实可以用gdb直接搜索。如下gdb代码能搜索0x30247bc8到0x30247e14地址中的机器码为0x800fe8bd的ARM指令。
root# ps aux
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
mobile 817 0.0 3.8 349472 9492 ?? Ss 10:18PM 0:00.27 /var/mobile/Applications/5E16589D-24B9-413D-B3F3-608F02FA5F7E/first_ipad_view.app/first_ipad_view root#gdb
GNU gdb 6.3.50.20050815-cvs (Sat Sep 19 05:37:57 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=arm-apple-darwin9 --target=". (gdb) attach 817
Attaching to process 817.
Reading symbols for shared libraries . done
Reading symbols for shared libraries warning: Could not find object file
............................................................. done
0x30c16668 in mach_msg_trap () (gdb)disassemble foo
0x00002864 <foo+0>: push {r7, lr}
0x00002866 <foo+2>: add r7, sp, #0
0x00002868 <foo+4>: sub sp, #4
0x0000286a <foo+6>: mov r3, sp
0x0000286c <foo+8>: mov r0, r3
0x0000286e <foo+10>: bl 0x277c <fulfill>
0x00002872 <foo+14>: sub.w sp, r7, #0 ; 0x0
0x00002876 <foo+18>: pop {r7, pc} 执行到<foo+18>后查看堆栈 (gdb) x/20x $sp
0x2fffeb60: 0x33334444 0x30c1a858 0x00002cc5 0x00122690
0x2fffeb70: 0x30794b8d 0x22443322 0x30c1a850 0x000003ea
0x2fffeb80: 0x00122690 0x00002cc5 0x34474dd7 0x30cc05d0
0x2fffeb90: 0x000003ea 0x00002cc5 0x0013a8d0 0x0013a8d0
0x2fffeba0: 0x2fffeb88 0x30c3d170 0x0000345c 0x3852c7ec