本帖最后由 SilenceNet 于 2010-12-10 13:44 编辑
typedef struct
{
FARPROC funcaddr; //函数地址
byte olddata[5]; //原数据
byte newdata[5]; //新数据
}HOOK_INFO;
HOOK_INFO hookInfo; //勾子信息
typedef NTSTATUS(NTAPI *pRtlDispatchException)(PEXCEPTION_RECORD pExcptRec,CONTEXT * pContext);
pRtlDispatchException RtlDispatchException=NULL;
VOID NTAPI KiUserExceptionDispatcher_BT(PEXCEPTION_RECORD pExcptRec,PCONTEXT pContext)
{
/*在这里面可以处理任何一个自己引发的异常,硬件断点单步这些都成,完全可以代替Debug API中的调试事件,但千万不能有错误,否则在这里是个死循环,如果自己处理完了,直接调用:ZwContinue就可以了,本函数,以及本函数中调用的另外两个函数,都可能不会返回,本函数是绝对不会返回,返回的话程序肯定也跑飞了,也不需要恢复HOOK啥的,
*/
/*这下面是函数原有结构,自己不处理的异常交给下面的,下面这两个函数未导出,需GG一下ntdll.lib库*/
DWORD retValue;
if (RtlDispatchException(pExcptRec,pContext))
{
retValue=::ZwContinue( pContext,0);
}else{
retValue=::ZwRaiseException(pExcptRec,pContext,0);
}
::AfxMessageBox("BT居然执行到这来了");
}
VOID NTAPI KiUserExceptionDispatcher(PEXCEPTION_RECORD pExcptRec,PCONTEXT pContext)
{
//这里面什么都不做,只作跳板用.
//有关这个跳板疑问的见:http://blog.csdn.net/SilenceNet/archive/2010/12/04/6054254.aspx
__asm
{
;push [esp+4]
;push [esp+4]
call KiUserExceptionDispatcher_BT
}
}
DWORD GetRDEAddress()
{
/*取Win7 64位的RtlDispatchException地址,ntdll基址+0x5865B */
DWORD dwBase=NULL;
dwBase=GetModuleBaseFromName(::GetCurrentProcessId(),"ntdll.dll"); //获取ntdll的基址
if(dwBase==NULL) return NULL;
dwBase=0x5865B+dwBase; //计算函数地址
return dwBase;
}
//初始化HOOK SEH
BOOL InitHookSEH()
{
::RtlZeroMemory(&hookInfo,sizeof(hookInfo));
HMODULE hModule = LoadLibraryA("ntdll.dll");
hookInfo.funcaddr=::GetProcAddress(hModule,"KiUserExceptionDispatcher");
if(hookInfo.funcaddr==NULL) return FALSE;
memcpy(hookInfo.olddata, hookInfo.funcaddr, 6); //保存原API数据
hookInfo.newdata[0] = 0xe9; //写入JMP
DWORD jmpaddr = (DWORD)KiUserExceptionDispatcher - (DWORD)hookInfo.funcaddr - 5; //目标地址-当前JMP指令地址=相对地址
memcpy(&hookInfo.newdata[1], &jmpaddr, 5);
DWORD dwOldProtect;
if(!::VirtualProtect((LPVOID)hookInfo.funcaddr,5,PAGE_EXECUTE_READWRITE,&dwOldProtect)) return FALSE;
::memcpy(hookInfo.funcaddr,hookInfo.newdata,5); //写入数据
DWORD dwBase=GetRDEAddress(); //取得ntdll中的未导出函数RtlDispatchException地址:
if(dwBase==NULL) return FALSE;
RtlDispatchException=(pRtlDispatchException)dwBase;
return TRUE;
}
--------------------------------------------------------------------
//可以在这价代码里面测试一下单步
CONTEXT ct;
ct.ContextFlags=CONTEXT_FULL;
GetThreadContext(hT,&ct)
ct.EFlags|=0x100;
SetThreadContext(hT,&ct)
// SEH将收到:EXCEPTION_SINGLE_STEP异常 //设置单步后,把自己的异常处理完,调用ZwContinue,紧接着后面一条指令就会引发EXCEPTION_SINGLE_STEP异常,这个异常中什么都不要处理,直接调用ZwContinue就行了,好玩的话就一直设置单步{:2_27:} , |