2010-11-12 3 views
10

Я нашел статью о саморедактирующем коде и попытался сделать несколько примеров, но у меня всегда возникают ошибки сегментации. Как я понимаю, есть нарушения в разрешениях памяти. Сегмент кода (r) ead/e (x) ecute и, следовательно, попытка направить результаты на эту ошибку. Есть ли способ протестировать программу либо путем изменения разрешений на память во время выполнения, либо раньше? Я использую linux, и пример написан на сборке GAS.Самомодифицирующийся код всегда с ошибками сегментации в Linux

.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: 
+0

Не уверен, как это делается на Linux, но вы можете либо проинструктировать ваш компоновщик использовать пользовательские флаги для .text-раздела, либо чтобы указать их в источнике (по умолчанию для .data RW, для .text is RX) – ruslik

+0

@ruslik могу ли я указать из источника разрешение сегмента кода (текста) с помощью rwx? –

ответ

14

Вы должны изменить разрешения доступа к памяти во время выполнения.

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

Могу ли я использовать эту функцию из сборки? Нужны ли мне какие-либо особые привилегии для его использования? –

+1

Да, вы можете. Легкий способ - скомпилировать код C с помощью mprotect в .S-файл (-S) и скопировать-вставить вызов mprotect на ваш код. Особые привилегии не нужны для памяти, принадлежащей вашему процессу, и не должно быть никаких защищенных патчей для ядра – osgx

+0

, есть хорошая статья (единственный недостаток - это использование синтаксиса intel) http: //asm.sourceforge. net/articles/smc.html – osgx

5

Современные процессоры имеют функцию DEP, которая предотвращает выполнение кода в стеке. Раньше это было возможно; теперь это не так. По умолчанию двоичный файл загружается в постоянную память.

С помощью этого способа вы можете использовать системный вызов mprotect, чтобы пометить местоположение вашего двоичного файла в памяти как исполняемый файл - ТАК ДЛИННО, КАК ВАШ КОД НЕ ЗАЩИЩЕН ОПАСНО. Поэтому не пытайтесь поместить код и стек, а затем прыгать в него.

+1

'mprotect PROT_READ | PROT_WRITE | PROT_EXEC' должен отключить DEP. Кроме того, это называется DEP только в мире MS – osgx

+0

Но я не пытаюсь манипулировать стеком, я просто пытаюсь изменить/сгенерировать инструкции в сегменте кода. –

+0

@osgx: _ «это называется DEP только в мире MS» _ [Это просто не так) (http://oleb.net/blog/2012/07/ios-hackers-handbook/); DEP - общий термин. –

1

Вы также можете отключить защиту от записи для всей программы, передавая переключатель -N линкера. Если вы ссылаетесь на компоновщик из gcc, пройдите Wl,-N. Если вы вызываете ld напрямую, пройдите -N.

Смежные вопросы