目前我正在使用被称为“天堂之门”的
windows / WOW64技巧,正如你们中的一些人可能知道的那样,即使在x86程序中也允许我们进入x64模式(当我测试它时我感到非常惊讶它工作!)但我知道所有
Windows版本都不支持它,所以我的代码(因为有代码)使用seh,它看起来像这样:
start: use32 ;; setup seh... call $33:.64bits_code ; specify 0x33 segment,it's that easy ;; success in x64 mode,quit seh... jmp .exit .64bits_code: use64 ;; ... use32 retf .seh_handler: use32 ;; ... xor eax,eax ; EXCEPTION_CONTINUE_EXECUTION ret .32bits_code: ; we have been called by a far call (well,indirectly,routed by a seh handler) ; HERE IS THE PROBLEM => Should i use a retf since cs and eip are on the stack,; or the exception has been triggered before pushing them??? ; "retf" or "jmp .exit"? .exit: xor eax,eax push eax call [ExitProcess]
我知道一个简单的“jmp .exit”可以解决这个问题,但我对此非常好奇
解决方法
当OS获得中断或发生故障时,它期望无论用户代码是什么,cpu都已在内核堆栈上保存了所需的状态,以便IRET可以无形地恢复正在执行的操作.
请注意,内核堆栈上的该状态不涉及“魔法”. “继续执行”仅意味着恢复rflags,cs:rip和ss:rsp的保存值并运行cs:rip最终指向的代码.
这意味着,如果没有特别涉及SEH,只考虑远程调用期间发生的任何类型的异常,实际上只有两种情况需要考虑:
>异常发生在“跳转之前”:没有被推送,内核堆栈上的状态表示我们应该通过重新启动调用指令来恢复.
>异常发生在跳转之后:cs:eip已被推,在.64bits_code标签处或之后的某处撕裂点,并且保存的状态表示要恢复,我们应跳转到64位代码.
如果cpu允许远程调用被“中间”中断,那么当OS继续执行时,将没有可能的cs:rip值产生一致的结果.例如,如果远程调用的返回地址在异常发生之前被推送但是保存的cs:rip指向远程调用指令,则最终会在堆栈上返回两个返回地址副本并且所有地狱都会松动.
现在,实际回答你的问题:它取决于操作系统告诉你发生异常的rIP的值.如果指向64位代码,则必须在堆栈上使用cs:eip,如果它指向32位代码,则可以安全地假设它尚未被推送.