linux - 用汇编语言访问 errno.h

标签 linux assembly error-handling x86 system-calls

我想以汇编语言访问 errno.h 中存在的 errno,以处理编写函数调用的错误。我发现某处为此目的在汇编语言中调用 _error ,但它抛出错误为:

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

我的汇编代码: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

如何在汇编语言中访问errno?

最佳答案

  • 您正在使用手写的汇编代码
  • 进行 x86 Linux 系统调用
  • 如果系统调用失败,条件 (unsigned long)eax > 0xfffff000将是真实的,-(signed long)eax将是错误代码。
  • 在伪 C 代码中:if (-4095 <= eax && eax <= -1) errno = -eax;
  • 因此,您不需要访问 errno处理汇编程序中的系统调用错误。您应该从 eax 导出 errno 值反而。

  • (暂停并考虑几秒钟。这是您问题中隐含的概念性误解)

    进一步说明

    问题:您正在进行系统调用,但没有了解 Linux 如何通过 syscall ABI 返回错误的详细信息。
  • 常规 Linux C 程序通过 glibc 包装函数进行系统调用
  • glibc 包装函数检查系统调用返回码,存储在 eax在 x86 上,并设置 errno如果需要,正确的错误代码
  • 常规 errno由 glibc 提供,是一个线程局部变量,要在汇编程序中访问它,您需要学习 Linux TLS ABI。看mmap64() 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>
    

    它检查 eax 中的系统调用返回值.

    和:
       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  
    

    它存储在哪里-eaxerrno并返回 -1
  • 你的 shellcode,ExitNewShell.asm , 在构建为独立可执行文件时不会与 glibc 链接,因此访问 errno除非您将该 shellcode 注入(inject)另一个进程,否则将无法工作,因为 glibc 不会在那里为 errno 分配线程本地存储槽。并存储值 -eax即使您做了所有正确的事情来访问线程本地存储,也会在系统调用失败后对其进行处理。

  • 笔记
  • gdbdis是我为使用 GDB 作为反汇编程序而编写的脚本。 (它被实现为“多调用二进制”,根据用于调用它的程序名称改变行为。)
  • 关于linux - 用汇编语言访问 errno.h,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29047592/

    相关文章:

    r - R 脚本中的 SSH 获取 MySQL 数据库

    assembly - EMU8086 是否有错误,或者我编写此代码时犯了错误?

    php - 获取 “mysqli::real_connect(): (HY000/2002): Connection refused”

    linux - libmpfr.so.4 与 --disable-shared 的依赖关系

    linux - 不能在 bash if 语句中使用 'sudo'

    linux - 如何确定逗号分隔字符串中字符串的顺序位置?

    assembly - 在 AArch64 的 GNU 汇编程序中打破长宏参数列表

    assembly - JE 的跳跃距离有限制吗?

    java - 为什么我的switch语句生成IOException

    django - 自定义500错误有时会出现空白页