I have been trying to create a simple chunk of shell code that allows me to modify a string by doing something simple like changing a letter, then print it out.
_start:
jmp short ender
starter:
xor ecx, ecx ;clear out registers
xor eax, eax
xor ebx, ebx
xor edx, edx
pop esi ;pop address of string into esi register
mov byte [esi+1], 41 ;try and put an ASCII 'A' into the second letter of the string
;at the address ESI+1
mov ecx, esi ;move our string into the ecx register for the write syscall
mov al, 4 ;write syscall number
mov bl, 1 ;write to STDOUT
mov dl, 11 ;string length
int 0x80 ;interrupt call
ender:
call starter
db 'hello world'
It's supposed to print out "hallo world". The problem occurs (segfault) when I try and modify a byte of memory with a mov
command like so.
mov byte [esi+1], 41
I ran the program though GDB and the pop esi
command works correctly, esi
is loaded with the address of the string and everything is valid. I can't understand why I cant modify a byte value at the valid address though. I am testing this "shellcode" by just running the executable generated by NASM and ld, I am not putting it in a C program or anything yet so the bug exists in the assembly.
Extra information
I am using x64 Linux with the following build commands:
nasm -f elf64 shellcode.asm -o shellcode.o
ld -o shellcode shellcode.o
./shellcode
I have pasted the full code here.
If I had to guess, I'd say db
hello world` is being compiled in as code, rather than data, and as such has read and execute permissions, but not write ones. So you're actually falling foul of page protection.
To change this, you need to place the string in a section .data
section and use nasm's variable syntax to find it. In order to modify the data as is, you're going to need to make a mprotect call to modify the permissions on your pages, and write to them. Note: these won't persist back to the executable file - mmap()
's MAP_PRIVATE
ensures that's the case.