1

我正在学习使用汇编编写一个简单的 shell 代码。当执行 mov 操作码以覆盖 db 数据时,出现段错误。为什么?任何指导表示赞赏!使用 gdb 调试确认数据在运行时与代码连续,并且程序的 readelf 分析确认数据段是可写的。

    section .text
    global _start
        _start:

          ; The following code calls execve("/bin/sh", argv, envp=0)
          jmp short two
    one:
          pop ebx
          xor eax, eax
          mov [ebx+12], eax
          mov [ebx+7], al
          mov [ebx+8], ebx
          lea ecx, [ebx+8]
          lea edx, [ebx+12]
          mov al, 11
          int 0x80
    two:
          call one
section .data align=1
          db '/bin/shzargvenvp'

阅读评论后的附加信息:

当在 linux 命令行 (./myshdb) 上独立运行时,以及当我使用 gdb 进入 mov 指令时(将 break 设置为“one”,运行,然后重复执行),它会出现分段错误。

是的,在 32 位 Ubuntu 安装上编译和运行。这是我正在使用的各种命令行(对于变体 shell 代码工作都可以正常工作):

nasm -f elf32 -g -F stabs myshdb.s -o myshdb.o
objdump -Mintel --disassemble myshdb.o
ld myshdb.o -o myshdb
readelf -a myshdb
gdb myshdb

使用不同的算法,编译和命令都可以正常工作并且程序运行正常。这是关于在代码之后立即接近数据并试图写入给我带来麻烦的数据部分。最初都是 .text 部分,但这显然是只读的,所以我认为在 1 字节边界上对齐的数据声明会起作用。1 字节边界有效,但不知何故,即使 readelf 说它已加载可写,写入也无法正常工作。请注意带有“W”标志的数据段中的 16 个字节(大小=0x10)。

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        08048080 000080 000025 00  AX  0   0 16
  [ 2] .data             PROGBITS        080490a5 0000a5 000010 00  WA  0   0  1
  [ 3] .stab             PROGBITS        00000000 0000b8 0000d8 0c      4   0  4
  [ 4] .stabstr          STRTAB          00000000 000190 00000a 00      0   0  1
  [ 5] .shstrtab         STRTAB          00000000 00029b 000036 00      0   0  1
  [ 6] .symtab           SYMTAB          00000000 00019c 0000d0 10      7   9  4
  [ 7] .strtab           STRTAB          00000000 00026c 00002f 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)

数据是否立即跟随代码?下面的 gdb 输出,在执行第一个 mov 操作码之前停止。数据在代码之后显示是连续的。EBX 包含地址 0x80480a5,它指向紧跟在代码后面的有效字符串数据。检查内存(x 0x80480a5)也可以确认一个连续的位置。

[----------------------------------registers-----------------------------------]
EAX: 0x0 
EBX: 0x80480a5 ("/bin/shZargvenvp")
ECX: 0x0 
EDX: 0x0 
ESI: 0x0 
EDI: 0x0 
EBP: 0x0 
ESP: 0xbfffeda0 --> 0x1 
EIP: 0x804808d (<one+3>:    mov    DWORD PTR [ebx+0xc],eax)
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048088 <zero>:    jmp    0x80480a0 <two>
   0x804808a <one>: pop    ebx
   0x804808b <one+1>:   xor    eax,eax
=> 0x804808d <one+3>:   mov    DWORD PTR [ebx+0xc],eax
   0x8048090 <one+6>:   mov    DWORD PTR [ebx+0x8],ebx
   0x8048093 <one+9>:   mov    BYTE PTR [ebx+0x7],al
   0x8048096 <one+12>:  lea    ecx,[ebx+0x8]
   0x8048099 <one+15>:  lea    edx,[ebx+0xc]
   [------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804808d in one ()
gdb-peda$ x 0x80480a5
0x80480a5:  "/bin/shZargvenvp"

@Employed Russian 要求从 reaelf -Wl 打印输出。这是我从头开始重建时的信息:

---------- code snippet compiled with nasm, ld -----------------
zero: jmp short two
one:  pop ebx
      xor eax, eax
      mov [ebx+12], eax
      mov [ebx+8], ebx
      mov [ebx+7], al
      lea ecx, [ebx+8]
      lea edx, [ebx+12]
      mov al, 11
      int 0x80
two:  call one
section .data align=1
msg:   db '/bin/sh0argvenvp' 

-------- readelf output as requested --------
readelf -Wl myshdb

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

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x0009d 0x0009d R E 0x1000
  LOAD           0x00009d 0x0804909d 0x0804909d 0x00010 0x00010 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .data 

-------------- run with gdb and step to mov instructions ----------
---------------registers--------------
EAX: 0x0 
EBX: 0x804809d ("/bin/sh0argvenvp")

----------- memory address checks ------------
gdb-peda$ p zero
$15 = {<text variable, no debug info>} 0x8048080 <zero>
gdb-peda$ p one
$16 = {<text variable, no debug info>} 0x8048082 <one>
gdb-peda$ p two
$17 = {<text variable, no debug info>} 0x8048098 <two>
gdb-peda$ p $ebx
$18 = 0x804809d
gdb-peda$ p msg
$19 = 0x6e69622f
gdb-peda$ x 0x804809d
0x804809d:  "/bin/sh0argvenvp"
gdb-peda$ x msg
0x6e69622f: <error: Cannot access memory at address 0x6e69622f>

换句话说,字符串消息可直接从代码 (0x804809d) 之后的内存位置获得。然而 msg 标签映射到 0x6e69622f,我如何使用 gdb 看到那里的数据?reaelf -Wl 输出告诉我什么?

4

1 回答 1

3

使用 gdb 调试确认数据在运行时与代码连续,并且程序的 readelf 分析确认数据段是可写的。

您期望db '...'立即跟进CALL one

这实际上并没有发生,您的.data部分位于不同的中(因为它需要不同的权限):

readelf -Wl myshdb
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x00094 0x00094 R   0x1000
  LOAD           0x001000 0x08049000 0x08049000 0x0001d 0x0001d R E 0x1000
  LOAD           0x002000 0x0804a000 0x0804a000 0x00010 0x00010 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00
   01     .text
   02     .data

请注意,这.data是在LOAD第二段中,并且该段从不同的页面开始。

可能让您感到困惑的是,您的链接器可能会留下以下代码的副本(我的版本没有 - 这对我来说都是 s)。.datatwo0

在任何情况下,您的代码原样尝试写入第一个 LOAD段,立即写入 结束后的位置two,但该段(显然)是不可写的。

于 2020-07-11T00:34:23.303 回答