首页
论坛
专栏
课程

[商业保护] [讨论][讨论]TP

2012-12-22 08:57 7729

[商业保护] [讨论][讨论]TP

2012-12-22 08:57
7729
#include <ntddk.h>
#define dprintf DbgPrint
#include <windef.h>
#include "debugport.h"
#define DNF_EXE  "DNF.exe"  //要检索的进程名
ULONG addr_DbgkpQueueMessage;
ULONG addr_DbgkpSetProcessDebugObject;
VOID Reg_DbgkpQueueMessage();
VOID Reg_DbgkpSetProcessDebugObject();
BYTE MovEaxAddress3[7]  = {0x8b,0xff,0x55,0x8b,0xec,0x83,0xec};  //b8f4289ab7
    //BYTE b_byte[]={0x8B,0xFF,0x55,0x8B,0xEC,0x81,0xEC};
BYTE MovEaxAddress2[7]  = {0x8b,0xff,0x55,0x8b,0xec,0x81,0xec};  //b8f4289ab7
        //BYTE b_byte[]={0x8B,0xFF,0x55,0x8B,0xEC,0x83,0xEC};

typedef struct _ServiceDescriptorTable {
        PVOID ServiceTableBase;    //System Service Dispatch Table 的基地址  
        PVOID ServiceCounterTable;
        //包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。
        unsigned int NumberOfServices;//由 ServiceTableBase 描述的服务的数目。  
        PVOID ParamTableBase; //包含每个系统服务参数字节数表的基地址-系统服务参数表
}*PServiceDescriptorTable;
extern PServiceDescriptorTable KeServiceDescriptorTable;

BYTE  *NtReadVirtualMemoryAddress    = NULL;  //NtReadVirtualMemory的地址
BYTE  *NtWriteVirtualMemoryAddress  = NULL;  //NtWriteVirtualMemory的地址

BYTE * KiAttachProcessAddress=NULL;
BYTE    MovEaxAddress[5]  = {0xB8,0,0,0,0};  //b8f4289ab7
//BYTE    MovEaxAddress1[5]  = {0xB8,f4,28,9a,b7};  //b8f4289ab7
BYTE    JmpEax[2]      = {0xff,0xe0};
BYTE MovEaxAddress1[5]={0xB8,0,0,0,0};
BYTE MovEax[6]={0,0,0,0,0,0};
BYTE MovEaxThread[6]={0,0,0,0,0,0};

BYTE MovEaxRW[2]={0,0};
BYTE MovEaxR[5]={0,0,0,0,0};
BYTE MovEaxW[5]={0,0,0,0,0};

BYTE Mov1[2]={0,0};//保存清零时的原来数据,以便卸载驱动用
BYTE Mov2[2]={0,0};//保存清零时的原来数据,以便卸载驱动用
BYTE Mov3[2]={0,0};//保存清零时的原来数据,以便卸载驱动用
BYTE Mov4[2]={0,0};//保存清零时的原来数据,以便卸载驱动用

KIRQL Irql;
ULONG MyGetFunAddress(IN PCWSTR FunctionName);
ULONG myGetCurrentAddress(IN ULONG index);
NTSTATUS unhook();
NTSTATUS unhook1();
NTSTATUS unhook2();
NTSTATUS unhook3();
NTSTATUS unhook4();
NTSTATUS unhook5();

NTSTATUS unhookT();

VOID WPOFF();
VOID WPON();

PEPROCESS  processEPROCESS = NULL;  //保存访问者的EPROCESS
ANSI_STRING  p_str1,p_str2;      //保存进程名称
BYTE    *ObOpenObjectByPointerAddress  = NULL; //ObOpenObjectByPointer的地址
BYTE    *p_TpHookAddress = NULL;        //TP的HOOK函数地址
BYTE    *p_ReturnAddress = NULL;        //返回到的地址
BYTE    *p_MyHookAddress = NULL;        //我们的HOOK函数在哪写入

//////////////////////////////////////////////////////////////////////
//  名称:  My_DbgkpSetProcessDebugObject
//  功能:  解除游戏保护对_My_DbgkpSetProcessDebugObject和DbgkpQueueMessage函数的HOOK(DNF)
//  参数:  
//  返回:  状态
//////////////////////////////////////////////////////////////////////
void My_DbgkpSetProcessDebugObject()
{
       
        Reg_DbgkpQueueMessage();
        Reg_DbgkpSetProcessDebugObject();
}

//////////////////////////////////////////////////////////////////////
//  名称:  Nakd_KiAttachProcess
//  功能:  My_RecoveryHook_KiAttachProcess的中继函数
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
_declspec (naked) NTSTATUS Nakd_KiAttachProcess()
{
        __asm
        {
                mov     edi,edi
                        push    ebp
                        mov     ebp,esp
                        push    ebx
                        push    esi
                        mov     eax,KiAttachProcessAddress  //注意这个是全局变量 BYTE*
                        add     eax,7
                        jmp     eax
        }
}
//////////////////////////////////////////////////////////////////////
//  名称:  RecoveryHook_KiAttachProcess
//  功能:  解除游戏保护对_KiAttachProcess函数的HOOK(DNF)
//  参数:  
//  返回:  状态
//////////////////////////////////////////////////////////////////////
NTSTATUS My_RecoveryHook_KiAttachProcess()
{
        BYTE    *KeAttachProcessAddress = NULL;  //KeAttachProcess函数地址
        BYTE    *p;

        KIRQL   Irql;
        //特征码
        BYTE  Signature1 = 0x56,  //p-1 ok
                  Signature2 = 0x57,  //p-2 ok
                  Signature3 = 0x5F,  //p+5 ok
                  Signature4 = 0x5E,  //p+6 ok
                  Signature5 = 0xE8;  //p第一个字节 ok
       
        //获得KeAttachProcess地址,然后通过特征码找到
        //KiAttachProcess的地址
        KeAttachProcessAddress = (BYTE*)MyGetFunAddress(L"KeAttachProcess");
        if (KeAttachProcessAddress == NULL)
        {
                KdPrint(("KeAttachProcess地址获取失败\n"));
                return  0;
        }
        //将p指向KeAttachProcess函数开始处
        p = KeAttachProcessAddress;
        while (1)
        {
                if ((*(p-1) == Signature1) &&
                        (*(p-2) == Signature2) &&
                        (*(p+5) == Signature3) &&
                        (*(p+6) == Signature4) &&
                        (*p    == Signature5))
                {
                        //定位成功后取地址
                        KiAttachProcessAddress = (PBYTE)(*(PULONG)(p+1)+(ULONG)(p+5));
                       
                        *(ULONG *)(MovEaxAddress1+1)=*(ULONG *)(KiAttachProcessAddress+1);
                       
                        KdPrint(("KiAttachProcessAddress地址%x\n",KiAttachProcessAddress));
            KdPrint(("Nakd_KiAttachProcess地址%x\n",Nakd_KiAttachProcess));
            KdPrint(("*(p-1)的特征码%x\n",*(p-1)));
            KdPrint(("*p的特征码%x\n",*p));
                        KdPrint(("MovEaxAddress1[0]%0x \n",MovEaxAddress1[0]));
                        KdPrint(("MovEaxAddress1[1]%0x \n",MovEaxAddress1[1]));
                        KdPrint(("MovEaxAddress1[2]%0x \n",MovEaxAddress1[2]));
                        KdPrint(("MovEaxAddress1[3]%0x \n",MovEaxAddress1[3]));
                        KdPrint(("MovEaxAddress1[4]%0x \n",MovEaxAddress1[4]));
                       
                        break;
                }
               
                //推动指针
                p++;
        }
       
        //计算中继函数地址
        *(ULONG *)(MovEaxAddress+1)=(ULONG)Nakd_KiAttachProcess;
       
        WPOFF();  //清除CR0
        //提升IRQL中断级
        Irql=KeRaiseIrqlToDpcLevel();
        //写入
        RtlCopyMemory(KiAttachProcessAddress,MovEaxAddress,5);
        RtlCopyMemory(KiAttachProcessAddress+5,JmpEax,2);
        //恢复Irql
        KeLowerIrql(Irql);
        WPON();    //恢复CR0
       
        return  STATUS_SUCCESS;
}

//////////////////////////////////////////////////////////////////////
//  名称:  Nakd_NtOpenProcess
//  功能:  My_RecoveryHook_NtOpenProcess的中继函数
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
_declspec (naked) NTSTATUS Nakd_NtOpenProcess()
{
        //获得调用者的EPROCESS
        processEPROCESS = IoGetCurrentProcess();
        //将调用者的进程名保存到str1中
        RtlInitAnsiString(&p_str1,(PCSZ)(ULONG)processEPROCESS+0x174);
        //将我们要比对的进程名放入str2
        RtlInitAnsiString(&p_str2,DNF_EXE);
        if (RtlCompareString(&p_str1,&p_str2,TRUE) == 0)
        {
                //说明是DNF进程访问了这里
               
                KdPrint(("DNF.exe的DebugPort地址为 %x",(ULONG)processEPROCESS+0xbc));
               
                __asm
                {
                        push    dword ptr [ebp-38h]
                                push    dword ptr [ebp-24h]
                                push    p_ReturnAddress
                                mov     eax,p_TpHookAddress
                                jmp     eax
                }
        }
        else
        {
                __asm
                {
                        push    dword ptr [ebp-38h]
                                push    dword ptr [ebp-24h]
                                push    p_ReturnAddress
                                mov     eax,ObOpenObjectByPointerAddress
                                jmp     eax
                }
        }
}

//////////////////////////////////////////////////////////////////////
//  名称:  My_RecoveryHook_NtOpenProcess
//  功能:  解除游戏保护对NtOpenProcess的HOOK
//  参数:  
//  返回:  状态
//////////////////////////////////////////////////////////////////////
NTSTATUS My_RecoveryHook_NtOpenProcess()
{
        BYTE    *NtOpenProcessAddress      = NULL;  //NtOpenProcess的地址
        BYTE    *p = NULL;      //临时
        //TOP5CODE  *top5code = NULL;  //保存5字节内容
        BYTE    JmpAddress[6] = {0xE9,0,0,0,0,0x90};
       
       
    //获取NtOpenProcess的地址
    NtOpenProcessAddress = (BYTE*)MyGetFunAddress(L"NtOpenProcess");
    if (NtOpenProcessAddress == NULL)
    {
                KdPrint(("NtOpenProcess地址获取失败\n"));
                return  0;//FAILED_TO_OBTAIN_FUNCTION_ADDRESSES;
    }
    //获取ObOpenObjectByPointer的地址
    ObOpenObjectByPointerAddress = (BYTE*)MyGetFunAddress(L"ObOpenObjectByPointer");
    if (ObOpenObjectByPointerAddress == NULL)
    {
                KdPrint(("ObOpenObjectByPointer地址获取失败\n"));
                return  0;//FAILED_TO_OBTAIN_FUNCTION_ADDRESSES;
    }
       
    //将p指向NtOpenProcess函数开始处
    p = NtOpenProcessAddress;
    //用一个无限循环来判断给定的特征码来确定被HOOK位置
    while (1)
    {
                if ((*(p-7)    == 0x50) && //ok
                        (*(p-0xE)  == 0x56) &&//ok
                        (*(p+0xd)  == 0x50) &&//ok
                        (*(p+0x16)  == 0x3b) &&//ok
                        (*(p+0x17)  == 0xce) &&//ok
                        (*p      == 0xE8) &&//ok
                        (*(p+5)    == 0x8b) &&//ok
                        (*(p+6)    == 0xf8))//ok
                {
                        KdPrint(("%0X \n",(ULONG)p));
                        break;
                }
                //推动指针向前走
                p++;
    }
       
    //将top5code指向 p 的当前处
    //用以取出 call [地址] 这5字节里面的地址
    //top5code = (TOP5CODE*)p;
    p_TpHookAddress = (PBYTE)(*(PULONG)(p+1)+(ULONG)(p+5));
    KdPrint(("p_TpHookAddress应该跳转的地址    %0X \n",(ULONG)p_TpHookAddress));
       
    //80580a6f e92c0d4c77      jmp     f7a417a0
    //找到我们写入自定义函数的地址
    p_MyHookAddress = p-6;
    *(BYTE *)MovEax=*(BYTE *)p_MyHookAddress;
        *(BYTE *)(MovEax+1)=*(BYTE *)(p_MyHookAddress+1);
        *(BYTE *)(MovEax+2)=*(BYTE *)(p_MyHookAddress+2);
        *(BYTE *)(MovEax+3)=*(BYTE *)(p_MyHookAddress+3);
        *(BYTE *)(MovEax+4)=*(BYTE *)(p_MyHookAddress+4);
        *(BYTE *)(MovEax+5)=*(BYTE *)(p_MyHookAddress+5);
    KdPrint(("MovEax%X \n",(ULONG)MovEax));
       
       
       
       
    KdPrint(("p_MyHookAddress%0X \n",(ULONG)p_MyHookAddress));
    //保存调用ObOpenObjectByPointer函数以后的返回地址
    p_ReturnAddress = p+5;
    KdPrint(("p_ReturnAddress%0X \n",(ULONG)p_ReturnAddress));
    KdPrint(("Nakd_NtOpenProcess%0X \n",(ULONG)Nakd_NtOpenProcess));
       
    //将一条JMP Nakd_NtOpenProcess写入到数组中
    *(ULONG *)(JmpAddress+1)=(ULONG)Nakd_NtOpenProcess - ((ULONG)p_MyHookAddress+5);
    KdPrint(("JmpAddress[0]%0x \n",JmpAddress[0]));
        KdPrint(("JmpAddress[1]%0x \n",JmpAddress[1]));
        KdPrint(("JmpAddress[2]%0x \n",JmpAddress[2]));
        KdPrint(("JmpAddress[3]%0x \n",JmpAddress[3]));
        KdPrint(("JmpAddress[4]%0x \n",JmpAddress[4]));
        KdPrint(("JmpAddress[5]%0x \n",JmpAddress[5]));
       
       
    WPOFF();  //清除CR0
    //提升IRQL中断级
    Irql=KeRaiseIrqlToDpcLevel();
    //写入
    RtlCopyMemory(p_MyHookAddress,JmpAddress,6);
        KdPrint(("p_MyHookAddress_hook后的地址%0X \n",*(ULONG *)(p_MyHookAddress)));
    //恢复Irql
    KeLowerIrql(Irql);
    WPON();    //恢复CR0
       
        return  STATUS_SUCCESS;
}

// NtOpenThread用到的全局变量[为了方便堆栈平衡的处理使用全局变量]
PEPROCESS  processEPROCESS_2 = NULL;  //保存访问者的EPROCESS
ANSI_STRING  p_str1_2,p_str2_2;             //保存进程名称
BYTE    *ObOpenObjectByPointerAddress_2  = NULL; //ObOpenObjectByPointer的地址
BYTE    *p_TpHookAddress_2 = NULL;      //TP的HOOK函数地址
BYTE    *p_ReturnAddress_2 = NULL;       //返回到的地址
BYTE    *p_MyHookAddress_2 = NULL;     //我们的HOOK函数在哪写入

//////////////////////////////////////////////////////////////////////
//  名称:  Nakd_ NtOpenThread
//  功能:  My_RecoveryHook_ NtOpenThread的中继函数
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
_declspec (naked) NTSTATUS Nakd_NtOpenThread()
{
        //获得调用者的EPROCESS
        processEPROCESS_2 = IoGetCurrentProcess();
        //将调用者的进程名保存到str1_2中
        RtlInitAnsiString(&p_str1_2,(PCSZ)(ULONG)processEPROCESS_2+0x174);
        //将我们要比对的进程名放入str2_2
        RtlInitAnsiString(&p_str2_2,DNF_EXE);
       
       
        if (RtlCompareString(&p_str1_2,&p_str2_2,TRUE) == 0)
        {
                //说明是DNF进程访问了这里
                __asm
                {
                            push    dword ptr [ebp-34h]
                                push    dword ptr [ebp-20h]
                                push    p_ReturnAddress_2
                                mov     eax,p_TpHookAddress_2
                                jmp     eax
                }
        }
        else
               
               
               
                __asm
    {
                    push    dword ptr [ebp-34h]
                        push    dword ptr [ebp-20h]
                        push    p_ReturnAddress_2
                        mov     eax,ObOpenObjectByPointerAddress_2
                        jmp     eax
    }
}

//////////////////////////////////////////////////////////////////////
//  名称:  My_RecoveryHook_ NtOpenThread
//  功能:  解除游戏保护对NtOpenThread的HOOK
//  参数:  
//  返回:  状态
//////////////////////////////////////////////////////////////////////
NTSTATUS My_RecoveryHook_NtOpenThread()
{
        BYTE    * NtOpenThreadAddress      = NULL;  // NtOpenThread的地址
        BYTE    *p= NULL;      //临时
       
        BYTE    JmpAddress[6] = {0xE9,0,0,0,0,0x90};
       
       
    //获取NtOpenThread的地址
    NtOpenThreadAddress = (BYTE*)MyGetFunAddress(L"NtOpenThread");
    if (NtOpenThreadAddress == NULL)
    {
                KdPrint(("NtOpenThread地址获取失败\n"));
                return  0;
    }
    //获取ObOpenObjectByPointer_2的地址
    ObOpenObjectByPointerAddress_2 = (BYTE*)MyGetFunAddress(L"ObOpenObjectByPointer");
    if (ObOpenObjectByPointerAddress_2 == NULL)
    {
                KdPrint(("ObOpenObjectByPointer地址获取失败\n"));
                return  0;
    }
       
    //将p指向NtOpenThread函数开始处
    p= NtOpenThreadAddress;
    //用一个无限循环来判断给定的特征码来确定被HOOK位置
   
       
       
       
       
       
       
       
        while (1)
    {
                if ((*(p-7)    == 0x50) && //ok
                        (*(p-0xE)  == 0x56) &&//ok
                        (*(p+0xd)  == 0x50) &&//ok
                        (*(p+0x1b)  == 0x3b) &&
                        (*(p+0x1c)  == 0xfe) &&
                        (*p      == 0xE8) &&//ok
                        (*(p+5)    == 0x8b) &&//ok
                        (*(p+6)    == 0xf8))//ok
                {
                        KdPrint(("p%0X \n",(ULONG)p));
                        break;
                }
                //推动指针向前走
                p++;
    }
       
    //将top5code_2指向 p_2 的当前处
    //用以取出 call [地址] 这5字节里面的地址
    //top5code_2 = (TOP5CODE_2 *)p_2;
    p_TpHookAddress_2 = (PBYTE)(*(PULONG)(p+1)+(ULONG)(p+5));
    KdPrint(("p_TpHookAddress_2应该跳转的地址    %0X \n",(ULONG)p_TpHookAddress_2));
       
    //找到我们写入自定义函数的地址
    p_MyHookAddress_2 = p-6;
       
    *(BYTE *)MovEaxThread=*(BYTE *)p_MyHookAddress_2;
        *(BYTE *)(MovEaxThread+1)=*(BYTE *)(p_MyHookAddress_2+1);
        *(BYTE *)(MovEaxThread+2)=*(BYTE *)(p_MyHookAddress_2+2);
        *(BYTE *)(MovEaxThread+3)=*(BYTE *)(p_MyHookAddress_2+3);
        *(BYTE *)(MovEaxThread+4)=*(BYTE *)(p_MyHookAddress_2+4);
        *(BYTE *)(MovEaxThread+5)=*(BYTE *)(p_MyHookAddress_2+5);
       
    KdPrint(("MovEaxThread!!!!!!!!!!!!!!!!!%X \n",(ULONG)MovEaxThread));
       
    //保存调用ObOpenObjectByPointer函数以后的返回地址
    p_ReturnAddress_2 = p+5;
        KdPrint((" p_MyHookAddress_2  %0X \n",(ULONG) p_MyHookAddress_2));
       
        KdPrint((" p_ReturnAddress_2  %0X \n",(ULONG)p_ReturnAddress_2));
       
    //将一条JMP Nakd_ NtOpenThread写入到数组中
    *(ULONG *)(JmpAddress+1)=(ULONG)Nakd_NtOpenThread - ((ULONG)p_MyHookAddress_2+5);
       
    WPOFF();  //清除CR0
    //提升IRQL中断级
    Irql=KeRaiseIrqlToDpcLevel();
    //写入
    RtlCopyMemory(p_MyHookAddress_2,JmpAddress,6);
    //恢复Irql
    KeLowerIrql(Irql);
    WPON();    //恢复CR0
       
        return  STATUS_SUCCESS;
}

//////////////////////////////////////////////////////////////////////
//  名称:  My_RecoveryHook_NtReadAndWriteMemory
//  功能:  解除游戏保护对NtReadVirtualMemory和
//      NtWriteVirtualMemory的HOOK
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
NTSTATUS My_RecoveryHook_NtReadAndWriteMemory()
{
        BYTE  Push1Ch[2]  = {0x6a,0x1c};  //0~2字节
        BYTE  PushAdd[5]  = {0x68,0xd8,0x6f,0x4f,0x80};  //NtReadVirtualMemory[物理机]
        BYTE  PushAdd2[5] = {0x68,0xf0,0x6f,0x4f,0x80};  //NtWriteVirtualMemory[物理机]
        KIRQL  Irql;
       
       
        //从SSDT表中获取NtReadVirtualMemory函数地址
        NtReadVirtualMemoryAddress = (BYTE*)myGetCurrentAddress(0xBA);
        if (NtReadVirtualMemoryAddress == NULL)
        {
                KdPrint(("NtReadVirtualMemory函数地址获取失败! \n"));
                return  0;//FAILED_TO_OBTAIN_FUNCTION_ADDRESSES;
        }

    //*(BYTE *)MovEax=*(BYTE *)p_MyHookAddress;
    *(BYTE *)MovEaxRW=*(BYTE *)NtReadVirtualMemoryAddress;
    *(BYTE *)(MovEaxRW+1)=*(BYTE *)(NtReadVirtualMemoryAddress+1);

    *(BYTE *)MovEaxR=*(BYTE *)(NtReadVirtualMemoryAddress+2);
        *(BYTE *)(MovEaxR+1)=*(BYTE *)(NtReadVirtualMemoryAddress+3);
        *(BYTE *)(MovEaxR+2)=*(BYTE *)(NtReadVirtualMemoryAddress+4);
        *(BYTE *)(MovEaxR+3)=*(BYTE *)(NtReadVirtualMemoryAddress+5);
        *(BYTE *)(MovEaxR+4)=*(BYTE *)(NtReadVirtualMemoryAddress+6);

        //从SSDT表中获取NtWriteVirtualMemory函数地址
        NtWriteVirtualMemoryAddress = (BYTE*)myGetCurrentAddress(0x115);
        if (NtWriteVirtualMemoryAddress == NULL)
        {
                KdPrint(("NtWriteVirtualMemory函数地址获取失败! \n"));
                return  0;//FAILED_TO_OBTAIN_FUNCTION_ADDRESSES;
        }
        *(BYTE *)MovEaxW=*(BYTE *)(NtWriteVirtualMemoryAddress+2);
        *(BYTE *)(MovEaxW+1)=*(BYTE *)(NtWriteVirtualMemoryAddress+3);
        *(BYTE *)(MovEaxW+2)=*(BYTE *)(NtWriteVirtualMemoryAddress+4);
        *(BYTE *)(MovEaxW+3)=*(BYTE *)(NtWriteVirtualMemoryAddress+5);
        *(BYTE *)(MovEaxW+4)=*(BYTE *)(NtWriteVirtualMemoryAddress+6);
       
       
        WPOFF();  //清除CR0
        //提升IRQL中断级
        Irql=KeRaiseIrqlToDpcLevel();
        //写入
        RtlCopyMemory(NtReadVirtualMemoryAddress,Push1Ch,2);
        RtlCopyMemory(NtReadVirtualMemoryAddress+2,PushAdd,5);
       
        RtlCopyMemory(NtWriteVirtualMemoryAddress,Push1Ch,2);
        RtlCopyMemory(NtWriteVirtualMemoryAddress+2,PushAdd2,5);
        //恢复Irql
        KeLowerIrql(Irql);
        WPON();    //恢复CR0
       
        return  STATUS_SUCCESS;
}

ULONG    uNtSetContextThreadAddress;
ULONG    uNtGetContextThreadAddress;
ULONG    TenNtSetContextThread, TenNtGetContextThread;
//////////////////////////////////////////////////////////////////////
//  名称:  _MyNtGetThreadContext
//  功能:  两个SSDT HOOK伪造函数的中继函数
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
_declspec (naked) NTSTATUS Nakd_NtGetThreadContext(HANDLE hThread, PCONTEXT pContext)
{
        __asm
        {
                jmp    dword ptr[TenNtGetContextThread]
        }
}

_declspec (naked) NTSTATUS Nakd_NtSetThreadContext(HANDLE hThread, PCONTEXT pContext)
{
        __asm
        {
                jmp    dword ptr[TenNtSetContextThread]
        }
}
//////////////////////////////////////////////////////////////////////
//  名称:  MyNtGetThreadContext && MyNtSetThreadContext
//  功能:  NtGetThreadContext与NtSetThreadContext函数被SSDT HOOK的伪造函数
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
UCHAR* PsGetProcessImageFileName( IN PEPROCESS Process );

NTSTATUS MyNtGetThreadContext(HANDLE hThread, PCONTEXT pContext)
{
        if ( _stricmp((const char*)PsGetProcessImageFileName(PsGetCurrentProcess()),DNF_EXE) )
        {
                return Nakd_NtGetThreadContext(hThread, pContext);
        }
        return STATUS_UNSUCCESSFUL;
}

NTSTATUS MyNtSetThreadContext(HANDLE hThread, PCONTEXT pContext)
{
        if ( _stricmp((const char*)PsGetProcessImageFileName(PsGetCurrentProcess()),DNF_EXE) )
        {
                return Nakd_NtSetThreadContext(hThread, pContext);
        }
        //DbgPrint("Dr7:%08X\n", pContext->Dr7);
        if ( pContext->Dr7 == 0x101 )
        {
                return Nakd_NtSetThreadContext(hThread, pContext);
        }
        return STATUS_UNSUCCESSFUL;
}

//////////////////////////////////////////////////////////////////////
//  名称:  My_Recovery_HardwareBreakpoint
//  功能:  通过对set与get进行SSDT HOOK来恢复硬件断点
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
NTSTATUS My_Recovery_HardwareBreakpoint()
{
        KIRQL    Irql;
        //获取地址
        uNtSetContextThreadAddress = (ULONG)KeServiceDescriptorTable->ServiceTableBase+0xD5 * 4;
        uNtGetContextThreadAddress = (ULONG)KeServiceDescriptorTable->ServiceTableBase+0x55 * 4;
       
        TenNtSetContextThread = *(ULONG*)uNtSetContextThreadAddress;
        TenNtGetContextThread = *(ULONG*)uNtGetContextThreadAddress;
       
        KdPrint(("Set地址:%0X\n",TenNtSetContextThread));
        KdPrint(("Get地址:%0X\n",TenNtGetContextThread));
       
        KdPrint(("Process:%0X \n",(ULONG)p_MyHookAddress));
        //KdPrint(("Thread:%0X \n",(ULONG)t_MyHookAddress));
       
        WPOFF();  //清除CR0
        //提升IRQL中断级
        Irql=KeRaiseIrqlToDpcLevel();
       
        //完成SSDT HOOK
        *(ULONG*)uNtGetContextThreadAddress = (ULONG)MyNtGetThreadContext;
        *(ULONG*)uNtSetContextThreadAddress = (ULONG)MyNtSetThreadContext;
       
        //恢复Irql
        KeLowerIrql(Irql);
        WPON();    //恢复CR0
       
        return STATUS_UNSUCCESSFUL;
}

//////////////////////////////////////////////////////////////////////
//  名称:  MyEnumKernelModule
//  功能:  枚举内核模块
//  参数:  str:内核模块名称
//      moduleadd:该模块地址[传出]
//      modulesie:该模块大小[传出]
//  返回:  
//////////////////////////////////////////////////////////////////////
//BOOLEAN  tlgstst= FALSE;  //如果找到了指定模块则设置为TRUE
ULONG size, index;
PVOID GetDriverBaseAdress(IN CHAR* str)
{
  NTSTATUS status;
  ULONG index;
  PULONG buf;
  PSYSTEM_MODULE_INFORMATION module;
  PVOID driverAddress = 0;
  char *sysname[256];
  char *hljname[256];
  ANSI_STRING    ModuleName1,ModuleName2;
  //BOOLEAN  tlgstst= FALSE;
  ZwQuerySystemInformation(SystemModuleInformation, &size, 0, &size);

  if (NULL == (buf = (PULONG)ExAllocatePool(PagedPool, size)))
  {
    DbgPrint("failed alloc memory failed_1 \n");
    return 0;
  }

  status = ZwQuerySystemInformation(SystemModuleInformation, buf, size, 0);
  if (!NT_SUCCESS(status))
  {
    DbgPrint("failed query_2\n");
    return 0;
  }

  module = (PSYSTEM_MODULE_INFORMATION)((PULONG)buf + 1);
  RtlInitAnsiString(&ModuleName1,str);

  for (index = 0; index <  *buf; index++)
  {
   // driverAddress = module[index].Base;
   // DbgPrint("Module found at:%x\n", driverAddress);
    sysname[index] = module[index].ImageName + module[index].ModuleNameOffset;
    //DbgPrint("Module found at:%s\n", sysname[index]);
    //hljname[index] = module[index].ImageName;
    //DbgPrint("imagename found at:%s\n", hljname[index]);
    RtlInitAnsiString(&ModuleName2,sysname[index]);
    if (RtlCompareString(&ModuleName1,&ModuleName2,TRUE) == 0)
   {
    sysname[index] = module[index].ImageName + module[index].ModuleNameOffset;
    DbgPrint("Module found at:%s\n", sysname[index]);
    driverAddress = module[index].Base;
    DbgPrint("Module found at:%x\n", driverAddress);
    //tlgstst = TRUE;
   
   
      break;
    }
    }
  
  
  ExFreePool(buf);
  return driverAddress;
}

//////////////////////////////////////////////////////////////////////
//  名称:  My_Recovery_Debugport
//  功能:  恢复游戏对debugport的清零操作
//  参数:  
//  返回:  
//////////////////////////////////////////////////////////////////////
BYTE  *sd1 = NULL,*sd2 = NULL,*pd = NULL;
BYTE  rreett[2] = {0x8b,0xff},rreett1[2] = {0xe9,0x40};
BYTE  *p1,*p2,*p3,*p4;

NTSTATUS My_Recovery_Debugport()
{
  NTSTATUS stats;
  
  ULONG  ModuleSize,ModuleAddress,i,number = 0;

  BYTE  *p;
  KIRQL  Irql;
  BYTE  C390[2] = {0xc3,0x90},C391[3]={0xc2,0x08,0x00};

  //获取指定的内核模块地址和字节数
  ModuleAddress = (ULONG)GetDriverBaseAdress("tesSafe.sys");
  if (ModuleAddress == 0)
  {
    return  0;//FAILED_TO_OBTAIN_FUNCTION_ADDRESSES;
  }
  KdPrint(("Address:%0X Sie:%d \n",ModuleAddress,size));
  
       
//将P指向内核模块开始处
  p1 = (BYTE*)ModuleAddress + 0x2124;//2123

  p2 = (BYTE*)ModuleAddress + 0x585e;//5855

  p3 = (BYTE*)ModuleAddress + 0x2080;//别人给的,只有这个没确定!

  p4 = (BYTE*)ModuleAddress + 0x3926;//监控

  KdPrint(("p1:%0X  \n",(ULONG)p1));
  KdPrint(("p2:%0X  \n",(ULONG)p2));
  KdPrint(("p3:%0X  \n",(ULONG)p3));
  KdPrint(("p4:%0X  \n",(ULONG)p4));

//干掉3个SD

      WPOFF();  //清除CR0
      //提升IRQL中断级
      Irql=KeRaiseIrqlToDpcLevel();
      //写入
      RtlCopyMemory(p4,C390,2);//这个是监控
      RtlCopyMemory(p1,C390,2);
      RtlCopyMemory(p2,C390,2);
      RtlCopyMemory(p3,C390,2);
      //RtlCopyMemory(p3,C391,3);
      //恢复Irql
      KeLowerIrql(Irql);
      WPON();    //恢复CR0
   
  
  return  STATUS_SUCCESS;
}

NTSTATUS unhookT()
{
       
       
   
    WPOFF();  //清除CR0
        //提升IRQL中断级
        Irql=KeRaiseIrqlToDpcLevel();
        //写入
    RtlCopyMemory(KiAttachProcessAddress,MovEaxAddress1,5);//1
        RtlCopyMemory(KiAttachProcessAddress+5,JmpEax,2);

        RtlCopyMemory(p_MyHookAddress,MovEax,6);//2

        RtlCopyMemory(p_MyHookAddress_2,MovEaxThread,6);//3

        RtlCopyMemory(NtReadVirtualMemoryAddress,MovEaxRW,2);//4
        RtlCopyMemory(NtReadVirtualMemoryAddress+2,MovEaxR,5);
        RtlCopyMemory(NtWriteVirtualMemoryAddress,MovEaxRW,2);
        RtlCopyMemory(NtWriteVirtualMemoryAddress+2,MovEaxW,5);

        *(ULONG*)uNtGetContextThreadAddress = TenNtGetContextThread;//5
        *(ULONG*)uNtSetContextThreadAddress = TenNtSetContextThread;

        RtlCopyMemory(p1,rreett,2);//6
        RtlCopyMemory(p2,rreett,2);
        RtlCopyMemory(p3,rreett1,2);
        RtlCopyMemory(p4,rreett,2);

        //恢复Irql
        KeLowerIrql(Irql);
        WPON();    //恢复CR0
       
        return  STATUS_SUCCESS;
       
       
}

VOID OnUnload(IN PDRIVER_OBJECT DriverObject)

{
       
       

        unhookT();
        KdPrint(("驱动卸载成功\n"));
       
       
       
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING pRegistryString)

{
    DriverObject->DriverUnload = OnUnload;
       
        My_DbgkpSetProcessDebugObject();
       
    My_RecoveryHook_KiAttachProcess();
   
    My_RecoveryHook_NtOpenProcess();
       
    My_RecoveryHook_NtOpenThread();

        My_RecoveryHook_NtReadAndWriteMemory();

        My_Recovery_HardwareBreakpoint();

    My_Recovery_Debugport();

    KdPrint(("驱动加载成功\n"));
        return STATUS_SUCCESS;
       
}

//////////////////////////////////////////////////////////////////////
//  名称:  MyGetFunAddress
//  功能:  获取函数地址
//  参数:  函数名称字符串指针
//  返回:  函数地址
//////////////////////////////////////////////////////////////////////
ULONG MyGetFunAddress( IN PCWSTR FunctionName)
{
        UNICODE_STRING UniCodeFunctionName;
        RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
        return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );   
}

//////////////////////////////////////////////////////////////////////
//  名称:  myGetCurrentAddress
//  功能:  获取SSDT表中指定函数的当前地址
//  参数:  index:指定函数在表中的索引号
//  返回: 刂?
//////////////////////////////////////////////////////////////////////
ULONG myGetCurrentAddress(IN ULONG index)
{
        ULONG    SSDT_Cur_Addr;
        __asm
        {
                    push  ebx
                        push  eax
                        mov    ebx,KeServiceDescriptorTable
                        mov    ebx,[ebx]
                        mov    eax,index
                        shl    eax,2
                        add    ebx,eax
                        mov    ebx,[ebx]
                        mov    SSDT_Cur_Addr,ebx
                        pop    eax
                        pop    ebx
        }
       
        return  SSDT_Cur_Addr;
}

VOID WPOFF()
{
        __asm
        {
                    cli
                        mov eax,cr0
                        and eax,not 10000h
                        mov cr0,eax
        }
}

VOID WPON()
{
        __asm
        {
                    mov eax,cr0
                        or eax,10000h
                        mov cr0,eax
                        sti
        }
}

#pragma INITCODE
VOID Reg_DbgkpQueueMessage()
{
        BYTE* _bp=(BYTE*)myGetCurrentAddress(0x7A);
        while(1)
        {
                if((*(_bp)==0x8B)&&(*(_bp+3)==0x89)&&(*(_bp+10)==0x74)&&(*(_bp+11)==0x48)&&(*(_bp+12)==0x68))
                {
                        addr_DbgkpQueueMessage=(ULONG)_bp-0xD;
                        break;
                }
                _bp++;
        }
        KdPrint(("DbgQueueMessage的地址为:%x\n",addr_DbgkpQueueMessage));
        //BYTE b_byte[]={0x8B,0xFF,0x55,0x8B,0xEC,0x81,0xEC};
        WPOFF();
        RtlCopyBytes((void*)addr_DbgkpQueueMessage,MovEaxAddress2,7);
        WPON();
}

#pragma PAGEDCODE
VOID Reg_DbgkpSetProcessDebugObject()
{
        BYTE* _bp=(BYTE*)addr_DbgkpQueueMessage;
        while(1)
        {
                if((*(_bp)==0x64)&&(*(_bp+6)==0x89)&&(*(_bp+9)==0x8D)&&(*(_bp+15)==0x89)&&(*(_bp+21)==0x33))
                {
                        addr_DbgkpSetProcessDebugObject=(ULONG)_bp-0xB;
                        break;
                }
                _bp++;
        }
        KdPrint(("DbgkpSetProcessDebugObject的地址为:%x\n",addr_DbgkpSetProcessDebugObject));
        //BYTE b_byte[]={0x8B,0xFF,0x55,0x8B,0xEC,0x83,0xEC};
        WPOFF();
        RtlCopyBytes((void*)addr_DbgkpSetProcessDebugObject,MovEaxAddress3,7);
        WPON();
}

最新的TP 轩辕传奇反断点调试原理是什么?
我可以附加了,就是下断点(全部类型的断点),就退出,可能是R3级动了手脚?

[公告]安全服务和外包项目请将项目需求发到看雪企服平台:https://qifu.kanxue.com

最新回复 (8)
学雄 1 2012-12-22 09:55
2
0
反断点,可能是在驱动层拦截 对进程的操作吧
猜测,要下断点,得打开进程,
要改变内存块的属性,还得打开进程
要下硬件断点,也得打开线程         
,拦截这些对进程或线程的obj操作,估计能反断点

应用层 使用crc校验能检测cc断点
应用层不断地枚举内存块属性,对比属性,也能反断点

当然,全部都是猜测哈,偶没玩过轩辕传奇
lwykj 2012-12-23 05:01
3
0
以前遇到过一次, 用内存断点当普通断点用,似乎有效,,,,,,, 不知道现在更新的如何了
veninson 2012-12-23 19:15
4
0
有个疑问,清零部分是cv过的,每次驱动更新重新加vm,清零和监控处的代码不会变吗?
Akihyou 2012-12-24 09:55
5
0
偶在想...都是TP的保护..在不同的游戏中会不一样吗?
小烦 1 2012-12-24 10:23
6
0
楼主想表达什么?
usano 2012-12-29 13:42
7
0
最新的TP 轩辕传奇反断点调试原理是什么?
我可以附加了,就是下断点(全部类型的断点),运行到断点就退出,可能是R3级动了手脚,
怀疑是R3级程序自已调试自已,断点时是TP的程序先接到断点事件
lwykj 2012-12-29 13:51
8
0
试验了下,应该是驱动做的手脚, 不知道是否idt上做了手脚
目前也在研究ing
hrpirip 1 2012-12-29 17:12
9
0
次奥。。。。。看得我眼睛生疼。
为何要用这种一个一个去恢复的方法呢,难道TP有检测KiFastCallEntry?
游客
登录 | 注册 方可回帖
返回