附加器

反调试系列调试标志寄存器

发布时间:2022/8/17 18:35:05   
疗效好的白癜风医院 http://baidianfeng.39.net/a_bdfnzhm/130821/4241377.html

调试标志寄存器

系统表中的特殊标志寄存器,即停留在进程内存中的、由操作系统设置的标志寄存器,可以用来指示进程正在被调试。这些标志寄存器的状态可以通过使用特定的API函数或检查内存中的系统表来验证。

这些技术是恶意软件最常使用的。

1.使用Win32API

以下技术使用现有的API函数(WinAPI或NativeAPI),这些函数检查进程内存中的系统结构,以寻找表明进程现在正在被调试的特定标志寄存器。

1.1.IsDebuggerPresent()

函数kernel32!IsDebuggerPresent()确定当前进程是否被用户模式的调试器如OllyDbg或x64dbg调试。一般来说,该函数只检查进程环境块(PEB)的BeingDebugged标志寄存器。

如果正在调试进程,可以使用以下代码终止进程:

汇编代码:

C/C++代码:

1.2.CheckRemoteDebuggerPresent()

函数kernel32!CheckRemoteDebuggerPresent()检查一个调试器(在同一台机器的不同进程中)是否连接到当前进程。

C/C++代码:

x86汇编:

x86-64汇编:

1.3.NtQueryInformationProcess()

函数ntdll!NtQueryInformationProcess()可以从一个进程中检索不同种类的信息。它接受一个ProcessInformationClass参数,该参数指定了你想得到的信息,并定义了ProcessInformation参数的输出类型。

1.3.1.ProcessDebugPort进程调试端口

可以使用ntdll!NtQueryInformationProcess()来检索进程的调试器端口号。有一个记录在案的类ProcessDebugPort,如果进程正在被调试,它会检索到一个等于0xFFFFFFFF(十进制-1)的DWORD值。

C/C++代码:

x86汇编:

x86-64汇编:

1.3.2.ProcessDebugFlags进程调试标志寄存器

一个叫做EPROCESS的内核结构代表一个进程对象,它包含NoDebugInherit字段。这个字段的反值可以通过一个无文件记录的类ProcessDebugFlags(0x1f)来检索。因此,如果返回值为0,则说明有调试器存在。

C/C++代码:

x86汇编:

x86-64汇编:

1.3.3.ProcessDebugObjectHandle进程调试对象句柄

当调试开始时,一个叫做"debugobject"的内核对象被创建。可以通过使用无文献记载的ProcessDebugObjectHandle(0x1e)类来查询这个句柄的值。

C/C++代码:

x86汇编:

x86-64汇编:

1.4.RtlQueryProcessHeapInformation()

ntdll!RtlQueryProcessHeapInformation()函数可以用来从当前进程的进程内存中读取堆标志寄存器。

C/C++代码:

1.5.RtlQueryProcessDebugInformation()

ntdll!RtlQueryProcessDebugInformation()函数可用于从被请求进程的进程内存中读取某些字段,包括堆标志寄存器。

C/C++代码:

1.6.NtQuerySystemInformation()

ntdll!NtQuerySystemInformation()函数接受一个参数,即要查询的信息类别。大多数类都没有被记录下来。这包括SystemKernelDebuggerInformation(0x23)类,它从WindowsNT开始就存在了。SystemKernelDebuggerInformation类返回两个标志寄存器的值。al中的KdDebuggerEnabled,和ah中的KdDebuggerNotPresent。因此,如果内核调试器存在,ah中的返回值为零。

C/C++代码:

反制措施

对于IsDebuggerPresent()。将进程环境块(PEB)的BeingDebugged标志设置为0。更多信息请参见BeingDebugged标志寄存器反制措施。

对于CheckRemoteDebuggerPresent()和NtQueryInformationProcess():由于CheckRemoteDebuggerPresent()调用NtQueryInformationProcess(),唯一的方法是拦截NtQueryInformationProcess()并在返回缓冲区设置以下值。

如果是ProcessDebugPort查询,则为0(或除-1外的任何值)。

如果是ProcessDebugFlags查询,则为非零值。

在ProcessDebugObjectHandle查询的情况下为0。

用RtlQueryProcessHeapInformation()、RtlQueryProcessDebugInformation()和NtQuerySystemInformation()函数反制这些检查的唯一方法是拦截它们并修改返回值:

RTL_PROCESS_HEAPS::HeapInformation::Heaps[0]:标志寄存器改为HEAP_GROWABLE,用于RtlQueryProcessHeapInformation()和RtlQueryProcessDebugInformation()。

SYSTEM_KERNEL_DEBUGGER_INFORMATION::DebuggerEnabled为0和系统_KERNEL_DEBUGGER_INFORMATION::DebuggerNotPresent为1。NtQuerySystemInformation()函数在查询SystemKernelDebuggerInformation的情况下。

2.手工检查

以下方法用于验证系统结构中的调试标志。他们手工检查进程的内存,而不使用特殊的调试API函数。

2.1.PEB!正在调试标志寄存器

这个方法只是检查PEB的BeingDebugged标志寄存器[的另一种方法,而不需要调用IsDebuggerPresent()。

32位进程:

64位进程:

WOW64进程:

C/C++代码:

2.2.NtGlobalFlag

进程环境块的NtGlobalFlag字段(32位Windows的0x68偏移,64位Windows的0xBC)默认为0。附加一个调试器并不改变NtGlobalFlag的值。但是,如果进程是由调试器创建的,则将设置以下标志寄存器:

FLG_HEAP_ENABLE_TAIL_CHECK(0x10)

FLG_HEAP_ENABLE_FREE_CHECK(0x20)

FLG_HEAP_VALIDATE_PARAMETERS(0x40)

调试器的存在可以通过检查这些标志寄存器的组合来检测。

32位进程:

64位进程:

WOW64进程:

C/C++代码:

2.3.堆标志寄存器

堆包含两个字段,它们会受到调试器存在的影响。具体如何影响,取决于Windows的版本。这些字段是标志寄存器(Flags)和强标志寄存器(ForceFlags)。

标志寄存器和强标志寄存器的值通常分别设置为HEAP_GROWABLE和0。

当调试器出现时,在WindowsNT、Windows和32位WindowsXP上,标志寄存器字段被设置为这些标志寄存器的组合。

HEAP_GROWABLE(2)

HEAP_TAIL_CHECKING_ENABLED(0x20)

HEAP_FREE_CHECKING_ENABLED(0x40)

HEAP_SKIP_VALIDATION_CHECKS(0x)

HEAP_VALIDATE_PARAMETERS_ENABLED(0x)

在64位的WindowsXP和WindowsVista及更高版本中,如果有调试器存在,Flags字段会被设置为这些标志寄存器组合:

HEAP_GROWABLE(2)

HEAP_TAIL_CHECKING_ENABLED(0x20)

HEAP_FREE_CHECKING_ENABLED(0x40)

HEAP_VALIDATE_PARAMETERS_ENABLED(0x)

当调试器出现时,ForceFlags字段被设置为这些标志寄存器的组合:

HEAP_TAIL_CHECKING_ENABLED(0x20)

HEAP_FREE_CHECKING_ENABLED(0x40)

HEAP_VALIDATE_PARAMETERS_ENABLED(0x)

C/C++代码:

2.3.堆保护

如果在NtGlobalFlag中设置了HEAP_TAIL_CHECKING_ENABLED标志寄存器,序列0xABABABAB将被附加在所分配的堆块的末端(在32位Windows中为2次,在64位Windows中为4次)。

如果在NtGlobalFlag中设置了HEAP_FREE_CHECKING_ENABLED标志寄存器,如果需要额外的字节来填充空的空间,直到下一个内存块,那么将附加序列0xFEEEFEEE。

C/C++代码:

反制措施

对于PEB!BeingDebugged标志寄存器:

将BeingDebugged标志设置为0,这可以通过DLL注入完成。如果你使用OllyDbg或x32/64dbg作为调试器,你可以选择各种反调试插件,如ScyllaHide。

对于NtGlobalFlag:

将NtGlobalFlag设置为0,这可以通过DLL注入完成。如果你使用OllyDbg或x32/64dbg作为调试器,你可以选择各种反调试插件,如ScyllaHide。

对于堆标志寄存器:

设置标志寄存器值为HEAP_GROWABLE,ForceFlags值为0,这可以通过DLL注入完成。如果你使用OllyDbg或x32/64dbg作为调试器,你可以选择各种反调试插件,如ScyllaHide。

对于堆保护:

手工修补32位的12字节和64位环境下的20字节的堆。拦截kernel32!HeapAlloc()并在其分配后修补堆。

备注:

本文投稿来自:作者王建达

原文

转载请注明:http://www.aideyishus.com/lktp/1223.html

------分隔线----------------------------

热点文章

  • 没有热点文章

推荐文章

  • 没有推荐文章