al-khaser学习笔记(一)Anti Debug

al-khaser

最近在研究开源项目al-khaser在野恶意软件使用的常用技术 

github https://github.com/LordNoteworthy/al-khaser

Anti Debug

这一部分主要是通过各种函数去确定当前进程是否处于被调试的状态。

VOID exec_check(int(*callback)(), TCHAR* szMsg)

两参数,第一参数是一个回调函数指针

第二参数是一个需要输出打印的字符串

功能 通过回调函数的返回值以及第二参数szMsg,在函数print_results(result, szMsg)进行具体的判断输出打印并记录到日志中

exec_check(&IsDebuggerPresentAPI, TEXT("Checking IsDebuggerPresent API () "));

/*这是一个Win32 Debugging API ,用于判断进程是否被调试*/

exec_check(&IsDebuggerPresentPEB, TEXT("Checking PEB.BeingDebugged "));

/*从进程中获得PEB  判断pPeb->BeingDebugged 是否被置为1,从而判断是否被调试  */ Process Environement Block (BeingDebugged)

exec_check(&CheckRemoteDebuggerPresentAPI, TEXT("Checking CheckRemoteDebuggerPresentAPI () "));

/*这是一个Win32 Debugging API ,同时可用于检查被监控线程是否被调试,*/

exec_check(&NtGlobalFlag, TEXT("Checking PEB.NtGlobalFlag "));Process Environement Block (NtGlobalFlag)

/*从PEB中取NTGlobalFlag,当进程被调试时,NTGlobalFlag会被置为

FLG_HEAP_ENABLE_TAIL_CHECK (0x10), FLG_HEAP_ENABLE_FREE_CHECK(0x20), 和 FLG_HEAP_VALIDATE_PARAMETERS(0x40),

0x70 =  FLG_HEAP_ENABLE_TAIL_CHECK |

FLG_HEAP_ENABLE_FREE_CHECK |

FLG_HEAP_VALIDATE_PARAMETERS

*/

exec_check(&HeapFlags, TEXT("Checking ProcessHeap.Flags "));ProcessHeap (Flags)Flags在不同版本的操作系统中位置不一,通过IsWindowsVistaOrGreater()判断大概版本

/*先获得ProcessHeap的地址,由于pHeapFlags在不同版本的操作系统中位置不一,需要IsWindowsVistaOrGreater()判断大概版本,从而利用pProcessHeap与偏移获得pHeapFlags的地址 */

exec_check(&HeapForceFlags, TEXT("Checking ProcessHeap.ForceFlags "));ProcessHeap (ForceFlags)ForceFlags在不同版本的操作系统中位置不一,通过IsWindowsVistaOrGreater()判断大概版本

/*先获得ProcessHeap的地址,由于ForceFlags在不同版本的操作系统中位置不一,需要IsWindowsVistaOrGreater()判断大概版本,从而利用pProcessHeap与偏移获得pHeapFlags的地址 */

exec_check(&NtQueryInformationProcess_ProcessDebugPort, TEXT("Checking NtQueryInformationProcess with ProcessDebugPort "));- NtQueryInformationProcess (ProcessDebugPort) 返回IsRemotePresent

/*该函数调用NtQuerySystemInformation来获得IsRemotePresent,当函数成功时IsRemotePresent不为 0*/

exec_check(&NtQueryInformationProcess_ProcessDebugFlags, TEXT("Checking NtQueryInformationProcess with ProcessDebugFlags "));

/*该函数调用NtQuerySystemInformation来获得NoDebugInherit,当函数成功时返回值为STATUS_SUCCESS,NoDebugInherit被置为0,表示正在被调试*/

exec_check(&NtQueryInformationProcess_ProcessDebugObject, TEXT("Checking NtQueryInformationProcess with ProcessDebugObject "));

/*该函数调用NtQuerySystemInformation来获得当前进程调试对象句柄,当函数成功         hDebugObject不为0表示正在被调试 */

exec_check(&NtSetInformationThread_ThreadHideFromDebugger, TEXT("Checking NtSetInformationThread with ThreadHideFromDebugger "));

/*将ThreadInformationClass设置为0x11(ThreadHideFromDebugger),用于隐藏调试器中的线程,调用之后调试器与该线程不再关联*/

exec_check(&CloseHandle_InvalideHandle, TEXT("Checking CloseHandle with an invalide handle "));

/*当进程被调试时,调用CloseHandle并传入无效句柄,会得到一个STATUS_INVALID_HANDLE的异常,函数返回TRUE*/

exec_check(&UnhandledExcepFil

terTest, TEXT("Checking UnhandledExcepFilterTest "));

/*当一个未知异常发生,且没有记录的应对方法时,

UnhandledExceptionFilter()会最后被调用

三种返回值

//EXCEPTION_EXECUTE_HANDLER equ 1 表示我已经处理了异常,可以优雅地结束了

//EXCEPTION_CONTINUE_SEARCH equ 0 表示我不处理,其他人来吧,于是windows调用默认的处理程序显示一个错误框,并结束

//EXCEPTION_CONTINUE_EXECUTION equ -1 表示错误已经被修复,请从异常发生处继续执行

RaiseException(EXCEPTION_FLT_DIVIDE_BY_ZERO, 0, 0, NULL);

该函数启用一个进程并使用结构化异常处理来处理私有的,软件生成的和应用程序定义的异常。

一个异常处理程序在引发异常并导致异常调度的时候需要经过以下步骤的处理:

1.如果有调试器,系统首先尝试通知进程的调试器。

2.如果这一进程不被调试,或者相关的调试器不处理异常,系统将尝试通过搜索发生异常的线程的堆栈来定位一个基于帧的异常处理程序。 系统首先会搜索当前栈帧,然后继续向后搜索栈帧。

3.如果没有找到基于帧的异常处理程序,或没有基于帧的异常处理程序处理该异常,系统将会第二次尝试通知进程的调试器。

4.如果该进程仍未被调试,或者相关的调试器不处理异常,系统以异常类型为基础提供默认的处理程序。 对于大多数异常,默认动作是调用ExitProcess函数。

即 当进程被调试时,会通知进程的调试器,而不会调用UnhandledExceptionFilter

*/

exec_check(&OutputDebugStringAPI, TEXT("Checking OutputDebugString "));

/*This Works only in Windows XP/2000

OutputDebugString()用于输出字符串给调试器显示。

我们通过GetLastError是否被置为Val,来判断是否有调试器与进程关联。

*/

exec_check(&HardwareBreakpoints, TEXT("Checking Hardware Breakpoints "));

/*硬件断点,intel下的,用Dr0-Dr7七个寄存器控制,在CONTEXT结构体中可以查询这些寄存器的状态*/

exec_check(&SoftwareBreakpoints, TEXT("Checking Software Breakpoints "));

/*软件断点 INT 3  获得函数地址和大小,以字节为单位查询是否存在0xCC */

exec_check(&Interrupt_0x2d, TEXT("Checking Interupt 0x2d "));

/*

AddVectoredExceptionHandler()注册一个定向的情况处理

__int2d()是一个用asm写的函数,利用指令 2D 测试进程是否被调试,当进程没有关联调试器,会返回一个异常,

当情况为异常断点时需要我们手动将Rip或Eip++

*/

exec_check(&Interrupt_3, TEXT("Checking Interupt 1 "));

/*

AddVectoredExceptionHandler()注册一个定向的情况处理

__debugbreak() Microsoft专用将在代码中引起断点,并在其中提示用户运行调试程序。当进程没有关联调试器,会返回一个异常,

当情况为异常断点时不需要我们手动将Rip或Eip++,原因 Int 2D instruction already increased EIP/RIP

*/

exec_check(&MemoryBreakpoints_PageGuard, TEXT("Checking Memory Breakpoints PAGE GUARD: "));

/*分配一块动态内存,将RET写入内存中,然后将这块内存标记成保护,再以函数的形式调用该地址。当进程被调试时,遇到RET指令会返回之前的栈,执行下一个语句。

反之,产生一个STATUS_GUARD_PAGE_VIOLATION的异常,说明进程没有被调试*/

exec_check(&IsParentExplorerExe, TEXT("Checking If Parent Process is explorer.exe: "));

/*判读父进程是不是创建窗口的

获得了创建窗口的线程的ID号且当进程只有一个线程的话,进程ID号也为此。

获得了父进程ID

*/

exec_check(&CanOpenCsrss, TEXT("Checking SeDebugPrivilege : "));

/*当进程被调试且被提权到administrator时,该进程可以打开Csrss进程,*/

exec_check(&NtQueryObject_ObjectTypeInformation, TEXT("Checking NtQueryObject with ObjectTypeInformation : "));

/*当调试开始,调试对象就会被创建,我们可以通过判断该对象是否存在从而判读进程是否被调试。通过NtCreateDebugObject获得DebugObjectHandle,利用NtQueryObject获得ObjectInformation

从而得到ObjectInformation 即调试对象的信息 */

exec_check(&NtQueryObject_ObjectAllTypesInformation, TEXT("Checking NtQueryObject with ObjectAllTypesInformation : "));

/*Support for Win10

当一个调试开始后,一个调试对象就会生成。我们可以通过判断该对象是否存在从而判读进程是否被调试。

两遍调用NtQueryObject,第一遍得到对象大小,申请一块内存,第二遍将对象全部信息放到这块内存里,

通过对象全部信息查找是否存在DebugObject这个对象,

*/

exec_check(&NtYieldExecutionAPI, TEXT("Checking NtYieldExecution : "));

/*NtYieldExecution使当前线程放弃自己的时间片,让已进入队列的线程执行,当没有线程执行或操作系统不允许切换发送时,函数返回STATUS_NO_YIELD_PERFORMED促使SwitchToThread返回0

当我们在被调试情况下,由于单步执行 时常会导致无法切换线程。这是一个不可靠的办法*/

exec_check(&SetHandleInformatiom_ProtectedHandle, TEXT("Checking CloseHandle protected handle trick : "));

/*创建了一个互斥体对象,利用SetHandleInformation将我们互斥体对象句柄标志改为HANDLE_FLAG_PROTECT_FROM_CLOSE

,最后关闭句柄。当进行调试时,会走到try-except 语句中return TRUE ,反之不进except 语句 return FALSE*/

时间: 2025-01-11 10:44:31

al-khaser学习笔记(一)Anti Debug的相关文章

【转】 C#学习笔记14——Trace、Debug和TraceSource的使用以及日志设计

[转] C#学习笔记14--Trace.Debug和TraceSource的使用以及日志设计 Trace.Debug和TraceSource的使用以及日志设计   .NET Framework 命名空间 System.Diagnostics 包含用于跟踪执行流程的 Trace.Debug 和 TraceSource 类,以及用于分析代码的 Process.EventLog 和 PerformanceCounter 类. 跟踪是一种在应用程序运行时监视其执行情况的方式.当开发 .NET Frame

Debug tool 学习笔记

GDB调试命令大全 gdb --pid 1235 gdb core.1234 where (bt)    //where the segmentation fault occurred f 1              //切换栈帧 info locals  //打印内存 WinDBG调试技巧 .ecxr command displays the context record Debug tool 学习笔记

51CTO学习笔记--Linux运维故障排查思路与系统调优技巧视频课程(高俊峰)

51CTO学习笔记--Linux运维故障排查思路与系统调优技巧视频课程 第一课 Linux运维经验分享与思路 1.一般把主机名,写到hosts下    127.0.0.1    hostname,因为很多应用要解析到本地.oracle没有这个解析可能启动不了. 2.注释掉UUID以及MAC地址,需要绑定网卡的时候,这个可能会有影响. 3.磁盘满了无法启动,  var下木有空间,无法创创建PID等文件,导致文件无法启动,按e   进入single  然后b  重启进入单用户模式. 4.ssh登陆系

汇编入门学习笔记 (四)—— [BX] 和 loop指令

疯狂的暑假学习之  汇编入门学习笔记 (四)-- [BX]  和 loop指令 参考:<汇编语言> 王爽 第5章 1.[BX] mov al,[1] 在debug中,会把bs:1 中数据赋给al,但在在masm中不会把bs:1 中数据赋给al,而是把 [1] 认为是 1 赋给al. 如果要实现在debug中的mov al,[1],在masm中就需要[bx] 如: mov bx,1 mov al,[bx] 还可以用 bs:[1] 的方式 如: mov al,bs:[1] 2.loop 循环 要使

汇编入门学习笔记 (十)—— 标志寄存器

疯狂的暑假学习之  汇编入门学习笔记 (十)--  标志寄存器 参考: <汇编语言> 王爽 第11章 CPU内部有一种特殊的寄存器叫标志寄存器(flag),它与ax,bx,cx等其他寄存器不同,它不是用来存放数据的,而是用来存放状态的.flag寄存器是按位器作用的,即只有0和1. flag寄存器的结构: 15     14    13    12     11     10     9     8     7     6     5     4     3     2     1     0

汇编入门学习笔记 (十一)—— 内中段

疯狂的暑假学习之  汇编入门学习笔记 (十一)--  内中段 参考: <汇编语言> 王爽 第12章 中断是指CPU在执行完当前指令后收到某种信息(中断信息),就不在接向下执行,而去对接收到的信息进行处理.中断信息可以来自CPU内部和外部,分内中断,外中断. 1. 内中断的产生 下面4中情况会产生内中断: (1)除法错误.如:div除法溢出 (2)单步执行.如debug中的单步调试 (3)执行into指令. (4)执行int指令 2. 处理中断信息 中断信息中包含8位的中断类型吗,用来表示要执行

嵌入式学习笔记101-uboot_1.1.6移植(1)

根据前篇博文(嵌入式学习笔记100-uboot1.1.6初体验)最后的结论,现在开始将其实现: a. 修改makefile的CROSS_COMPILE指定编译器 arm-linux-gcc -v –> gcc version 3.4.5 CROSS_COMPILE = /opt/EmbedSky/crosstools_3.4.5_softfloat/gcc-3.4.5-glibc-2.3.6/arm-linux/bin/arm-linux- chmod -R 777 u-boot-1.1.6/

CoAP学习笔记——nodeJS node-coap返回JSON数据包

0 前言 本文说明如何使用node-coap返回JSON数据包.CoAP是专门为物联网系统开发的面向网络的应用层协议栈,CoAP建立在UDP协议之上尽可能减少网络开销,又具有HTTP Restful类型的特性.node-coap使用nodejs实现了coap的客户端和服务器端. [测试环境]--ubuntu/Linux [相关博文] [CoAP协议文档--The Constrained Application Protocol (CoAP)] [CoAP协议学习--CoAP基础] [CoAP学习

storm学习笔记完整记录(一)

storm有两种运行模式(本地模式和集群模式) 1. 首先创建一个类似于HelloWorld的简单程序,以便进入storm的大门,包结构如下: 2.从包结构可以知道,这是一个Maven Project,pom.xml的内容如下: <project xmlns="http://maven.apache.org/POM/4.0.0"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"