静态反调试技术(2)

NtQueryInformationProcess()

下面介绍一种利用NtQuertInformationProcess()API探测调试器的技术。通过NtQuertInformationProcess()API可以获取各种与进程相关的信息。函数定义如下

NtQueryInformationProcess ( 
IN HANDLE ProcessHandle, // 进程句柄 
IN PROCESSINFOCLASS InformationClass, // 信息类型 
OUT PVOID ProcessInformation, // 缓冲指针 
IN ULONG ProcessInformationLength, // 以字节为单位的缓冲大小 
OUT PULONG ReturnLength OPTIONAL // 写入缓冲的字节数 
); 

第一个参数是希望操作的进程句柄,这个句柄必须以PROCESS_QUERY_INFORMATION模式存取。为了取得一个句柄,我们必须用OpenProcess函数:

HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,dwProcessID); 

第二个参数是请求信息的类型,这个参数可以有许多个值,为这个参数指定特定值并去调用函数,相关信息就会设置到第三个参数PVOID ProcessInformation

因此,如果第二个参数是ProcessBasicInformation的话,则第三个参数必须为一个指针指向结构PROCESS_BASIC_INFORMATION

 typedef struct 
{
    
     
      DWORD ExitStatus; // 接收进程终止状态 
      DWORD PebBaseAddress; // 接收进程环境块地址 
      DWORD AffinityMask; // 接收进程关联掩码 
      DWORD BasePriority; // 接收进程的优先级类 
      ULONG UniqueProcessId; // 接收进程ID 
      ULONG InheritedFromUniqueProcessId; //接收父进程ID 
} PROCESS_BASIC_INFORMATION; 

PROCESSINFOCLASS是枚举类型,拥有的值如下所示:

enum PROCESSINFOCLASS
{
    
    
    ProcessBasicInformation = 0,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort = 7,				//0x7
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass,
    ProcessWow64Information = 26,
    ProcessImageFileName = 27,
    ProcessDebugObjectHandle = 30,			//0x1E
    ProcessDebugFlags = 31,					//0x1F
    SystemKernelDebuggerInformation = 35
};

以上代码中与调试器探测相关的成员为ProcessDebugPort(0x7),ProcessDebugObjectHandle(0x1E),ProcessDebugFlags(0x1F)

ProcessDebugPort(0x7)

进程处于调试状态时,系统就会为它分配一个调试端口(Debug Port)。PROCESSINFOCLASS参数的值设置为 ProcessDebugPort(0x7)时,调用NtQueryInformationProcess()函数就能获取调试端口。若进程处于非调试状态,则变量 ProcessDebugPort的值设置为0;若进程处于调试状态,则变量 ProcessDebugPort的值设置为0xFFFFFFFF

ProcessDebugPort=0x7;
DWORD dwDebugPort = 0;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugPort,
                               &dwDebugPort,
                               sizeof(dwDebugPort),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugPort) = 0x%X\n", dwDebugPort);
    if( dwDebugPort != 0x0  )  printf("  => Debugging!!!\n\n");
    else                       printf("  => Not debugging...\n\n");

CheckRemoteDebuggerPresent()

CheckRemoteDebuggerPresent() API与IsdebuggerPresent() API类似,用来检测进程是否处于调试状态。CheckRemoteDebuggerPresent()函数不仅可以用来检测当前进程,还可以用来检测其它进程是否处于被调试状态。
在这里插入图片描述

CheckRemoteDebuggerPresent()内部代码如下:

在这里插入图片描述
在这里插入图片描述
这个参数7即 ProcessDebugPort

ProcessDebugObjectHandle(0x1E)

调试进程时会生成调试对象(Debug Object)。函数的第二个参数值为 ProcessDebugObjectHandle(0x1E)时,调用函数后通过第三个参数就能获取调用对象句柄。进程属于调试状态时,调试对象句柄就存在;若进程处于非调试状态,则调试对象句柄值为NULL

ProcessDebugObjectHandle=0x1E;
HANDLE hDebugObject = NULL;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugObjectHandle,
                               &hDebugObject,
                               sizeof(hDebugObject),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugObjectHandle) = 0x%X\n", hDebugObject);
    if( hDebugObject != 0x0  )  printf("  => Debugging!!!\n\n");
    else                        printf("  => Not debugging...\n\n");

ProcessDebugFlags(0x1F)

检测Debug Flags(调试标志)的值也可以判断进程是否处于被调试状态,函数的第二个参数设置为ProcessDebugFlags(0x1F)时,调用函数后通过第三个参数即可获取调试标志的值:若为,则进程处于被调试状态;若为1,则进程处于非调试状态。

 	ProcessDebugFlags=0x1F;
	BOOL bDebugFlag = TRUE;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugFlags,
                               &bDebugFlag,
                               sizeof(bDebugFlag),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugFlags) = 0x%X\n", bDebugFlag);
    if( bDebugFlag == 0x0  )  printf("  => Debugging!!!\n\n");
    else                      printf("  => Not debugging...\n\n");
}

调试程序代码

#include "stdio.h"
#include "windows.h"
#include "tchar.h"
 
enum PROCESSINFOCLASS
{
    
    
    ProcessBasicInformation = 0,
    ProcessQuotaLimits,
    ProcessIoCounters,
    ProcessVmCounters,
    ProcessTimes,
    ProcessBasePriority,
    ProcessRaisePriority,
    ProcessDebugPort = 7,
    ProcessExceptionPort,
    ProcessAccessToken,
    ProcessLdtInformation,
    ProcessLdtSize,
    ProcessDefaultHardErrorMode,
    ProcessIoPortHandlers,
    ProcessPooledUsageAndLimits,
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup,
    ProcessPriorityClass,
    ProcessWx86Information,
    ProcessHandleCount,
    ProcessAffinityMask,
    ProcessPriorityBoost,
    MaxProcessInfoClass,
    ProcessWow64Information = 26,
    ProcessImageFileName = 27,
    ProcessDebugObjectHandle = 30,
    ProcessDebugFlags = 31,
    SystemKernelDebuggerInformation = 35
};
 
void MyNtQueryInformationProcess()
{
    
    
    typedef NTSTATUS (WINAPI *NTQUERYINFORMATIONPROCESS)(
        HANDLE ProcessHandle,
        PROCESSINFOCLASS ProcessInformationClass,
        PVOID ProcessInformation,
        ULONG ProcessInformationLength,
        PULONG ReturnLength
    );
 
    NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess = NULL;
 
    pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)
                                 GetProcAddress(GetModuleHandle(L"ntdll.dll"), 
                                                "NtQueryInformationProcess");
 
    // ProcessDebugPort (0x7)
    DWORD dwDebugPort = 0;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugPort,
                               &dwDebugPort,
                               sizeof(dwDebugPort),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugPort) = 0x%X\n", dwDebugPort);
    if( dwDebugPort != 0x0  )  printf("  => Debugging!!!\n\n");
    else                       printf("  => Not debugging...\n\n");
 
    // ProcessDebugObjectHandle (0x1E)
    HANDLE hDebugObject = NULL;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugObjectHandle,
                               &hDebugObject,
                               sizeof(hDebugObject),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugObjectHandle) = 0x%X\n", hDebugObject);
    if( hDebugObject != 0x0  )  printf("  => Debugging!!!\n\n");
    else                        printf("  => Not debugging...\n\n");
 
    // ProcessDebugFlags (0x1F)
    BOOL bDebugFlag = TRUE;
    pNtQueryInformationProcess(GetCurrentProcess(),
                               ProcessDebugFlags,
                               &bDebugFlag,
                               sizeof(bDebugFlag),
                               NULL);
    printf("NtQueryInformationProcess(ProcessDebugFlags) = 0x%X\n", bDebugFlag);
    if( bDebugFlag == 0x0  )  printf("  => Debugging!!!\n\n");
    else                      printf("  => Not debugging...\n\n");
}
 
int _tmain(int argc, TCHAR* argv[])
{
    
    
    MyNtQueryInformationProcess();
 
    printf("\npress any key to quit...\n");
    _gettch();
 
    return 0;
}

在这里插入图片描述
strongOD->Options中的*KernelMode可以绕过。

NtQuerySystemInformation()

这是基于调试环境检测的反调试技术。

注意:
前面所介绍的反调试技术,我们通过探测调试器来判断自己的进程是否处于被调试状态,这是一种非常直接的调试器探测方法。除此之外,还有间接探测调试器的方法,借助该方法可以检测调试环境,若显露出调试器的端倪,则立刻停止执行程序。

运用这种反调试技术可以检测当前OS是否在调试模式下运行。

OS的调试模式:
为了使用winDbg工具调试系统内核(Kernel Debugging),需要先准备2个系统(Host Target)并连接(Serial,1394,USB,Direct Cable)。其中,Target的OS以调试模式运行,连接到Host系统的WinDbg上台后即可调试。

设置调试模式方法:

windows XP:编辑"C:\boot.ini"

windows 7:使用bcdedit.exe实用程序
在这里插入图片描述
在这里插入图片描述

ntdll!NtQuerySystemInformation()API是一个系统函数,用来获取当前运行的多种OS信息。

typedef NTSTATUS (__stdcall *NTQUERYSYSTEMINFORMATION)
(IN   SYSTEM_INFORMATION_CLASS SystemInformationClass,

IN OUT PVOID          SystemInformation,

IN   ULONG          SystemInformationLength,

OUT   PULONG         ReturnLength OPTIONAL);

NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;

第一个参数是dwRecordType,这个参数指定了我们所查询的系统信息类型,为了查询系统HANDLE列表,我们定义一个常量#define NT_HANDLE_LIST 16(这个数值我是查资料得到的,如果谁有更详细的资料,也请让我共享一下)。

第二个参数是一个指针,这个指针用来返回系统句柄列表,在调用NtQuerySystemInformation函数之前,必须为这个指针分配足够的内存空间,否则函数调用会出错。

第三个参数是指定你为HandleList所分配的内存空间大小,单位是byte。

第四个参数是NtQuerySystemInformation返回的HandleList的大小;如果NtQuerySystemInformation函数调用成功,返回值将是0,否则可以使用GetLastError()获得详细的错误代码。

SYSTEM_INFORMATION_CLASS 是枚举类型,拥有的值如下:

typedef enum _SYSTEM_INFORMATION_CLASS {
    
    
SystemBasicInformation,// 0 Y N
SystemProcessorInformation,// 1 Y N
SystemPerformanceInformation,// 2 Y N
SystemTimeOfDayInformation,// 3 Y N
SystemNotImplemented1,// 4 Y N // SystemPathInformation
SystemProcessesAndThreadsInformation,// 5 Y N
SystemCallCounts,// 6 Y N
SystemConfigurationInformation,// 7 Y N
SystemProcessorTimes,// 8 Y N
SystemGlobalFlag,// 9 Y Y
SystemNotImplemented2,// 10 YN // SystemCallTimeInformation
SystemModuleInformation,// 11 YN
SystemLockInformation,// 12 YN
SystemNotImplemented3,// 13 YN // SystemStackTraceInformation
SystemNotImplemented4,// 14 YN // SystemPagedPoolInformation
SystemNotImplemented5,// 15 YN // SystemNonPagedPoolInformation
SystemHandleInformation,// 16 YN
SystemObjectInformation,// 17 YN
SystemPagefileInformation,// 18 YN
SystemInstructionEmulationCounts,// 19 YN
SystemInvalidInfoClass1,// 20
SystemCacheInformation,// 21 YY
SystemPoolTagInformation,// 22 YN
SystemProcessorStatistics,// 23 YN
SystemDpcInformation,// 24 YY
SystemNotImplemented6,// 25 YN // SystemFullMemoryInformation
SystemLoadImage,// 26 NY // SystemLoadGdiDriverInformation
SystemUnloadImage,// 27 NY
SystemTimeAdjustment,// 28 YY
SystemNotImplemented7,// 29 YN // SystemSummaryMemoryInformation
SystemNotImplemented8,// 30 YN // SystemNextEventIdInformation
SystemNotImplemented9,// 31 YN // SystemEventIdsInformation
SystemCrashDumpInformation,// 32 YN
SystemExceptionInformation,// 33 YN
SystemCrashDumpStateInformation,// 34 YY/N
SystemKernelDebuggerInformation,// 35 YN  //0x23
SystemContextSwitchInformation,// 36 YN
SystemRegistryQuotaInformation,// 37 YY
SystemLoadAndCallImage,// 38 NY // SystemExtendServiceTableInformation
SystemPrioritySeparation,// 39 NY
SystemNotImplemented10,// 40 YN // SystemPlugPlayBusInformation
SystemNotImplemented11,// 41 YN // SystemDockInformation
SystemInvalidInfoClass2,// 42 // SystemPowerInformation
SystemInvalidInfoClass3,// 43 // SystemProcessorSpeedInformation
SystemTimeZoneInformation,// 44 YN
SystemLookasideInformation,// 45 YN
SystemSetTimeSlipEvent,// 46 NY
SystemCreateSession,// 47 NY
SystemDeleteSession,// 48 NY
SystemInvalidInfoClass4,// 49
SystemRangeStartInformation,// 50 YN
SystemVerifierInformation,// 51 YY
SystemAddVerifier,// 52 NY
SystemSessionProcessesInformation// 53 YN
} SYSTEM_INFORMATION_CLASS;

SystemInformationClass参数传入SystemKernelDebuggerInformation值(0x23)即可判断当前OS在调试模式下运行

SystemKernelDebuggerInformation0x23

void MyNtQuerySystemInformation()
{
    
    
   //检测当前OS是否运行在调试模式下,WinDbg
    typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(
        ULONG SystemInformationClass,
        PVOID SystemInformation,
        ULONG SystemInformationLength,
        PULONG ReturnLength
    );
 
    typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION 
    {
    
    
        BOOLEAN DebuggerEnabled;
        BOOLEAN DebuggerNotPresent;
    } SYSTEM_KERNEL_DEBUGGER_INFORMATION, *PSYSTEM_KERNEL_DEBUGGER_INFORMATION;
 
    NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
  
    NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)  
                                GetProcAddress(GetModuleHandle(L"ntdll"), 
                                               "NtQuerySystemInformation");
 
    ULONG SystemKernelDebuggerInformation = 0x23;
    ULONG ulReturnedLength = 0;
    SYSTEM_KERNEL_DEBUGGER_INFORMATION DebuggerInfo = {
    
    0,};
 
    NtQuerySystemInformation(SystemKernelDebuggerInformation, 
                             (PVOID) &DebuggerInfo, 
                             sizeof(DebuggerInfo),      // 2 bytes
                             &ulReturnedLength);
 
    printf("NtQuerySystemInformation(SystemKernelDebuggerInformation) = 0x%X 0x%X\n", 
           DebuggerInfo.DebuggerEnabled, DebuggerInfo.DebuggerNotPresent);
    if( DebuggerInfo.DebuggerEnabled )  printf("  => Debugging!!!\n\n");
    else                                printf("  => Not debugging...\n\n");
}

在上述代码中调用NtQuerySystemInformation()API时,第一个参数(SystemInformaticationClass)的值设置为SystemKernelDebuggerInformation(0x23),第二个参数(SystemInformation)为SYSTEM_KERNEL_DEBUGGER_INFORMATION结构体的地址。当API返回时,若系统处在调试模式下,则SYSTEM_KERNEL_DEBUGGER_INFORMATION.DebuggerEnable的值设置为1(SYSTEM_KERNEL_DEBUGGER_INFORMATION.DebuggerEnable的值恒为1)

破解之法

在Windows XP 系统中编辑boot.ini文件,删除“/debugport=coml /baudrate=115200 /debug”值。在windows 7系统的命令行窗口中执行“bcdedit /debug off”命令即可。并且,若重启系统则要以正常模式启动。

NTQueryObject()

系统中的某个调试器调试进程时,会创建1个调试对象类型的内核对象。检测该对象是否存在即可判断是否有进程正在被调试。

ntdll!NTQueryObject() API用来获取系统各种内核对象的信息,NTQueryObject()函数的定义如下

NTSTATUS NtQueryObject(

_In_opt_  HANDLE  Handle,

_In_        OBJECT_INFORMATION_CLASS objectInformationClass,

_Out_opt_ PVOID   ObjectInformation,

_In_ ULONG ObjectInformationLength,

_Out_opt_ PULONG ReturnLength

);

调用NTQueryObject()函数前,先向第二个参数 OBJECT_INFORMATION_CLASS objectInformationClass赋于某个特定的值,调用API后,包含相关信息的结构指针就被返回到第三个参数PVOID ObjectInformation


     
typedef enum _OBJECT_INFORMATION_CLASS {
    
    
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
    ObjectAllInformation,//3
    ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;

首先使用ObjectAllTypeInformation值获取系统所有对象的信息,然后从中检测是否存在调试对象。NtQueryObject()API使用方法复杂。

1.获取内核对象信息链表的大小

ULONG lSize = 0;
pNtQueryObject(NULL, ObjectAllTypesInformation, &lSize, sizeof(lSize), &lSize);

2.分配内存

void *pBuf = NULL;
pBuf = VirtualAlloc(NULL, lSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

3.获取内核对象信息链表

	typedef struct _OBJECT_TYPE_INFORMATION {
    
    
        UNICODE_STRING TypeName;
        ULONG TotalNumberOfHandles;
        ULONG TotalNumberOfObjects;
    }OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
 
    typedef struct _OBJECT_ALL_INFORMATION {
    
    
        ULONG                   NumberOfObjectsTypes;
        OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
    } OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;
    pNtQueryObject((HANDLE)0xFFFFFFFF, ObjectAllTypesInformation, pBuf, lSize, NULL);
   POBJECT_ALL_INFORMATION pObjectAllInfo = (POBJECT_ALL_INFORMATION)pBuf;

调用NtQueryObject()函数后,系统的所有对象的信息代码就被存入pBuf,然后将pBuf转换(casing)为POBJECT_ALL_INFORMATION类型。POBJECT_ALL_INFORMATION结构体_OBJECT_TYPE_INFORMATION结构体数组构成。实际内核对象类型的信息就被存储在_OBJECT_TYPE_INFORMATION结构体数组中,然后通过循环检索即可查看是否存在“调试对象”对象类型。

完整代码:

#include "stdio.h"
#include "windows.h"
#include "tchar.h"
 
typedef enum _OBJECT_INFORMATION_CLASS {
    
    
    ObjectBasicInformation,
    ObjectNameInformation,
    ObjectTypeInformation,
  	ObjectAllTypesInformation,
    ObjectHandleInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
 
void MyNtQueryObject()
{
    
    
     //基于检测调试环境
    //系统中的某个调试器调试进程时,会创建1个调试对象类型的内核对象。检测该对象
    //是否存在即可判断是否有进程正在被调试(注意不是当前进程)。
    typedef struct _LSA_UNICODE_STRING {
    
    
        USHORT Length;
        USHORT MaximumLength;
        PWSTR Buffer;
    } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
 
    typedef NTSTATUS (WINAPI *NTQUERYOBJECT)(
        HANDLE Handle,
        OBJECT_INFORMATION_CLASS ObjectInformationClass,
        PVOID ObjectInformation,
        ULONG ObjectInformationLength,
        PULONG ReturnLength
    );
    
    #pragma pack(1)
    typedef struct _OBJECT_TYPE_INFORMATION {
    
    
        UNICODE_STRING TypeName;
        ULONG TotalNumberOfHandles;
        ULONG TotalNumberOfObjects;
    }OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
 
    typedef struct _OBJECT_ALL_INFORMATION {
    
    
        ULONG                   NumberOfObjectsTypes;
        OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
    } OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;
    #pragma pack()
       
    POBJECT_ALL_INFORMATION pObjectAllInfo = NULL;
    void *pBuf = NULL;
    ULONG lSize = 0;
    BOOL bDebugging = FALSE;
 
    NTQUERYOBJECT pNtQueryObject = (NTQUERYOBJECT)
                                    GetProcAddress(GetModuleHandle(L"ntdll.dll"), 
                                                   "NtQueryObject");
 
    // Get the size of the list
    pNtQueryObject(NULL, ObjectAllTypesInformation, &lSize, sizeof(lSize), &lSize);
 
    // Allocate list buffer
    pBuf = VirtualAlloc(NULL, lSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 
    // Get the actual list
    pNtQueryObject((HANDLE)0xFFFFFFFF, ObjectAllTypesInformation, pBuf, lSize, NULL);
 
    pObjectAllInfo = (POBJECT_ALL_INFORMATION)pBuf;
 
    UCHAR *pObjInfoLocation = (UCHAR *)pObjectAllInfo->ObjectTypeInformation;
    POBJECT_TYPE_INFORMATION pObjectTypeInfo = NULL;
    for( UINT i = 0; i < pObjectAllInfo->NumberOfObjectsTypes; i++ )
    {
    
    
        pObjectTypeInfo = (POBJECT_TYPE_INFORMATION)pObjInfoLocation;
       if( wcscmp(L"DebugObject", pObjectTypeInfo->TypeName.Buffer) == 0 )
        {
    
    
            bDebugging = (pObjectTypeInfo->TotalNumberOfObjects > 0) ? TRUE : FALSE;
            break;
        }
        
        // calculate next struct
        pObjInfoLocation = (UCHAR*)pObjectTypeInfo->TypeName.Buffer;
        pObjInfoLocation += pObjectTypeInfo->TypeName.Length;
        pObjInfoLocation = (UCHAR*)(((ULONG)pObjInfoLocation & 0xFFFFFFFC) + sizeof(ULONG));
    }
 
    if( pBuf )
    VirtualFree(pBuf, 0, MEM_RELEASE);
 
    printf("NtQueryObject(ObjectAllTypesInformation)\n");
    if( bDebugging )  printf("  => Debugging!!!\n\n");
    else              printf("  => Not debugging...\n\n");
}
 
int _tmain(int argc, TCHAR* argv[])
{
    
    
    MyNtQueryObject();
 
    printf("\npress any key to quit...\n");
    _gettch();
 
    return 0;
}

strongOD->Options中的*KernelMode可以绕过。

破解之法

在这里插入图片描述
在这里插入图片描述
位于0xCB184A地址处的call dword ptr ss:[ebp-0x3C] 指令是用来调用ntdll.ZwQueryObject()API的,

在这里插入图片描述
此时查看栈可以发现,第二个参数值为ObjectAllTypesInformation(3),将该值修改为0后再执行0xCB184A地址处的指令,这样就无法探测到调试器的存在了

在这里插入图片描述
或者直接把这个API给勾取,输入ObjectAllTypesInformation(3)值或者直接操作结果值,也不会被探测到

反调试技术系列:

静态反调试技术(1)https://blog.csdn.net/CSNN2019/article/details/113105292
静态反调试技术(2)https://blog.csdn.net/CSNN2019/article/details/113147820
静态反调试技术(3)https://blog.csdn.net/CSNN2019/article/details/113178232
动态反调试技术 https://blog.csdn.net/CSNN2019/article/details/113181558
高级反调试技术 https://blog.csdn.net/CSNN2019/article/details/113263215

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/113147820