当前位置: 首页 > news >正文

软件反调试(2)- 基于窗口列表的检测

反调原理

通过枚举屏幕上所有的窗口,来检测当前是否打开了调试器

EnumWindows 枚举的时候,会进行窗口回调处理,直到所有窗口回调都结束后函数才返回

VS 提供了 Spy++ 可以查看窗口的信息,通过工具下的菜单可以打开 Spy++ 程序

20250702181531

打开 Spy++ 程序,并打开其搜索窗口,左键按下窗口上的圆饼,并将光标拖动到应用的窗口上

这时候,搜索窗口上就会显示要查看窗口的信息,如这里显示窗口标题为 x64dbg [管理员]

20250702182006

在打开 x64dbg 的情况下,通过 CheckDebugWindowByEnum 函数,编译并运行 anti02.exe 程序,终端显示输出如下的信息

20250702185742

除了通过 EnumWindows 的方式进行枚举,也可以通过 GetWindow 的方式进行遍历查找窗口

每个进程的主窗口通常都是顶级窗口,一个进程通常会有一个到多个顶级窗口,可以通过遍历顶级窗口搜索目标进程

通过 CheckDebugWindowByFind 函数,编译并运行 anti02.exe 程序,终端显示输出如下的信息

20250702185659

实现代码

完成的实现代码如下,包含前面说的两种方式 CheckDebugWindowByEnum 和 CheckDebugWindowByFind


#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <windows.h>
#include <TlHelp32.h>BOOL isDebugging = FALSE;
std::string g_szWindowsTile = "";BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{char windows_title[256] = { 0 };char class_name[256] = { 0 };GetWindowText(hwnd, windows_title, 256);if (strlen(windows_title) > 0 && strstr(windows_title, g_szWindowsTile.c_str()) != 0){std::cout << "handle:" << hwnd << " find debug windows:" << windows_title << std::endl;isDebugging = TRUE;}return TRUE;
}bool CheckDebugWindowByEnum(const char* szWindowTitle)
{isDebugging = false;g_szWindowsTile = szWindowTitle;EnumWindows(EnumWindowsProc, NULL);return isDebugging;
}bool CheckDebugWindowByFind(const char* szWindowName)
{std::vector<HWND> vec;HWND hWnd = GetTopWindow(0);while (hWnd){if (GetParent(hWnd) == 0){vec.push_back(hWnd);}hWnd = GetWindow(hWnd, GW_HWNDNEXT);}char szTempName[MAX_PATH] = { 0 };for (auto& v : vec){GetWindowTextA(v, szTempName, MAX_PATH);if (strstr(szTempName, szWindowName) != 0){std::cout << "find debug windows:" << szTempName << std::endl;return true;}memset(szTempName, 0, sizeof(szTempName));}return false;
}void ThreadProc()
{while (true){if (CheckDebugWindowByFind("x64dbg")) //CheckDebugWindowByEnum("x64dbg"){std::cout << "Debugging..." << std::endl;}else{std::cout << "Running..." << std::endl;}std::this_thread::sleep_for(std::chrono::milliseconds(1000));}
}int main()
{std::thread thrd(ThreadProc);thrd.join();return 0;
}

逆向处理

和前面的[基于进程列表的检测]一样,修改内存中的 x64dbg 字符串,然后保存到补丁文件

重新运行补丁过的文件,已经去掉了基于窗口列表的反调试检测

http://www.dtcms.com/a/265149.html

相关文章:

  • 外侧三兵策略
  • 睿抗省赛2023
  • 【通识】机器学习相关
  • YOLOv11剪枝与量化(二)通道剪枝技术原理
  • 【Ragflow】30.离线环境迁移方案
  • 数据库9:数据库字符编码调整与校队(排序)规则
  • STM32F103_Bootloader程序开发11 - 实现 App 安全跳转至 Bootloader
  • UI 设计|审美积累 | 拟物化风格(Skeuomorphism)
  • 基于Jeecgboot3.8.1的vue3版本前后端分离的flowable流程管理平台
  • ai之RAG本地知识库--基于OCR和文本解析器的新一代RAG引擎:RAGFlow 认识和源码剖析
  • 学习笔记(29):训练集与测试集划分详解:train_test_split 函数深度解析
  • SimBa:实现深度强化学习参数scaling up
  • 多路I/O转接服务器(select、poll、epoll)
  • 跨境贸易的主要挑战是什么?
  • monorepo + Turborepo --- 构建仓库结构
  • 如何设置电脑定时休眠?操作指南详解
  • 从 PostgreSQL 到 DolphinDB:数据实时同步一站式解决方案
  • 金融安全生命线:用AWS EventBridge和CloudTrail构建主动式入侵检测系统
  • 少样本学习在计算机视觉中的应用:原理、挑战与最新突破
  • Java 导出PDF 1、内容可以插入自定义表格 2、内容插入图片
  • Python3 学习(菜鸟)-06迭代器与生成器
  • 碰一碰矩阵发布源码开发技术揭秘-支持OEM贴牌搭建
  • 在幸狐RV1106板子上用gcc14.2本地编译安装apache2.4.63,开启http2和tls1.3,并且https支持XP系统的IE6-8浏览器
  • 《汇编语言:基于X86处理器》第6章 条件处理(2)
  • 为什么我画的频谱图和audacity、audition不一样?
  • containerd 项目主要目录简要说明
  • Flink-1.19.0源码详解-番外补充3-StreamGraph图
  • 精准定义 RediSearch 索引 Schema
  • LeetCode Hot 100 哈希【Java和Golang解法】
  • 无人机状态识别研究梳理2025.7.2