各种反调试技术原理与实例VC版 - 图文 下载本文

http://ucooper.com }

AfxMessageBox(\发现OD\ } else { AfxMessageBox(\没有OD\ } CloseHandle(hProcess); } }while(Process32Next(hProcessSnap,&tp32)); }

CloseHandle(hProcessSnap);

12. DebugObject: NtQueryObject()

除了识别进程是否被调试之外,其他的调试器检测技术牵涉到检查系统当中是否有调试器正在运行。逆向论坛中讨论的一个有趣的方法就是检查DebugObject类型内核对象的数量。这种方法之所以有效是因为每当一个应用程序被调试的时候,将会为调试对话在内核中创建一个DebugObject类型的对象。

DebugObject的数量可以通过ntdll!NtQueryObject()检索所有对象类型的信息而获得。NtQueryObject接受5个参数,为了查询所有的对象类型,ObjectHandle参数被设为NULL,ObjectInformationClass参数设为ObjectAllTypeInformation(3): NTSTATUS NTAPI NtQueryObject( IN HANDLE ObjectHandle,

IN OBJECT_INFORMATION_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG Length, OUT PULONG ResultLength )

这个API返回一个OBJECT_ALL_INFORMATION结构,其中NumberOfObjectsTypes成员为所有的对象类型在ObjectTypeInformation数组中的计数: typedef struct _OBJECT_ALL_INFORMATION{ ULONG NumberOfObjectsTypes; OBJECT_TYPE_INFORMATION ObjectTypeInformation[1]; }

检测例程将遍历拥有如下结构的ObjectTypeInformation数组: typedef struct _OBJECT_TYPE_INFORMATION{ [00] UNICODE_STRING TypeName; [08] ULONG TotalNumberofHandles; [0C] ULONG TotalNumberofObjects; ...more fields... }

TypeName成员与UNICODE字符串\比较,然后检查TotalNumberofObjects 或 TotalNumberofHandles 是否为非0值。

写意互联网,关注搜索引擎技术,涉猎搜索引擎优化、软件破解、PHP网站建设、Wordpress应用等

http://ucooper.com #ifndef STATUS_INFO_LENGTH_MISMATCH

#define STATUS_INFO_LENGTH_MISMATCH ((UINT32)0xC0000004L) #endif

typedef enum _POOL_TYPE { NonPagedPool, PagedPool,

NonPagedPoolMustSucceed, DontUseThisType,

NonPagedPoolCacheAligned, PagedPoolCacheAligned,

NonPagedPoolCacheAlignedMustS } POOL_TYPE;

typedef struct _UNICODE_STRING { USHORT Length;

USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING;

typedef UNICODE_STRING *PUNICODE_STRING; typedef const UNICODE_STRING *PCUNICODE_STRING;

typedef enum _OBJECT_INFORMATION_CLASS {

typedef struct _OBJECT_TYPE_INFORMATION {

UNICODE_STRING TypeName; ULONG TotalNumberOfHandles; ULONG TotalNumberOfObjects; WCHAR Unused1[8];

ULONG HighWaterNumberOfHandles; ULONG HighWaterNumberOfObjects; WCHAR Unused2[8];

ACCESS_MASK InvalidAttributes; GENERIC_MAPPING GenericMapping; ACCESS_MASK ValidAttributes; BOOLEAN SecurityRequired; ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectDataInformation

// Result is OBJECT_BASIC_INFORMATION structure // Result is OBJECT_NAME_INFORMATION structure // Result is OBJECT_TYPE_INFORMATION structure // Result is OBJECT_ALL_INFORMATION structure

ObjectAllTypesInformation,

// Result is OBJECT_DATA_INFORMATION structure

} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;

写意互联网,关注搜索引擎技术,涉猎搜索引擎优化、软件破解、PHP网站建设、Wordpress应用等

http://ucooper.com

typedef struct _OBJECT_ALL_INFORMATION {

typedef struct _OBJECT_ALL_TYPES_INFORMATION { ULONG NumberOfTypes;

OBJECT_TYPE_INFORMATION TypeInformation[1];

} OBJECT_ALL_TYPES_INFORMATION, *POBJECT_ALL_TYPES_INFORMATION;

typedef UINT32 (__stdcall *ZwQueryObject_t) (

void CDetectODDlg::OnNTQueryObject() {

hNtDLL = GetModuleHandle(\if(hNtDLL){

ZwQueryObject = (ZwQueryObject_t)GetProcAddress(hNtDLL, \

UINT32 iResult = ZwQueryObject(NULL, ObjectAllTypesInformation, NULL, NULL, &dwSize); if(iResult==STATUS_INFO_LENGTH_MISMATCH) {

Types

=

// TODO: Add your control notification handler code here // 调试器必须正在调试才能检测到,仅打开OD是检测不到的 HMODULE hNtDLL; DWORD dwSize; UINT i;

UCHAR KeyType=0;

OBJECT_ALL_TYPES_INFORMATION *Types; OBJECT_TYPE_INFORMATION ZwQueryObject_t ZwQueryObject;

*t;

IN HANDLE ObjectHandle,

IN OBJECT_INFORMATION_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG Length,

OUT PULONG ResultLength );

ULONG NumberOfObjectsTypes;

OBJECT_TYPE_INFORMATION ObjectTypeInformation[1]; BOOLEAN MaintainHandleCount; USHORT MaintainTypeList; POOL_TYPE PoolType;

ULONG DefaultPagedPoolCharge; ULONG DefaultNonPagedPoolCharge;

} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;

} OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;

(OBJECT_ALL_TYPES_INFORMATION*)VirtualAlloc(NULL,dwSize,MEM_COMMIT,PAGE_READWRITE)

写意互联网,关注搜索引擎技术,涉猎搜索引擎优化、软件破解、PHP网站建设、Wordpress应用等

http://ucooper.com ; }

}

}

AfxMessageBox(\没有OD!\VirtualFree (Types,0,MEM_RELEASE);

for (t=Types->TypeInformation,i=0;iNumberOfTypes;i++) { }

if ( !_wcsicmp(t->TypeName.Buffer,L\比较两个是否相等,这个L很特{ }

t=(OBJECT_TYPE_INFORMATION

*)((char

if(t->TotalNumberOfHandles > 0 || t->TotalNumberOfObjects > 0) { }

break; // Found Anyways

AfxMessageBox(\发现OD\

VirtualFree (Types,0,MEM_RELEASE); return;

if (Types == NULL) return;

if (iResult=ZwQueryObject(NULL,ObjectAllTypesInformation, Types, dwSize, &dwSize)) return;

殊,本地的意思

*)t->TypeName.Buffer+((t->TypeName.MaximumLength+3)&~3));

13. OllyDbg:Guard Pages

这个检查是针对OllyDbg的,因为它和OllyDbg的内存访问/写入断点特性相关。

除了硬件断点和软件断点外,OllyDbg允许设置一个内存访问/写入断点,这种类型的断点是通过页面保护来实现的。简单地说,页面保护提供了当应用程序的某块内存被访问时获得通知这样一个途径。

页面保护是通过PAGE_GUARD页面保护修改符来设置的,如果访问的内存地址是受保护页面的一部分,将会产生一个STATUS_GUARD_PAGE_VIOLATION(0x80000001)异常。如果进程被OllyDbg调试并且受保护的页面被访问,将不会抛出异常,访问将会被当作内存断点来处理,而壳正好利用了这一点。 示例

下面的示例代码中,将会分配一段内存,并将待执行的代码保存在分配的内存中,然后启用页面的PAGE_GUARD属性。接着初始化标设符EAX为0,然后通过执行内存中的代码来引发STATUS_GUARD_PAGE_VIOLATION异常。如果代码在OllyDbg中被调试,因为异常处理例程不会被调用所以标设符将不会改变。 对策

由于页面保护引发一个异常,逆向分析人员可以故意引发一个异常,这样异常处理例程将会被调用。在示例中,逆向分析人员可以用INT3指令替换掉RETN指令,一旦INT3指令被

写意互联网,关注搜索引擎技术,涉猎搜索引擎优化、软件破解、PHP网站建设、Wordpress应用等