• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運轉,開心的工作
            簡單、開放、平等的公司文化;尊重個性、自由與個人價值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            詳談內核三步走Inline Hook實現

            Posted on 2009-10-17 11:56 S.l.e!ep.¢% 閱讀(927) 評論(0)  編輯 收藏 引用 所屬分類: Windows WDM
            詳談內核三步走Inline?Hook實現

            (一)Inline?hook原理
            Inline?hook通俗的說就是對函數執行流程進行修改,達到控制函數過濾操作的目的。理論上我們可以在函數任何地方把原來指令替換成我們的跳轉指令,也確實有些人在inline
            的時候做的很深,來躲避inline?的檢測,前提是必須對函數的流程和指令非常熟悉,且這種深層次的inlline?不具有通用性,穩定性也是問題。本文討論的是具有通用性的兩類inline的實現。
            Inline?hook原理:解析函數開頭的幾條指令,把他們Copy到數組保存起來,然后用一個調用我們的函數的幾條指令來替換,如果要執行原函數,則在我們函數處理完畢,再執行我們保存起來的開頭幾條指令,然后調回我們取指令之后的地址執行。
            整個Inline?hook的過程就大體這樣,中間牽扯到對函數的檢查,地址的獲取就直接調用函數即可。
            本文所要討論的兩類Inline?hook都是基于上面原理。?

            說明三點:
            1、堆棧平衡是重中之重,參數壓棧也需要格外注意
            2、CR0寄存器中的WP位控制處理器是否允許往只讀內存頁寫入,為0禁用保護機制。
            3、提高中斷級別到DISPATCH_LEVEL,禁止線程切換產生的中斷
            ?????????????????????
            (二)inline?hook應用
            Inline?hook可分為兩類:
            (1)inline?導出函數,選擇ObReferenceObjectByHandle做例子。
            (2)inline?未導出函數,選擇KiInsertQueueApc做例子。
            導出函數前幾個字節可以利用windbg自己查看是什么內容,而未導出函數就需要自己解析指令確定需要hook幾個字節,其間還有很多問題需要注意。當大家真正的弄懂了我這篇文章,回頭再看inline?hook就會覺得inline也不過如此。
            下面通過2個例子來講inline?hook的使用(這部分知識網上也有很多,但都很零散不系統,本文部分思路及代碼的確參考了網上資源,有抄襲之嫌,希望讀者諒解。我一直強調“授人以魚不如授人以漁”,代碼并不重要,關鍵是思想。)
            1、inline?hook?ObReferenceObjectByHandle保護進程
            ObReferenceObjectByHandle屬于ntoskrnl.exe導出函數,在內核中調用頻繁。
            NtCreateProcess創建進程需要調用ObReferenceObjectByHandle,NtTerminateProcess需要調用ObReferenceObjectByHandle,基于這我們就可以利用Hook來保護進程同時屏蔽進程的創建。
            效果:已經運行的記事本任務管理器無法結束
            流程:
            HookObReferenceObjectByHandle------DetourMyObReferenceObjectByHa?ndle----------UnHookObReferenceObjectByHandle
            核心代碼分析如下:
            //=======================================inline?HOOK?ObReferenceObjectByHandle===========================

            //ObReferenceObjectByHandle是ntoskrnl.exe導出函數,采用HOOK前五個字節的方式

            //字節型數據??unsigned?char
            ULONG??CR0VALUE;
            BYTE??OriginalBytes[5]={0};?????????????//保存原始函數前五個字節???????????
            BYTE?JmpAddress[5]={0xE9,0,0,0,0};???????//跳轉到HOOK函數的地址

            extern?POBJECT_TYPE?*PsProcessType;

            NTKERNELAPI?NTSTATUS?ObReferenceObjectByHandle(
            ?????????????????????????
            ?????????????????????????IN?HANDLE??Handle,
            ?????????????????????????IN?ACCESS_MASK??DesiredAccess,
            ?????????????????????????IN?POBJECT_TYPE??ObjectType??OPTIONAL,
            ?????????????????????????IN?KPROCESSOR_MODE??AccessMode,
            ?????????????????????????OUT?PVOID??*Object,
            ?????????????????????????OUT?POBJECT_HANDLE_INFORMATION??HandleInformation??OPTIONAL
            ?????????????????????????
            ?????????????????????????);

            //HOOK函數

            NTSTATUS?DetourMyObReferenceObjectByHandle(
            ???????????????????????
            ???????????????????????IN?HANDLE??Handle,???????????
            ???????????????????????IN?ACCESS_MASK??DesiredAccess
            ???????????????????????IN?POBJECT_TYPE??ObjectType??OPTIONAL,?
            ???????????????????????IN?KPROCESSOR_MODE??AccessMode,
            ???????????????????????OUT?PVOID??*Object,
            ???????????????????????OUT?POBJECT_HANDLE_INFORMATION??HandleInformation??OPTIONAL);

            //

            //hook流程?HookObReferenceObjectByHandle---DetourMyObReferenceObjectByHandle---UnHookObReferenceObjectByHandle

            void??HookObReferenceObjectByHandle()

            {
            ??
            ??//賦值前面定義的數組
            ??KIRQL?Irql;
            ??KdPrint(("[ObReferenceObjectByHandle]?:0x%x",ObReferenceObjectByHandle));??//地址驗證
            ??//保存函數前五個字節內容
            ??RtlCopyMemory(OriginalBytes,(BYTE?*)ObReferenceObjectByHandle,5);
            ??//保存新函數五個字節之后偏移
            ??*(ULONG?*)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5);
            ??//開始inline?hook
            ??//關閉內存寫保護
            ??_asm
            ????
            ??{
            ????push?eax
            ??????
            ??????mov?eax,?cr0?
            ??????mov?CR0VALUE,?eax?
            ??????and?eax,?0fffeffffh??
            ??????mov?cr0,?eax
            ??????pop?eax
            ??}
            ??
            ??//提升IRQL中斷級
            ??Irql=KeRaiseIrqlToDpcLevel();
            ??//函數開頭五個字節寫JMP?
            ??RtlCopyMemory((BYTE?*)ObReferenceObjectByHandle,JmpAddress,5);
            ??//恢復Irql
            ??KeLowerIrql(Irql);
            ??//開啟內存寫保護
            ??
            ??__asm
            ????
            ??{???????
            ????
            ????push?eax
            ??????
            ??????mov?eax,?CR0VALUE?
            ??????
            ??????mov?cr0,?eax
            ??????
            ??????pop?eax
            ??????
            ??}
            ??
            }



            _declspec?(naked)?NTSTATUS?OriginalObReferenceObjectByHandle(IN?HANDLE??Handle,
            ???????????????????????????????
            ???????????????????????????????IN?ACCESS_MASK??DesiredAccess,
            ???????????????????????????????
            ???????????????????????????????IN?POBJECT_TYPE??ObjectType??OPTIONAL,
            ???????????????????????????????
            ???????????????????????????????IN?KPROCESSOR_MODE??AccessMode,
            ???????????????????????????????
            ???????????????????????????????OUT?PVOID??*Object,
            ???????????????????????????????
            ???????????????????????????????OUT?POBJECT_HANDLE_INFORMATION??HandleInformation??OPTIONAL)
            ???????????????????????????????
            {
            ??
            ??_asm
            ????
            ??{???
            ????
            ????mov?edi,edi
            ??????push?ebp
            ??????mov?ebp,esp
            ??????mov?eax,ObReferenceObjectByHandle
            ??????add?eax,5
            ??????jmp?eax????????????????
            ??????
            ??}
            ??
            }


            NTSTATUS?DetourMyObReferenceObjectByHandle(
            ???????????????????????
            ???????????????????????IN?HANDLE??Handle,
            ???????????????????????
            ???????????????????????IN?ACCESS_MASK??DesiredAccess,
            ???????????????????????
            ???????????????????????IN?POBJECT_TYPE??ObjectType??OPTIONAL,
            ??????????????????
            ???????????????????????IN?KPROCESSOR_MODE??AccessMode,
            ???????????????????????
            ???????????????????????OUT?PVOID??*Object,
            ???????????????????????
            ???????????????????????OUT?POBJECT_HANDLE_INFORMATION??HandleInformation??OPTIONAL)
            ???????????????????????
            {
            ??
            ??NTSTATUS?status;
            ??
            ??//調用原函數
            ??
            ??status=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);
            ??
            ??if((status==STATUS_SUCCESS)&&(DesiredAccess==1))
            ????
            ??{???
            ????
            ????if(ObjectType==?*PsProcessType)
            ??????
            ????{
            ??????
            ??????if(?_stricmp((char?*)((ULONG)(*Object)+0x174),"notepad.exe")==0)
            ????????
            ??????{???
            ????????
            ????????ObDereferenceObject(*Object);
            ????????
            ????????return?STATUS_INVALID_HANDLE;
            ????????
            ??????}
            ??????
            ????}
            ????
            ??}
            ??
            ??return?status;
            ??
            }



            void?UnHookObReferenceObjectByHandle()

            {
            ??
            ??//把五個字節再寫回到原函數
            ??
            ??KIRQL?Irql;
            ??
            ????//關閉寫保護
            ??
            ??_asm
            ????
            ??{
            ????
            ????push?eax
            ??????
            ??????mov?eax,?cr0?
            ??????
            ??????mov?CR0VALUE,?eax?
            ??????
            ??????and?eax,?0fffeffffh??
            ??????
            ??????mov?cr0,?eax
            ??????
            ??????pop?eax
            ??????
            ??}
            ??
            ????//提升IRQL到Dpc
            ??
            ????Irql=KeRaiseIrqlToDpcLevel();
            ??
            ??RtlCopyMemory((BYTE?*)ObReferenceObjectByHandle,OriginalBytes,5);
            ??
            ??KeLowerIrql(Irql);
            ??
            ????//開啟寫保護
            ??
            ??__asm
            ????
            ??{???????
            ????
            ????????push?eax
            ??????mov?eax,?CR0VALUE?
            ??????mov?cr0,?eax
            ??????
            ??????pop?eax
            ??????
            ??}
            }

            驅動加載后,結束記事本程序如下:
            ?
            ????(圖?一)

            詳細分析:
            1、ObReferenceObjectByHandle分析
            NTSTATUS?
            ??ObReferenceObjectByHandle(
            ????IN?HANDLE??Handle,
            ????IN?ACCESS_MASK??DesiredAccess,
            ????IN?POBJECT_TYPE??ObjectType??OPTIONAL,
            ????IN?KPROCESSOR_MODE??AccessMode,
            ????OUT?PVOID??*Object,
            ????OUT?POBJECT_HANDLE_INFORMATION??HandleInformation??OPTIONAL
            ????);
            函數原型如上,由句柄獲取對象指針,函數返回值:
            STATUS_SUCCESS????????????????????????調用成功
            STATUS_OBJECT_TYPE_MISMATCH????????
            STATUS_ACCESS_DENIED?????????????????權限不夠
            STATUS_INVALID_HANDLE????????????????無效句柄?????????

            調用NtTerminateProcess需要調用ObReferenceObjectByHandle,因此我們通過對函數返回值進程修改來達到保護進程。但是NtCreateProcess(最終調用的PspCreateProcess)同樣調用這個函數,如果不加區分的話,創建進程同樣被禁止了,那么如何區分到底是誰在調用呢。參考WRK,我發現可以通過第二個參數DesiredAccess來判別,創建進程和結束進程第二個參數明顯不同,PROCESS_CREATE_PROCESS和PROCESS_TERMINATE,問題就解決了。
            PspCreateProcess位于?WRK-v1.2\base\ntos\ps\create.c
            調用ObReferenceObjectByHandle代碼:
            Status?=?ObReferenceObjectByHandle?(ParentProcess,
            ????????????????????????????????????????????PROCESS_CREATE_PROCESS,
            ????????????????????????????????????????????PsProcessType,
            ????????????????????????????????????????????PreviousMode,
            ????????????????????????????????????????????&Parent,
            ????????????????????????????????????????????NULL);
            NtTerminateProcess位于?WRK-v1.2\base\ntos\ps\psdelete.c
            調用ObReferenceObjectByHandle代碼:
            st?=?ObReferenceObjectByHandle?(ProcessHandle,
            ????????????????????????????????????PROCESS_TERMINATE,
            ????????????????????????????????????PsProcessType,
            ????????????????????????????????????KeGetPreviousModeByThread(&Self->Tcb),
            ????????????????????????????????????&Process,
            ????????????????????????????????????NULL);
            DesiredAccess參數說明:
            #define?PROCESS_TERMINATE?????????(0x0001)?//?winnt
            #define?PROCESS_CREATE_THREAD?????(0x0002)?//?winnt
            #define?PROCESS_SET_SESSIONID?????(0x0004)?//?winnt
            #define?PROCESS_VM_OPERATION??????(0x0008)?//?winnt
            #define?PROCESS_VM_READ???????????(0x0010)?//?winnt
            #define?PROCESS_VM_WRITE??????????(0x0020)?//?winnt
            //?begin_ntddk?begin_wdm?begin_ntifs
            #define?PROCESS_DUP_HANDLE????????(0x0040)?//?winnt
            //?end_ntddk?end_wdm?end_ntifs
            #define?PROCESS_CREATE_PROCESS????(0x0080)?//?winnt
            #define?PROCESS_SET_QUOTA?????????(0x0100)?//?winnt
            #define?PROCESS_SET_INFORMATION???(0x0200)?//?winnt
            #define?PROCESS_QUERY_INFORMATION?(0x0400)?//?winnt
            #define?PROCESS_SET_PORT??????????(0x0800)
            #define?PROCESS_SUSPEND_RESUME????(0x0800)?//?winnt

            2、函數調用說明
            C語言中我們調用一個函數就直接寫函數名就可以,但是實際是進行了下面的操作:
            把函數參數壓入堆棧,壓入函數返回地址,調用函數,為新函數開辟堆棧空間申請局部變量,
            恢復堆棧保持堆棧平衡
            (_stdcall調用方式)匯編代碼就是:
            Push?參數4
            Push?參數3
            Push?參數2
            Push?參數1
            Call??函數??;call指令同時完成2個操作,一是把返回地址壓入堆棧,二跳轉到調用函數入口地址

            Push??ebp
            Mov?ebp,esp
            Sub??esp,?XX??;開辟棧幀空間
            ……
            Add??esp?,XX
            Pop?ebp
            Retn??????????;恢復堆棧平衡
            堆棧詳細情況:
            ESP
            局部變量





            EBP
            返回地址
            參數1
            參數2
            參數3
            參數4
            堆棧是由高地址到低地址。
            參數就通過EBP來去,四字節對齊的

            參數4----------------------EBP+0x14
            參數3----------------------EBP+0x10
            參數2----------------------EBP+0xc
            參數1---------------------?EBP+0x8
            局部變量則通過Ebp-XX來獲取

            因此inline的時候要時刻考慮堆棧平衡,破壞了堆棧平衡就會導致函數崩潰。
            我通常inline?hook的思路就是三步走:
            HOOK函數-----DetourMy處理函數----------UnHook函數
            處理函數中對返回結果或者中間數據進行修改處理,然后調用原始函數。由于在我們處理的時候原始函數已經被hook了,所以我自己構造了一個原始函數,但是由于參數在我們hook前已經壓人堆棧了,所以這里我們不用重新開辟棧幀,因此聲名函數類型為_declspec?(naked)
            。有人就會問那么你調用處理函數的時候,參數不是重復壓棧了,這里請注意,我們是通過JMP方式跳轉到我們處理函數入口地址的,而不是Call的形式,所以并沒有執行上面所說的函數調用過程,參數仍然是原始函數的。也就是說在真個inline?hook過程中我們不能破壞原始棧幀的EBP。

            關于函數調用很棧幀的相關聯系可能比較難理解,我也在盡肯能的用通俗的話來解釋清楚,有什么不理解的地方或者個人見解歡迎大家跟我交流。

            2、inline?hook?KiInsertQueueApc對抗插APC殺進程
            KiInsertQueueAPc為內核未導出函數,我下面提供的代碼可以作為未導出函數inline的通用模板來使用,大家根據自己需要進行修改,基于inline?ObReferenceObjectByHandle已經把原理分析了,這部分我就不詳加分析,仍然采用的但不走,Hook函數---DetourMy函數---UnHook函數
            直接看核心代碼:
            //===================inline?hook?KiInsertQueueApc====================
            //KiInsertQueueApc為內核未導出函數,可以從導出函數KeInsertQueueApc定位
            //修改KiInsertQueueApc開頭5字節
            //處理函數思路:apc-->kthread---apc_state--eprocess--進程名字
            //HookKiInsertQueueApc---DetourMyKiInsertQueueApc---UnHookKiInsertQueueApc
            ULONG?CR0VALUE;
            ULONG?g_KiInsertQueueApc;
            ???????????
            BYTE?JmpAddress[5]={0xE9,0,0,0,0};???????//跳轉到HOOK函數的地址
            BYTE??OriginalBytes[5]={0};?????????????//保存原始函數前五個字

            VOID?FASTCALL?DetourMyKiInsertQueueApc(IN?PKAPC?Apc,IN?KPRIORITY?Increment);

            VOID?WPOFF()
            {
            ??_asm
            ????
            ??{
            ????
            ????push?eax
            ??????
            ??????mov?eax,?cr0?
            ??????
            ??????mov?CR0VALUE,?eax?
            ??????
            ??????and?eax,?0fffeffffh??
            ??????
            ??????mov?cr0,?eax
            ??????
            ??????pop?eax
            ??????cli
            ??????
            ??};
            ??
            }

            VOID?WPON()
            {
            ????__asm
            ????
            ??{???????
            ????sti
            ????push?eax
            ??????
            ??????mov?eax,?CR0VALUE?
            ??????
            ??????mov?cr0,?eax
            ??????
            ??????pop?eax
            ??????
            ??};
            }
            //1、獲取KiInsertQueueApc地址
            ULONG?GetFunctionAddr(?IN?PCWSTR?FunctionName)?????//PCWSTR常量指針,指向16位UNICODE
            {
            ??UNICODE_STRING?UniCodeFunctionName;
            ??RtlInitUnicodeString(?&UniCodeFunctionName,?FunctionName?);
            ??return?(ULONG)MmGetSystemRoutineAddress(?&UniCodeFunctionName?);???
            }

            ULONG?GetKiInsertQueueApcAddr()
            {
            ??ULONG?sp_code1=0x28,sp_code2=0xe8,sp_code3=0xd88a;??//特征碼,sp_code3?windbg顯示錯誤,應該為d88a
            ??ULONG?address=0;
            ??PUCHAR?addr;
            ??PUCHAR?p;
            ??addr=(PUCHAR)GetFunctionAddr(L"KeInsertQueueApc");
            ??for(p=addr;p<p+PAGE_SIZE;p++)
            ??{
            ????if((*(p-1)==sp_code1)&&(*p==sp_code2)&&(*(PUSHORT)(p+5)==sp_code3))
            ????{
            ??????address=*(PULONG)(p+1)+(ULONG)(p+5);
            ??????break;
            ????}
            ??}
            ??KdPrint(("[KeInsertQueueApc]?addr?%x\n",(ULONG)addr));
            ????KdPrint(("[KiInsertQueueApc]?address?%x\n",address));
            ????return?address;
            }

            VOID?HookKiInsertQueueApc()
            {???
            ??KIRQL?Irql;
            ??g_KiInsertQueueApc=GetKiInsertQueueApcAddr();
            ??KdPrint(("[KiInsertQueueApc]?KiInsertQueueApc?%x\n",g_KiInsertQueueApc));
            ????//?保存原函數的前字節內容
            ????RtlCopyMemory?(OriginalBytes,?(BYTE*)g_KiInsertQueueApc,?5);
            ??//新函數對原函數的偏移地址
            ????*(?(ULONG*)(JmpAddress?+?1)?)?=?(ULONG)DetourMyKiInsertQueueApc?-?(ULONG)g_KiInsertQueueApc?-?5;
            ????//?禁止系統寫保護,提升IRQL到DPC
            ????WPOFF();
            ????Irql?=?KeRaiseIrqlToDpcLevel();
            ????//inline?hook函數
            ??RtlCopyMemory?(?(BYTE*)g_KiInsertQueueApc,?JmpAddress,?5?);
            ????//?恢復寫保護,降低IRQL
            ????KeLowerIrql(Irql);
            ????WPON();??
            }
            //原函數
            _declspec?(naked)?VOID?FASTCALL?OriginalKiInsertQueueApc(IN?PKAPC?Apc,IN?KPRIORITY?Increment)
            {
            ??_asm
            ??{
            ????//前五個字節
            ????mov?edi,edi
            ??????push?ebp
            ??????mov?ebp,esp
            ??????
            ??????mov?eax,g_KiInsertQueueApc
            ??????add?eax,5
            ??????jmp?eax
            ??}
            }
            //處理函數
            //apc--kthread--apc_state--eprocess
            VOID?FASTCALL?DetourMyKiInsertQueueApc(IN?PKAPC?Apc,IN?KPRIORITY?Increment)
            {
            ??ULONG?thread;
            ??ULONG?process;
            ??if(MmIsAddressValid((PULONG)((ULONG)Apc+0x008)))????//地址驗證?KAPC結構+008--->kthread
            ????thread=*((PULONG)((ULONG)Apc+0x008));
            ??else
            ????return?;
            ??if(MmIsAddressValid((PULONG)((ULONG)thread+0x044)))?//kthread+30-->KAPC_STATE+10-->eprocess
            ????process=*((PULONG)((ULONG)thread+0x044));
            ??else
            ????return?;
            ????if(MmIsAddressValid((PULONG)((ULONG)process+0x174)))??//eprocess+174---->進程名字
            ??{
            ????if((_stricmp((char?*)((ULONG)process+0x174),"notepad.exe")==0)&&(Increment==2))
            ????{
            ??????return?;

            ????}
            ????else
            ??????OriginalKiInsertQueueApc(Apc,Increment);

            ??}
            ??else
            ????return;
            }

            //卸載函數
            VOID?UnHookKiInsertQueueApc()
            {
            ??KIRQL?Irql;
            ????WPOFF();
            ????Irql?=?KeRaiseIrqlToDpcLevel();
            ????//inline?hook函數
            ????RtlCopyMemory?(?(BYTE*)g_KiInsertQueueApc,?OriginalBytes,?5);
            ????//?恢復寫保護,降低IRQL
            ????KeLowerIrql(Irql);
            ????WPON();??
            }
            ?考慮到大家水平不一,對一些問題我詳細如下:
            1、特征碼的尋找
            利用windbg的kernel?debug來查找:
            uf??KeInsertQueueApc
            nt!KeInsertQueueApc+0x3b:
            804e6d0a?8b450c??????????mov?????eax,dword?ptr?[ebp+0Ch]
            804e6d0d?8b5514??????????mov?????edx,dword?ptr?[ebp+14h]
            804e6d10?894724??????????mov?????dword?ptr?[edi+24h],eax
            804e6d13?8b4510??????????mov?????eax,dword?ptr?[ebp+10h]
            804e6d16?8bcf????????????mov?????ecx,edi
            804e6d18?894728??????????mov?????dword?ptr?[edi+28h],eax
            804e6d1b?e8523fffff????????call????nt!KiInsertQueueApc?(804dac72)
            804e6d20?8ad8?(錯誤)??mov?????bl,al
            特征碼就是sp_code1=0x28?sp_code2=0xe8?sp_code3=0xd88a(windbg顯示有誤,應該是d88a

            這種方法就是通過已導出函數定位未導出函數通常使用的方法,具有通用性。詳細見代碼。

            2、取EPRocess的過程
            Apc-----kthread-----apc_state—eprocess
            dt??_KAPC?????????????偏移0x008指向KTHREAD
            dt??_KTHREAD?????????偏移0x034指向KAPC_STATE
            dt??_KAPC_STATE??????偏移0x10指向EPROCESS
            dt??_EPROCESS?????????偏移0x174指向進程名


            (三)總結
            ?很多人覺得inline?hook比較難,處理起來很麻煩。但是我相信看完我這篇文章,你一定不會這么認為了,inline?hook其實只要細心,注意細節跟別的hook沒什么兩樣。本人采用的三步走inline?hook做到了把inline簡單化,同時有保證了堆棧的平衡。
            ?由于代碼采用的硬編碼,編譯環境是sp3+VMware,請根據自己操作系統自行修改。歡迎讀者跟我交流。
            久久久久久久综合日本亚洲| 性欧美丰满熟妇XXXX性久久久| 久久精品日日躁夜夜躁欧美 | 99久久国产综合精品五月天喷水| 久久天天躁狠狠躁夜夜网站| 狠狠色丁香婷婷久久综合五月| 一本色综合久久| 久久精品国产免费观看三人同眠| 99久久精品免费看国产一区二区三区 | 中文成人无码精品久久久不卡 | 2021精品国产综合久久| 99久久99久久久精品齐齐| 97久久天天综合色天天综合色hd| 精品久久久久久亚洲| 久久久久99精品成人片三人毛片 | 无码乱码观看精品久久| 亚洲人成无码www久久久| 性做久久久久久久久浪潮| 狠狠色丁香婷婷久久综合五月| 四虎国产精品成人免费久久| 一本久道久久综合狠狠躁AV| 97久久婷婷五月综合色d啪蜜芽| 久久精品亚洲中文字幕无码麻豆| 精品国产一区二区三区久久| 久久亚洲欧洲国产综合| 久久精品国产99久久久古代| 91精品国产色综合久久| 午夜精品久久久久久久无码| 精品国产一区二区三区久久久狼| 丁香五月综合久久激情| 精品久久久中文字幕人妻| 久久99精品国产麻豆宅宅| 欧美久久亚洲精品| 久久国产乱子伦精品免费强| 综合久久一区二区三区 | 久久国产精品无码网站| 精品多毛少妇人妻AV免费久久| 久久久九九有精品国产| 99久久国产综合精品女同图片| 亚洲国产天堂久久综合网站| 伊人色综合久久天天人手人婷|