首页 > 编程知识 正文

win10动态屏保,win7消息队列安装

时间:2023-05-05 04:56:06 阅读:156413 作者:4758

Windows x64将unwind信息0x000x01添加到动态代码中

0x00

64位程序堆栈的回溯与32位大不相同,调试器和RtlCaptureStackBackTrace不再使用ebp链遍历整个堆栈,而只使用prolog信息回溯堆栈通常的C/C函数的prolog信息在编译时被生成并记录在PE64文件的unwind信息中,另外与当前函数相对应的异常处理函数也被追加到unwind信息的末尾。 因此,对于不存在unwind信息的函数,异常处理进程无法找到其异常处理函数,无法正常展开堆栈并找到调用方,无法找到上层异常处理函数并跳过SEH的处理链,捕获异常最终程序崩溃了,但没有痕迹。 这里的可能性很大是因为x64的堆栈在展开时具有容错能力。 具体请参考以前的文章“windows x64异常发布流程”

因此,在很多手写汇编中,虽然崩溃了,但是发现不能正常生成dump,对错误检查产生了很大的影响。

当然,添加对方写程序集的unwind信息比较简单。 以MASM汇编器为例,可以通过添加. PUSHREG, ALLOCSTACK告诉汇编器相应的栈操作。 具体来说,我知道Directives Reference。 当然,在手写汇编过程中,请务必遵循x64 prolog规范。 否则,展开就会出错。 具体而言,请参阅x64软件转换器。

对于已编译的函数,可以在windbg中使用. fnent命令显示unwind信息。 在kernelbase上! 以ReadFile为例,以下是其unwind信息。

对于0x01动态生成的代码,无法通过手写程序集的方法生成unwind信息。 在这里,有两种方法可以比较容易地实现unwind信息的生成。

第一个是根据x64 exception handling的描述,手动构造结构体。 一般来说,只要不是非常复杂的prolog,就比较容易实现。

另一种方法比较巧妙,在很多情况下,我们生成的动态代码都有基础的汇编代码。 动态代码的结构首先从基础的汇编代码中复制,然后修改其中的一些变量形成新代码。 这种东西一般在hook引擎上使用。 在这种情况下,可以根据第一部分将unwind信息添加到程序集中,然后将其复制到动态代码中使用。

以下是添加到easyhook动态代码中的unwind信息的代码。

typedef union _ unwind _ code { struct } ucharcodeoffset; UCHAR UnwindOp : 4; UCHAR OpInfo : 4; (; 短帧偏移; } UNWIND_CODE,* PUNWIND_CODE; typedef struct _ unwind _ info { uchar version :3; UCHAR Flags : 5; UCHAR SizeOfProlog; UCHAR CountOfCodes; UCHAR FrameRegister : 4; UCHAR FrameOffset : 4; //For alignment purposes,thisarrayalwayshasanevennumberofentries,andthefinalentryispotentiallyunusedunwind _ codeunwid staticvoidstopme { } static exception _ dispositionjustcontinuesearch (p exception _ recordexceptionrecord,ulong 64 estable pdispatcher _ contextdispatchercontext ) {return ExceptionContinueSearch; }静态void stop metoo () uchargetunwindcodearraycnt (uchar UC ) ) return((UC1 )1) 1; } ulonggetunwindinfolength (dword 64dw image base,PRUNTIME_FUNCTION pFuncEntry ) if (! pfunc entry (返回0; pun wind _ info pinfo=(pun wind _ info ) ) dwimagebasepfuncentry-unwindinfoaddress; ulongulsum=field _ offset (unwind _ info,UnwindCode ); _ _ try { uchar CNT=getunwindcodearraycnt (pinfo-count of codes ); ulsum=CNT*sizeof(Unwin

D_CODE); ulSum += sizeof(ULONG) * 2; } __except (EXCEPTION_EXECUTE_HANDLER) { return 0; } return ulSum;}ULONG GetExceptionFuncLength(){ auto dwSM = (DWORD64)StopMe; auto dwSM2 = (DWORD64)StopMeToo; auto excpFunc = (DWORD64)JustContinueSearch; DWORD dwDiff = 0; if (dwSM > excpFunc) { dwDiff = dwSM - excpFunc; } else if (dwSM2 > excpFunc) { dwDiff = dwSM2 - excpFunc; } if (!dwDiff || (dwDiff > 0x20)) { return 0x20; } return dwDiff;}void LhBuildUnwindInfoForTrampoline(LOCAL_HOOK_INFO* pHook,unsigned char* uc,int nSize){#ifndef _WIN64 return;#endif if (!uc || !nSize) return; if (!pHook || !pHook->Trampoline) { return; } DWORD64 dwImageBase = 0; auto pOriFuncEnt = RtlLookupFunctionEntry((ULONG_PTR)GetTrampolinePtr(), &dwImageBase, nullptr); if (!pOriFuncEnt) { return; }DWORD64 dwPreImageBase = 0;auto pFuncEntry = RtlLookupFunctionEntry((ULONG_PTR)pHook->Trampoline, &dwPreImageBase, nullptr);if (pFuncEntry) {RtlDeleteFunctionTable(pFuncEntry);} auto nLen = GetUnwindInfoLength(dwImageBase,pOriFuncEnt); if (!nLen) return; //ImageBase is pHook auto nTotalSize = sizeof(RUNTIME_FUNCTION) + nLen + GetExceptionFuncLength() + 10;//padding 10 bytes to if (nTotalSize > nSize) return; memset(uc, 0, nTotalSize); PRUNTIME_FUNCTION pRF = (PRUNTIME_FUNCTION)uc; PUNWIND_INFO pInfo = (PUNWIND_INFO)(pRF + 1); pRF->BeginAddress = (DWORD64)pHook->Trampoline - (DWORD64)pHook; pRF->EndAddress = pRF->BeginAddress + GetTrampolineSize(); pRF->UnwindInfoAddress = (DWORD64)pInfo - (DWORD64)pHook; PUNWIND_INFO pOriUnwindInfo = (PUNWIND_INFO)(dwImageBase + pOriFuncEnt->UnwindInfoAddress); memcpy(pInfo, pOriUnwindInfo, FIELD_OFFSET(UNWIND_INFO, UnwindCode) + pOriUnwindInfo->CountOfCodes * sizeof(UNWIND_CODE)); auto nIdx = FIELD_OFFSET(UNWIND_INFO, UnwindCode) + GetUnwindCodeArrayCnt(pOriUnwindInfo->CountOfCodes) * sizeof(UNWIND_CODE); auto pHandlerVA = (ULONG*)((unsigned char*)pInfo + nIdx); auto pExceptFunc = pHandlerVA + 2; *pHandlerVA = (ULONG)((DWORD64)pExceptFunc - (DWORD64)pHook); *(pHandlerVA + 1) = 1; memcpy(pExceptFunc, JustContinueSearch, GetExceptionFuncLength()); pInfo->Flags |= UNW_FLAG_EHANDLER; RtlAddFunctionTable(pRF, 1, (DWORD64)pHook);}

对以上代码有几个点需要解释下:

从第一节列出的文档中可以知道,unwind信息是包含在RUNTIME_FUNCTION之中的,所以我们也要填充RUNTIME_FUNCTION结构;RUNTIME_FUNCTION 与 unwind信息中的地址都是VA与ImageBase的差值,并且差值要可以用DWORD表示。其中ImageBase我们可以随便定,只要其小于所有我们需要索引的结构的地址即可,并且在 RtlAddFunctionTable 第三个参数中传入ImageBase地址。由此,我们只要分配足够容纳动态代码,RUNTIME_FUNCTION ,unwind信息等的Buffer,并将其首地址作为ImageBase使用即可。LhBuildUnwindInfoForTrampoline中第一个参数就是这个作用;LhBuildUnwindInfoForTrampoline中的第二个参数是存放RUNTIME_FUNCTION与unwind信息的起始地址,其在ImageBase代表的buffer范围之内;第三个参数是uc可用的最大的长度;GetTrampolinePtr()返回手写汇编的地址,对其调用 RtlLookupFunctionEntry 可以获取其 RUNTIME_FUNCTION 信息,从而可以将其拷贝到我们构造的 RUNTIME_FUNCTION 中;GetUnwindCodeArrayCnt返回值都是偶数,这个是prolog规范要求的,具体可以见第一节的链接。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。