首页
社区
课程
招聘
聊聊游戏辅助那些事上部第一篇——过掉那些讨厌的游戏保护。
发表于: 2017-2-20 14:12 31397

聊聊游戏辅助那些事上部第一篇——过掉那些讨厌的游戏保护。

2017-2-20 14:12
31397

这个系列计划分为上下两部,上部是内置型辅助,下部是按键型辅助。我不保证会写完。

聊聊游戏辅助那些事上部第一篇——过掉那些讨厌的游戏保护。

相对以前那些裸奔游戏,现在的新游戏多少都会有些保护,这是绕不过去的坎。

下面针对我发现的几个保护方法,逐个的聊一聊。

1、R3应用层下,DebugActiveProcess 加载调试器时,会设置一个远程断点,而这个远程断点其实多此一举,反而有时会触发反调试检测。唯一要做的就是绕过它。

这是NtDebugActiveProcess的上层函数,DbgUiDebugActiveProcess的反汇编代码:
_NtDebugActiveProcess@8 (775909A4h) 
7760FC64  mov         esi,eax        // 原始返回地址
7760FC66  test        esi,esi 
7760FC68  jl          _DbgUiIssueRemoteBreakin@4 (7760FC03h) 
7760FC72  mov         esi,eax 
7760FC74  test        esi,esi 
7760FC76  jge         _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,
  &param,
  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;
}

最后预告一下,本系列的第二篇,聊聊游戏辅助那些事上部第二篇——跟踪是个苦力活,调试器有什么好建议?

当然什么时候发我自己也不知道了,因为还没写呢。想看的就自己关注了。



[课程]Linux pwn 探索篇!

收藏
免费 7
支持
分享
最新回复 (75)
雪    币: 3255
活跃值: (4399)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
收藏下~
2017-2-20 14:43
0
雪    币: 172
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
make
2017-2-20 16:48
0
雪    币: 216
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
好期待这一系列的文章
2017-2-21 08:39
0
雪    币: 157
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
mark,顺便问一下,收藏贴子功能在那里?
2017-2-21 09:19
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
mark
,简单明了
2017-2-21 09:35
0
雪    币: 205
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
╮(╯▽╰)╭,过调试真是个体力活
2017-2-21 13:57
0
雪    币: 284
活跃值: (250)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
8
膜拜大表哥
2017-2-21 20:45
0
雪    币: 1140
活跃值: (102)
能力值: ( LV4,RANK:48 )
在线值:
发帖
回帖
粉丝
9
莫一个,说不定我用得着
2017-2-21 21:42
0
雪    币: 1140
活跃值: (102)
能力值: ( LV4,RANK:48 )
在线值:
发帖
回帖
粉丝
10
..怎么不支持旧论坛的表情了
2017-2-21 21:42
0
雪    币: 1140
活跃值: (102)
能力值: ( LV4,RANK:48 )
在线值:
发帖
回帖
粉丝
11
请问下能过南极动物的驱动不
2017-2-21 21:45
0
雪    币: 273
活跃值: (412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
可以  可以
2017-2-21 23:35
2
雪    币: 552
活跃值: (4032)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
13
mark一下,还是旧版的论坛看着舒服。
2017-2-22 10:29
0
雪    币: 8
活跃值: (107)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
mark...
2017-2-22 15:39
0
雪    币: 461
活跃值: (304)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
15
Mark,已收藏
2017-2-22 15:58
0
雪    币: 36
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
膜拜大神~
2017-2-23 14:52
0
雪    币: 2155
活跃值: (2547)
能力值: ( LV12,RANK:667 )
在线值:
发帖
回帖
粉丝
17

好文章,mark一下

2017-2-23 22:06
0
雪    币: 12406
活跃值: (4007)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
18
mark
2017-2-24 01:56
0
雪    币: 4668
活跃值: (1713)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
跟帖  收藏
2017-2-24 03:08
0
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
win4  64位上的游戏保护知识终于放出来了,O(∩_∩)O哈哈~
2017-2-24 08:13
0
雪    币: 48
活跃值: (167)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
可以、很强势,mark先~
2017-2-24 20:10
0
雪    币: 2305
活跃值: (4554)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
新版的收藏在哪里···
2017-2-24 21:46
0
雪    币: 3700
活跃值: (3817)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
23
回帖收藏!!!
2017-2-25 17:20
0
雪    币: 25
活跃值: (506)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
mark一下!
2017-2-25 23:56
0
雪    币: 236
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
回帖收藏
2017-2-26 10:25
0
游客
登录 | 注册 方可回帖
返回
//