关于同一条消息有other个问题,但当我尝试执行一系列调用某些函数的机器代码时,我似乎特意遇到了这个问题。在我的情况下,我调用exit(0),它在同一程序中被调用为典型的C时工作正常。但是,作为练习,我将EIP设置为某些机器代码的地址(您可以称之为“shellcode”),例如
const char code[] =
"\x6A\x00" // push 0"
"\xFF\x15\x00\x00\x00\x00" //system call, 'read access violation': call dword ptr [__imp__exit]
"\x5D" //pop ebp
"\xC3"; //ret
我将收到消息“访问冲突读取位置0x00000000。”。 “\ x6A \ x00”指令将运行,但对exit(0)的调用将抛出此异常。
这是使用/ GS-在VS2010中编译的C,并且还运行具有执行权限的“shellcode”,但是仍然存在某种不可执行的内存或堆栈保护?为什么这条指令会导致错误?
int main()
{
void *exec = VirtualAlloc(0, sizeof(code), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, code, sizeof(code));
//EIP = exec in debug->immediate
exit(0);
}
答案 0 :(得分:1)
如果你反汇编你的shellcode,你会得到类似的东西(AT& T语法):
00000000 <_code>:
0: 6a 00 push $0x0
2: ff 15 00 00 00 00 call *0x0
8: 5d pop %ebp
9: c3 ret
call
指令通过地址0进行内存间接跳转:它从内存地址0加载目标并跳转到该位置。由于内存地址0无效(在极少数情况下它可能有效,但这也不例外),会导致访问冲突。
通常,在编译C代码时,外部函数的跳转会被占位符替换,并且链接器会在链接时填充这些占位符。当您在运行时生成shellcode时,您没有链接器的帮助,因此您必须自己完成。您需要弄清楚您想要的目标地址是什么,并直接在shellcode中填写,如果您不确切知道shellcode将在哪个地址执行,可能会使用一些与位置无关的技巧。