CE找不到基址,跟丢、循环的原理和解决方案
2025-10-18 21:38:25 | 世界杯足球队 | admin | 5303°c
简介
使用CE手动查找基址时,经常遇到搜索到其中某一层的时候突然没有结果了,或者在某几层之间不断循环,无法找到最终的静态地址的情况。本文通过一个简单的Demo,以查找Player数组基址为例,浅析导致上述原因的原因,并给出解决方案
视频教程
B站同名账号:KrnlsYs 有本文内容对应的视频,还有完整的CE入门教程以及其他编程话题的教程等,推荐有学习需求的读者关注
示例代码
注意:不同版本不同编译器对该代码编译生成的汇编指令都会不同,你有可能无法复现本章内容
#include
#include
struct Player
{
int id;
char padding[0x300];
int health;
};
struct PlayerManager
{
char padding[0x20];
std::vector
} PlayerMgr;
int main()
{
for (size_t i = 0; i < 10; i++)
{
auto player = new Player;
player->id = i;
player->health = 100;
PlayerMgr.players.push_back(player);
}
int id = -1;
std::cin >> id;
while (true)
{
std::cin.get();
PlayerMgr.players[id]->health -= 4;
std::cout << "Player " << id << " health: " << PlayerMgr.players[id]->health << '\n';
}
return 0;
}
操作流程
定位血量地址
运行程序后用CE附加,搜索100,之后随便输入一个索引,然后回车使其血量变化,搜索96,很容易找到血量地址
定位player地址
对改地址右键查找访问,然后回到demo,回车
易知第三条的rcx是players[6]的结构体地址
查找数组地址
搜索上述players[6]的结构体地址,发现有两个结果
对两个地址都查找访问,然后回到demo再次使血量变化
发现上边一条是rbp,也就是堆栈相关的指令,所以不管它
所以使用第二个地址查找访问的结果进行寻址
坑点1
注意这两条指令
前后寄存器是一致的,含义是把右边的rax当做地址取值,然后赋值给rax寄存器本身。问题来了:我们要追的地址也存储在rax中,而且是在这条指令执行之前的rax。然而CE给我们显示出的rax是执行后的结果
因此直接搜索这个rax是错误的方法
同时容易发现,此时的rax正是我们之前搜索的players[6]的结构体地址,也就是说我们陷入了某种诡异的循环
解决的方式是:在反汇编中对这条指令下断点,然后回到demo使血量发生变化,CE会把程序断在该指令执行之前,此时获取的是正确的rax。搜索这个rax有可能找到正确的地址
断下后得到正确的rax
坑点2
复制该rax,取消断点继续运行,然后搜素该rax
这个方法可以解决一部分问题,但遗憾的是,在这个例子中仍然没有结果
既然常规的查找访问无法找到正确基址,我们就手动追查基址
以第一条为例,来到这条反汇编的上方,看看rax是从哪里来
稍有基础的人都会知道,此处的rax来自上方call的返回值,所以我们进call看看返回值从何而来
找到ret附近,看看最后一次对rax的赋值是什么指令
通过lea rax,[rax+rcx*8]对rax进行了最后一次赋值,不难看出此处又嵌套了第一个坑点,即我们要追查的rax已被执行后的结果覆盖
那么,为什么在坑点1中下断获取到执行前的rax也搜不到任何结果?通过上图可以知道,即使是执行前的rax,它也仅仅是寄存器中的一个数值,从未出现在内存中,自然无法通过内存扫描得到
问题解决
所以我们对这条lea rax,[rax+rcx*8]下断,获取此处执行前的rax
取消断点,运行,搜索
成功找到数组地址