欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

游戏保护大放送之GPK

程序员文章站 2022-04-12 21:40:10
作 者: wtxpwh     GPK也没有啥特别。龙之谷多开检测和别的不一样。   直接上代码。   代码:   &nbs...
作 者: wtxpwh
 
 
GPK也没有啥特别。龙之谷多开检测和别的不一样。
 
直接上代码。
 
代码:
 
 
#include "struct.h"
#include "FGPK.h"
 
//////////////////////////////////////////////////////////////////////////
 
char g_pFindOrigCode[8];
ULONG KiSystemService_hack_address=0;
PULONG  pSSDTKernel;
PSERVICE_DESCRIPTOR_TABLE_SHADOW _KeServiceDescriptorTable;
PSERVICE_DESCRIPTOR_TABLE_SHADOW  ShadowTable;
unsigned long SSDT_reentry_address,SSDTDW_reentry_address;
 
 
ULONG g_Dra_count=0;
ULONG g_Sem_count=0;
 
//////////////////////////////////////////////////////////////////////////
void RePlaceSSDT();
void RestoreSSDT();
 
ULONG Pass_NtCreateMutant();
VOID UnDetour_NtCreateMutant();
 
ULONG Pass_NtQuerySystemInformation();
VOID UnDetour_NtQuerySystemInformation();
 
ULONG Pass_NtOpenProcess();
VOID UnDetour_NtOpenProcess();
 
NTSTATUS HookFindWindow();
NTSTATUS UnHookFindWindow();
 
ULONG Pass_NtReadVirtualMemory();
VOID UnDetour_NtReadVirtualMemory();
 
ULONG Pass_NtCreateSemaphore();
VOID UnDetour_NtCreateSemaphore();
 
 
ULONG Pass_NtReleaseSemaphore();
VOID UnDetour_NtReleaseSemaphore();
 
ULONG Pass_NtOpenSemaphore();
VOID UnDetour_NtOpenSemaphore();
 
ULONG Pass_NtQueryObject();
VOID UnDetour_NtQueryObject();
 
 
ULONG Pass_NtWaitForSingleObject();
VOID UnDetour_NtWaitForSingleObject();
 
NTSTATUS InitSWSSDT();
 
//////////////////////////////////////////////////////////////////////////
 
NTSTATUS
DriverEntry(
  PDRIVER_OBJECT pDriverObj,
  PUNICODE_STRING pRegistryString
  )
{
  NTSTATUS status = STATUS_SUCCESS;
  UNICODE_STRING ustrLinkName;
  UNICODE_STRING ustrDevName;   
  PDEVICE_OBJECT pDevObj;
 
  dprintf("[FGPK] DriverEntry\n");
 
  pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
  pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
  pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
  pDriverObj->DriverUnload = DriverUnload;
 
 
  RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
  status = IoCreateDevice(pDriverObj,
        0,
        &ustrDevName,
        FILE_DEVICE_UNKNOWN,
        0,
        FALSE,
        &pDevObj);
 
  if(!NT_SUCCESS(status))  {
    dprintf("[FGPK] IoCreateDevice = 0x%x\n", status);
    return status;
  }
 
  RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
  status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName); 
  if(!NT_SUCCESS(status)) {
    dprintf("[FGPK] IoCreateSymbolicLink = 0x%x\n", status);
    IoDeleteDevice(pDevObj); 
    return status;
  }
 
 
  //
  // 添加执行代码
  //
 
  RePlaceSSDT();
 
  InitSWSSDT();
 
  Pass_NtQueryObject();
 
  Pass_NtCreateMutant();
 
  Pass_NtCreateSemaphore();
 
//  Pass_NtReleaseSemaphore();
 
//  Pass_NtOpenSemaphore();
 
//  Pass_NtWaitForSingleObject();
 
  Pass_NtQuerySystemInformation();
 
  Pass_NtOpenProcess();
 
  Pass_NtReadVirtualMemory();
 
  HookFindWindow();
 
  return STATUS_SUCCESS;
}
 
 
VOID
DriverUnload(
  PDRIVER_OBJECT pDriverObj
  )

  UNICODE_STRING strLink;
  RtlInitUnicodeString(&strLink, LINK_NAME);
 
  //
  // 添加卸载代码
  //
 
 
 
//  UnDetour_NtOpenSemaphore();
 
//  UnDetour_NtWaitForSingleObject();
 
  UnDetour_NtCreateSemaphore();
 
//  UnDetour_NtReleaseSemaphore();
 
  UnDetour_NtCreateMutant();
 
  UnDetour_NtQueryObject();
 
  UnDetour_NtQuerySystemInformation();
 
  UnDetour_NtOpenProcess();
 
  UnDetour_NtReadVirtualMemory();
 
  UnHookFindWindow();
 
  RestoreSSDT();
 
 
//  Sleep(5000);
 
  IoDeleteSymbolicLink(&strLink);
  IoDeleteDevice(pDriverObj->DeviceObject);
  dprintf("[FGPK] Unloaded\n");
}
 
 
NTSTATUS
DispatchCreate(
  PDEVICE_OBJECT pDevObj,
  PIRP pIrp
  )
{
  pIrp->IoStatus.Status = STATUS_SUCCESS;
  pIrp->IoStatus.Information = 0;
 
  dprintf("[FGPK] IRP_MJ_CREATE\n");
 
  IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  return STATUS_SUCCESS;
}
 
 
NTSTATUS
DispatchClose(
  PDEVICE_OBJECT pDevObj,
  PIRP pIrp
  )
{
  pIrp->IoStatus.Status = STATUS_SUCCESS;
  pIrp->IoStatus.Information = 0;
 
  dprintf("[FGPK] IRP_MJ_CLOSE\n");
 
  IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  return STATUS_SUCCESS;
}
 
 
NTSTATUS
DispatchIoctl(
  PDEVICE_OBJECT pDevObj,
  PIRP pIrp
  )
{
  NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  PIO_STACK_LOCATION pIrpStack;
  ULONG uIoControlCode;
  PVOID pIoBuffer;
  ULONG uInSize;
  ULONG uOutSize;
 
  pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
  pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
  uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
  uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
 
  switch(uIoControlCode) {
 
    case IOCTL_HELLO: {
     
      dprintf("[FGPK] Hello\n");
      status = STATUS_SUCCESS;
    }
    break;
 
    //
    // 添加执行代码
    //
 
  }
 
  if(status == STATUS_SUCCESS)
    pIrp->IoStatus.Information = uOutSize;
  else
    pIrp->IoStatus.Information = 0;
 
  /////////////////////////////////////
  pIrp->IoStatus.Status = status;
  IoCompleteRequest(pIrp, IO_NO_INCREMENT);
 
  return status;
}
 
 
//////////////////////////////////////////////////////////////////////////
 
 
 
void __declspec(naked) my_function_detour_KiFastCallEntry()
{
  __asm
  {
    cmp     ecx,10h
      jne     SSDT
      mov    edi,KeServiceDescriptorTable
      sub    edi,0x10
      jmp    [SSDTDW_reentry_address]
 
SSDT:
    mov    edi,KeServiceDescriptorTable
      add    edi,0x20
      jmp    [SSDT_reentry_address]
 
 
  }
 
}
 
UCHAR findcode[]={0x83,0xf9,0x10,0x75};
 
VOID FindHackAddr()
{
    ULONG  uSysenter;
    ULONG i=0;
    PUCHAR strSysenter;
 
  __asm{
        mov ecx,0x176
        rdmsr
        mov uSysenter,eax  //得到KiFastCallEntry地址
      }
  strSysenter=(PUCHAR)uSysenter;
  for (i=0;i<0x100;i++)
  {
    if (
      findcode[0]==strSysenter[i] &&
      findcode[1]==strSysenter[i+1] &&
      findcode[2]==strSysenter[i+2] &&
      findcode[3]==strSysenter[i+3] )
    {
      break;
    }
 
  }
 
  KiSystemService_hack_address=uSysenter+i;
 
}
ULONG HookSysCall()
{
  KIRQL  oldIrql;
 
 
  unsigned char newcode[] = { 0xE9, 0x44, 0x33, 0x22, 0x11};
 
  char *actual_function;
 
  int i = 0;
 
  FindHackAddr();
 
  if (KiSystemService_hack_address==0)
  {
    dprintf("find hack address error!\n");
    return 0;
  }
 
  actual_function =(char*) KiSystemService_hack_address;
 
  SSDT_reentry_address = KiSystemService_hack_address+0x20;
  SSDTDW_reentry_address = KiSystemService_hack_address+0x5;
 
  *( (unsigned long *)(&newcode[1]) ) = (ULONG)my_function_detour_KiFastCallEntry-KiSystemService_hack_address-5;
 
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  for(i=0;i < 5;i++)
  {
    g_pFindOrigCode[i] = actual_function[i];
    actual_function[i] = newcode[i];
  }
  KeLowerIrql(oldIrql);
  WPON();
 
  return 1;
}
 
 
 
unsigned long AddMyServiceTable()
{
 
 
  ULONG  nSDTKerCallLen;
 
 
 
  __asm
  {
    pushad
      mov   eax,KeServiceDescriptorTable
      mov   _KeServiceDescriptorTable,eax
      sub   eax,0x40
      mov   ShadowTable,eax
      popad
  }
  nSDTKerCallLen  =  _KeServiceDescriptorTable->ntoskrnl.NumberOfServices;
 
 
  pSSDTKernel =  (PULONG)ExAllocatePool( NonPagedPool, nSDTKerCallLen*sizeof(ULONG) );
  if(!pSSDTKernel)
  {
    dprintf("AddMyServiceTable  alloc fail\n");
    return 0;
  }
  memset( (PVOID)pSSDTKernel, 0, nSDTKerCallLen*sizeof(ULONG));
 
 
  //填充新的SSDT表
  //
  RtlCopyMemory( (PVOID)pSSDTKernel,(PVOID)_KeServiceDescriptorTable->ntoskrnl.ServiceTableBase,nSDTKerCallLen*sizeof(ULONG) );
 
 
  RtlCopyMemory( (PVOID)&_KeServiceDescriptorTable->NotUse1,
    (PVOID)&_KeServiceDescriptorTable->ntoskrnl,sizeof(SERVICE_DESCRIPTOR_TABLE) );
 
 
 
  RtlCopyMemory( (PVOID)&ShadowTable->NotUse1,(PVOID)&ShadowTable->ntoskrnl,sizeof(SERVICE_DESCRIPTOR_TABLE)*2);
 
  WPOFF();
  RtlCopyMemory((PVOID)&_KeServiceDescriptorTable->NotUse1.ServiceTableBase, &pSSDTKernel, sizeof(ULONG));
 
  RtlCopyMemory((PVOID)&ShadowTable->NotUse1.ServiceTableBase, &pSSDTKernel, sizeof(ULONG));
 
  WPON();
 
  return 1;
}
 
void RePlaceSSDT()
{
  if (AddMyServiceTable())
  {
    HookSysCall();
  }
 
}
 
void RestoreSSDT()
{
  int i;
  char *actual_function = (char *)(KiSystemService_hack_address);
  KIRQL  oldIrql;
  WPOFF();
 
  KeRaiseIrql( DISPATCH_LEVEL,&oldIrql );
 
  for(i=0;i < 5;i++)
  {
    actual_function[i] = g_pFindOrigCode[i];
  }
 
  KeLowerIrql( oldIrql );
  ExFreePool(pSSDTKernel);
 
  WPON();
 
}
 
//////////////////////////////////////////////////////////////////////////
 
 
//////////////////////////////////////////////////////////////////////////
typedef NTSTATUS (*NTQUERYOBJECT)
(
 IN HANDLE ObjectHandle,
 IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
 OUT PVOID ObjectInformation,
 IN ULONG ObjectInformationLength,
 OUT PULONG ReturnLength OPTIONAL
 );
NTQUERYOBJECT OrgNtQueryObject;
 
//*****************************************************************************************************************
NTSYSAPI
NTSTATUS
NTAPI
ObQueryNameString(
               __in       PVOID Object,
               __out_opt  POBJECT_NAME_INFORMATION ObjectNameInfo,
               __in       ULONG Length,
               __out      PULONG ReturnLength
               );
 
 
NTSTATUS GetObjectNameFromHandle(HANDLE Objecthandle,PUNICODE_STRING filename)
{
//   PFILE_OBJECT      pFileObject;
//   OBJECT_HANDLE_INFORMATION HandleInformationObject;
  NTSTATUS nTstatus;
  POBJECT_NAME_INFORMATION pObjectInformation;
  PVOID Object;
  OBJECT_HANDLE_INFORMATION HandleInformation = {0};
  ULONG TempReturnLength;
 
 
  pObjectInformation=ExAllocatePool(PagedPool,0x100);
  RtlZeroMemory(pObjectInformation,0x100);
 
  __try
  {
    nTstatus = ObReferenceObjectByHandle( Objecthandle,
      0,
      NULL,
      0,
      &Object,
      &HandleInformation );
 
    if (NT_SUCCESS( nTstatus ))
    {
      nTstatus = ObQueryNameString( Object,
        (POBJECT_NAME_INFORMATION)pObjectInformation,
        0x100,
        &TempReturnLength
         );
 
      RtlCopyUnicodeString(filename,(PUNICODE_STRING)&(pObjectInformation->Name));
      return 0;
    }
   
     
   
   
  }
  __except(1)
  {
    dprintf("GetObjectNameFromHandle error!\n");
  }
 
  return -1;
 
}
//********************************************************************************************************************
 
NTSTATUS __stdcall MyNtQueryObject(
                   HANDLE ObjectHandle,
                   OBJECT_INFORMATION_CLASS ObjectInformationClass,
                   PVOID ObjectInformation,
                   ULONG ObjectInformationLength,
                   PULONG ReturnLength)
{
  NTSTATUS nTstatus;
 
  UNICODE_STRING Objectname;
  UNICODE_STRING oldname;
 
  __try
  {
    if(strcmp(GetProcessNameFromEProc(0),"DragonNest.exe")==0)
    {
      //DragonNest pid 3548 ObjectNameInformation MyNtQueryObject name \BaseNamedObjects\dnx_579876753682410 handle 00000614
 
      nTstatus=OrgNtQueryObject(ObjectHandle,ObjectInformationClass,ObjectInformation,ObjectInformationLength,ReturnLength);
      switch (ObjectInformationClass)
      {
      case ObjectNameInformation:
        if(ObjectInformation!=NULL)
        {
 
          POBJECT_NAME_INFORMATION  pobj_name=(POBJECT_NAME_INFORMATION)ObjectInformation;
          RtlInitUnicodeString(&oldname,L"\\BaseNamedObjects\\dnx_57987675368241");
          if (pobj_name->Name.Buffer)
          {
            if (wcsstr(pobj_name->Name.Buffer,L"\\BaseNamedObjects\\dnx_57987675368241"))
            {
              dprintf("DragonNest pid %d ObjectNameInformation MyNtQueryObject name %wZ handle %08x\n",PsGetCurrentProcessId(),&(pobj_name->Name),(ULONG)ObjectHandle);
              RtlCopyUnicodeString(&(pobj_name->Name),&oldname);
              dprintf("DragonNest pid %d ObjectNameInformation MyNtQueryObject name %wZ handle %08x\n",PsGetCurrentProcessId(),&(pobj_name->Name),(ULONG)ObjectHandle);
 
            }
          }
        }
        break;
      case ObjectBasicInformation:
        if(ObjectInformation!=NULL)
        {
          POBJECT_BASIC_INFORMATION  pobj_basic=(POBJECT_BASIC_INFORMATION)ObjectInformation;
          dprintf("DragonNest pid %d ObjectBasicInformation HandleCount %d handle %08x\n",PsGetCurrentProcessId(),pobj_basic->HandleCount,(ULONG)ObjectHandle);
        }
        break;
 
      }
 
    }
 
  }
  __except(1)
  {
    dprintf("MyNtQueryObject error!\n");
  }
 
 
  return nTstatus;
}
 
ULONG Pass_NtQueryObject()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 163 * 4;   
 
  (ULONG)OrgNtQueryObject = *(ULONG*)Address;    //保存此地址
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)MyNtQueryObject;      //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtQueryObject()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 163 * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OrgNtQueryObject;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
 
 
 
 
 
 
//////////////////////////////////////////////////////////////////////////
typedef NTSYSAPI NTSTATUS (__stdcall *ZWCREATEMUTANT)(
  OUT PHANDLE             MutantHandle,
  IN ACCESS_MASK          DesiredAccess,
  IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
  IN BOOLEAN              InitialOwner );
 
ZWCREATEMUTANT OrgZwCreateMutant;
OBJECT_ATTRIBUTES tmpobjatus;
 
NTSTATUS __stdcall MyZwCreateMutant(
                  OUT PHANDLE             MutantHandle,
                  IN ACCESS_MASK          DesiredAccess,
                  IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
                  IN BOOLEAN              InitialOwner )
{
  PUNICODE_STRING p_mutex_name;
  UNICODE_STRING uni_count;
  WCHAR wzCount[3];
  UNICODE_STRING tmpunicodestring;
 
  if (!strcmp(GetProcessNameFromEProc(0),"DragonNest.exe"))
  {
    if(ObjectAttributes==NULL)
      return OrgZwCreateMutant(MutantHandle,DesiredAccess,ObjectAttributes,InitialOwner);
 
    p_mutex_name=ObjectAttributes->ObjectName;
 
    if(p_mutex_name  )
    {
      if (p_mutex_name->Buffer)
      {
    //    dprintf("mutex %S\n",p_mutex_name->Buffer);
 
        if (!wcscmp(p_mutex_name->Buffer,L"Global\\MutexDragonNest"))
        {
            dprintf("fack mutex!\n");
            return STATUS_SUCCESS;
          __try
          {
            RtlInitUnicodeString(&tmpunicodestring,L"Global\\MutexDragonNest");
            RtlZeroMemory(wzCount,3*sizeof(WCHAR));
            wzCount[0]=(WCHAR)(0x30+g_Dra_count);
            g_Dra_count++;
            if(g_Dra_count==20)  g_Dra_count=0;
 
            RtlInitUnicodeString(&uni_count,wzCount);
        //    dprintf("uni_count %wZ\n",&uni_count);
        //    p_mutex_name->MaximumLength=0x100;
            RtlAppendUnicodeStringToString(&tmpunicodestring,&uni_count);
 
            dprintf("tmpunicodestring %wZ\n",&tmpunicodestring);
 
            InitializeObjectAttributes(&tmpobjatus,&tmpunicodestring,ObjectAttributes->Attributes,ObjectAttributes->RootDirectory,ObjectAttributes->SecurityDescriptor);
 
            //dprintf("mutex %S\n",p_mutex_name->Buffer);
 
            return OrgZwCreateMutant(MutantHandle,DesiredAccess,&tmpobjatus,InitialOwner);
           
 
          }
          __except(1)
          {
            dprintf("MyZwCreateMutant error\n");
          }
 
         
        }
      }
 
    }
  }
 
  return OrgZwCreateMutant(MutantHandle,DesiredAccess,ObjectAttributes,InitialOwner);
}
 
ULONG Pass_NtCreateMutant()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 43 * 4;   
 
  (ULONG)OrgZwCreateMutant = *(ULONG*)Address;    //保存此地址
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)MyZwCreateMutant;      //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtCreateMutant()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 43 * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OrgZwCreateMutant;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
 
 
 
//////////////////////////////////////////////////////////////////////////
 
 
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)
(
 ULONG SystemInformationCLass,
 PVOID SystemInformation,
 ULONG SystemInformationLength,
 PULONG ReturnLength
 );
 
NTQUERYSYSTEMINFORMATION OldNtQuerySystemInformation;
 
 
typedef struct _SYSTEM_BASIC_INFORMATION {
  BYTE Reserved1[24];
  PVOID Reserved2[4];
  CCHAR NumberOfProcessors;
} SYSTEM_BASIC_INFORMATION;
 
 
 
NTSTATUS NewNtQuerySystemInformation(
                   IN ULONG SystemInformationClass,
                   IN PVOID SystemInformation,
                   IN ULONG SystemInformationLength,
                   OUT PULONG ReturnLength)
{
 
  NTSTATUS ntStatus;
  UNICODE_STRING gamename;
  UNICODE_STRING launchername;
 
 
  ntStatus = OldNtQuerySystemInformation(
    SystemInformationClass,
    SystemInformation,
    SystemInformationLength,
    ReturnLength );
 
 
  if (!_stricmp(GetProcessNameFromEProc(0),"DragonNest.exe") || !_stricmp(GetProcessNameFromEProc(0),"dnlauncher.exe"))
  {
 
    if( NT_SUCCESS(ntStatus))
    {
 
 
      if(SystemInformationClass == 5)
      {
 
        struct _SYSTEM_PROCESSES *curr = (struct _SYSTEM_PROCESSES *)SystemInformation;
        struct _SYSTEM_PROCESSES *prev = NULL;
 
        while(curr)
        {
 
          if (curr->ProcessName.Buffer != NULL)
          {
            //  dprintf("processid %d\n",curr->ProcessId);
 
            RtlInitUnicodeString(&gamename,L"DragonNest.exe");
            RtlInitUnicodeString(&launchername,L"dnlauncher.exe");
           
 
            if((!RtlCompareUnicodeString(&(curr->ProcessName),&gamename,FALSE) && (ULONG)PsGetCurrentProcessId()!=curr->ProcessId) ||
              !RtlCompareUnicodeString(&(curr->ProcessName),&launchername,FALSE))
            {
              //  dprintf("FIND DNF PDI %d\n",curr->ProcessId);
 
              if(prev)
              {
                if(curr->NextEntryDelta)
                {
                  prev->NextEntryDelta += curr->NextEntryDelta;
                }
 
                else
                {
                  prev->NextEntryDelta = 0;
                }
              }
              else
              {
                if(curr->NextEntryDelta)
                {
 
                  (char *)SystemInformation += curr->NextEntryDelta;
                }
                else
                {
                  SystemInformation = NULL;
                }
 
              }
 
 
            }
            else
            {
              prev = curr;
            }
          }
 
          if(curr->NextEntryDelta)
          {
            ((char *)curr += curr->NextEntryDelta);
          }
          else
          {
            curr = NULL;
          }
 
 
        }
      }
 
 
    }
 
  }
 
  return ntStatus;
}
 
ULONG Pass_NtQuerySystemInformation()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 173 * 4;   
 
  (ULONG)OldNtQuerySystemInformation = *(ULONG*)Address;    //保存此地址
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)NewNtQuerySystemInformation;      //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtQuerySystemInformation()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 173 * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OldNtQuerySystemInformation;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
 
//////////////////////////////////////////////////////////////////////////
 
 
//////////////////////////////////////////////////////////////////////////NtOpenProcess
 
 
ULONG OldNtProcessAdd;
 
 
NTSTATUS
NewNtOpenProcess (
        __out PHANDLE ProcessHandle,
        __in ACCESS_MASK DesiredAccess,
        __in POBJECT_ATTRIBUTES ObjectAttributes,
        __in_opt PCLIENT_ID ClientId
        )
{
 
  HANDLE Handle;
  KPROCESSOR_MODE PreviousMode;
  NTSTATUS Status;
  PEPROCESS Process;
  PETHREAD Thread;
  CLIENT_ID CapturedCid={0};
  BOOLEAN ObjectNamePresent;
  BOOLEAN ClientIdPresent;
  ACCESS_STATE AccessState;
  AUX_ACCESS_DATA AuxData;
  ULONG Attributes;
  LUID SeDebugPrivilege = {0};
 
  PEPROCESS tempeprocess;
 
  if (!strcmp("DragonNest.exe",GetProcessNameFromEProc(0)) || !strcmp("dnlauncher.exe",GetProcessNameFromEProc(0)))
  {
    PsLookupProcessByProcessId(ClientId->UniqueProcess,&tempeprocess);
    __try
    {
      if (
        !strcmp("DML.exe",GetProcessNameFromEProc(tempeprocess)) ||
        (!strcmp("DragonNest.exe",GetProcessNameFromEProc(tempeprocess)) && PsGetCurrentProcessId()!=ClientId->UniqueProcess)
        /*!strcmp("DeRoX.exe",GetProcessNameFromEProc(tempeprocess))*/
        )
      {
        return STATUS_ACCESS_DENIED;
      }
 
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
      dprintf("GetExceptionCode %08x\n",GetExceptionCode());
      return GetExceptionCode();
    }
 
   
  }
 
  return NtOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes, ClientId);
}
 
 
ULONG Pass_NtOpenProcess()
{
 
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase +  0x7A * 4;
 
  OldNtProcessAdd = *(ULONG*)Address;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)NewNtOpenProcess;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
 
  return 1;
}
 
VOID UnDetour_NtOpenProcess()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase +  0x7A * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = OldNtProcessAdd;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
 
}
 
//////////////////////////////////////////////////////////////////////////
typedef
NTSTATUS
(*NTREADVIRTUALMEMORY)(
          IN HANDLE ProcessHandle,
          IN PVOID BaseAddress,
          OUT PVOID Buffer,
          IN ULONG NumberOfBytesToRead,
          OUT PULONG NumberOfBytesReaded OPTIONAL );
 
NTREADVIRTUALMEMORY OldNtReadVirtualMemoryAdd;
 
NTSTATUS NewNtReadVirtualMemory(
                IN HANDLE               ProcessHandle,
                IN PVOID                BaseAddress,
                OUT PVOID               Buffer,
                IN ULONG                NumberOfBytesToRead,
                OUT PULONG              NumberOfBytesReaded OPTIONAL
                )
{
 
  NTSTATUS    status;
  PEPROCESS   pEProcess=0;
  char*       proname=0;
 
  if (!strcmp("DragonNest.exe",GetProcessNameFromEProc(0)))
  {
    if (!ProcessHandle)
    {
      return 0;
 
    }
 
    status = ObReferenceObjectByHandle(ProcessHandle,PROCESS_ALL_ACCESS,NULL,0,&pEProcess,NULL);
 
    if(!NT_SUCCESS(status))
    {
      dprintf("ObReferenceObjectByHandle fail! %08x \n",status);
      return 0;
 
    }
    ObDereferenceObject(pEProcess);
    proname=GetProcessNameFromEProc(pEProcess);
    if (PsGetCurrentProcessId()!=PsGetProcessId(pEProcess))
    {
      if (!strcmp("DragonNest.exe",proname) || !strcmp("MDL.exe",proname))
      {
        return STATUS_ACCESS_DENIED;
      }
    }
 
  }
  return OldNtReadVirtualMemoryAdd(ProcessHandle,BaseAddress,Buffer,NumberOfBytesToRead,NumberOfBytesReaded);
 
}
 
 
 
//////////////////////////////////////////////////////////////////////////NtReadVirtualMemory
 
 
 
ULONG Pass_NtReadVirtualMemory()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 0xBA * 4;    //得到NtReadVirtualMemory的服务地址
 
  (ULONG)OldNtReadVirtualMemoryAdd = *(ULONG*)Address;    //保存此地址
 
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)NewNtReadVirtualMemory;  //HOOK SSDT
 
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtReadVirtualMemory()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 0xBA * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OldNtReadVirtualMemoryAdd;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
//////////////////////////////////////////////////////////////////////////
 
 
 
//////////////////////////////////////////////////////////////////////////
 
typedef NTSTATUS (*NTCREATESEMAPHORE)(
          OUT PHANDLE             SemaphoreHandle,
          IN ACCESS_MASK          DesiredAccess,
          IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
          IN ULONG                InitialCount,
          IN ULONG                MaximumCount );
 
NTCREATESEMAPHORE OrgNtCreateSemaphore;
 
ULONG semhandle=0;
 
NTSTATUS __stdcall MyNtCreateSemaphore(
                     OUT PHANDLE             SemaphoreHandle,
                     IN ACCESS_MASK          DesiredAccess,
                     IN POBJECT_ATTRIBUTES   ObjectAttributes OPTIONAL,
                     IN ULONG                InitialCount,
                     IN ULONG                MaximumCount
                     )
{
  PUNICODE_STRING p_mutex_name;
  UNICODE_STRING uni_count={0};
//  WCHAR wzCount[3];
 
  NTSTATUS nTstatus;
  __try
  {
    if (!strcmp(GetProcessNameFromEProc(0),"DragonNest.exe"))
    {
      if(ObjectAttributes==NULL)
        return OrgNtCreateSemaphore(SemaphoreHandle,DesiredAccess,ObjectAttributes,InitialCount,MaximumCount);
 
      p_mutex_name=ObjectAttributes->ObjectName;
 
      if(p_mutex_name  )
      {
        if (p_mutex_name->Buffer)
        {
          //dprintf("Semaphore %S\n",p_mutex_name->Buffer);
          //dnx_57987675368241
 
          if (!wcscmp(p_mutex_name->Buffer,L"dnx_57987675368241"))
          {     
            /*         
            nTstatus=OrgNtCreateSemaphore(SemaphoreHandle,DesiredAccess,ObjectAttributes,InitialCount,MaximumCount);
            dprintf("Semaphore %S\n",p_mutex_name->Buffer);
            dprintf("OrgNtCreateSemaphore nTstatus %08x\n",nTstatus);
            //    semhandle=(ULONG)*SemaphoreHandle;
            //    dprintf("DragonNest pid %d MyNtCreateSemaphore dnx_57987675368241 handle %08x\n",PsGetCurrentProcessId(),semhandle);
            return nTstatus;
            */     
 
           
            while(1)
            {
              nTstatus=OrgNtCreateSemaphore(SemaphoreHandle,DesiredAccess,ObjectAttributes,InitialCount,MaximumCount);
              if (nTstatus==STATUS_OBJECT_NAME_EXISTS)
              {
                dprintf("STATUS_OBJECT_NAME_EXISTS\n");
                
              //  RtlZeroMemory(wzCount,3*sizeof(WCHAR));
              //  wzCount[0]=(WCHAR)(0x30+g_Sem_count);
                g_Sem_count++;
                if(g_Sem_count==20)  g_Sem_count=0;
                uni_count.Buffer=(PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE);
                uni_count.MaximumLength=BUFFER_SIZE;
                nTstatus=RtlIntegerToUnicodeString(g_Sem_count,10,&uni_count);
                  if (NT_SUCCESS(nTstatus))
                  {
                    p_mutex_name->MaximumLength=0x100;
                    RtlAppendUnicodeStringToString(p_mutex_name,&uni_count);
                  }
                  else
                  {
                    dprintf("RtlIntegerToUnicodeString error!\n");
                  }
 
              //  RtlInitUnicodeString(&uni_count,wzCount);
              }
              else
              {
                dprintf("CreateSemaphore sucess! Semaphore name %S\n",p_mutex_name->Buffer);
                return nTstatus;
              }
 
            }
            //  MaximumCount=10;
            //  dprintf("DragonNest CreateSemaphore MaximumCount :%d InitialCount :%d\n",MaximumCount,InitialCount);
            //  dprintf("fack mutex!\n");
            //  return STATUS_SUCCESS;
          }
        }
 
      }
    }
  }
  __except(1)
  {
    dprintf("MyNtCreateSemaphore error\n");
  }
  return OrgNtCreateSemaphore(SemaphoreHandle,DesiredAccess,ObjectAttributes,InitialCount,MaximumCount);
}
 
ULONG Pass_NtCreateSemaphore()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 51 * 4;   
 
  (ULONG)OrgNtCreateSemaphore = *(ULONG*)Address;    //保存此地址
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)MyNtCreateSemaphore;      //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtCreateSemaphore()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 51 * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OrgNtCreateSemaphore;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
//////////////////////////////////////////////////////////////////////////
 
typedef NTSTATUS (*NTRELEASESEMAPHORE)(
 
           IN HANDLE               SemaphoreHandle,
           IN ULONG                ReleaseCount,
           OUT PULONG              PreviousCount OPTIONAL );
 
NTRELEASESEMAPHORE OrgNtReleaseSemaphore;
 
NTSTATUS __stdcall MyNtReleaseSemaphore(
                    IN HANDLE               SemaphoreHandle,
                    IN ULONG                ReleaseCount,
                    OUT PULONG              PreviousCount OPTIONAL
                    )
{
  UNICODE_STRING semaphorename;
  __try
  {
    if (!strcmp(GetProcessNameFromEProc(0),"DragonNest.exe"))
    {
 
      if (semhandle==(ULONG)SemaphoreHandle)
      {
        dprintf("DragonNest pid %d ReleaseSemaphore handle %08x\n",PsGetCurrentProcessId(),SemaphoreHandle);
      }
     
/*
      if (!GetObjectNameFromHandle(SemaphoreHandle,&semaphorename))
      {
        if (!wcscmp(semaphorename.Buffer,L"dnx_57987675368241"))
        {
          dprintf("DragonNest pid %d ReleaseSemaphore name %wZ\n",PsGetCurrentProcessId(),&semaphorename);
        }
       
      }
      */
    }
  }
  __except(1)
  {
    dprintf("MyNtReleaseSemaphore error!\n");
  }
  return OrgNtReleaseSemaphore(SemaphoreHandle,ReleaseCount,PreviousCount);
}
 
ULONG Pass_NtReleaseSemaphore()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 189 * 4;   
 
  (ULONG)OrgNtReleaseSemaphore = *(ULONG*)Address;    //保存此地址
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)MyNtReleaseSemaphore;      //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtReleaseSemaphore()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 189 * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OrgNtReleaseSemaphore;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
//////////////////////////////////////////////////////////////////////////
 
 
typedef  NTSTATUS (*NTOPENSEMAPHORE)(
 
        OUT PHANDLE             SemaphoreHandle,
        IN ACCESS_MASK          DesiredAccess,
        IN POBJECT_ATTRIBUTES   ObjectAttributes );
 
NTOPENSEMAPHORE OrgNtOpenSemaphore;
 
NTSTATUS __stdcall MyNtOpenSemaphore(
                   OUT PHANDLE             SemaphoreHandle,
                   IN ACCESS_MASK          DesiredAccess,
                   IN POBJECT_ATTRIBUTES   ObjectAttributes )
{
  PUNICODE_STRING p_mutex_name;
  __try
  {
    if (!strcmp(GetProcessNameFromEProc(0),"DragonNest.exe"))
    {
  //    dprintf("DragonNest pid %d OpenSemaphore\n",PsGetCurrentProcessId());
 
      p_mutex_name=ObjectAttributes->ObjectName;
 
      if(p_mutex_name  )
      {
        if (p_mutex_name->Buffer)
        {
          if (!wcscmp(p_mutex_name->Buffer,L"dnx_57987675368241"))
          {
            dprintf("DragonNest PID %d NtOpenSemaphore name %S\n",PsGetCurrentProcessId(),p_mutex_name->Buffer);
          } 
        }
      }
 
     
    }
  }
  __except(1)
  {
    dprintf("MyNtOpenSemaphore error!\n");
  }
  return OrgNtOpenSemaphore(SemaphoreHandle,DesiredAccess,ObjectAttributes);
}
 
ULONG Pass_NtOpenSemaphore()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 126 * 4;   
 
  (ULONG)OrgNtOpenSemaphore = *(ULONG*)Address;    //保存此地址
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
  *((ULONG*)Address) = (ULONG)MyNtOpenSemaphore;      //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
  return 1;
}
 
//反补丁,用于最后恢复用
VOID UnDetour_NtOpenSemaphore()
{
  KIRQL oldIrql;
  ULONG  Address=0;
 
  Address = (ULONG)_KeServiceDescriptorTable->NotUse1.ServiceTableBase + 126 * 4;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();
 
  *((ULONG*)Address) = (ULONG)OrgNtOpenSemaphore;  //HOOK SSDT
  KeLowerIrql(oldIrql);
  WPON();
}
//////////////////////////////////////////////////////////////////////////
 
 
 
typedef NTSTATUS (*NTWAITFORSINGLEOBJECT)(
 
            IN HANDLE&n