我该如何强制发送SIGILL信号给我的程序?

4
我想做一些关于动态生成代码的恶意黑客攻击,我希望当操作系统达到未知的操作码时,它会发送一个SIGILL给我。这将让我为我的程序添加元信息层等等。
然而,对于我的小测试程序来说,似乎操作系统没有发送SIGILL,而是发送了SIGBUS或SIGSEGV。我猜测这意味着内存所在的页面上有一个NX位被设置了。
如何让内存可执行?有什么提示吗?
以下是我的测试程序参考:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>

void SIGILL_handler(int sig)
{
    printf("Handling SIGILL\n");
}

typedef void(*FUNC)(void);

int main()
{
    signal(SIGILL, SIGILL_handler);

    int *bad = malloc(16);
    memset(bad, 255, 16);
    ((FUNC)bad)();

    printf("Returning like it's no big deal\n");

    return 0;
}
2个回答

6

mprotect是你的好帮手。它与POSIX兼容(SVr4,POSIX.1-2001),因此应该可以在OS X和Linux下工作。

int pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize == -1) {
    perror("sysconf");
    exit(1);
}

/* allocate 16 aligned pages */
void *bad = memalign(pagesize, 16 * pagesize);
if (NULL == bad) {
    fprintf("aah, out of mem :-(\n");
    exit(1);
}

if (-1 == mprotect(bad, 16 * pagesize, PROT_READ | PROT_WRITE | PROT_EXEC)) {
    perror("mprotect");
    exit(1);
}

第二次编辑:使用memalign函数可能不太兼容。在OS X和Linux上,我会尝试memalignvalloc,如果两者都不起作用,就使用常规的malloc并添加足够的字节到返回的指针中以使其对齐 :-).


3
考虑使用 mmap(3)。它可以让你在一个系统调用中分配具有适当保护位的内存,还可以避免无意中更改其他恰好位于同一页内的内存的保护位。 - Adam Rosenfield
我很好奇它是否起作用。我使用 mmap 方法,但只得到 SIGSEGV。 addr = mmap (NULL, 8, PROT_EXEC, MAP_ANONYMOUS, 0, 0); ((FUNC)addr) (); - Diwakar Sharma
@DiwakarSharma 你的内存将被清零。这意味着你将执行大量的零操作,而在英特尔上,以下指令0000 add [bx+si],al表示你将取消引用一个指针,这可能会导致SIGSEGV崩溃。要导致非法指令,您应该使用0x0F0B填充mmap的内存,这是Intel上的非法指令UD2。例如,在执行之前,可以使用*((unsigned char *)addr) = 0x0f; *((unsigned char *)addr+1) = 0x0b; - Johannes Weiss
你可能想要添加 PROT_READ - Johannes Weiss
哦,而且要写入内存,你还需要 PROT_WRITE。所以是 PROT_READ | PROT_WRITE | PROT_EXEC - Johannes Weiss

0

我知道这是老旧的,但如果有人试图强制生成SIGILL,则另一种选择是使用内联汇编,如下所示:

asm(".byte 0x0f, 0x0b");

或者

asm("ud2");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接