C:如何在运行时在我的程序中更改自己的程序?

D. *_*sin -2 c self-modifying self-reference

在运行时,汇编程序或机器代码(它是什么?)应该在RAM中的某个位置.我可以以某种方式访问​​它,读取甚至写入它吗?

这仅用于教育目的.

所以,我只能编译这段代码.我真的在这里读书吗?

#include <stdio.h>
#include <sys/mman.h>

int main() {
    void *p = (void *)main;
    mprotect(p, 4098, PROT_READ | PROT_WRITE | PROT_EXEC);
    printf("Main: %p\n Content: %i", p, *(int *)(p+2));
    unsigned int size = 16;
    for (unsigned int i = 0; i < size; ++i) {
        printf("%i ", *((int *)(p+i)) );
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我补充一下

*(int*)p =4;
Run Code Online (Sandbox Code Playgroud)

那是一个分段错误.


从答案中,我可以构造以下代码,在运行时修改它自己:

#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>

void * alignptr(void * ptr, uintptr_t alignment) {
    return (void *)((uintptr_t)ptr & ~(alignment - 1));
}

// pattern is a 0-terminated string
char* find(char *string, unsigned int stringLen, char *pattern) {
    unsigned int iString = 0;
    unsigned int iPattern;
    for (unsigned int iString = 0; iString < stringLen; ++iString) {
        for (iPattern = 0;
            pattern[iPattern] != 0
            && string[iString+iPattern] == pattern[iPattern];
            ++iPattern);
        if (pattern[iPattern] == 0) { return string+iString; }
    }
    return NULL;
}

int main() {
    void *p = alignptr(main, 4096);
    int result = mprotect(p, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
    if (result == -1) {
        printf("Error: %s\n", strerror(errno));
    }

    // Correct a part of THIS program directly in RAM
    char programSubcode[12] = {'H','e','l','l','o',
                                ' ','W','o','r','l','t',0};
    char *programCode = (char *)main;
    char *helloWorlt = find(programCode, 1024, programSubcode);
    if (helloWorlt != NULL) {
        helloWorlt[10] = 'd';
    }   
    printf("Hello Worlt\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这真太了不起了!谢谢你们!

Cli*_*ord 6

原则上,实际上您的操作系统可以保护自己免受危险代码的侵害!

在计算机拥有非常微小的记忆(20世纪50年代)的时代,自我修改代码可能被视为一种"巧妙的技巧".它后来(当它不再需要时)被认为是不好的做法 - 导致代码很难维护和调试.

在更现代的系统中(在20世纪末),它成为一种表明病毒和恶意软件的行为.因此,所有现代桌面操作系统都不允许修改程序的代码空间,并且还阻止执行注入数据空间的代码.具有MMU的现代系统可以将存储器区域标记为只读,并且例如不可执行.

如何获取代码空间地址的简单问题 - 这很简单.例如,函数指针值通常是函数的地址:

int main()
{
    printf( "Address of main() = %p\n", (void*)main ) ;
}
Run Code Online (Sandbox Code Playgroud)

另请注意,在现代系统中,此地址将是虚拟而非物理地址.