聊聊遊戲輔助那些事上部第一篇——過掉那些討厭的遊戲保護。
這個系列計劃分為上下兩部,上部是內建型輔助,下部是按鍵型輔助。我不保證會寫完。
聊聊遊戲輔助那些事上部第一篇——過掉那些討厭的遊戲保護。
相對以前那些裸奔遊戲,現在的新遊戲多少都會有些保護,這是繞不過去的坎。
下面針對我發現的幾個保護方法,逐個的聊一聊。
1、R3應用層下,DebugActiveProcess 載入偵錯程式時,會設定一個遠端斷點,而這個遠端斷點其實多此一舉,反而有時會觸發反除錯檢測。唯一要做的就是繞過它。
這是NtDebugActiveProcess的上層函式,DbgUiDebugActiveProcess的反彙編程式碼:
_DbgUiDebugActiveProcess@4:
00: mov edi,edi
7760FC4C push ebp
7760FC4D mov ebp,esp
7760FC4F mov eax,dword ptr fs:[00000018h]
7760FC55 push esi
7760FC56 push dword ptr [eax+0F24h]
7760FC5C push dword ptr [ebp+8]
7760FC5F call _NtDebugActiveProcess@8 (775909A4h)
7760FC64 mov esi,eax // 原始返回地址
7760FC66 test esi,esi
7760FC68 jl
_DbgUiDebugActiveProcess@4+36h (7760FC80h)
7760FC6A push dword ptr [ebp+8]
7760FC6D call
_DbgUiIssueRemoteBreakin@4 (7760FC03h)
7760FC72 mov esi,eax
7760FC74 test esi,esi
7760FC76 jge
_DbgUiDebugActiveProcess@4+36h (7760FC80h)
7760FC78 push dword ptr [ebp+8]
7760FC7B call _DbgUiStopDebugging@4 (7760FB88h)
7760FC80 mov eax,esi
7760FC82 pop esi // +0x1E後的返回地址
7760FC83 pop ebp
7760FC84 ret 4
下面是64位 WINDOW7 下面的 NtDebugActiveProcess 的鉤子函式的具體程式碼,繞過遠端斷點的方法是在返回地址上加偏移0x1E
//
// NtDebugActiveProcess
//
NTSTATUS WINAPI DbgNtDebugActiveProcess64(
__in HANDLE ProcessHandle,
__in HANDLE DebugObjectHandle )
{
NTSTATUS Status = TrueNtDebugActiveProcess(ProcessHandle, DebugObjectHandle);
KdPrint((_T("NtDebugActiveProcess 返回值: 0x%08x!\r\n"), Status));
//
// 繞過應用層的遠端斷點,完全多此一舉啊。
//
if (NT_SUCCESS(Status))
{
LPVOID ReturnAddress = (LPSTR)&ProcessHandle - sizeof(DWORD);
*(LPDWORD)ReturnAddress += 0x1E;
}
return Status;
}
2、如果保護程式有驅動,那麼在R0核心層下除錯埠清零會是絕大多數遊戲保護的選擇。程式的除錯埠儲存了一個偵錯程式對像,當有異常發生時,作業系統的異常處理程式會查詢這個埠,如果存在偵錯程式,就會將異常傳送給偵錯程式,偵錯程式會優先獲得異常處理的權利。
網上有不少方法,這兒採用自建除錯埠管理的方法繞過它,呵呵,你想清零就清零,反正我又不用它。直接上獲取設定除錯埠的相關程式碼。
typedef struct _DEBUGED_PROCESS_ENTRY
{
LIST_ENTRY EventList;
PEPROCESS Process;
PDEBUG_OBJECT DebugPort;
ULONG KeExceptionDispatchCount;
}DEBUGED_PROCESS_ENTRY, *PDEBUGED_PROCESS_ENTRY;
LIST_ENTRY DebugedProcessList;
PDEBUG_OBJECT GetDebugPort(PEPROCESS Process)
{
PDEBUG_OBJECT DebugObject = NULL;
PLIST_ENTRY Entry;
PDEBUGED_PROCESS_ENTRY DebugedProcess;
ExAcquireFastMutex(&DebugedProcessListMutex);
for (Entry = DebugedProcessList.Flink; Entry != &DebugedProcessList; Entry = Entry->Flink)
{
DebugedProcess = CONTAINING_RECORD(Entry, DEBUGED_PROCESS_ENTRY, EventList);
if (DebugedProcess->Process == Process)
{
DebugedProcess->KeExceptionDispatchCount++;
DebugObject = DebugedProcess->DebugPort;
}
}
ExReleaseFastMutex(&DebugedProcessListMutex);
return DebugObject;
}
NTSTATUS SetDebugPort(PEPROCESS Process, PDEBUG_OBJECT DebugProt)
{
PDEBUGED_PROCESS_ENTRY DebugedProcess;
DebugedProcess = (PDEBUGED_PROCESS_ENTRY)ExAllocatePoolWithTag(NonPagedPool,
sizeof(DEBUGED_PROCESS_ENTRY),
'DotP');
if (DebugedProcess)
{
ExAcquireFastMutex(&DebugedProcessListMutex);
DebugedProcess->Process = Process;
DebugedProcess->DebugPort = DebugProt;
DebugedProcess->KeExceptionDispatchCount = 0;
InsertTailList(&DebugedProcessList, &DebugedProcess->EventList);
ExReleaseFastMutex(&DebugedProcessListMutex);
return STATUS_SUCCESS;
}
else
{
return STATUS_INSUFFICIENT_RESOURCES;
}
}
這是真正的核心程式碼,注意看註釋。後面的 DeviceIoControlDispatch 會呼叫這個函式。
NTSTATUS
OnNtDebugActiveProcess(
IN HANDLE ProcessHandle,
IN HANDLE DebugObjectHandle
)
{
_KdPrint(("NtDebugActiveProcess %x, %x\r\n", ProcessHandle, DebugObjectHandle));
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode;
PEPROCESS Process;
PDEBUG_OBJECT DebugObject;
LIST_ENTRY TempList;
PAGED_CODE();
PreviousMode = KeGetPreviousMode();
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_SET_PORT,
*PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
DebugObject = GetDebugPort(Process);
if (DebugObject)
{
Status = STATUS_PORT_ALREADY_SET;
}
if (NT_SUCCESS(Status))
{
//
// 呼叫系統的除錯程式符加函式
//
_KdPrint(("TrueNtDebugActiveProcess Enter\r\n"));
Status = NtDebugActiveProcess(ProcessHandle, DebugObjectHandle);
_KdPrint(("TrueNtDebugActiveProcess Leave\r\n"));
if (NT_SUCCESS(Status))
{
Status = ObReferenceObjectByHandle(DebugObjectHandle,
DEBUG_PROCESS_ASSIGN,
*DbgkDebugObjectType,
PreviousMode,
(PVOID*)&DebugObject,
NULL);
if (NT_SUCCESS(Status))
{
//
// 無痕除錯,需要清理除錯標誌,儲存事件列表
//
TempList = DebugObject->EventList;
//
// 從除錯對像中移除事件列表
//
InitializeListHead(&DebugObject->EventList);
//
// 清理程式的除錯埠及除錯標誌,不用你清零除錯埠了,我自己就直接清零了。
//
DbgkClearProcessDebugObject(Process, DebugObject);
//
// 恢復除錯對像的事件列表
//
DebugObject->EventList = TempList;
SetDebugPort(Process, DebugObject);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(DebugObject);
}
}
}
}
if (!NT_SUCCESS(Status))
{
ObDereferenceObject(Process);
}
return Status;
}
但是用 OnNtDebugActiveProcess 載入那是完全不除錯,因為這個函式不用你清零除錯埠了,我自己就直接清零了。然後就要對DbgkForwardException下鉤子,讓我們自己儲存的除錯埠發揮作用。具體程式碼。
BOOLEAN
OnDbgkForwardException(
IN PEXCEPTION_RECORD ExceptionRecord,
IN BOOLEAN DebugException,
IN BOOLEAN SecondChance
)
{
DBGKM_APIMSG m;
PDBGKM_EXCEPTION args;
NTSTATUS st;
PAGED_CODE();
if (!DebugException)
{
return FALSE;
}
//
// 程式設定了除錯埠,或者沒有影射當前程式的除錯埠
//
if (GetDebugPort(PsGetCurrentProcess()) == NULL)
{
return FALSE;
}
//
// 除錯埠被置零。
//
_KdPrint(("DbgkForwardException ExceptionAddress = %08x, ExceptionCode = %08x \r\n", ExceptionRecord->ExceptionAddress, ExceptionRecord->ExceptionCode));
args = &m.u.Exception;
//
// Initialize the debug LPC message with default information.
//
_KdPrint(("DBGKM_FORMAT_API_MSG\r\n"));
DBGKM_FORMAT_API_MSG(m,DbgKmExceptionApi,sizeof(*args));
//
// Fill in the remainder of the debug LPC message.
//
_KdPrint(("args->ExceptionRecord = *ExceptionRecord\r\n"));
args->ExceptionRecord = *ExceptionRecord;
args->FirstChance = !SecondChance;
//
// Send the debug message to the destination LPC port.
//
_KdPrint(("DbgkpSendApiMessage\r\n"));
st = DbgkpSendApiMessage(&m,DebugException);
//
// If the send was not successful, then return a FALSE indicating that
// the port did not handle the exception. Otherwise, if the debug port
// is specified, then look at the return status in the message.
//
if (!NT_SUCCESS(st) ||
((DebugException) &&
(m.ReturnedStatus == DBG_EXCEPTION_NOT_HANDLED || !NT_SUCCESS(m.ReturnedStatus))))
{
_KdPrint(("DbgkForwardException FAILED, STATUS = %08x, DebugException = %d, ReturnedStatus = %08x!\r\n", st, DebugException, m.ReturnedStatus));
return FALSE;
}
else
{
_KdPrint(("DbgkForwardException SUCCESSED!\r\n"));
return TRUE;
}
}
上面的兩個函式用到了幾個沒有匯出的核心函式,這就需要自己定位相關的函式了,這裡就不再展開定位的方法了。
偵錯程式在應用層需要新增鉤子函式:DbgNtDebugActiveProcess64,與前面的 DbgNtDebugActiveProcess64 的差別在不再呼叫 TrueNtDebugActiveProcess,而是通過 DeviceIoControl 呼叫我們自己的NtDebugActiveProcess
//
// NtDebugActiveProcess
//
NTSTATUS WINAPI DbgNtDebugActiveProcess64(
__in HANDLE ProcessHandle,
__in HANDLE DebugObjectHandle )
{
NTSTATUS Status;
DWORD lResultLength;
PARAM_NtDebugActiveProcess64 param;
param.ProcessHandle = ProcessHandle;
param.DebugObjectHandle = DebugObjectHandle;
DeviceIoControl(
g_hModuleDbgHelper,
IOCTL_NtDebugActiveProcess,
¶m,
sizeof(param),
&Status,
sizeof(Status),
&lResultLength,
0);
KdPrint((_T("NtDebugActiveProcess 返回值: 0x%08x!\r\n"), Status));
if (NT_SUCCESS(Status))
{
LPVOID ReturnAddress = (LPSTR)&ProcessHandle - sizeof(DWORD);
*(LPDWORD)ReturnAddress += 0x1E;
}
return Status;
}
3、偵錯程式對像降權。當系統的偵錯程式對像的訪問許可權被設定為零時,表現為附加不上所有程式,遊戲保護讓我們建立的除錯對像成為沒有除錯許可權的除錯對像。處理方法:重建一個除錯對像型別,然後替換掉系統的除錯對像型別。
NTSTATUS
DbgkCreateDebugObjectType(
POBJECT_TYPE* DebugObjectType
)
{
NTSTATUS Status;
UNICODE_STRING Name;
POBJECT_TYPE SysDebugObjectType;
POBJECT_TYPE ObpTypeObjectType;
PAGED_CODE();
//
// 先開啟系統本身的除錯對像
//
RtlInitUnicodeString(&Name, L"\\ObjectTypes\\DebugObject");
ObpTypeObjectType = ObGetObjectType(*PsProcessType);
Status = ObReferenceObjectByName(&Name, OBJ_CASE_INSENSITIVE, NULL, 0, ObpTypeObjectType, KernelMode, NULL, (PVOID*)&SysDebugObjectType);
if (NT_SUCCESS(Status))
{
//
// 系統偵錯程式的對像關閉函式
//
(OB_CLOSE_METHOD&)SysDbgkpCloseObject = SysDebugObjectType->TypeInfo.CloseProcedure;
//
// 先試著開啟我們的除錯對像型別,如果開啟成功,直接使用即可
//
RtlInitUnicodeString(&Name, L"\\ObjectTypes\\NewDebugObject");
Status = ObReferenceObjectByName(&Name, OBJ_CASE_INSENSITIVE, NULL, 0, ObpTypeObjectType, KernelMode, NULL, (PVOID*)DebugObjectType);
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
{
RtlInitUnicodeString(&Name, L"NewDebugObject");
GENERIC_MAPPING GenericMapping = { STANDARD_RIGHTS_READ | DEBUG_READ_EVENT,
STANDARD_RIGHTS_WRITE | DEBUG_PROCESS_ASSIGN,
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
DEBUG_ALL_ACCESS };
OBJECT_TYPE_INITIALIZER oti = { 0 };
oti.Length = sizeof(oti);
oti.SecurityRequired = TRUE;
oti.InvalidAttributes = 0;
oti.PoolType = NonPagedPool;
oti.DeleteProcedure = SysDebugObjectType->TypeInfo.DeleteProcedure;
oti.CloseProcedure = (OB_CLOSE_METHOD)DbgkpCloseObject;
oti.ValidAccessMask = DEBUG_ALL_ACCESS;
oti.GenericMapping = GenericMapping;
oti.DefaultPagedPoolCharge = 0;
oti.DefaultNonPagedPoolCharge = 0;
Status = ObCreateObjectType(&Name, &oti, NULL, DebugObjectType);
}
else if (NT_SUCCESS(Status))
{
(*DebugObjectType)->TypeInfo.CloseProcedure = (OB_CLOSE_METHOD)DbgkpCloseObject;
}
ObDereferenceObject(SysDebugObjectType);
}
return Status;
}
NTSTATUS DbgkInitialize()
{
POBJECT_TYPE NewDebugObjectType;
Status = DbgkCreateDebugObjectType(&NewDebugObjectType);
if (NT_SUCCESS(Status))
{
*DbgkDebugObjectType = NewDebugObjectType;
}
}
DbgkDebugObjectType 為系統核心偵錯程式對像地址,可以通過符號搜尋獲取地址。TP在啟動後會讓所用的附加或啟動除錯失敗,然後我們來這麼一下,整個世界就安靜了。
4、這裡感謝一下微軟,64位的PG幫了我們不少忙,幹掉了很多的遊戲保護。在64位的系統下,遊戲保護基本上過掉這三個就可以了,當然最後還要加上一個過PG的布丁。32位下則一般還還需要過掉 NtOpenProcess,NtReadVirtualMemory,NtWriteVirtualMemory,NtQuerySystemInformation等幾個函式,如果採用主動式難度不算很大。所謂主動式就是你走你的陽關道,我走我的獨木橋,我另外開闢一條路走,把鉤子下在應用層,讓所有呼叫這些函式都轉到我的函式上來。而且這些鉤子不是加在遊戲程式上,而是加在偵錯程式上。
貼一個32下的應用層 NtOpenProcess 鉤子函式:利用 DeviceIoControl 跳到核心層,呼叫我們自己的核心層的 NtOpenProcess,其它的就不一一貼了。
//
// NtOpenProcess
//
NTSTATUS WINAPI DbgNtOpenProcess32
(
__out PHANDLE ProcessHandle,
__in ACCESS_MASK DesiredAccess,
__in POBJECT_ATTRIBUTES ObjectAttributes,
__in_opt PCLIENT_ID ClientId)
{
DWORD lResultLength;
NTSTATUS Status;
DeviceIoControl(
g_hModuleDbgHelper,
IOCTL_NtOpenProcess,
&ProcessHandle,
DWORD((&ClientId) + 1) - DWORD(&ProcessHandle),
&Status,
sizeof(Status),
&lResultLength,
0);
KdPrint((_T("NtOpenProcess 返回值: 0x%08x!\r\n"), Status));
return Status;
}
5、前面幾個應用層的鉤子都用到了 DeviceIoControl,所以貼一下驅動中的 DeviceIoControlDispatch 函式。
NTSTATUS DbgHelperDeviceIoControlDispatch
(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp )
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
PDBGHELPER_DEVICE_EXTENSION deviceExtension;
ULONG inputLength;
ULONG outputLength;
_KdPrint( (__FUNCTION__"++. IRP %p", Irp) );
deviceExtension = (PDBGHELPER_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
// Get our IRP stack location
irpStack = IoGetCurrentIrpStackLocation(Irp);
// Get the buffer lengths
inputLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_NtOpenProcess:
{
_KdPrint(("IOCTL_NtOpenProcess"));
PARAM_NtOpenProcess* ioBuffer = (PARAM_NtOpenProcess*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtOpenProcess)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫真正的函式 NtOpenProcess
//
status = DbgHelperNtOpenProcess(ioBuffer->ProcessHandle, ioBuffer->DesiredAccess, ioBuffer->ObjectAttributes, ioBuffer->ClientId);
_KdPrint(("STATUS = 0x%08x, ProcessHandle = 0x%08x, ProcessId = 0x%08x, ThreadId = 0x%08x", status, ioBuffer->ProcessHandle ? *ioBuffer->ProcessHandle : (PHANDLE)-1, ioBuffer->ClientId->UniqueProcess, ioBuffer->ClientId->UniqueThread));
*(NTSTATUS *)ioBuffer = status;
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
case IOCTL_NtCreateDebugObject:
{
_KdPrint(("IOCTL_NtCreateDebugObject Enter\n"));
PARAM_NtCreateDebugObject* ioBuffer = (PARAM_NtCreateDebugObject*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtCreateDebugObject)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫我們自己的函式 NtCreateDebugObject,返回的 DebugObjectHandle 相容系統的除錯對像
//
status = OnNtCreateDebugObject(ioBuffer->DebugObjectHandle, ioBuffer->DesiredAccess, ioBuffer->ObjectAttributes, ioBuffer->Flags);
_KdPrint(("STATUS = 0x%08x, DebugObjectHandle = 0x%08x, DesiredAccess = 0x%08x, Flags = 0x%08x", status, ioBuffer->DebugObjectHandle ? *ioBuffer->DebugObjectHandle : (HANDLE)-1, ioBuffer->DesiredAccess, ioBuffer->Flags));
*(NTSTATUS *)ioBuffer = status;
_KdPrint(("IOCTL_NtCreateDebugObject Leave\n"));
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
case IOCTL_NtDebugActiveProcess:
{
_KdPrint(("IOCTL_NtDebugActiveProcess Enter\n"));
PARAM_NtDebugActiveProcess* ioBuffer = (PARAM_NtDebugActiveProcess*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtDebugActiveProcess)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫我們自己的函式 NtDebugActiveProcess
//
status = OnNtDebugActiveProcess(ioBuffer->ProcessHandle, ioBuffer->DebugObjectHandle);
_KdPrint(("STATUS = 0x%08x, ProcessHandle = 0x%08x, DebugObjectHandle = 0x%08x", status, ioBuffer->ProcessHandle, ioBuffer->DebugObjectHandle));
*(NTSTATUS *)ioBuffer = status;
_KdPrint(("IOCTL_NtDebugActiveProcess Leave\n"));
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
case IOCTL_NtRemoveProcessDebug:
{
_KdPrint(("IOCTL_NtRemoveProcessDebug Enter\n"));
PARAM_NtRemoveProcessDebug* ioBuffer = (PARAM_NtRemoveProcessDebug*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtRemoveProcessDebug)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫我們自己的函式 NtRemoveProcessDebug
//
status = OnNtRemoveProcessDebug(ioBuffer->ProcessHandle, ioBuffer->DebugObjectHandle);
_KdPrint(("STATUS = 0x%08x, ProcessHandle = 0x%08x, DebugObjectHandle = 0x%08x", status, ioBuffer->ProcessHandle, ioBuffer->DebugObjectHandle));
*(NTSTATUS *)ioBuffer = status;
_KdPrint(("IOCTL_NtRemoveProcessDebug Leave\n"));
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
case IOCTL_NtReadVirtualMemory:
{
_KdPrint(("IOCTL_NtReadVirtualMemory"));
PARAM_NtReadVirtualMemory* ioBuffer = (PARAM_NtReadVirtualMemory*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtReadVirtualMemory)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫我們自己的 NtReadVirtualMemory 函式
//
status = DbgHelperNtReadVirtualMemory(ioBuffer->ProcessHandle, ioBuffer->BaseAddress, ioBuffer->Buffer, ioBuffer->BufferSize, ioBuffer->NumberOfBytesWritten);
_KdPrint(("STATUS = 0x%08x, ProcessHandle = 0x%08x, BaseAddress = 0x%08x, BufferSize = 0x%08x", status, ioBuffer->ProcessHandle, ioBuffer->BaseAddress, ioBuffer->BufferSize));
*(NTSTATUS *)ioBuffer = status;
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
case IOCTL_NtWriteVirtualMemory:
{
_KdPrint(("IOCTL_NtWriteVirtualMemory"));
PARAM_NtWriteVirtualMemory* ioBuffer = (PARAM_NtWriteVirtualMemory*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtWriteVirtualMemory)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫我們自己的 NtWriteVirtualMemory 函式
//
status = DbgHelperNtWriteVirtualMemory(ioBuffer->ProcessHandle, ioBuffer->BaseAddress, ioBuffer->Buffer, ioBuffer->BufferSize, ioBuffer->NumberOfBytesWritten);
_KdPrint(("STATUS = 0x%08x, ProcessHandle = 0x%08x, BaseAddress = 0x%08x, BufferSize = 0x%08x", status, ioBuffer->ProcessHandle, ioBuffer->BaseAddress, ioBuffer->BufferSize));
*(NTSTATUS *)ioBuffer = status;
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
case IOCTL_NtQuerySystemInformation:
{
_KdPrint(("IOCTL_NtQuerySystemInformation Enter\n"));
PARAM_NtQuerySystemInformation* ioBuffer = (PARAM_NtQuerySystemInformation*)Irp->AssociatedIrp.SystemBuffer;
if ((ioBuffer == NULL) || (inputLength != sizeof(PARAM_NtQuerySystemInformation)) || (outputLength < sizeof(NTSTATUS)))
{
return CompleteIrp(Irp, STATUS_INVALID_PARAMETER, 0);
}
else
{
//
// 呼叫我們自己的函式 NtRemoveProcessDebug
//
status = NtQuerySystemInformation(ioBuffer->SystemInformationClass, ioBuffer->SystemInformation, ioBuffer->SystemInformationLength, ioBuffer->ReturnLength);
_KdPrint(("STATUS = 0x%08x, SystemInformationClass = %d, SystemInformation = %d", status, ioBuffer->SystemInformationClass, ioBuffer->SystemInformation));
*(NTSTATUS *)ioBuffer = status;
_KdPrint(("IOCTL_NtQuerySystemInformation Leave\n"));
return CompleteIrp(Irp, STATUS_SUCCESS, sizeof(NTSTATUS));
}
}
break;
default:
status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
break;
}
_KdPrint( (__FUNCTION__"--. IRP %p STATUS %x", Irp, status) );
return status;
}
最後預告一下,本系列的第二篇,聊聊遊戲輔助那些事上部第二篇——跟蹤是個苦力活,偵錯程式有什麼好建議?
當然什麼時候發我自己也不知道了,因為還沒寫呢。想看的就自己關注了。
相關文章
- 聊聊網路的那些事
- 聊聊前端排序的那些事前端排序
- 聊聊viewport那些事兒View
- 技術演講那些事:如何不讓你的演講令人討厭
- 聊聊蘋果證書的那些事蘋果
- 那些被遊戲公司成就的和毀掉的IP遊戲
- 聊聊java就業那些事Java就業
- 聊聊web快取那些事!Web快取
- 守護程式那些事
- 來聊聊移動休閒遊戲研發、推廣、變現的那些事遊戲
- 聊聊瀏覽器的那些事兒瀏覽器
- 聊聊 QianKun JS 沙箱的那些事JS
- 遊戲開發過程中需求變化那些事遊戲開發
- 一張圖看懂遊戲線上運營那些事遊戲
- 遊戲開發專案管理那些事遊戲開發專案管理
- 遊戲用研那些事:用研目的&誤區遊戲
- 聊聊那些年遇到過的奇葩程式碼
- 聊聊 TCP 長連線和心跳那些事TCP
- 聊聊 SVG 基本形狀轉換那些事SVG
- 遊戲首次測投前,你需要知道的那些事......遊戲
- 我們來聊聊Cookie、Session和Storage的那些事CookieSession
- 聊聊spring bean名稱命名的那些事兒SpringBean
- 聊聊 Material Design 裡,陰影的那些事兒!Material Design
- 聊聊Django應用的部署和效能的那些事兒Django
- 關於電子遊戲,那些被人們誤解的事實遊戲
- 那些被遺忘的Enix遊戲遊戲
- 聊聊那些年的騷操作!!!
- Synchronized的那些事synchronized
- webassembly 的那些事Web
- ViewPager的那些事Viewpager
- 一起聊聊資料標註那些事兒
- 聊聊訊息中介軟體(1),AMQP那些事兒MQ
- Java 混淆那些事(六):Android 混淆的那些瑣事JavaAndroid
- 遊戲史上那些投資巨大卻血本無歸的遊戲遊戲
- 被噴了!聊聊我開源的RPC框架那些事RPC框架
- rem那些事REM
- JavaScript那些事JavaScript
- mysql那些事MySql