Я учусь писать простой шелл-код на ассемблере. Я получаю ошибку сегмента, когда код операции mov выполняет запись поверх данных db. Зачем? Любое руководство приветствуется! Отладка с помощью gdb подтверждает, что данные смежны с кодом во время выполнения, а повторный анализ программы подтверждает, что сегмент данных доступен для записи.
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'
Дополнительная информация после чтения комментариев:
It Segment сбои при автономном запуске в командной строке linux (./myshdb), а также когда я перехожу в инструкцию mov с помощью gdb (устанавливаю break на «один», выполняю, затем повторяю шаг).
Да, компиляция и запуск на 32-битной установке Ubuntu. Вот различные командные строки, которые я использую (все они отлично работают для варианта кода оболочки):
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 говорит, что она загружена с возможностью записи. Обратите внимание на 16 байтов (размер = 0x10) в сегменте данных с флагом «W».
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"
@ Работники русского языка запросили распечатку у 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?