分享
 
 
 

编写自己的缓冲区溢出利用程序(下)

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

(续)

by 黑猫(virtualcat@hotmai.com)

值得注意的是: 如果象上面所说的, 我们输入的字串长度为二十个'A'--刚好复盖完0xbffff6b0

所指的单元, 那么此时从栈中弹出给eip的内容将是0x41414141, 而不是0x8048443, 程序

将跳到0x41414141去执行那里的指令, 由于0x41414141对于当前进程来说是不可访问的,

所以导致段出错(Segmentation fault), 进程停止执行.

这是我们的第三个焦点.

如果我们能计算好位移(offset), 用我们准备好的代码的入口地址来覆盖0xbffff6b0所

指的单元, 那么从栈中弹出给eip的内容就是我们的代码的入口地址, 程序将跳到我们的

代码去继续执行.

分析到这里, 我们已经清楚了C语言函数调用的机制了. main函数的后续指令对于我们的

分析已无关紧要. 但是为了保持文章的完整, 我们继续再往下看看.

此时栈的情况:

(gdb) x/10x $esp

0xbffff6b4: 0xbffff856 0xbffff6d8 0x400349cb 0x00000002

0xbffff6c4: 0xbffff704 0xbffff710 0x40013868 0x00000002

0xbffff6d4: 0x08048350 0x00000000

进程在内存中的相关影像:

(内存高址)

| ...... |

+--------+

|00000000|

0xbffff6d8 +--------+ <-- 调用main函数前的ebp

|08048350|

+--------+

|00000002|

+--------+

|40013868|

+--------+

|bffff710|

+--------+

|bffff704| argv的地址(即argv[0]的地址)

0xbffff6c4 +--------+

|00000002| argc的值

0xbffff6c0 +--------+

|400349cb|

0xbffff6bc +--------+ <-- 调用main函数前的esp

|bffff6d8| 调用main函数前的ebp

0xbffff6b8 +--------+ <-- main函数的ebp

|bffff856| 字符串"AAAAAAAA"在内存中的起始地址

0xbffff6b4 +--------+ <-- 当前esp

|08048443| (垃圾) vulFunc函数的返回地址

0xbffff6b0 +--------+

|bffff6b8| (垃圾) main函数的ebp

0xbffff6ac +--------+

|bffff600| (垃圾)

0xbffff6a8 +--------+

|41414141| (垃圾)

0xbffff6a4 +--------+

|41414141| (垃圾)

0xbffff6a0 +--------+

|bffff856| (垃圾) 字符串"AAAAAAAA"在内存中的起始地址

0xbffff69c +--------+

|bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址

0xbffff698 +--------+

| ...... |

(内存低址)

再看看后续的指令做了些什么?

0x8048443 : add $0x4,%esp ; 抛弃栈中为被调用函数准备的参数.

0x8048446 : jmp 0x804845b ; 跳转到0x804845b继续执行

0x8048448 : mov 0xc(%ebp),%eax ; 0x8048433 jne的条件判断跳转

; 入口(即argc!=2的情况)

; 把ebp+0xc所指向的内存单元的

; 内容赋给eax, 从上面的分析我

; 们知道里面放的是argv的地址

0x804844b : mov (%eax),%edx ; 把eax指向的地址的内存单元里

; 的内容赋给edx, 我们知道argv

; 是个数组, argv的值就是argv[0]

0x804844d : push %edx ; 把argv[0]入栈. 注意这里的

; argv[0]其实是个地址值.

0x804844e : push $0x80484bb ; 把常数0x80484bb入栈

; 以上为调用printf函数准备参数.

0x8048453 : call 0x8048330 ; 调用printf函数

0x8048458 : add $0x8,%esp ; 抛弃为调用printf函数准备的参数

0x804845b : leave ; 恢复调用main函数的函数的栈帧

0x804845c : ret ; 返回到调用main函数的函数

估计0x80484bb指向的是printf函数的format字串, 看看是不是?

(gdb) x/1s 0x80484bb

0x80484bb <_IO_stdin_used+15>: "Usage: %s \n"

果然是. 那从0x8048448到0x8048458这段指令就是C语言

printf("Usage: %s \n", argv[0]);

的等价汇编语句了.

我们把断点设到0x804845b, 再继续执行.

(gdb) b *0x804845b

Breakpoint 6 at 0x804845b

(gdb) c

Continuing.

Breakpoint 6, 0x804845b in main ()

下一条指令是leave, 应该是恢复调用函数的函数的栈帧.

单步执行一下, 看看寄存器及栈的情况.

(gdb) si

0x804845c in main ()

(gdb) i reg

eax 0x10 16

ecx 0x400 1024

edx 0x4010a980 1074833792

ebx 0x4010c1ec 1074840044

esp 0xbffff6bc -1073744196

ebp 0xbffff6d8 -1073744168

esi 0x4000ae60 1073786464

edi 0xbffff704 -1073744124

eip 0x804845c 134513756

eflags 0x386 902

(以下省略)

...

(gdb) x/8x $esp

0xbffff6bc: 0x400349cb 0x00000002 0xbffff704 0xbffff710

0xbffff6cc: 0x40013868 0x00000002 0x08048350 0x00000000

下一条指令是ret, 我们知道栈顶放的是main函数的返回地址(0x400349cb).

此时进程在内存中的相关影像:

(内存高址)

| ...... |

+--------+

|00000000|

0xbffff6d8 +--------+ <-- 调用main函数前的ebp

|08048350|

+--------+

|00000002|

+--------+

|40013868|

+--------+

|bffff710|

+--------+

|bffff704| argv的地址(即argv[0]的地址)

0xbffff6c4 +--------+

|00000002| argc的值

0xbffff6c0 +--------+

|400349cb| main函数的返回地址

0xbffff6bc +--------+ <-- 当前esp

|bffff6d8| (垃圾) 调用main函数前的ebp

0xbffff6b8 +--------+

|bffff856| (垃圾) 字符串"AAAAAAAA"在内存中的起始地址

0xbffff6b4 +--------+

|08048443| (垃圾) vulFunc函数的返回地址

0xbffff6b0 +--------+

|bffff6b8| (垃圾) main函数的ebp

0xbffff6ac +--------+

|bffff600| (垃圾)

0xbffff6a8 +--------+

|41414141| (垃圾)

0xbffff6a4 +--------+

|41414141| (垃圾)

0xbffff6a0 +--------+

|bffff856| (垃圾) 字符串"AAAAAAAA"在内存中的起始地址

0xbffff69c +--------+

|bffff6a0| (垃圾) vulFunc函数栈帧中分配的十二个字节起始地址

0xbffff698 +--------+

| ...... |

(内存低址)

再单步执行, 返回到调用main函数的函数

(gdb) si

0x400349cb in __libc_start_main (main=0x804842c , argc=2, argv=0xbffff704, init=0x80482c0 <_init>,

fini=0x804848c <_fini>, rtld_fini=0x4000ae60 <_dl_fini>, stack_end=0xbffff6fc)

at ../sysdeps/generic/libc-start.c:92

92 ../sysdeps/generic/libc-start.c: No such file or directory.

原来是 __libc_start_main 函数调用了我们的main函数, 看来和概述里说的有些出入,

但这对于我们来讲不是很重要. 如果想看[url=http://www.pccode.net].net" class="wordstyle"源码, 请到../sysdeps/generic/libc-start.c

文件中找.

(gdb) x/16x $esp

0xbffff6c0: 0x00000002 0xbffff704 0xbffff710 0x40013868

0xbffff6d0: 0x00000002 0x08048350 0x00000000 0x08048371

0xbffff6e0: 0x0804842c 0x00000002 0xbffff704 0x080482c0

0xbffff6f0: 0x0804848c 0x4000ae60 0xbffff6fc 0x40013e90

从上面可以看到, stack_end=0xbffff6fc, 也就是说我们的进程的栈底地址为0xbffff6fc,

在调用__libc_start_main函数前依次推了如下七个参数入栈:

0xbffff6fc -> 进程的栈底

0x4000ae60 -> _dl_fini函数的人口地址.

0x0804848c -> _fini函数的入口地址

0x080482c0 -> _init函数的入口地址

0xbffff704 -> argv命令行参数地址的地址

0x00000002 -> argc命令行参数个数值

0x0804842c -> 我们的main函数入口

从上面的分析可推出, 在内存地址0xbffff6dc的内容0x08048371就是__libc_start_main函数

的返回地址了.

我们来看看是什么函数调用了__libc_start_main.

(gdb) disas 0x08048371

Dump of assembler code for function _start:

0x8048350 <_start>: xor %ebp,%ebp

0x8048352 <_start+2>: pop %esi

0x8048353 <_start+3>: mov %esp,%ecx

0x8048355 <_start+5>: and $0xfffffff8,%esp

0x8048358 <_start+8>: push %eax

0x8048359 <_start+9>: push %esp

0x804835a <_start+10>: push %edx

0x804835b <_start+11>: push $0x804848c

0x8048360 <_start+16>: push $0x80482c0

0x8048365 <_start+21>: push %ecx

0x8048366 <_start+22>: push %esi

0x8048367 <_start+23>: push $0x804842c

0x804836c <_start+28>: call 0x8048320 <__libc_start_main>

0x8048371 <_start+33>: hlt

0x8048372 <_start+34>: nop

0x8048373 <_start+35>: nop

(省略以下的nop)

End of assembler dump.

原来是_start函数调用了__libc_start_main函数.

至于_start函数调用__libc_start_main函数后, 接是如何调用_init函数和_dl_runtime_resove

函数来调用共享库函数和我们的main函数然后退出的, 已经远远脱离了本文的主题, 这里不再继

续介绍.

(gdb) x/1024x 0xbffff6f0

0xbffff6f0: 0x0804848c 0x4000ae60 0xbffff6fc 0x40013e90

0xbffff700: 0x00000002 0xbffff83e 0xbffff856 0x00000000

0xbffff710: 0xbffff85f 0xbffff881 0xbffff88f 0xbffff89e

0xbffff720: 0xbffff8c4 0xbffff8d2 0xbffff900 0xbffff91a

0xbffff730: 0xbffff932 0xbffff94d 0xbffff9a8 0xbffff9df

0xbffff740: 0xbffffaf3 0xbffffb06 0xbffffb11 0xbffffb31

0xbffff750: 0xbffffb5a 0xbffffb68 0xbffffc72 0xbffffc7e

0xbffff760: 0xbffffc8f 0xbffffca4 0xbffffcb4 0xbffffcbf

0xbffff770: 0xbffffcd7 0xbffffcf5 0xbffffd0e 0xbffffd19

0xbffff780: 0xbffffd23 0xbffffd6c 0xbffffd79 0xbffffda0

0xbffff790: 0xbffffdb2 0xbffffdc1 0xbffffde6 0xbffffe08

0xbffff7a0: 0xbffffe10 0xbfffffd3 0x00000000 0x00000003

0xbffff7b0: 0x08048034 0x00000004 0x00000020 0x00000005

0xbffff7c0: 0x00000006 0x00000006 0x00001000 0x00000007

0xbffff7d0: 0x40000000 0x00000008 0x00000000 0x00000009

0xbffff7e0: 0x08048350 0x0000000b 0x000001f5 0x0000000c

0xbffff7f0: 0x000001f5 0x0000000d 0x00000004 0x0000000e

0xbffff800: 0x00000004 0x00000010 0x008001bf 0x0000000f

0xbffff810: 0xbffff839 0x00000000 0x00000000 0x00000000

0xbffff820: 0x00000000 0x00000000 0x00000000 0x00000000

0xbffff830: 0x00000000 0x00000000 0x38356900 0x682f0036

0xbffff840: 0x2f656d6f 0x65776f74 0x74742f72 0x2f737775

0xbffff850: 0x2f6c6469 0x41410070 0x41414141 0x4c004141

0xbffff860: 0x4f535345 0x3d4e4550 0x73752f7c 0x69622f72

...

(省略)

...

0xbfffffd0: 0x54003a35 0x75413d5a 0x61727473 0x2f61696c

0xbfffffe0: 0x0057534e 0x6d6f682f 0x6f742f65 0x2f726577

0xbffffff0: 0x77757474 0x64692f73 0x00702f6c 0x00000000

0xc0000000: Cannot access memory at address 0xc0000000

我们知道内存单元0xbffff704放的是指argv[0]的地址, 那么0xbffff708放的就是argv[1]

的地址了. 0xbffff700里放的是argc的值.

那么0xbffff710里放的是什么呢? 看样子象是指向字符串的地址, 让我们来看看.

(gdb) x/1s 0xbffff85f

0xbffff85f: "LESSOPEN=|/usr/bin/lesspipe.sh %s"

(gdb)

0xbffff881: "HISTSIZE=1000"

...

再看看最后一个.

(gdb) x/1s 0xbfffffd3

0xbfffffd3: "TZ=Australia/NSW"

0xc0000000以后的地址空间已不是进程能合法访问的了.

原来都是些SHELL的环境变量字符串.

这一片东西是从内存地址0xbffff839开始的, 让我们再看看.

(gdb) x/1s 0xbffff839

0xbffff839: "i586"

(gdb)

0xbffff83e: "/home/vcat/p" ===> 细心的朋友会发现这里已被俺改掉了,

让俺保留一点私隐吧 ;)

(gdb)

0xbffff856: "AAAAAAAA"

(gdb)

0xbffff85f: "LESSOPEN=|/usr/bin/lesspipe.sh %s"

...

我们得出结论: 0xbffff700放的是argc的值; 0xbffff704放的是argv[0]的地址,

0xbffff708放的是argv[1]的地址; 0xbffff710--0xbffffa4放的是指向各个环境变量

字符串起始地址的指针; 从内存地址0xbffff839开始依次存放的是: 系统平台信息字

串; 命令行字串; 环境变量字串.

至于0xbffff7a8--0xbffff838里放的是什么, 还有待研究. 由于对本文不是至关重要,

暂时放一下.

分析到这, 我们来组合一下进程在内存的影像:

(内存高址)

| ...... | ...省略了一些我们不需要关心的区

+--------+

|00000000|\

0xbffffffc +--------+ \

| ...... | \

\

| ...... | \

0xbffff844 +--------+ 系统平台信息串(如:"i586")和命令行参数及环境变量字串

|2f656d6f| /

0xbffff840 +--------+ /

|682f0036| /

0xbffff83c +--------+ /

|38356900|/ --> 从内存地址0xbffff839开始, 0x69353836="i586"

0xbffff838 +--------+

| ...... |\

里面放

[1] [2] [3] [4] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有