C语言读取外部进程内存时,首次查询后修改目标变量再查无匹配结果的问题
C语言读取外部进程内存时,首次查询后修改目标变量再查无匹配结果的问题
我仔细看了你的代码和问题描述,核心问题其实出在内存区域的过滤条件上,另外还有几个小bug也会影响结果,下面给你一步步分析和解决:
1. 最关键的问题:内存保护属性判断错误
你现在的代码只扫描了PAGE_READONLY(只读)的内存区域,但我们要找的变量不管是在栈上还是堆上,对应的内存保护属性都是PAGE_READWRITE(可读写)的!这就导致第一次扫描时,你根本没扫到真正的变量地址,链表中存的全是其他只读区域里碰巧和目标值相等的“巧合值”——这些值当然不会跟着目标进程的变量变化,所以后续查询自然匹配不上。
修复这个问题很简单,把内存区域的判断条件改一下:
// 原代码 if (mbi.State == MEM_COMMIT && (mbi.Protect & PAGE_READONLY)) // 修改为:同时包含只读和可读写区域 if (mbi.State == MEM_COMMIT && (mbi.Protect & (PAGE_READONLY | PAGE_READWRITE)))
2. ask_current_value函数的潜在崩溃bug
你在处理输入换行符时,直接解引用了memchr的返回值,但如果用户输入的内容没有换行(比如输入长度刚好填满buffer,或者直接按了Ctrl+Z),memchr会返回NULL,这时候解引用就会导致程序崩溃。
修复这个bug:
int ask_current_value(){ char buffer[128]; printf("Current value: "); fgets(buffer, sizeof(buffer), stdin); // 先检查是否找到换行符,再修改 char* newline_pos = memchr(buffer, '\n', sizeof(buffer)); if (newline_pos != NULL) { *newline_pos = '\0'; } return atoi(buffer); }
3. 其他需要确认的细节
- 链表实现正确性:你提到
linked_list.c的第一个元素是垃圾数据,循环从i=1开始没问题,但要确保linked_list_len、fetch_linked_list_element、delete_element_at_index这些函数的索引逻辑是正确的,比如linked_list_len返回的长度是否包含头节点,避免漏扫或者越界访问。 - 目标进程变量的稳定性:如果你的测试程序把变量放在栈上,要注意栈帧的生命周期——比如如果变量是某个函数的局部变量,函数返回后栈帧会被销毁,变量地址就失效了。建议把目标变量改成全局变量或者堆上分配的变量,确保地址在程序运行期间固定:
// 目标测试程序示例 #include <stdio.h> #include <stdlib.h> int global_target = 0; // 全局变量,地址固定 // 或者堆分配:int* heap_target = malloc(sizeof(int)); *heap_target = 0; int main() { int input; while (1) { printf("Set target value: "); scanf("%d", &input); global_target = input; printf("New value: %d\n", global_target); } free(heap_target); // 堆分配的话最后记得释放 return 0; } - 变量类型匹配:确保扫描程序和目标程序的变量类型一致——你用
int来存储值,目标程序的变量也要是int,避免因为类型大小(比如long是4/8字节)不匹配导致扫描错误。
修复后的测试流程
- 编译并运行目标测试程序,记下它的PID;
- 编译你的扫描程序(记得链接
linked_list.c); - 输入PID,然后输入目标变量的初始值,第一次扫描会得到所有包含该值的地址(包括真正的变量地址);
- 修改目标程序的变量值,回到扫描程序输入新值,此时程序会过滤掉不匹配的地址,最后剩下的就是目标变量的真实地址,后续修改目标值时这个地址的内容会跟着变化。
内容来源于stack exchange
相关产品推荐
相关产品推荐

