13

自己変更コードに関する記事を見つけていくつかの例を試してみましたが、常にセグメンテーション違反が発生します。私が理解できる限り、メモリ権限に違反があります。コードセグメントは(r)ead / e(x)ecuteであるため、書き込みを試みるとこの障害が発生します。実行時またはそれ以前にメモリ権限を変更してプログラムをテストする方法はありますか?私は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:
4

3 に答える 3

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 */
}
于 2010-11-12T21:59:18.787 に答える
5

最新の CPU には、スタックでのコードの実行を防止する DEP と呼ばれる機能があります。以前は、これが可能でした。今はそうではありません。デフォルトでは、バイナリは読み取り専用メモリにロードされます。

邪魔にならないように、mprotect システム コールを使用して、メモリ内のバイナリの場所を実行可能としてマークすることができます - コードが DEP 保護されていない限り。したがって、コードとスタックを配置してからそれにジャンプしようとしないでください。

于 2010-11-12T21:58:54.340 に答える
3

-Nスイッチをリンカーに渡すことで、プログラム全体の書き込み保護を無効にすることもできます。gcc からリンカーを呼び出す場合は、Wl,-N. ld直接呼び出す場合は、 を渡し-Nます。

于 2015-07-08T23:33:55.300 に答える