Loading... # 一、背包及背包物品遍历 通过相关API及IDA静态分析,定位如下函数 ```c/c++ bool __fastcall sub_14171E500(__int64 a1, int a2, _QWORD *a3, int *a4, _DWORD *a5) { __int64 v8; // rdi __int64 localPlayerPtr; // rax bool v10; // cc int v12; // eax int v13; // eax int v14; // eax __int64 bagPtr; // rax unsigned __int128 bagGUID; // [rsp+20h] [rbp-18h] BYREF *a3 = 0i64; *a4 = -1; v8 = (int)a1; *a5 = 2; sub_1410E0EE0(a1); if ( !localPlayerPtr ) // localPlayerPtr 实际为sub_1410E0EE0(a1)返回值 return 0; *a4 = a2; if ( (int)v8 >= 0 ) { if ( (int)v8 >= 11 ) return *a3 && *a4 >= 0 && *a4 < *(_DWORD *)*a3; bagGUID = (unsigned int)v8 < 0xB && ((int)v8 < 4 || sub_141252550()) ? *((_OWORD *)&unk_142FA0450 + v8) : (unsigned __int128)0i64; bagPtr = ((__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD))ObjGUID2Ptr)( &bagGUID, 4i64, "D:\\BuildServer\\WoW\\1\\work\\DedicatedCheckout\\Classic\\Source\\Ui\\ContainerFrame.cpp", 614i64); if ( bagPtr ) *a3 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)bagPtr + 0x350i64))(bagPtr); if ( (int)v8 < 4 ) return *a3 && *a4 >= 0 && *a4 < *(_DWORD *)*a3; goto LABEL_23; } *a3 = localPlayerPtr + 0x28640; // item-guid数组指针 switch ( (_DWORD)v8 ) { case 0xFFFFFFFB: v14 = *a4 + 0x4B; *a4 = v14; v10 = v14 <= 81; break; case 0xFFFFFFFD: v13 = *a4 + 0x5E; *a4 = v13; v10 = v13 <= 125; break; case 0xFFFFFFFE: v12 = *a4 + 0x2F; *a4 = v12; if ( v12 > 74 ) return 0; LABEL_23: *a5 = 3; return *a3 && *a4 >= 0 && *a4 < *(_DWORD *)*a3; case 0xFFFFFFFF: *a4 += 0x17; v10 = *a4 <= (int)(sub_1412544D0(*a3) + 23); break; default: return *a3 && *a4 >= 0 && *a4 < *(_DWORD *)*a3; } if ( !v10 ) return 0; return *a3 && *a4 >= 0 && *a4 < *(_DWORD *)*a3; } ``` 根据上述伪代码,大胆猜测: 1. `&unk_142FA0450 + v8`为背包指针或者GUID; 2. `*a3 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)bagPtr + 0x350i64))(bagPtr)`与背包中物品有关系。 通过Cheat Engine验证,发现: 1. `&unk_142FA0450 + bagIndex`为背包GUID。 2. 虚函数:`bagPtr + 0x350`为`lea rax, qword ptr ds:[rcx+0x00001730]`,观察 `bagPtr+0x1730`处值,发现`*(bagPtr+0x1730+8)`为背包物品GUID数组。 考虑到游戏存在系统自带背包,在上述伪代码中,背包物品指针为`localPlayerPtr + 0x28640` 因此,有了如下遍历函数: ```c++ void DbgWin::OnBnClickedButton3() { // TODO: 在此添加控件通知处理程序代码 std::string str = ""; for (auto i = -1; i < 5; i++) { if (utils::read<DWORD64>(g_ModuleHandle + offset::BagGUID + i * 16) == 0) //背包为空 { if (i == -1) //系统自带背包 { DWORD64 playerAddr = getLocalPlayerPtr(); auto ptr = utils::read<DWORD64>(playerAddr + 0x28648); str += "ptr:" + utils::ptr2str(ptr)+"\tCapacity:20 ---->默认背包\r\n"; for (int j = 0; j < 20; j++) { if (utils::read<DWORD64>(ptr + (j + 23) * 16) == 0) //物品为空 continue; auto ItemPtr = guid2ptr((char*)(ptr + (j + 23) * 16)); //背包ptr auto pDescript = utils::read<DWORD64>(ItemPtr + offset::StorageField); auto id = utils::read<DWORD64>(pDescript + offset::ItemID); auto count = utils::read<DWORD64>(pDescript + offset::ItemStackCount); str += " (" + std::to_string(i + 1) + "," + std::to_string(j + 1) + ")\tid:" + std::to_string(id) + "\tcount:" + std::to_string(count) + "\r\n"; } } continue; } auto ptr = guid2ptr((char*)(g_ModuleHandle + offset::BagGUID + i * 16)); //背包ptr str+="ptr:"+ utils::ptr2str(ptr) ; auto size = utils::read<uint32_t>(ptr + offset::BagItemOffset + offset::BagItemsCapacity); auto itemguidptr = utils::read<DWORD64>(ptr + offset::BagItemOffset + offset::BagItemGUIDOffset); str += "\tCapacity:" + std::to_string(size) +"\tItemGuidPtrs:"+ utils::ptr2str(itemguidptr)+ "\r\n"; for (auto j = 0; j < size; j++) { if (utils::read<DWORD64>(itemguidptr + j * 16) == 0) //物品为空 continue; auto ItemPtr = guid2ptr((char*)(itemguidptr + j * 16)); //背包ptr auto pDescript = utils::read<DWORD64>(ItemPtr + offset::StorageField); auto id = utils::read<DWORD64>(pDescript + offset::ItemID); auto count = utils::read<DWORD64>(pDescript + offset::ItemStackCount); str += " (" + std::to_string(i+1)+"," + std::to_string(j + 1)+")\tid:" + std::to_string(id) +"\tcount:" + std::to_string(count) + "\r\n"; } } SetDlgItemText(IDC_EDIT1, str.c_str()); } ``` 运行效果如下图所示:  # 二、装备物品遍历 由于人物只能佩戴19件装备,有了如下遍历。 ```c++ void DbgWin::OnBnClickedButton8() { // TODO: 在此添加控件通知处理程序代码 DWORD64 playerAddr = getLocalPlayerPtr(); auto ptr = utils::read<DWORD64>(playerAddr + 0x28648); std::string str = "ptr:" + utils::ptr2str(ptr) + "\r\n"; for (int i = 0; i < 19; i++) { char guid[128] = "\0"; g_Func_guid2Str((unsigned char*)(ptr + i * 16), guid, 128);//游戏guid转str函数 str += "ptr:" + utils::ptr2str(ptr + i * 16)+"\tindex:" + std::to_string(i+1) + "\tguid:" + std::string(guid) + "\r\n"; } SetDlgItemText(IDC_EDIT1, str.c_str()); } ``` 其效果如下图所示:  # 三、buff、debuf遍历 ```c++ void DbgWin::OnBnClickedButton15() { // TODO: 在此添加控件通知处理程序代码 DWORD64 playerAddr = getLocalPlayerPtr(); auto count = utils::read<DWORD>(playerAddr + offset::AuraCount1); std::string str = ""; for (int i = 0; i < count; i++) { auto aruaID = utils::read<DWORD>(playerAddr + i * offset::AuraSize + offset::AuraTable1 + offset::AuraSpellId); auto timeLeft = utils::read<DWORD>(playerAddr + i * offset::AuraSize + offset::AuraTable1 + offset::AuraTimeLeft); auto flags = utils::read<UINT16>(playerAddr + i * offset::AuraSize + offset::AuraTable1 + offset::AuraFlags); auto lv = utils::read<UINT16>(playerAddr + i * offset::AuraSize + offset::AuraTable1 + offset::AuraLevel); char guid[128] = "\0"; g_Func_guid2Str((unsigned char*)(playerAddr + i * offset::AuraSize + offset::AuraTable1 + offset::AuraOwnerGUID), guid, 128); if(aruaID!=0) str += "ID:" + std::to_string(aruaID) + "\ttimeLeft:" + std::to_string(timeLeft) + "\tflags:" + std::to_string(flags) + "\tlv:" + std::to_string(lv) + "\towner:" + std::string(guid)+"\r\n"; } SetDlgItemText(IDC_EDIT1, str.c_str()); } ``` 游戏中unit对象(type为3)buff遍历方式同上。 最后修改:2021 年 09 月 22 日 11 : 37 AM © 禁止转载