通过全局变量和自擦除代码来防Dump(2)

本文介绍了使用memcpy实现代码段自擦除的方法,以增强软件的反Dump保护。通过修改内存权限并覆盖代码段,使得Dump工具无法简单地获取原始代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过全局变量和自擦除代码来防Dump(2)

write by 九天雁翎(JTianLing) -- blog.youkuaiyun.com/vagrxie

讨论新闻组及文件

通过全局变量和自擦除代码来防Dump 》中我提到了用WriteProcessMemory来完成代码段的自擦除,其实这并不是什么好的手段,因为使用了Win32 API,对于分析你代码的人来说,这是明摆着告诉对方你要干什么,破解手段在原文中也提到了不少。其实,当时我去搜寻WriteMemroy API但是并不存在的时候,我就在想,为什么微软不提供,并且,同样的,有ReadProcessMemory但是有ReadMemory,为什么要使用的时候都需要通过GetCurrentProcess()作为第一参数这样奇怪的形式,这个MS一贯的作风不符。这两个函数只在WinCE中有提供,普通Windows并没有,其实后来仔细想想就想通了,因为读写另外的进程的内存你必须要通过额外API,所以有这样的API给你来使用,但是读写自己的内存根本就不需要别的特殊的API,自己进程访问和改写自己进程中的数据是没有限制的。因此,需要做自擦除的操作仅仅需要memcpy或者memset就可以了!

下面是改进的示例:

1 #include "windows.h"
2 #include "tchar.h"
3
4 void Run()
5 {
6 // begin of the func
7 DWORD ldwBegin = 0;
8 __asm
9 {
10 call $+5
11 pop eax
12 mov ldwBegin, eax
13 }
14 DWORD ldwOldPro = 0;
15 // Must have this step
16 if(!VirtualProtect((void*)ldwBegin, 1000, PAGE_EXECUTE_READWRITE, &ldwOldPro))
17 {
18 printf( "VirtualProtectEx failed (%d)./n", GetLastError() );
19 return;
20 }
21
22 MessageBox(NULL, _T("Right"), _T("Hello World"), MB_OK);
23
24 // begin of the func
25 DWORD ldwEnd = 0;
26 __asm
27 {
28 call $+5
29 pop eax
30 mov ldwEnd, eax
31 }
32
33 DWORD ldwFuncLen = ldwEnd - ldwBegin;
34 BYTE *lpbyRand = new BYTE[ldwFuncLen];
35
36 DWORD ldwWritten = 0;
37 memcpy((void*)ldwBegin, lpbyRand, ldwFuncLen);
38
39 delete[] lpbyRand;
40 }
41
42 int main(int argc, char* argv[])
43 {
44 Run();
45 MessageBox(NULL, _T("OK"), _T("OK"), MB_OK);
46
47 return 0;
48 }
49
50

这样做后,就没有办法简单的将memcpy挂上使其无效化来使得擦除无效,而且,从发现你的目的的难度上来讲也更加大一些,毕竟memcpy这种函数使用的频率太高了,你可能因为各种原因使用它,而不仅仅是反Dump的目的。这也加大了分析的难度:)

write by 九天雁翎(JTianLing) -- blog.youkuaiyun.com/vagrxie

<think>好的,我现在需要帮助用户了解如何使用GDB调试C++生成的core dump文件,并查看局部变量全局变量。首先,用户之前已经询问过如何在C++中生成core dump而不崩溃,现在他们想进一步分析这个dump文件。 用户可能是在开发或维护一个C++项目,遇到了程序崩溃的问题,生成了core dump,现在需要调试。他们可能对GDB不太熟悉,尤其是如何查看变量。需要详细但清晰的步骤,避免使用过于专业的术语,但又要确保准确性。 首先,我应该确认用户的环境是否已经正确配置生成core dump,比如ulimit设置core_pattern路径,这在之前的回答中已经提到过。不过可能需要简要回顾,但用户这次的问题更多是关于调试而不是生成。 接下来,用户需要知道如何用GDB加载core dump文件。需要说明命令格式,比如gdb <程序路径> <core文件路径>。然后是如何查看堆栈回溯,使用bt或where命令。这可能帮助用户定位崩溃点。 查看变量部分,局部变量全局变量有不同的方法。局部变量通常在堆栈帧中,所以需要选择正确的帧(frame命令),然后使用info locals。而全局变量可以直接用print,但要注意作用域。需要提醒用户编译时必须有调试信息(-g选项),否则变量可能不可见。 另外,用户可能不知道如何检查变量类型或跟踪变量值的变化,这些也是调试中的常见需求。需要给出具体的命令,比如ptypedisplay,以及如何退出。 可能的疑问点包括:如何确定当前帧是否正确,如果变量被优化掉了怎么办,或者core文件没有对应的可执行文件。需要提前考虑这些情况,并在注意事项中说明,比如确保使用带调试符号的可执行文件,以及避免优化选项。 最后,示例部分可以帮助用户更直观地理解步骤。通过一个简单的代码示例,展示生成core dump,并用GDB分析,这样用户可以将理论应用到实际中。 总结步骤应该是:加载core文件,查看堆栈,选择帧,检查局部全局变量,其他调试命令,注意事项。结构清晰,逐步引导用户完成操作,同时提醒常见问题,确保他们能够顺利调试。</think>以下是在 C++ 中使用 GDB 调试核心转储(core dump)并查看局部变量全局变量的完整指南: --- ### 一、调试准备 #### 1. 编译时添加调试符号 ```bash g++ -g -o my_program my_program.cpp # -g 参数保留调试信息 ``` #### 2. 核心转储文件要求 - 确保核心转储文件(如 `core` 或 `core.1234`)与可执行文件版本一致 - 核心转储路径可通过以下命令查看: ```bash cat /proc/sys/kernel/core_pattern ``` --- ### 二、GDB 调试核心转储 #### 1. 启动 GDB ```bash gdb ./my_program core.1234 # 格式:gdb <程序路径> <core文件路径> ``` #### 2. 查看崩溃位置 ```gdb (gdb) bt # 查看堆栈回溯 (backtrace) (gdb) where # 等价于 bt ``` #### 3. 切换堆栈帧 ```gdb (gdb) frame 2 # 切换到第 2 层堆栈帧(通过 bt 显示的编号选择) (gdb) up # 向上切换一层 (gdb) down # 向下切换一层 ``` --- ### 三、查看变量 #### 1. 查看局部变量 ```gdb (gdb) info locals # 显示当前帧所有局部变量 (gdb) p my_var # 打印特定局部变量值 ``` #### 2. 查看全局变量 ```gdb (gdb) p ::global_var # 打印全局变量(需加双冒号) (gdb) p 'namespace::var' # 打印命名空间中的变量 ``` #### 3. 查看变量类型 ```gdb (gdb) ptype my_var # 显示变量类型 (gdb) whatis my_var # 显示变量类型简写 ``` --- ### 四、其他调试命令 | 命令 | 作用 | |-------------------------|-----------------------------| | `list` | 显示当前代码上下文 | | `disassemble` | 查看当前函数的汇编代码 | | `info registers` | 查看寄存器值 | | `x/10xw &my_var` | 以十六进制查看变量的内存数据 | --- ### 五、示例演示 #### 1. 崩溃代码示例 ```cpp #include <iostream> int global = 42; void crash() { int* ptr = nullptr; *ptr = 5; // 触发段错误 } int main() { crash(); return 0; } ``` #### 2. 调试过程 ```bash # 生成 core dump 后 gdb ./my_program core.1234 (gdb) bt # 显示崩溃在 crash() 函数 (gdb) frame 1 # 切换到 crash 函数栈帧 (gdb) info locals # 显示 ptr = 0x0 (gdb) p global # 显示全局变量(gdb) p ptr # 验证空指针 ``` --- ### 六、注意事项 1. **调试符号必须存在**:编译时必须使用 `-g` 选项 2. **优化级别影响**:使用 `-O0` 编译避免优化导致变量不可见 3. **动态链接库**:若程序依赖第三方库,需确保调试时库版本一致 4. **核心转储权限**:检查 `core` 文件是否可读(`chmod +r core.1234`) 通过上述方法,可以精准定位崩溃时的变量状态,帮助快速诊断内存错误、空指针访问等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值