我尝试使用动态生成的代码做一些讨厌的hacky事情,我希望操作系统在遇到未知的操作码时向我发送SIGILL。这将让我添加一层关于我的程序的元信息等等。
然而,对于我的小测试程序,似乎OS不发送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;
}
答案 0 :(得分: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下尝试memalign
,valloc
,如果两者都不起作用,只需使用常规malloc
并为返回的指针添加足够的字节,使其对齐:-)。
答案 1 :(得分:0)
我意识到这是旧的,但如果其他人试图强制生成SIGILL,那么另一种选择是使用内联汇编,如下所示:
asm(".byte 0x0f, 0x0b");
或
asm("ud2");