Self Modifying Code Always Segmentation Faults on Linux

Self modifying code always segmentation faults on Linux

You should to change memory access permissions in runtime.

#include <sys/mman.h>

void *addr = get_address_of_instruction_pointer();
int length = 4096; /* size of a page */

if (mprotect(addr, length, PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
/* current code page is now writable and code from it is allowed for execution */
}

Why I cannot single stepping into aeskeygenassist instruction in self-modifying code?

I assume you forgot to link with --omagic to make the .text section writable.


So mov BYTE PTR ds:0x804807f,ah segfaults, and it's right before aeskeygenassist. You can't keep single-stepping after your program crashes. (You have no handler for SIGSEGV, and the default action is to terminate your program).

When I tried this on my desktop out of curiosity, I can imagine interpreting the behaviour as single-stepping getting "stuck" before aeskeygenassist, if I ignore the segfault message!!! and the fact that trying again says "the program is no longer running".

From a GDB session:

(gdb) layout reg
(gdb) starti # like run with an implicit breakpoint on the first instruction
(gdb) si
0x0000000000401004 in _start ()
0x0000000000401008 in _start () ## I kept pressing return to repeat the command
0x000000000040100c in _start ()
0x000000000040100e in roundloop ()
0x0000000000401012 in roundloop ()
0x0000000000401014 in roundloop () # the MOV store

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401014 in roundloop () # still pointing at the MOV store

Notice that RIP is still pointing at the mov. 0x8048074 in your 32-bit build, 0x401014 in my 64-bit build of the same source.


From the ld manual:

-N

--omagic

Set the text and data sections to be readable and writable. Also, do not page-align the data segment, and disable linking against
shared
libraries. If the output format supports Unix style magic numbers, mark the output as "OMAGIC". Note: Although a writable text
section is
allowed for PE-COFF targets, it does not conform to the format specification published by Microsoft.

Your code works fine for me if I link with:

  nasm -felf64 aes.asm &&
ld --omagic aes.o -o aes

Alternatively, you could make an mprotect system call to give the page containing this code PROT_READ|PROT_WRITE|PROT_EXEC.

GDB's layout reg disassembly window even updates disassembly for aeskeygenassist after its immediate is modified by store.


Also note that Self-Modifying Code (SMC) is extremely slow on modern x86. Full pipeline nuke after every store near instructions being executed. You'd be much better off unrolling with an assembler macro.

Also, you can't ret from _start under Linux; it's not a function. The stack pointer points to argc, not a return address. Make an _exit system call with int 0x80 for 32-bit code. When I say "works" I meant it reaches that ret and segfaults on code-fetch from address 1 after popping argc into RIP.

Also, use default rel for RIP-relative addressing of the store; it's more compact. Or I guess you're building a 32-bit executable out of this for some reason, based on your code addresses. I didn't notice that at first, that's why I tested as a 64-bit executable. Fortunately you used labels correctly, and aeskeygenassist is the same length in both modes, so it still works.

Segmentation fault in mov instruction


rdi contains the address of a piece of code

Many systems provide protection from malicious code by actively preventing writes to code areas(a). For example, the code selector may point to a memory block which is marked read-only (unless you're running the code trying to modify it in some form of privileged mode).

You're almost certainly running into this protection mechanism in this case. How you solve it (assuming it's allowed) will depend on more details on your environment than you have currently provided (operation system, for example).

For example, under Linux, you can use mprotect to change protections for some address ranges in your virtual memory space.


(a) Some also stop you from executing data as if it was code which means that, even if you move the code to somewhere you can write, you may not be able to execute it.

Self modifying code always segmentation faults on Linux

You should to change memory access permissions in runtime.

#include <sys/mman.h>

void *addr = get_address_of_instruction_pointer();
int length = 4096; /* size of a page */

if (mprotect(addr, length, PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
/* current code page is now writable and code from it is allowed for execution */
}

Gdb toggling breakpoints in self-modifying code

There are two ways in which GDB places a breakpoint. One is by setting certain special registers to instruct the CPU to break (raise an interrupt, which the kernel then translates into a signal to the debugger) when that line is executed. These are what GDB refers to as "hardware break points". If they are not supported on your hardware, then they are not supported.

The other way is to actually modify the code, and replace the first instruction of the line in which to break with a command to raise said interrupt. For example, under Intel X86, the command to raise an interrupt, say "int 5", is two bytes long, but the command to raise interrupt 3 is only one byte long. This is so it can be used for precisely this purpose.

The debugger replaces the instruction with the breaking one, and once the break point is hit, replaces that code back with what it had before the debugger interfered. Yes, this technique does not work with self modifying code (nor, I should mention, with code in read only memory, such as written to flash).

If your code is orderly enough (and, obviously, it is not particularly orderly), you can break once right after the code is written to memory, and only then place a second break point at the right location. If you study GDB's scripting capabilities hard enough, you can even make that automatic, so that you will not be bothered with the first break point.

All in all, if you are writing self modifying code, you are off the trodden path. Good luck. You're going to need it.

Shachar

Is there any way to create a counter by self-modifying in MIPS?

This is the solution which I found:

# subroutine
nextInt: # return value is in $v0
add $v0,$zero,0
la $t0,nextInt # load subroutine address
lw $t1,0($t0) # load content of address
addi $t1,$t1,1 # change content (increment)
sw $t1,0($t0) # save
jr $ra

memory management and segmentation faults in modern day systems (Linux)

Technically, the operating system is able to allocate any memory page on access, but there are important reasons why it shouldn't or can't:

different memory regions serve different purposes.

  • code. It can be read and executed, but shouldn't be written to.
  • literals (strings, const arrays). This memory is read-only and should be.
  • the heap. It can be read and written, but not executed.
  • the thread stack. There is no reason for two threads to access each other's stack, so the OS might as well forbid that. Moreover, the tread stack can be de-allocated when the tread ends.
  • memory-mapped files. Any changes to this region should affect a specific file. If the file is open for reading, the same memory page may be shared between processes because it's read-only.
  • the kernel space. Normally the application should not (or can not) access that region - only kernel code can. It's basically a scratch space for the kernel and it's shared between processes. The network buffer may reside there, so that it's always available for writes, no matter when the packet arrives.
  • ...

The OS might assume that all unrecognised memory access is an attempt to allocate more heap space, but:

  • if an application touches the kernel memory from user code, it must be killed. On 32-bit Windows, all memory above 1<<31 (top bit set) or above 3<<30 (top two bits set) is kernel memory. You should not assume any unallocated memory region is in the user space.
  • if an application thinks about using a memory region but doesn't tell the OS, the OS may allocate something else to that memory (OS: sure, your file is at 0x12341234; App: but I wanted to store my data there). You could tell the OS by touching the end of your array (which is unreliable anyways), but it's easier to just call an OS function. It's just a good idea that the function call is "give me 10MB of heap", not "give me 10MB of heap starting at 0x12345678"
  • If the application allocates memory by using it then it typically does not de-allocate at all. This can be problematic as the OS still has to hold the unused pages (but the Java Virtual Machine does not de-allocate either, so hey).

Different runs of a program results in different addresses for variables

This is called memory layout randomisation and is used, alongside of proper permissions (stack space is not executable), to make buffer overflow attacks much more difficult. You can still kill the app, but not execute arbitrary code.

Some links on memory allocation (e.g. in heap).

Do you mean, what algorithm the allocator uses? The easiest algorithm is to always allocate at the soonest available position and link from each memory block to the next and store the flag if it's a free block or used block. More advanced algorithms always allocate blocks at the size of a power of two or a multiple of some fixed size to prevent memory fragmentation (lots of small free blocks) or link the blocks in a different structures to find a free block of sufficient size faster.

An even simpler approach is to never de-allocate and just point to the first (and only) free block and holds its size. If the remaining space is too small, throw it away and ask the OS for a new one.

There's nothing magical about memory allocators. All they do is to:

  • ask the OS for a large region and
  • partition it to smaller chunks
  • without

    • wasting too much space or
    • taking too long.

Anyways, the Wikipedia article about memory allocation is http://en.wikipedia.org/wiki/Memory_management .

One interesting algorithm is called "(binary) buddy blocks". It holds several pools of a power-of-two size and splits them recursively into smaller regions. Each region is then either fully allocated, fully free or split in two regions (buddies) that are not both fully free. If it's split, then one byte suffices to hold the size of the largest free block within this block.



Related Topics



Leave a reply



Submit