从游戏中学习逆向:获取OW的实体

我们接着上一次来讲。上次提到Entity_Admin,首先我们需要在这个位置读到实体。通过IDA进行逆向工程,查找游戏用到entity_admin的地方,我们可以轻松找到Entity_Admin位于base+35F5300(这一偏移不具有时效性!仅适用于一个版本)

  1. uintptr_t entity_list = SDK->RPM<uint64_t>(SDK->dwGameBase + offset::Address_entity_base);

    这一行通过在dwGameBase游戏基地址的基础上执行读取操作(RPM),获取游戏内存中实体列表的基址。变量entity_list将保存此基址。

  2. MEMORY_BASIC_INFORMATION mbi{}; VirtualQueryEx(SDK->hProcess, (LPCVOID)entity_list, &mbi, sizeof(mbi));

    这些行查询与给定句柄(SDK->hProcess)关联的进程的虚拟内存信息,查询的地址为entity_list。检索到的信息存储在mbi结构中。这是为后续读取实体做准备

  3. SIZE_T entity_list_size = mbi.RegionSize / sizeof(Entity);

    这计算了实体列表的大小,基于内存信息结构中的RegionSize和单个Entity对象的大小。

  4. Entity* raw_list = new Entity[entity_list_size];

    在这里,执行动态内存分配,创建了一个大小为entity_list_sizeEntity对象数组。

  5. if (ReadProcessMemory(SDK->hProcess, (LPCVOID)entity_list, raw_list, mbi.RegionSize, nullptr))

    此行尝试使用ReadProcessMemory函数从游戏进程中读取内存内容。它从entity_list地址开始读取一个大小为mbi.RegionSize的内存块,将内容存储在raw_list数组中。

  6. 随后的代码片段处理已从内存中读取的实体:

    • 它遍历每个raw_list中的Entity
    • 对于每个实体,它通过验证cur_entity是否非零来检查其是否为有效实体。
    • 如果实体有效,它使用DecryptComponent函数解密一个组件,并检查common_linker是否非零。
    • 如果common_linker有效,它从内存中检索一个unique_id
    • 然后,它再次遍历raw_list,以查找具有相同unique_id的另一个实体。
    • 如果找到这样的实体,则将(possible_common, cur_entity)对添加到result集合中。
  7. 最后,delete[] raw_list;释放了动态分配的raw_list数组的内存,函数返回result集合

uintptr_t entity_list = SDK->RPM<uint64_t>(SDK->dwGameBase + offset::Address_entity_base);

	MEMORY_BASIC_INFORMATION mbi{};
	VirtualQueryEx(SDK->hProcess, (LPCVOID)entity_list, &mbi, sizeof(mbi));

	SIZE_T entity_list_size = mbi.RegionSize / sizeof(Entity);
	Entity* raw_list = new Entity[entity_list_size];

	if (ReadProcessMemory(SDK->hProcess, (LPCVOID)entity_list, raw_list, mbi.RegionSize, nullptr))
	{
		for (size_t i = 0; i < entity_list_size; ++i)
		{
			uint64_t cur_entity = raw_list[i].entity;
			if (cur_entity)
			{
				uint64_t common_linker = DecryptComponent(cur_entity, TYPE_LINK);
				if (common_linker)
				{
					uint32_t unique_id = SDK->RPM<uint32_t>(common_linker + 0xD4);

					for (size_t x = 0; x < entity_list_size; ++x)
					{
						uint64_t possible_common = raw_list[x].entity;
						if (possible_common && SDK->RPM<uint32_t>(possible_common + 0x118) == unique_id)
						{
							result.emplace_back(possible_common, cur_entity);
							break;
						}
					}
				}
			}
		}
	}

	delete[] raw_list;
	return result;
}

我们可以新建一个进程,一直用来获取游戏内的实体。由于这一部分获取的只是parent和Link,所以不需要一直执行,只需要在新实体生成(有新玩家、新物体)的时候执行一次。所以我们可以设置在这个进程中一秒或者两秒执行一次。

后面我们再新建一个进程,从上面获取到的内容中,对所有可能用到的组件进行解密。解密完成之后,存储到我们的entities Vector中。注意涉及到相同Vector的两个进程一定要加互斥锁,不然一定会导致进程异常结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值