繁体   English   中英

C:如何检查是否已写入 memory 地址?

[英]C: How can I check if a memory address has been written?

C中有没有办法检查我自己的进程的memory地址是否写入?
例如:如果我的程序接受放置在缓冲区中的输入,我是否可以通过检查缓冲区的下一个地址是否已写入来检查输入是否溢出缓冲区?
我知道我可以检查缓冲区的下一个地址的内容并验证它是否已被修改,但是这样对我正在处理的工作不利......

我正在研究保护缓冲区溢出和格式字符串错误的情况

我知道我可以检查缓冲区的下一个地址的内容并验证它是否已被修改,但是这样对我正在处理的工作不利......

不幸的是,这是在没有平台和实现特定扩展的情况下使用 C 时唯一的可能性。

However, there are C compilers that can produce machine code which will detect many buffer overflows in these kinds of context - for example GCC has switches -fsanitize=undefined and -fsanitize=address which can be used together and which will output diagnostics to the terminal当发生缓冲区溢出时。 它们使程序运行速度慢得多。 或者,您可以使用valgrind运行程序,它也可以调试分配缓冲区溢出的多种情况。

要添加到您的研究中:

If programming on linux platform that supports mprotect call and when dealing with only dynamic allocation, you can overallocate the memory to at least more then 1 page and mprotect the memory after the memory that you return as dynamically allocated.

例如:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdalign.h>
#include <sys/mman.h>
#include <stddef.h>
#include <signal.h>

#if PROTECT_ME
void *malloc2(size_t size) {
    const size_t maxalign = _Alignof(max_align_t);
    assert(size < getpagesize() - sizeof(size_t) - maxalign); // roughly, could be TODO

    // allocate memory
    char * const pnt = mmap(NULL, getpagesize() + 1,
        PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    assert(pnt != (void*)-1);
    assert((uintptr_t)pnt % getpagesize() == 0);

    // calculate a pointer right after the returned pointer that has
    // to be aligned
    char * const end = pnt + getpagesize();
    char * const beg = end - size - (size % maxalign);

    // I store size in the memory before the data
    memcpy(beg - sizeof(size), &size, sizeof(size));

    // protect the data behind the pointer
    assert((uintptr_t)end % getpagesize() == 0);
    const int err = mprotect(end, 1, 0);
    assert(err == 0);

    return beg;
}

void free2(void *beg) {
    // extract size for memory preceding the data
    size_t size;
    memcpy(&size, beg - sizeof(size), sizeof(size));

    // calculate mmap returned pointer
    const size_t maxalign = _Alignof(max_align_t);
    char * const end = beg + size + (size % maxalign);
    char * const pnt = end - getpagesize();

    assert((uintptr_t)pnt % getpagesize() == 0);
    int err = munmap(pnt, getpagesize() * 2);
    assert(err == 0);
}

void signal_segv(int a) {
    fprintf(stderr, "The process had written to a bad place\n");
    abort();
}

__attribute__((__constructor__))
void _init_me(void) {
    signal(SIGSEGV, signal_segv);
}

#define malloc malloc2
#define free free2

#endif


int main() {
    int *a = malloc(5 * sizeof(*a));
    for (int i = 0; i < 10; ++i) {
        a[i] = i;  // will write out-of-bounds for a array when i == 5
        fprintf(stderr, "a[%d]=%d\n", i, a[i]);
    }
    free(a);
}

gcc编译,无保护运行:

$ gcc 1.c && ./a.out
a[0]=0
a[1]=1
a[2]=2
a[3]=3
a[4]=4
a[5]=5
a[6]=6
a[7]=7
a[8]=8
a[9]=9

但是在平台上启用保护的情况下,SIGSEGV 应该在向数组写入“足够”(对齐)越界时生成:

$ gcc -DPROTECT_ME=1 1.c && ./a.out
a[0]=0
a[1]=1
a[2]=2
a[3]=3
a[4]=4
a[5]=5
The process had written to a bad place
Aborted (core dumped)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM