5

So I have been following some tutorials on assembly and the instructor compiles the following code:

;hello3.asm  attempts to make the code position independent

section .text
global _start

_start:
;clear out the registers we are going to need
xor eax, eax
xor ebx, ebx
xor ecx, ecx
xor edx, edx

;write(int fd, char *msg, unsigned int len)
mov al, 4
mov bl, 1
;Owned!!! =  4f,77,6e,65,64,21,21,21
;push !,!,!,d
push 0x21212164
;push e,n,w,O 
push 0x656e774f
mov ecx, esp
mov dl, 8
int 0x80

;exit(int ret)
mov al,1
xor ebx, ebx
int 0x80

Note that the message Owned!!! is pushed into the stack rather than kept in the .text segment. So, when I try to execute it, I get a Segment Fault error!

If instead I keep the message in the .text, then, everything works fine.

The commands I used to execute:

$> nasm -f elf64 hello4.asm 
$> ld -o hello hello4.o 

Any ideas?

3
  • 1
    @perror wow you can't answer it but , want to earn rep by correcting the question -_- May 28, 2016 at 8:35
  • 2
    I do not gain any reputation by correction your spelling... It just hurt my eyes, so I fix it. Be more careful next time, we have some standards when asking questions here (even stupid ones).
    – perror
    May 28, 2016 at 15:00
  • @DhayalanPro No need to take it so harshly, all StackExchange sites allow community edits if required, i don't see anything wrong with that. May 28, 2016 at 15:42

3 Answers 3

6

The segmentation fault error doesn't have anything to do with pushing the strings on the stack.

I used gdb to debug it, and the problem lies at:

;exit(int ret)
mov al,1
xor ebx, ebx
int 0x80

Changing

mov al,1

to

mov eax,1

Fixes the segmentation fault.

Tested on Kali Linux.

6
  • yes ,but the fact that having mov eax,1 will introduce 00 in the payload , thats why we use mov al,1 Would like to know why its crashing , I use kali too May 29, 2016 at 15:50
  • If you are on Kali, then let msfvenom take care of that. Example: msfvenom --platform linux -a x86 -f elf -b "\x00\xff" -o outputbin < inputbin
    – JeffreyZ
    May 29, 2016 at 16:04
  • I know msfvenom , learning Exploit writing so :D May 29, 2016 at 16:14
  • Also, if you want to do this without msfvenom, you could replace "mov eax,1" with "xor eax,eax inc eax" to avoid the 00s
    – JeffreyZ
    May 29, 2016 at 16:17
  • yeah i just changed the code to xor rax,rax mov al, 0x3c But still 00 comes because i have a mov di, 2 any idea ? May 29, 2016 at 16:20
2

In addition to the answer by @user2389688 it's important to note that the syscall numbers are wrong if you're doing amd64, as are the passed in registers. Here's a 64 bit abi version which corrects the differences, and provides the intended output.

;hello3.asm  attempts to make the code position independent
; rewrite of hello3.asm to use 64 bit syscall interface
section .text
global _start

_start:
xor rax, rax ; syscall
xor rdi, rdi ; arg1
xor rsi, rsi ; arg2
xor rdx, rdx ; arg3

; write(int fd, char *msg, unsigned int len)
mov al, 1
mov di, ax
;Owned!!! =  4f,77,6e,65,64,21,21,21
;push !,!,!,d
;push e,n,w,O
sub rsp, 8
mov dword [rsp], 'Owne'
mov dword [rsp + 4], 'd!!!'
mov rsi, rsp
mov dl, 8 
syscall

; exit(int ret)
; syscall errors will result in rax having a negative value so you
; can't just move al
mov eax, 0xffffffc3
not eax
xor rdi, rdi
syscall
4
  • yes we can indeed move al , thats what they do for the payload to not have 00 in them May 29, 2016 at 15:54
  • Eliminating 0 can be done in a bunch of ways. However, if the previous syscall had an error, then the upper bits of eax won't be 0. I've updated the code in my answer to eliminate the 0s.
    – broadway
    May 29, 2016 at 19:34
  • actually this works too mov al, 0x3c May 29, 2016 at 19:57
  • 1
    only if the write didn't produce an error. You can xor it first to avoid that problem, though. There's lots of ways to avoid 0 bytes.
    – broadway
    May 29, 2016 at 20:02
1

I tried your code in a 64 bit machine and there are some considerations:

when you push the 2 snippets of the string, the stack is containing a void word between them:

Breakpoint 1, 0x000000000040009a in _start () [bp before int 0x80] 
(gdb) x/4wx $rsp
0x7fffffffde30: 0x656e774f  0x00000000  0x21212164  0x00000000

This causes the write syscall to fail (as we are indicating the length is 8). So, right after the syscall, in the register %rax contain an error code:

(gdb) ni
0x000000000040009c in _start ()
(gdb) info reg
rax            0xfffffffffffffff2   -14

After that, we move a byte with mov al,1, BUT the resulting value of %rax is: 0xffffffffffffff01.

The exit syscall won't be performed and the code will continue with the contents of the memory... The results are not deterministic... (The segfault occurs somewhere, in my case tries to access to *%rsi when the register %rsi contains a 0.

I hope this helps to anyone.

BTW. Just in case, better if you introduce a null value before the string, in this way you are sure the string will end in a NULL value. Otherwise, if the memory contains another value, write() may print some strange characters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.