自我修改代码总是在Linux上的分段错误

我find一篇关于自我修改代码的文章,并试图做一些例子,但是我总是得到分段错误。 正如我所能理解的,在内存权限中存在违规。 代码段是(r)ead / e(x)ecute,因此尝试写入结果导致此故障。 有没有办法通过在运行时或之前更改内存权限来testing程序? 我正在使用Linux,而且这个例子是用GAS程序集编写的。

.extern memcpy .section .data string: .asciz "whatever" string_end: .section .bss .lcomm buf, string_end-string .section .text .globl main main: call changer mov $string, %edx label: push string_end-string push $buf push $string call memcpy changer: mov $offset_to_write, %esi mov $label, %edi mov $0xb, %ecx loop1: lodsb stosb loop loop1 ret offset_to_write: push 0 call exit end: 

所以在修改osgx之后,这是一个工作代码(实际上,如果你组装&连接&运行崩溃,但是如果你使用gdb,它会修改它的代码!)

 .extern memcpy .section .data string: .asciz "Giorgos" string_end: .section .bss .lcomm buf, string_end-string .section .text .globl main main: lea (main), %esi # get the start of memory region to # change its permissions (smc-enabled) andl $0xFFFFF000, %esi # align to start of a pagesize pushl $7 # permissions==r|w|x pushl $4096 # page size pushl %esi # computed start address call mprotect call changer # function that does smc mov $string, %edx label: push string_end-string # this code will be overridden push $buf # and never be executed! push $string call memcpy changer: mov $offset_to_write, %esi # simple copy bytes algorithm mov $label, %edi mov $0xb, %ecx loop1: lodsb stosb loop loop1 ret offset_to_write: # these instructions will be push $0 # executed eventually call exit end: 

您应该在运行时更改内存访问权限。

 #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 */ } 

现代的CPU有一个称为DEP的功能,可以防止堆栈上的代码执行。 以前,这是可能的; 现在,它不是。 二进制文件默认加载到只读存储器中。

除此之外,您可以使用mprotect系统调用来将您的二进制文件在内存中的位置标记为可执行文件 – 因为您的代码没有被保护。 所以不要尝试把代码和堆栈,然后跳进去。

您也可以通过将交换机-N传递给链接器来禁用整个程序的写保护。 如果从gcc调用链接器,则传递Wl,-N 。 如果直接调用ld ,则传递-N