user3097712
user3097712

Reputation: 1675

Syscalls in assembly code

I write a little program to understand syscalls. In the following you will find creat(...) and write(...). It should be easy. So, as you maybe guess, what the program does is it creates first a file and then it fills it with a text. It should be also position independent code. Therefore, I write it using the "jump-call-pop" combination.

So, it looks like:

   Section  .text

             global  _start

_start:
        jmp short   GoToFileName

fileCreation:
        pop       esi              ; address of file name
        xor       eax, eax         ; clear eax
        mov byte  [esi+13], al     ; terminate file name string with NULL
        mov       cx, 0x309        ; create file with all possible permissions
        mov       ebx, esi         ; ebx gets address of file name
        mov       al, 0x8          ; al gets syscall number 8 of creat()
        int       0x80             ; create the file
        mov       edx, eax         ; write resulting file descriptor in edx
       jmp short TextInput

copyProcess:
       pop       esi              ; address of input string
       xor       eax, eax         ; clear eax
       mov byte  [esi+23], al     ; terminate input string with NULL
       mov       dl, 0x17         ; dl gets number of bytes to write
       mov       ecx, esi         ; ecx gets address of input string
       mov       ebx, edx         ; ebx gets file descriptor of created file
       mov       al, 0x4          ; al gets syscall number of write
       int       0x80             ; write that input string


GoToFileName:
     call     fileCreation
     db       '/tmp/file.text'

TextInput:
    call     copyProcess
    db       'This the output file'

When I compile it, link it and then run it...nothing happens /tmp directory. Only the file is created. But it is empty. As comparison, I write the same in C. The C code works. In the /tmp, suddenly a file.txt is created. But using the assembly code it does not work. Another point is the following: When I only take the creation part(fileCreation), then the assembly works. But when I combine it with the write part(copyProcess) then the whole does not work. Therefore, I assume that my mistake is somewhere in the copyProcess part. But I could not find it.

Can somebody help me ?

Upvotes: 0

Views: 1579

Answers (1)

scottt
scottt

Reputation: 7228

Your code had some bugs:

  1. You were clobbering the file descriptor stored in EDX
  2. On x86, writing to DL does NOT clear DH, writing to DX does NOT clear the upper half of EDX.
  3. File permissions are specified in octal, i.e. base 8. So octal 0777 is hex 0x1ff.
  4. By calling create() instead of open(..., O_CREAT) you can't handle the case where the file already exists.
  5. It's better to pre NULL-terminate your filename string since text sections are usually not writable. I get that you're trying to write shellcode but this point still holds.
  6. You were passing the wrong buffer length to write()

This code works:

Section  .text

             global  _start

_start:
        jmp short   GoToFileName

open:
        pop       esi              ; address of file name
        mov       edx, 0x1ff       ; 0777
        mov       ecx, 0x41        ; O_CREAT | O_WRONLY
        mov       ebx, esi         ; ebx gets address of file name
        mov       eax, 0x5         ; SYS_open
        int       0x80             
        mov       ebx, eax         ; write resulting file descriptor in EBX
        jmp short TextInput

write:
       pop       esi              ; address of input string
       mov       edx, 20          ; edx gets number of bytes to write
       mov       ecx, esi         ; ecx gets address of input string
       mov       eax, 0x4         ; SYS_write
       int       0x80

exit:
       mov       ebx, 0
       mov       eax, 1
       int       0x80


GoToFileName:
     call     open
     db       '/tmp/file.text',00

TextInput:
    call     write
    db       'This the output file'

Follow-up Question

When I add the NULL-terminator at the end of my string, must I then count the NULL, too?

Answer

  • You're making two system calls here:
    • open() takes a NULL terminated filename
    • writ() takes a byte array and a length
  • The NULL termination is only for open(). write() doesn't care about NULL termination because it just tries to write LENGTH bytes.

Upvotes: 3

Related Questions