作者:綠林科技
QQ:1473656864
大家調試的時候都可以知道,盛*大遊戲(泡泡堂)的外殼是Themida,可以用OD創建進程,但不能附加遊戲,本來想只用一個驅動文件來過保護的,但在Win 7的HOOK裏判斷進程名,會出問題,導致系統奔潰,而這在Win XP卻不會,個人比較鬱悶!
所以用了另一個辦法來判斷指定進程,就是進程的PID,這個比較唯一。Ring 3創建進程,並掛起進程,然後安裝驅動,向驅動傳遞遊戲的進程PID,然後驅動就執行HOOK,通過進程PID來判斷是否要跳轉。
功能,可以用CE打開進程,讀取,修改進程,用CE的調試器附加進程。
最後說明下,這個必須在Win 7下,且你的SSDT表是乾淨的,沒有騰訊的QQProtect.sys這個驅動文件在執行,SSDT沒有被HOOK。可以用安全工具把QQProtect.sys由系統引導啓動設置成手動啓動。
下面貼上代碼:
Ring 3層的MFC程序:
安裝驅動的函數:
void CDriverProtectDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知處理程序代碼
InstallCWinThread = AfxBeginThread(InstallDriverThread,this);
}
安裝驅動的函數:
BOOL CDriverProtectDlg::LoadNTDriver(wchar_t* lpszDriverName, wchar_t* lpszDriverPath)
{
wchar_t szDriverImagePath[256];
::GetFullPathNameW(strPath,256,szDriverImagePath,NULL);
BOOL bRet = FALSE;
SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK=NULL;//NT驅動程序的服務句柄
hServiceMgr = ::OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if( hServiceMgr == NULL )
{
m_DriverINFORMATION.SetWindowTextW(L"打開服務失敗!");
bRet = FALSE;
goto BeforeLeave;
}
else
{
////OpenSCManager成功
m_DriverINFORMATION.SetWindowTextW(L"OpenSCManager成功!");
}
//創建驅動所對應的服務
hServiceDDK = CreateServiceW(hServiceMgr,lpszDriverName,lpszDriverName,SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_IGNORE,szDriverImagePath,NULL,NULL,NULL,NULL,NULL);
DWORD dwRtn;
//判斷服務是否失敗
if (hServiceDDK == NULL)
{
dwRtn = GetLastError();
if (dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS)
{
//由於其他原因創建服務失敗
strError.Format(L"%d",dwRtn);
m_DriverINFORMATION.SetWindowTextW(L"由於其他原因創建服務失敗!" + strError);
bRet = FALSE;
goto BeforeLeave;
}
else
{
m_DriverINFORMATION.SetWindowTextW(L"服務創建失敗,是由於服務已經創立過!");
}
// 驅動程序已經加載,只需要打開
hServiceDDK=::OpenServiceW(hServiceMgr,lpszDriverName, SERVICE_ALL_ACCESS);
if( hServiceDDK == NULL )
{
//如果打開服務也失敗,則意味錯誤
dwRtn = GetLastError();
strError.Format(L"%d",dwRtn);
m_DriverINFORMATION.SetWindowTextW(L"如果打開服務也失敗,則意味錯誤!" + strError);
bRet = FALSE;
goto BeforeLeave;
}
else
{
m_DriverINFORMATION.SetWindowTextW(L"打開服務成功!");
}
}
else
{
m_DriverINFORMATION.SetWindowTextW(L"創建服務成功!");
}
bRet= ::StartServiceW( hServiceDDK, NULL, NULL );
if( !bRet )
{
DWORD dwRtn = GetLastError();
if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )
{
strError.Format(L"%d",dwRtn);
m_DriverINFORMATION.SetWindowTextW(L"開啓此項服務失敗!");
bRet = FALSE;
goto BeforeLeave;
}
else
{
if( dwRtn == ERROR_IO_PENDING )
{
//設備被掛住
m_DriverINFORMATION.SetWindowTextW(L"設備被掛住!");
bRet = FALSE;
goto BeforeLeave;
}
else
{
//服務已經開啓
m_DriverINFORMATION.SetWindowTextW(L"打開服務失敗,因爲服務已經開啓!");
bRet = TRUE;
goto BeforeLeave;
}
}
}
bRet = TRUE;
BeforeLeave:
//離開前關閉打開的句柄
if(hServiceDDK)
{
CloseServiceHandle(hServiceDDK);
}
if(hServiceMgr)
{
CloseServiceHandle(hServiceMgr);
}
return bRet;
}
安裝驅動的線程:
// 安裝驅動的線程函數
UINT __cdecl CDriverProtectDlg::InstallDriverThread(LPVOID pParam)
{
CDriverProtectDlg* pDlg = NULL;
pDlg = (CDriverProtectDlg*)pParam;
pDlg->UpdateData(TRUE);
if (pDlg->strPath.IsEmpty())
{
AfxMessageBox(L"請選擇驅動路徑!");
return 0;
}
if (pDlg->strrGamePath.IsEmpty())
{
AfxMessageBox(L"請選擇遊戲路徑!");
return 0;
}
if (!pDlg->LoadNTDriver(L"HelloDDK",pDlg->strPath.GetBuffer()))
{
pDlg->UnloadNTDriver(L"HelloDDK");
pDlg->LoadNTDriver(L"HelloDDK",pDlg->strPath.GetBuffer());
}
HANDLE hDevice =
::CreateFileW(L"\\\\.\\HelloDDK",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL ); // no template
if (hDevice == INVALID_HANDLE_VALUE)
{
pDlg->m_DriverINFORMATION.SetWindowTextW(L"打開驅動錯誤!");
return 1;
}
DWORD Pid = pDlg->TransferProcessID(pDlg->strrGamePath.GetBuffer());
int a = (int)Pid;
UCHAR* InputBuffer = new UCHAR[a];
UCHAR* OutputBuffer= new UCHAR[a];
BOOL bRet;
DWORD dwOutput;
//輸入緩衝區作爲輸入,輸出緩衝區作爲輸出
bRet = DeviceIoControl(hDevice, IOCTL_TEST1, InputBuffer, a, OutputBuffer, a, &dwOutput, NULL);
if (bRet)
{
pDlg->m_DriverINFORMATION.SetWindowTextW(L"開啓保護成功!");
}
CloseHandle(hDevice);
delete []InputBuffer;
delete []OutputBuffer;
//AfxEndThread(0);
ResumeThread(pDlg->ProcessMainThread);
pDlg = NULL;
return 0;
}
ring 0層的驅動函數的代碼:
DeviceIoControl的派遣函數:
#pragma PAGEDCODE
NTSTATUS HelloDDKDeviceIOControl(IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
KdPrint(("Enter HelloDDKDeviceIOControl\n"));
//得到當前堆棧
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//得到輸入緩衝區大小
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
//得到輸出緩衝區大小
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
//得到IOCTL碼
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
ULONG info = 0;
switch (code)
{ // process request
case IOCTL_TEST1:
{
KdPrint(("IOCTL_TEST1\n"));
GameProcessID = (int)cbin;
//KIRQL oldirql;
//ASSERT(KeGetCurrentIrql()<=DISPATCH_LEVEL);
//KeRaiseIrql(DISPATCH_LEVEL,&oldirql);
HookNtOpenProcess();
HookNtReadVirtualMemory();
HookNtWriteVirtualMemory();
HookNtClose();
HookNtProtectVirtualMemory();
HookPsSuspendThread();
HookNtGetContextThread();
HookNtQueryPerformanceCounter();
HookNtSetContextThread();
HookKiAttachProcess();
HookNtDeviceIoControlFile();
//KeLowerIrql(oldirql);
//緩衝區方式IOCTL
//顯示輸入緩衝區數據
UCHAR* InputBuffer = (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
這個爲全局變量 int GameProcessID;
下面是繞過的鉤子函數(部分):
#include "HookNtDeviceIoControlFile.h"
#include "Function.h"
extern int GameProcessID;
int SrcNtDeviceIoControlFileAddr;
int OldCallNtDeviceIoControlFileAddr;
int NewCallNtDeviceIoControlFileAddr;
int JmpNtDeviceIoControlFileAddr;
int Index;
int NtDeviceIoControlFileAddr;
/*
0x81C7948C | 55 | push ebp |
0x81C7948D | 8BEC | mov ebp, esp |
0x81C7948F | 6A 01 | push 1 |
0x81C79491 | FF75 2C | push dword ptr [ebp+2C] |
0x81C79494 | FF75 28 | push dword ptr [ebp+28] |
0x81C79497 | FF75 24 | push dword ptr [ebp+24] |
0x81C7949A | FF75 20 | push dword ptr [ebp+20] |
0x81C7949D | FF75 1C | push dword ptr [ebp+1C] |
0x81C794A0 | FF75 18 | push dword ptr [ebp+18] |
0x81C794A3 | FF75 14 | push dword ptr [ebp+14] |
0x81C794A6 | FF75 10 | push dword ptr [ebp+10] |
0x81C794A9 | FF75 0C | push dword ptr [ebp+C] |
0x81C794AC | FF75 08 | push dword ptr [ebp+8] |
0x81C794AF | E8 BD90FBFF | call 81C32571 |
0x81C794B4 | 5D | pop ebp |
0x81C794B5 | C2 2800 | retn 28 |
*/
static __declspec(naked) void MyNtDeviceIoControlFile()
{
__asm
{
push ebp
mov ebp, esp
push 1
push dword ptr [ebp+0x2C]
push dword ptr [ebp+0x28]
push dword ptr [ebp+0x24]
push dword ptr [ebp+0x20]
push dword ptr [ebp+0x1C]
push dword ptr [ebp+0x18]
push dword ptr [ebp+0x14]
push dword ptr [ebp+0x10]
push dword ptr [ebp+0xC]
push dword ptr [ebp+0x8]
}
if (PanDuanProcessID()==GameProcessID)
{
__asm
{
jmp NewCallNtDeviceIoControlFileAddr
call OldCallNtDeviceIoControlFileAddr
jmp JmpNtDeviceIoControlFileAddr
}
}
else
{
__asm
{
call OldCallNtDeviceIoControlFileAddr
jmp JmpNtDeviceIoControlFileAddr
}
}
}
void HookNtDeviceIoControlFile()
{
char code[1]={(char)0xE8};
Index=GetFunctionIndex(ZwDeviceIoControlFile);
SrcNtDeviceIoControlFileAddr=SearchFeature(GetSSDTFunctionAddr(Index),code,1);
OldCallNtDeviceIoControlFileAddr=GetCallAddr(SrcNtDeviceIoControlFileAddr);
NewCallNtDeviceIoControlFileAddr=SrcNtDeviceIoControlFileAddr-1;
JmpNtDeviceIoControlFileAddr=SrcNtDeviceIoControlFileAddr+4;
NtDeviceIoControlFileAddr=SSDTHookEngine(Index,(int)MyNtDeviceIoControlFile);
}
void UnHookNtDeviceIoControlFile()
{
SSDTUnHookEngine(Index,NtDeviceIoControlFileAddr);
}
經研究KiAttachProcess沒有檢測
#include "HookKiAttachProcess.h"
#include "Function.h"
extern int GameProcessID;
int SrcKiAttachProcessAddr;
int KiMoveApcState;
int KiInSwapSingleProcess;
int HvlLongSpinCountMask;
int HvlEnlightenments;
int HvlNotifyLongSpinWait;
int _imp_KfLowerIrql;
int KiSwapProcess;
int SrcKeStackAttachProcessAddr;
int KeStackAttachProcessCall_1;
int KeStackAttachProcessCall_2;
int SrcKeAttachProcessAddr;
int KeAttachProcessCall_1;
static __declspec(naked) void MyKiAttachProcess()
{
// if (PanDuanProcessID()==GameProcessID)
// {
// __asm
// {
// mov edi,edi
// push ebp
// mov ebp,esp
// push ebx
// mov ebx,dword ptr [ebp+8]
// push esi
// mov esi,eax
// mov eax,dword ptr [ebp+10h]
// push edi
// lea edi,[esi+40h]
// push edi
// call KiMoveApcState
// mov ecx,dword ptr [ebp+10h]
// mov dword ptr [edi+4],edi
// mov dword ptr [edi],edi
// lea eax,[esi+48h]
// mov dword ptr [eax+4],eax
// mov dword ptr [eax],eax
// lea eax,[esi+170h]
// mov byte ptr [esi+54h],0
// mov byte ptr [esi+55h],0
// mov byte ptr [esi+56h],0
// cmp ecx,eax
// jne KiAttachProcess_52
//KiAttachProcess_3f:
// mov dword ptr [esi+168h],eax
// mov dword ptr [esi+16Ch],edi
// mov byte ptr [esi+134h],1
//KiAttachProcess_52:
// push 8
// pop eax
// lea edx,[ebx+74h]
// lock xadd dword ptr [edx],eax
// mov dword ptr [ebp+8],eax
// mov eax,dword ptr [ebp+8]
// test al,7
// jne KiAttachProcess_76
//KiAttachProcess_66:
// mov dword ptr [esi+50h],ebx
// xor eax,eax
// add esi,60h
// lock and dword ptr [esi],eax
// push dword ptr [ecx+10h]
// jmp KiAttachProcess_cb
//KiAttachProcess_76:
// lea edi,[esi+60h]
// xor eax,eax
// mov ecx,edi
// lock and dword ptr [ecx],eax
// mov eax,ebx
// call KiInSwapSingleProcess
// and dword ptr [ebp+8],0
// jmp KiAttachProcess_b4
//KiAttachProcess_8d:
// inc dword ptr [ebp+8]
// mov eax,dword ptr [ebp+8]
// test dword ptr [HvlLongSpinCountMask],eax
// jne KiAttachProcess_ac
//KiAttachProcess_9b:
// test byte ptr [HvlEnlightenments],40h
// je KiAttachProcess_ac
//KiAttachProcess_a4:
// push eax
// call HvlNotifyLongSpinWait
// jmp KiAttachProcess_ae
//KiAttachProcess_ac:
// pause
//KiAttachProcess_ae:
// mov eax,dword ptr [edi]
// test eax,eax
// jne KiAttachProcess_8d
//KiAttachProcess_b4:
// xor eax,eax
// mov ecx,edi
// inc eax
// xchg eax,dword ptr [ecx]
// test eax,eax
// jne KiAttachProcess_8d
//KiAttachProcess_bf:
// mov dword ptr [esi+50h],ebx
// lock and dword ptr [edi],eax
// mov eax,dword ptr [ebp+10h]
// push dword ptr [eax+10h]
//KiAttachProcess_cb:
// push ebx
// call KiSwapProcess
// mov cl,byte ptr [ebp+0Ch]
// call dword ptr [_imp_KfLowerIrql]
// pop edi
// pop esi
// pop ebx
// pop ebp
// ret 0Ch
// }
// }
// else
// {
// __asm
// {
// jmp SrcKiAttachProcessAddr
// }
// }
__asm
{
jmp SrcKiAttachProcessAddr
}
}
void HookKiAttachProcess()
{
char code[1]={(char)0xE8};
SrcKiAttachProcessAddr=Win7GetKiAttachProcessAddr();
KiMoveApcState = GetCallAddr(SearchFeature(SrcKiAttachProcessAddr,code,1));
//DbgPrint("SrcKiAttachProcessAddr = %x",SrcKiAttachProcessAddr);
//DbgPrint("KiMoveApcState = %x",KiMoveApcState);
KiInSwapSingleProcess = GetCallAddr(SearchFeature(SearchFeature(SrcKiAttachProcessAddr,code,1)+1,code,1));
//DbgPrint("KiInSwapSingleProcess = %x",KiInSwapSingleProcess);
HvlLongSpinCountMask=(*((int*)(SrcKiAttachProcessAddr+0x8D+8)));
//DbgPrint("HvlLongSpinCountMask = %x",HvlLongSpinCountMask);
HvlEnlightenments=(*((int*)(SrcKiAttachProcessAddr+0x9B+2)));
//DbgPrint("HvlEnlightenments = %x",HvlEnlightenments);
HvlNotifyLongSpinWait=GetCallAddr(SearchFeature(SearchFeature(SearchFeature(SrcKiAttachProcessAddr,code,1)+1,code,1)+1,code,1));
//DbgPrint("HvlNotifyLongSpinWait = %x",HvlNotifyLongSpinWait);
KiSwapProcess = GetCallAddr(SearchFeature(SearchFeature(SearchFeature(SearchFeature(SrcKiAttachProcessAddr,code,1)+1,code,1)+1,code,1)+1,code,1));
//DbgPrint("KiSwapProcess = %x",KiSwapProcess);
_imp_KfLowerIrql=(*((int*)(SrcKiAttachProcessAddr+0xCB+11)));
//DbgPrint("_imp_KfLowerIrql = %x",_imp_KfLowerIrql);
SrcKeStackAttachProcessAddr=GetFunCtionAddr(L"KeStackAttachProcess");
//DbgPrint("SrcKeStackAttachProcessAddr = %x",SrcKeStackAttachProcessAddr);
KeStackAttachProcessCall_1=SearchFeature(SearchFeature(SearchFeature(SrcKeStackAttachProcessAddr,code,1)+1,code,1)+1,code,1);
//DbgPrint("KeStackAttachProcessCall_1 = %x",KeStackAttachProcessCall_1);
KeStackAttachProcessCall_2=SearchFeature(SearchFeature(SearchFeature(SearchFeature(SrcKeStackAttachProcessAddr,code,1)+1,code,1)+1,code,1)+1,code,1);
//DbgPrint("KeStackAttachProcessCall_2 = %x",KeStackAttachProcessCall_2);
SrcKeAttachProcessAddr=GetFunCtionAddr(L"KeAttachProcess");
//DbgPrint("SrcKeAttachProcessAddr = %x",SrcKeAttachProcessAddr);
KeAttachProcessCall_1=SearchFeature(SearchFeature(SrcKeAttachProcessAddr,code,1)+1,code,1);
//DbgPrint("KeAttachProcessCall_1 = %x",KeAttachProcessCall_1);
CallHook(KeStackAttachProcessCall_1,(int)MyKiAttachProcess);
CallHook(KeStackAttachProcessCall_2,(int)MyKiAttachProcess);
CallHook(KeAttachProcessCall_1,(int)MyKiAttachProcess);
}
void UnHookKiAttachProcess()
{
CallHook(KeStackAttachProcessCall_1,SrcKiAttachProcessAddr);
CallHook(KeStackAttachProcessCall_2,SrcKiAttachProcessAddr);
CallHook(KeAttachProcessCall_1,SrcKiAttachProcessAddr);
}
工程在Win 7的VS2010編譯環境測試通過,因爲有硬編碼,所以不適合Win XP,因爲64位的系統的SSDT表不可寫,所以不適合64位的系統。
Visual C/C++,彙編語言,驅動交流羣:177822398、 177822108
附註:一直想找個合適的安全類編程開發測試的工作
下面貼上附件:
http://pan.baidu.com/share/link?shareid=3246773275&uk=3155594444
CALL HOOK了KeStackAttachProcess和KeAttachProcess內核函數
KiAttachProcess的反彙編代碼:
nt!KiAttachProcess:
81875b9c 8bff mov edi,edi
81875b9e 55 push ebp
81875b9f 8bec mov ebp,esp
81875ba1 53 push ebx
81875ba2 8b5d08 mov ebx,dword ptr [ebp+8]
81875ba5 56 push esi
81875ba6 8bf0 mov esi,eax
81875ba8 8b4510 mov eax,dword ptr [ebp+10h]
81875bab 57 push edi
81875bac 8d7e40 lea edi,[esi+40h]
81875baf 57 push edi
81875bb0 e84d020000 call nt!KiMoveApcState (81875e02)
81875bb5 8b4d10 mov ecx,dword ptr [ebp+10h]
81875bb8 897f04 mov dword ptr [edi+4],edi
81875bbb 893f mov dword ptr [edi],edi
81875bbd 8d4648 lea eax,[esi+48h]
81875bc0 894004 mov dword ptr [eax+4],eax
81875bc3 8900 mov dword ptr [eax],eax
81875bc5 8d8670010000 lea eax,[esi+170h]
81875bcb c6465400 mov byte ptr [esi+54h],0
81875bcf c6465500 mov byte ptr [esi+55h],0
81875bd3 c6465600 mov byte ptr [esi+56h],0
81875bd7 3bc8 cmp ecx,eax
81875bd9 7513 jne nt!KiAttachProcess+0x52 (81875bee)
81875bdb 898668010000 mov dword ptr [esi+168h],eax
81875be1 89be6c010000 mov dword ptr [esi+16Ch],edi
81875be7 c6863401000001 mov byte ptr [esi+134h],1
81875bee 6a08 push 8
81875bf0 58 pop eax
81875bf1 8d5374 lea edx,[ebx+74h]
81875bf4 f00fc102 lock xadd dword ptr [edx],eax
81875bf8 894508 mov dword ptr [ebp+8],eax
81875bfb 8b4508 mov eax,dword ptr [ebp+8]
81875bfe a807 test al,7
81875c00 7510 jne nt!KiAttachProcess+0x76 (81875c12)
81875c02 895e50 mov dword ptr [esi+50h],ebx
81875c05 33c0 xor eax,eax
81875c07 83c660 add esi,60h
81875c0a f02106 lock and dword ptr [esi],eax
81875c0d ff7110 push dword ptr [ecx+10h]
81875c10 eb55 jmp nt!KiAttachProcess+0xcb (81875c67)
81875c12 8d7e60 lea edi,[esi+60h]
81875c15 33c0 xor eax,eax
81875c17 8bcf mov ecx,edi
81875c19 f02101 lock and dword ptr [ecx],eax
81875c1c 8bc3 mov eax,ebx
81875c1e e84f4f0500 call nt!KiInSwapSingleProcess (818cab72)
81875c23 83650800 and dword ptr [ebp+8],0
81875c27 eb27 jmp nt!KiAttachProcess+0xb4 (81875c50)
81875c29 ff4508 inc dword ptr [ebp+8]
81875c2c 8b4508 mov eax,dword ptr [ebp+8]
81875c2f 8505342b9781 test dword ptr [nt!HvlLongSpinCountMask (81972b34)],eax
81875c35 7511 jne nt!KiAttachProcess+0xac (81875c48)
81875c37 f6052c2b978140 test byte ptr [nt!HvlEnlightenments (81972b2c)],40h
81875c3e 7408 je nt!KiAttachProcess+0xac (81875c48)
81875c40 50 push eax
81875c41 e865840600 call nt!HvlNotifyLongSpinWait (818de0ab)
81875c46 eb02 jmp nt!KiAttachProcess+0xae (81875c4a)
81875c48 f390 pause
81875c4a 8b07 mov eax,dword ptr [edi]
81875c4c 85c0 test eax,eax
81875c4e 75d9 jne nt!KiAttachProcess+0x8d (81875c29)
81875c50 33c0 xor eax,eax
81875c52 8bcf mov ecx,edi
81875c54 40 inc eax
81875c55 8701 xchg eax,dword ptr [ecx]
81875c57 85c0 test eax,eax
81875c59 75ce jne nt!KiAttachProcess+0x8d (81875c29)
81875c5b 895e50 mov dword ptr [esi+50h],ebx
81875c5e f02107 lock and dword ptr [edi],eax
81875c61 8b4510 mov eax,dword ptr [ebp+10h]
81875c64 ff7010 push dword ptr [eax+10h]
81875c67 53 push ebx
81875c68 e89728ffff call nt!KiSwapProcess (81868504)
81875c6d 8a4d0c mov cl,byte ptr [ebp+0Ch]
81875c70 ff1558418181 call dword ptr [nt!_imp_KfLowerIrql (81814158)]
81875c76 5f pop edi
81875c77 5e pop esi
81875c78 5b pop ebx
81875c79 5d pop ebp
81875c7a c20c00 ret 0Ch
81875c7d 90 nop
81875c7e 90 nop
81875c7f 90 nop
81875c80 90 nop
81875c81 90 nop
可以下硬件斷點