【问题标题】:Raising BRK in assembly on i386 Linux在 i386 Linux 上的汇编中提高 BRK
【发布时间】:2016-04-03 14:15:01
【问题描述】:

我发现并研究了x86 memory access segmentation fault,但它在我的代码中不起作用。不同之处可能在于我不使用单独的 .text 和 .data 段,而是通过创建自定义 ELF 标头将所有段保存在一个段中。这是否解释了 SYS_BRK 调用失败的原因?

然后程序继续使内存页面读/写/执行等。 我试图找到说明问题的最小代码示例。

在 kdbg 中,示例确实有效,但从命令行启动时无效,因此会打印消息。

            cpu   386
            bits  32

; System calls used
%assign     SYS_EXIT    1
%assign     SYS_WRITE   4
%assign     SYS_BRK     45
%assign     SYS_MPROTECT 125

; flags for SYS_MPROTECT
%assign     PROT_READ   1
%assign     PROT_WRITE  2
%assign     PROT_EXEC   4

%assign     STDOUT      1

memstart:   org         0x08048000

ehdr:                                           ; Elf32_Ehdr (see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
            db      0x7F, "ELF"                 ; e_ident[EI_MAG0..EI_MAG03]
            db      1                           ; e_ident[EI_CLASS]
            db      1                           ; e_ident[EI_DATA]
            db      1                           ; e_ident[EI_VERSION]
            db      0                           ; e_ident[EI_OSABI]
            db      0                           ; e_ident[EI_ABIVERSION]
  times 7   db      0                           ; e_ident[EI_PAD]
            dw      2                           ; e_type
            dw      3                           ; e_machine
            dd      1                           ; e_version
            dd      start                       ; e_entry
            dd      phdr - $$                   ; e_phoff
            dd      0                           ; e_shoff
            dd      0                           ; e_flags
            dw      ehdrsize                    ; e_ehsize
            dw      phdrsize                    ; e_phentsize
            dw      1                           ; e_phnum
            dw      0                           ; e_shentsize
            dw      0                           ; e_shnum
            dw      0                           ; e_shstrndx
ehdrsize    equ     $ - ehdr

phdr:                                           ; Elf32_Phdr
            dd      1                           ; p_type
            dd      0                           ; p_offset
            dd      $$                          ; p_vaddr
            dd      $$                          ; p_paddr
            dd      filesize                    ; p_filesz
            dd      filesize                    ; p_memsz
            dd      5                           ; p_flags
            dd      0x1000                      ; p_align
phdrsize    equ     $ - phdr

memsize:    dd      16*4096                     ; = 16 * 4K pages
memtop:     dd      0


start:      ;int     3
            xor     ebx, ebx                    ; find the amount of allocated memory
            mov     eax, SYS_BRK
            int     0x80                        ; eax contains current memtop

            sub     eax, memstart               ; got enough memory?
            test    eax, [memsize]
            ja      memgood

            mov     eax, memstart               ; raise memory limit to memstart + memsize
            add     eax, [memsize]
            mov     ebx, eax
            mov     ecx, eax                    ; save requested memory size in ecx
            mov     eax, SYS_BRK
            int     0x80
            cmp     eax, ecx
            jne     brk_error                   ; raising memory limit failed

memgood:    mov     edx, (PROT_READ | PROT_WRITE | PROT_EXEC)
            mov     ecx, [memsize]              ; make memory read/write/execute
            mov     ebx, memstart
            mov     eax, SYS_MPROTECT
            int     0x80
            test    eax, eax
            js      bailout

            jmp     launch                      ; lets start the party


brk_error:  mov     edx, brkelen
            mov     ecx, brke
            mov     ebx, STDOUT
            mov     eax, SYS_WRITE
            int     0x80
            jmp     bailout
brke:       db      'SYS_BRK failed, bye', 10
brkelen     equ     $ - brke

bailout:    mov     eax, SYS_EXIT
            xor     ebx, ebx
            int     0x80

launch:     mov     edx, succlen
            mov     ecx, succ
            mov     ebx, STDOUT
            mov     eax, SYS_WRITE
            int     0x80
            jmp     bailout
succ:       db      'Success with mem config, bye', 10
succlen     equ     $ - succ

filesize    equ $ - $$

【问题讨论】:

  • 我看到了您的回答并验证它有效。标头是常规的,只是只有一个段,因此没有代码/数据/bss 分隔。 (哎呀,突然进入帖子)。我编辑了问题以显示完整的初始化,但这并没有什么不同,所以我把这些部分省略了。
  • 对不起,(第一次使用)。我的代码的问题是第二次调用 BRK。当我将int 3 放在int 128 前面时,我得到了关于调试器断点的预期消息。如果我把它放在程序永远不会到达那里。从控制台运行时,程序似乎只是挂起。
  • 我已经删除了我所有的 cmets,因为你现在提供了实际的代码 lol
  • 我还没有完全理解你的代码,但是混合代码和数据会导致L1缓存的使用效率低下。 Intel 和 AMD CPU 使用分离的 L1I 和 L1D 高速缓存,因此例如加载 brke 字符串将要求高速缓存行位于 L1D 高速缓存中,而周围的代码将要求高速缓存行位于 L1I 高速缓存中。 OTOH,这确实意味着线路在 L2 中很热。此外,您必须通过jmp 处理数据,从而降低获取代码的效率。通常你将字符串和其他只读数据放在.rodata 中,这会将它们与代码分开,但仍然在.text 部分中。

标签: linux assembly system-calls i386 brk


【解决方案1】:

您应该在这里使用cmp 而不是test

    sub     eax, memstart               ; got enough memory?
    test    eax, [memsize]
    ja      memgood

SYS_BRK 描述的内存区域在可执行文件之后开始一个 0 到 0x02000000 的随机偏移,除非地址空间布局随机化被禁用,我怀疑你的调试器会这样做。您可以使用mmap 在指定地址分配内存(不要设置MAP_FIXED,除非您想覆盖现有映射)。

但是,使用 brkmprotect 进行的整个练习似乎毫无意义,因为除了程序启动时的堆栈之外,内存完全按照 ELF 标头指定的方式分配,您可以:

phdr:                                           ; Elf32_Phdr
            dd      1                           ; p_type
            dd      0                           ; p_offset
            dd      $$                          ; p_vaddr
            dd      $$                          ; p_paddr
            dd      filesize                    ; p_filesz
            dd      16*4096                     ; p_memsz
            dd      7                           ; p_flags
            dd      0x1000                      ; p_align
phdrsize    equ     $ - phdr

【讨论】:

  • 谢谢蒂莫西。这可能是要走的路。该程序有点重写和扩大自己,声称有额外的空间来这样做。我没有考虑地址空间布局随机化。但是修改 Elf 标头并重新启动应该可以解决问题。
  • 禁用地址空间随机化被证明是解决方案。所以程序以setarch $(uname -m) -RL ./lf 启动,解决了这个问题。谢谢@蒂莫西。见 [stackoverflow.com/questions/5194666/….
猜你喜欢
  • 2014-04-30
  • 2014-05-28
  • 1970-01-01
  • 2012-06-13
  • 2012-06-07
  • 2011-11-20
  • 2013-11-12
相关资源
最近更新 更多