根据PPC反汇编代码分析堆栈内容

来源:互联网 发布:win10软件图标异常 编辑:程序博客网 时间:2024/05/16 05:10

1 栈帧

我们知道,发生函数调用时,通常被调用函数会保存调用函数的现场,然后才会继续执行被调用函数的指令,被调用函数执行完成之后,就会恢复调用函数的现场,继续执行调用函数的指令。栈帧就是在堆栈中保存每一次函数调用现场的一个基本单元。每一次函数调用都会在堆栈中记录函数的栈帧。

2 汇编指令

    下面我们反汇编下DbugExcShowAll函数,得到如下的反汇编代码。

               DbugExcShowAll:

0x103e48cc  9421ffd0   stwu        r1,-48(r1)

0x103e48d0  7c0802a6   mfspr       r0,LR

0x103e48d4  93810020   stw         r28,32(r1)

0x103e48d8  93a10024   stw         r29,36(r1)

0x103e48dc  93e1002c   stw         r31,44(r1)

0x103e48e0  90010034   stw         r0,52(r1)

0x103e48e4  7c3f0b78   or          r31,r1,r1

0x103e48e8  3d20108d   lis         r9,0x108d #4237------r9=0x108d0000

0x103e48ec  8009a690   lwz         r0,-22896(r9)-----

0x103e48f0  901f0008   stw         r0,8(r31)

Stwu指令将调用函数的栈帧地址r1,存储到(r1-48)字节处,并且r1=(r1-48),然后将调用函数的LR值写入到r0寄存器,然后将r0保存到堆栈中,也就是将调用函数的LR值保存到栈中,另外这里r1偏移了52个字节,但是,当前堆栈只扩展了48字节的空间,意味着此时已经到了上一层函数栈帧空间,也就是说上一层函数的lr的内容会保存在上一层栈帧空间中。也可以这么认为,在函数调用栈帧中,当前函数的堆栈地址,lr地址会保存到栈帧的栈顶(低地址)。

3 寄存器信息

下面是现场的寄存器信息:


name         pid      tid     ppid     PRI      STATUS

---------------------------------------------------------

t287805096   90      90       39       64      T

 

esp:0x79dfdc10             eip :0x103e4920

vm_size:123196  KB        vm_lock :0       KB

vm_data:97060   KB        vm_stack :3076    KB

vm_rss  :16280  KB        vm_exe   :8424   KB

task_size   :0xaa50        resident :4070

start_code  :0x10000000   end_code :0x108394d4

start_stack:0x79dffe20    stack_size :0x1fee20

stack_used:0x2210

r0:0x00000000  r1: 0x79dfdc10  r2: 0x79dffe20  r3: 0x0000003b

r4:0x00000001  r5: 0x00000000  r6: 0x0000003b  r7: 0x1068ed94

r8:0x0000d032  r9: 0x00000000  r10: 0x00000001  r11: 0x79dfdc10

r12:0xc4c3c000  r13: 0x108d1a80  r14: 0x00000000  r15: 0x00000000

r16:0x111e02d0  r17: 0x00000000  r18: 0x11278ea8  r19: 0x10002040

r20:0x00000006  r21: 0x0000002a  r22: 0x7efffe20  r23: 0x0000002d

r24:0x79c01000  r25: 0x79c00000  r26: 0x00000000  r27: 0x00000000

r28:0x00000000  r29: 0x00000000  r30: 0x10002040  r31: 0x79dfdc10

pc:0x103e4920  ps: 0x0000d032  cr: 0x22000088  lr: 0x103e4900

ctr:0x10677938  xer: 0x20000000  fpscr: 0x00000000

从寄存器信息可以看出,当前函数堆栈地址为0x79dfdc10,从上面的汇编可以看出,

该地址是通过上一层函数堆栈偏移48字节获取到的。那么上一层函数堆栈地址为0x79DFDC40。从上面的汇编上看,执行完调用函数本身的下一条指令应该保存到r1+52 = 0x79DFDC44这个地址处。

4 堆栈内容

根据上面的分析,栈顶应该保存的是调用函数的栈地址,栈顶之后的4字节应该保存的是调用函数的lr地址。以DbugExcShowAll的栈帧为例:

79DFDC10:  79 dfdc 40 10 3e 49 00 00 00 00 00 00 00 00 00   *y..@.>I.........*

79DFDC20:  79 dffe 20 00 00 00 00 11 27 8e a8 00 00 00 00  *y.. .....'......*

79DFDC30:  00 0000 00 00 00 00 00 10 00 20 40 79 df fc 50  *.......... @y..P*

79DFDC40:  79 dffd 60 10 00 24 ac 00 00 00 00 00 00 00 01  *y..`..$.........*

79DFDC50:  00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00  *................*

79DFDC60:  00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00  *................*

79DFDC70:  00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00  *................*

栈顶保存的内容为0x79dfdc40,根据之前的分析,该地址正是调用DbugExcShowAll函数的栈地址,接着栈顶的之后的4字节地址保存的正是LR的地址。从汇编上看不出DbugExcShowAll的lr地址是什么时候放入到0x79DFDC14中的。但是,从上面分析可以看出0x79DFDC44对应的内容为0x100024ac,正是task_wrapper对应的代码空间,也就是执行完DbugExcShowAll需要执行的下一条指令。

 通过tt命令,可以看到函数的调用链正是task_wrapper=>DbugExcShowAll。

 

task:t287805096pid:90

task callfunc info:

0x106740f4  pthread_start_thread     +0x000000e0 task_wrapper( 0 )

0x10002040  task_wrapper             +0x00000468 DbugExcShowAll(  )

0x103e48cc  DbugExcShowAll

 

总结

   Ppc的栈帧结构比较清晰,从堆栈内容中比较容易分析出函数的调用关系,在堆栈遭到破坏时,还可以通过汇编代码,从汇编代码的堆栈扩展已经堆栈中保存的lr地址,大致推断出破坏堆栈的函数。但是,要非常注意,排除栈中残留的历史堆栈的干扰。

0 0
原创粉丝点击