ASM 按原样工作,但不在 C 程序中

逆向工程 部件 数据库 外壳代码
2021-06-25 01:07:50

我有这块 ASM:

section .text
    global _start

_start:
    xor  eax, eax
    push eax         ; 0 to finish the /bin//sh string
    push 0x68732f2f  ; //sh
    push 0x6e69622f  ; /bin
    mov  ebx, esp
    mov  al, 0xb
    int  0x80

如果我这样做,效果很好:

$ nasm -f elf shellcode.asm && ld -o shellcode shellcode.o
$ ./shellcode
$ # the new shell

但是现在,使用十六进制翻译:

$ objdump -s shellcode

shellcode:     file format elf32-i386

Contents of section .text:
  8048060 31c05068 2f2f7368 682f6269 6e89e3b0  1.Ph//shh/bin...
  8048070 0bcd80                               ...

在这里使用:

const char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80";

int main(){
    (*(void(*)()) shellcode)();
    return 0;
}

结果是:

$ gcc -o shellcode shellcode.c
$ ./shellcode
Segmentation fault

我尝试练习我的 ASM 并重新创建此处提供的ASM 我无法解释的不同之处在于,在他的有效载荷上,他将额外0/bin//sh字符串和地址入堆栈。

我认为因为我使用的是 fastcall 约定,所以我不必设置堆栈,但显然这里还有更多事情要做。

有谁知道为什么 shellcode 拒绝运行以及为什么设置堆栈更改“正确”它?


编辑:

当我尝试运行程序时,gdb我得到以下结果:

$ gdb ./shellcode
(gdb) run
Program received signal SIGSEGV, Segmentation fault.
0x080484b3 in shellcode ()

这是readelf命令输出:

$ readelf -l -S shellcode
There are 30 section headers, starting at offset 0x1150:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000040 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0804820c 00020c 000045 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048252 000252 000008 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         0804825c 00025c 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             0804827c 00027c 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048284 000284 000010 08   A  5  12  4
  [11] .init             PROGBITS        08048294 000294 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482c0 0002c0 000030 04  AX  0   0 16
  [13] .text             PROGBITS        080482f0 0002f0 000192 00  AX  0   0 16
  [14] .fini             PROGBITS        08048484 000484 000014 00  AX  0   0  4
  [15] .rodata           PROGBITS        08048498 000498 00001c 00   A  0   0  4
  [16] .eh_frame_hdr     PROGBITS        080484b4 0004b4 00002c 00   A  0   0  4
  [17] .eh_frame         PROGBITS        080484e0 0004e0 0000b0 00   A  0   0  4
  [18] .init_array       INIT_ARRAY      08049f08 000f08 000004 00  WA  0   0  4
  [19] .fini_array       FINI_ARRAY      08049f0c 000f0c 000004 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049f10 000f10 000004 00  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        0804a000 001000 000014 04  WA  0   0  4
  [24] .data             PROGBITS        0804a014 001014 000008 00  WA  0   0  4
  [25] .bss              NOBITS          0804a01c 00101c 000004 00  WA  0   0  1
  [26] .comment          PROGBITS        00000000 00101c 00002b 01  MS  0   0  1
  [27] .shstrtab         STRTAB          00000000 001047 000106 00      0   0  1
  [28] .symtab           SYMTAB          00000000 001600 000430 10     29  45  4
  [29] .strtab           STRTAB          00000000 001a30 00024e 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point 0x80482f0
There are 9 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00590 0x00590 R E 0x1000
  LOAD           0x000f08 0x08049f08 0x08049f08 0x00114 0x00118 RW  0x1000
  DYNAMIC        0x000f14 0x08049f14 0x08049f14 0x000e8 0x000e8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x0004b4 0x080484b4 0x080484b4 0x0002c 0x0002c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x000f08 0x08049f08 0x08049f08 0x000f8 0x000f8 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .eh_frame_hdr
   07
   08     .init_array .fini_array .jcr .dynamic .got

此 shellcode 的比较

以下是差异:

Hamza (working)     |   me

ASM

xor    eax, eax     |   xor    eax, eax
push   eax          |   push   eax
push   0x68732f2f   |   push   0x68732f2f
push   0x6e69622f   |   push   0x6e69622f
mov    ebx, esp     |   mov    ebx, esp
push   eax          |
push   ebx          |
mov    esp, ecx     |
mov    al, 0xb      |   mov    al, 0xb
int    0x80         |   int    0x80

Stack before the interrupt (each line is a word)

&(/bin//sh)         | /bin
0                   | //sh
/bin                | 0
//sh                |
0                   |

Registers before the interrupt

eax    0xb          |   0xb
ebx    &(/bin//sh)  |   &(/bin//sh)
ecx    esp          |   ?

如您所见,堆栈因字符串的地址和额外的0发生变化,并且他的ecx寄存器设置为最后一个esp值。这些差异使他的 shellcode 可以工作(直接使用nasm&ldC程序内部,没有任何更改)。


编辑:

一些进展,当有效载荷在 C 程序中运行时,有一个额外的指令:

(gdb)  x/14i 0x80484a0
   ...
   0x80484b3 <shellcode+19>:    mov    $0xb,%al
   0x80484b5 <shellcode+21>:    int    $0x80
   0x80484b7 <shellcode+23>:    add    %al,(%ecx)

虽然我不知道(还)为什么ecx寄存器会随着中断的返回值而增加,但清除寄存器可以xor ecx, ecx解决这个问题。

这是工作汇编:

section .text
    global _start

_start:
    xor  eax, eax
    push eax
    push 0x68732f2f
    push 0x6e69622f
    mov  ebx, esp
    xor  ecx, ecx
    mov  al, 0xb
    int  0x80
2个回答

你的 shellcode 的问题以及你是否从 C 程序运行时它不同的原因是初始值。

执行execv(第二页)时使用的寄存器是:

  • eax = 0x0b
  • ebx = ptr 到文件名
  • ecx = ptr 到 argv
  • edx = ptr 到环境变量

但实际上重要的只有ebxeax另外两个我们可以取消。

如果你只运行你的 shellcode,寄存器的默认值是0x0这样我们就可以免费取消ecx&edx了。

在此处输入图片说明

当您从 C 程序执行 shellcode 时,情况并非如此。

在此处输入图片说明

如您所见,寄存器已经有一些初始值,因此您需要正确准备它们。这就是为什么添加可以xor ecx,ecx解决问题的原因。

至于您从中获取的示例ecx被分配给堆栈指针,但在堆栈上有一个指向“/b​​in/sh”的值,这也可以(甚至可能比 更好0x00

好的,所以根据gdbshellcode 确实运行,所以它可能被放入.text. 您应该尝试单步执行shellcode(例如使用stepi)以查看它出错的指令。