Skip to content
Advertisement

Accessing errno.h in assembly language

I want to access errno present in errno.h in assembly language in order to handle errors of write function call. I found somewhere that make call to _error in assembly language for this purpose but it is throwing errors as :

ExitNewShell.asm:71: error: symbol `_error' undefined
ExitNewShell.asm:85: error: symbol `_error' undefined
ExitNewShell.asm:98: error: symbol `_error' undefined
ExitNewShell.asm:111: error: symbol `_error' undefined
ExitNewShell.asm:124: error: symbol `_error' undefined
ExitNewShell.asm:137: error: symbol `_error' undefined
ExitNewShell.asm:150: error: symbol `_error' undefined
ExitNewShell.asm:163: error: symbol `_error' undefined
ExitNewShell.asm:176: error: symbol `_error' undefined

My assembly code : ExitNewShell.asm

[SECTION .text]

global _start


_start:

        jmp ender

        starter:

        xor eax, eax    ;clean up the registers
        xor ebx, ebx
        xor edx, edx
        xor ecx, ecx

        mov al, 4       ;syscall write
        mov bl, 1       ;stdout is 1
        pop ecx         ;get the address of the string from the stack
        mov dl, 11       ;length of the string
        int 0x80
    cmp eax,0xffffffff
    jne exit
    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff2
    mov dl,14 
    lea ecx,[msg1]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit


    callOff2:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff3
    mov dl,14 
    lea ecx,[msg2]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff3:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff4
    mov dl,14 
    lea ecx,[msg3]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff4:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff5
    mov dl,14 
    lea ecx,[msg4]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff5:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff6
    mov dl,14 
    lea ecx,[msg5]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff6:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff7
    mov dl,14 
    lea ecx,[msg6]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff7:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff8
    mov dl,14 
    lea ecx,[msg7]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff8:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne callOff9
    mov dl,14 
    lea ecx,[msg8]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    callOff9:

    call _error
    mov eax,[eax]
    cmp eax,0xb
    jne exit
    mov dl,14 
    lea ecx,[msg9]
    mov bl,1
    mov al,4
    int 0x80
    jmp exit

    exit:
        xor eax, eax
        mov al, 1       ;exit the shellcode
        xor ebx,ebx
        int 0x80

        ender:
        call starter    ;put the address of the string on the stack
        db 'Hello World',0xa

[SECTION .data]

msg1 db 'ERROR - EAGAIN',0
msg2 db 'ERROR - EBADF',0
msg3 db 'ERROR - EPIPE',0
msg4 db 'ERROR - EFAULT',0
msg5 db 'ERROR - EFBIG',0
msg6 db 'ERROR - EINTR',0
msg7 db 'ERROR - EINVAL',0
msg8 db 'ERROR - EIO',0
msg9 db 'ERROR - ENOSPC',0

How to access errno in assembly language?

Advertisement

Answer

  • You’re making x86 Linux syscalls from hand written assembler code
  • If a syscall fails, the condition (unsigned long)eax > 0xfffff000 will be true and -(signed long)eax will be the error code.
    • In pseudo C code: if (-4095 <= eax && eax <= -1) errno = -eax;
  • Thus, you do NOT need to access errno to handle syscall errors in assembler. You should derive the errno value from eax instead.

(Pause and think about this for a few seconds. It’s a conceptual misunderstanding implicit in your question)

Further Explanation

The problem: you’re making system calls but didn’t learn the details of how Linux returns errors through the syscall ABI.

  • Regular Linux C programs make syscalls through glibc wrapper functions
  • glibc wrapper functions check the syscall return code, stored in eax on x86, and set errno to the correct error code if required
  • The regular errno, provided by glibc, is a thread local variable, to access it in assembler you’ll need learn the Linux TLS ABI. Look at the mmap64() syscall wrapper in glibc:
$ gdbdis /lib/libc.so.6 mmap64
   0x4ef952a0 : push   %ebp
   0x4ef952a1 : push   %ebx
   0x4ef952a2 : push   %esi
   0x4ef952a3 : push   %edi
   0x4ef952a4 : mov    0x28(%esp),%edx
   0x4ef952a8 : mov    0x2c(%esp),%ecx
   0x4ef952ac :    test   $0xfff,%edx
   0x4ef952b2 :    jne    0x4ef952eb 
   0x4ef952b4 :    shrd   $0xc,%ecx,%edx
   0x4ef952b8 :    shr    $0xc,%ecx
   0x4ef952bb :    jne    0x4ef952eb 
   0x4ef952bd :    mov    %edx,%ebp
   0x4ef952bf :    mov    0x14(%esp),%ebx
   0x4ef952c3 :    mov    0x18(%esp),%ecx
   0x4ef952c7 :    mov    0x1c(%esp),%edx
   0x4ef952cb :    mov    0x20(%esp),%esi
   0x4ef952cf :    mov    0x24(%esp),%edi
   0x4ef952d3 :    mov    $0xc0,%eax
   0x4ef952d8 :    call   *%gs:0x10
   0x4ef952df :    pop    %edi
   0x4ef952e0 :    pop    %esi
   0x4ef952e1 :    pop    %ebx
   0x4ef952e2 :    pop    %ebp
   0x4ef952e3 :    cmp    $0xfffff000,%eax
   0x4ef952e8 :    ja     0x4ef952f6 
   0x4ef952ea :    ret    
   0x4ef952eb :    pop    %edi
   0x4ef952ec :    pop    %esi
   0x4ef952ed :    pop    %ebx
   0x4ef952ee :    pop    %ebp
   0x4ef952ef :    mov    $0xffffffea,%eax
   0x4ef952f4 :    jmp    0x4ef952f6 
   0x4ef952f6 :    call   0x4efd8b33 
   0x4ef952fb :    add    $0xd3d05,%ecx
   0x4ef95301 :    mov    -0x10c(%ecx),%ecx
   0x4ef95307 :   neg    %eax
   0x4ef95309 :   mov    %eax,%gs:(%ecx)
   0x4ef9530c :   or     $0xffffffff,%eax
   0x4ef9530f :   ret   

See:

   0x4ef952e3 <+67>:    cmp    $0xfffff000,%eax
   0x4ef952e8 <+72>:    ja     0x4ef952f6 <mmap64+86>

where it checks the syscall return value in eax.

and:

   0x4ef952f6 <+86>:    call   0x4efd8b33 <__x86.get_pc_thunk.cx>
   0x4ef952fb <+91>:    add    $0xd3d05,%ecx
   0x4ef95301 <+97>:    mov    -0x10c(%ecx),%ecx
   0x4ef95307 <+103>:   neg    %eax
   0x4ef95309 <+105>:   mov    %eax,%gs:(%ecx)
   0x4ef9530c <+108>:   or     $0xffffffff,%eax
   0x4ef9530f <+111>:   ret  

where it stores -eax to errno and returns -1

  • Your shellcode, ExitNewShell.asm, won’t be linked with glibc when built as a standalone executable, thus accessing errno won’t work unless you inject that shellcode into another process, since glibc wouldn’t be there to allocate a thread local storage slot for errno and store the value -eax to it after a syscall failure, even if you do all the right things to access thread local storage.

Notes

  • gdbdis is a script I wrote to use GDB as a disassembler. (It’s implemented as a “multi-call binary” that changes behavior according to the program name used to invoke it.)
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement