我正在学习使用汇编编写一个简单的 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 输出告诉我什么?