反调试与反反调试

[TOC]ide

反调试与反反调试

什么是反调试? 什么是反反调试?

静态反调试

  • 特色:通常在调试开始时阻拦调试者,调试只须要找到缘由后就能够一次性突破函数

  • PEB :star:工具

    • BeginDebug : 调试标志位
    // 经过检查 PEB.BeingDebuged 字段判断是否被调试
    // 能够在目标程序运行以前修改对应的字段为 0 进行反反调试
    bool CheckBeingDebugged()
    {
    	__asm 
    	{
    		; 获取到 PEB 的内容
    		mov eax, fs:[0x30]
    		; 获取 PEB 内偏移为 2 大小为 1 字节的字段
    		movzx eax, byte ptr[eax + 2]
    	}
    }
    
    
    int main()
    {
    	if (CheckBeingDebugged())
    		printf("当前处于[被]调试状态\n");
    	else
    		printf("当前处于[非]调试状态\n");
    
    	system("pause");
    	return 0;
    }
    // 使用 IsDebuggerPresent 原理一样是判断 PEB.BeingDebuged
    // 经过 HOOK 函数和修改对应字段的方式能够进行反调试
    
    int main()
    {
    	if (IsDebuggerPresent())
    		printf("当前处于[被]调试状态\n");
    	else
    		printf("当前处于[非]调试状态\n");
    
    	system("pause");
    	return 0;
    }
    • Ldr 内存状态
    • Heap (Flags, Force Flags): 堆状态
    • NtGlobalFlag : 内核全局标记
      • 经过PEB.NtGlobalFlag 判断是否被调试,当处于被调试状态时PEB.NtGlobalFlag 保存的是 0x70,能够经过修改标志反反调试
    bool CheckNtGlobalFlag()
    {
    	__asm
    	{
    		; 获取到 PEB, 保存在 FS :[0x30]
    		mov eax, fs : [0x30]
    		;获取到 NtGlobalFlag 字段的内容
    		mov eax, [eax + 0x68]
    	}
    }
    int main()
    {
    	if (CheckNtGlobalFlag())
    		printf("当前处于[被]调试状态\n");
    	else
    		printf("当前处于[非]调试状态\n");
    
    	system("pause");
    	return 0;
    }
  • TEBspa

    • StaticUnicodeString :静态缓冲区
  • 使用原始 API插件

    • NtQuerySystemInformationProcess()
      • ProcessDebugPort(0x07): 获取调试端口
      • ProcessDebugObjectHandle(0x1E): 获取调试句柄
      • ProcessDebugFlag(0x1F): 获取调试标记
    • NtQuerySystemInformation():
      • SystemKernelDeBuggerInformation(0x23) :获取系统调试状态 (双机
    • NtQueryObject() : 遍历系统内核
  • 攻击调试器调试

    • NtSetInformationThread()
      • ThreadHideFormDebugger(0x11)
  • 打开进程检查code

    • SetDebugPrivilege :arrow_right: 检查进程是否具备调试权限
  • 利用**TLS**回调函数orm

  • 使用普通API进程

    • 父进程的检查
      • 若是一个进程被正常打开,那么它的父进程应该是 Explorer.exe,也就是资源管理器,若是判断不是,就可能被调试,提供参考。
    bool CheckParentProcess()
    {
    
    	struct PROCESS_BASIC_INFORMATION {
    		ULONG ExitStatus; 			// 进程返回码
    		PPEB  PebBaseAddress;		// PEB 地址
    		ULONG AffinityMask;			// CPU 亲和性掩码
    		LONG  BasePriority;			// 基本优先级
    		ULONG UniqueProcessId;		// 本进程PID
    		ULONG InheritedFromUniqueProcessId; // 父进程PID
    	}stcProcInfo;
    
    	// 查询到目标进程的对应信息,主要是 父进程 ID
    	NtQueryInformationProcess(
    		GetCurrentProcess(), 
    		ProcessBasicInformation, 
    		&stcProcInfo,
    		sizeof(stcProcInfo), 
    		NULL);
    
    	// 查询资源管理器对应的 PID
    	DWORD ExplorerPID = 0;
    	DWORD CurrentPID = stcProcInfo.InheritedFromUniqueProcessId;
    	GetWindowThreadProcessId(FindWindow(L"Progman", NULL), &ExplorerPID);
    
    	// 比对两个 PID 的值,相同就OK,不一样就可能被调试
    	return ExplorerPID == CurrentPID ? false : true;
    }
    
    
    int main()
    {
    	if (CheckParentProcess())
    		printf("当前处于[被]调试状态\n");
    	else
    		printf("当前处于[非]调试状态\n");
    
    	system("pause");
    	return 0;
    }
    • 窗口名检查
      • 原理是经过查找窗口类或窗口名称对应的窗口是否存在来进行调试器或其它分析工具的检查。[缺点是窗口的的名字一般不是固定的,检查起来很是的不方便]
      • 还能够经过遍历进程的方式来检查调试器或其它工具是否存在。[缺点是能够经过修改 exe 的名字修改进程名]
    int main()
    {
    	if (FindWindow(NULL, L"OllyDbg"))
    		printf("存在调试器\n");
    	else
    		printf("没检测到调试器\n");
    
    	return 0;
    }
    • 进程名检查
      • 原理就是查询 EPROCESS 结构体中相关的字段,由于不能在 R3 修改 R0 的数据,因此只能 HOOK
    bool CheckProcessDebugPort() 
    {
    	int nDebugPort = 0;
    	NtQueryInformationProcess(
    		GetCurrentProcess(), 	// 目标进程句柄
    		ProcessDebugPort, 		// 查询信息类型(7)
    		&nDebugPort, 			// 输出查询信息
    		sizeof(nDebugPort), 	// 查询类型大小
    		NULL); 					// 实际返回数据大小
    
    	// 若是返回的是 -1 ,那么就被调试了
    	return nDebugPort == 0xFFFFFFFF ? true : false;
    }
    
    
    int main()
    {
    	if (CheckProcessDebugPort())
    		printf("当前处于[被]调试状态\n");
    	else
    		printf("当前处于[非]调试状态\n");
    
    	system("pause");
    	return 0;
    }
    • 文件名及文件路径检查
    • 注册表检查
    • 。。。

动态反调试

  • 特色:通常在调试的过程当中阻拦调试者,可在调试的过程当中被频繁触发所以须要调试者随时关注
  • 使用SEH
    • 异常
    • 断点
    • SetUnhandleedExceptionFilter()
  • 时间检查
  • 单步检查
  • 补丁检查
  • 反反汇编
  • 偷取代码
  • 分页保护
  • 虚拟机

OllyDbg插件编写

  1. 插件一般是以什么样的方式存在的?

一般以DLL的方式存在的,可是后缀名可能会有变化内存

  1. 应用程序如何找到全部的插件?

全部的插件都应该被保护到具体的路径中

  1. 应用程序怎样知道是否符合本身的要求?
  • 插件必须提供指定的名称的函数说明本身的信息,插件还须要经过对应名称的函数提供具体的功能
相关文章
相关标签/搜索