3

My main section is defined as section .code write

I deliberately removed the exec parameter, and noticed that, after assembling and linking, the program runs fine.

objdump -d myprogram is empty. And gdb cannot debug it : break _start says "Function _start not defined", but info variables shows _start.

But the program still runs. How's that possible ?

Architecture is intel 32-bit, on linux (ubuntu 12).

The probram is doing an execve syscall, opening a /bin/sh shell.

The nasm program :

global _start

section .code write

_start:
        jmp short call_shellcode

shellcode:
        pop esi

        xor ebx, ebx
        mov byte [esi +7], bl
        mov dword [esi +8], esi
        mov dword [esi +12], ebx

        lea ebx, [esi]
        lea ecx, [esi +8]
        lea edx, [esi +12]

        xor eax, eax
        mov al, 0xb
        int 0x80

call_shellcode:
        call shellcode
        message db "/bin/shABBBBCCCC"
trogne
  • 3,402
  • 3
  • 33
  • 50
  • What architecture are you programming for? – fuz Oct 03 '19 at 18:01
  • Added in updated post – trogne Oct 03 '19 at 18:03
  • What assembler are you using? FASM? I assume your CPU is Pentium II or newer so it supports PAE page tables and thus the NX bit. But if not then Linux can't make a page readable but not executable on obsolete 2-level x86 32-bit page tables. Check `/proc/PID/maps` or `.../smaps` and see if the mapping containing the entry-point address is in a mapping that the kernel made executable. – Peter Cordes Oct 03 '19 at 18:21
  • Any reason you're using `section .code` instead of the standard `.text`? And for defining `__start` instead of the normal `_start`? Anyway, you can get GDB to stop before the first instruction with the `starti` command (instead of `run`), or on older GDB like yours, `b *0` then `run`. Then delete the invalid breakpoint. – Peter Cordes Oct 03 '19 at 18:24
  • I use nasm. I do use "_start", not "__start". I don't know what to check about cpu and pages. I switched to a custom ".code" section because with the ".text" section there's no write access by default. I'm curious about why my program can execute without the "exec" param (or with the "noexec" param). I added the nasm code in my post. – trogne Oct 03 '19 at 19:03
  • In GDB, `starti` not found, and `b *0` then `run` is not working (same with "exec" set) : I get "Error accessing memory address 0x0: Input/output error.". In "maps", how do I check "if the mapping containing the entry-point address is in a mapping that the kernel made executable" ? – trogne Oct 03 '19 at 19:25
  • 2
    The [`elf(5)` man page](https://linux.die.net/man/5/elf) says the the executable gets flags like `PF_X`, `ET_EXEC` and `DT_EXEC` and friends. Since some (all?) are missing in your executable, you can probably suspect the dynamic linker is not following the specification. The linker is probably following [Postel's Law](https://en.wikipedia.org/wiki/Robustness_principle) and trying to make things work. – jww Oct 03 '19 at 21:51
  • `"Error accessing memory address 0x0: Input/output error."` is the whole point of that hack: to get the process started and then stop because of the error setting the breakpoint, instead of from actually hitting the breakpoint. That's why I said "then delete the invalid breakpoint". You can't actually set one at address `0`, that's not mapped. See Ruslan's answer on [Stopping at the first machine code instruction in GDB](//stackoverflow.com/q/10483544). Although your probably don't have have PIE executables so you can use the top answer that gets the entry-point address from the metadata. – Peter Cordes Oct 04 '19 at 04:44
  • @trogne: In `/proc/$PID/maps`, look for the `X` flag in the permissions field of the line that contains the address that EIP is in. – Peter Cordes Oct 04 '19 at 04:44
  • @jww I see, the linker might try to make this work ! But it makes objdump/gdb not working correctly, and that is still a question. @Peter Cordes, ok `B *0` trick works ! pmap shows the same "x" (executable) as with the process with "exec" param. – trogne Oct 04 '19 at 11:59
  • With only "write", objdump shows the dump with option "-D" (disassemble-all) : "Like -d, but disassemble the contents of all sections, not just those expected to contain instructions." So I understand that without "exec", it is not expected to contain instructions, hence `objdump -d myprogram` is empty, and gdb might in some way not "expecting" those instructions either... – trogne Oct 04 '19 at 14:44
  • Unless you take special care, linking a NASM source file will be like `gcc -zexecstack` which actually made everything executable [Unexpected exec permission from mmap when assembly files included in the project](https://stackoverflow.com/q/58260465). (until recent changes especially for 64-bit executables: [Linux default behavior of executable .data section changed between 5.4 and 5.9?](https://stackoverflow.com/a/64837581)) – Peter Cordes Apr 14 '21 at 04:01

0 Answers0