对于外面公开的源码看基本都是基于UWORLD那张对象表开发的,该表内保存的都是游戏当前环境内所用到的对象数据。其实在游戏内还有一张对象的缓冲表,这张缓冲表内包含了当前游戏进程内所有的对象数据,下面分析下这张表的使用。
1、获取缓冲表
随便找个数据跟下就会发现如下代码:
00007FF62794DE8D 7F 14 jnle TslGame.00007FF62794DEA3
00007FF62794DE8F 48 8B C8 mov rcx,rax
00007FF62794DE92 48 8B 82 E0 00 00 00 mov rax,qword ptr ds:[rdx+0x000000E0]
00007FF62794DE99 4C 39 04 C8 cmp qword ptr ds:[rax+rcx*8],r8
00007FF62794DE9D 75 04 jne TslGame.00007FF62794DEA3
00007FF62794DE9F B0 01 mov al,0x01
00007FF62794DEA1 EB 02 jmp TslGame.00007FF62794DEA5
00007FF62794DEA3 32 C0 xor al,al
00007FF62794DEA5 84 C0 test al,al
00007FF62794DEA7 74 47 je TslGame.00007FF62794DEF0
00007FF62794DEA9 8B 47 18 mov eax,dword ptr ds:[rdi+0x18] ;ActorIndex 下面解密
00007FF62794DEAC 33 DB xor ebx,ebx
00007FF62794DEAE 35 E5 BA 92 B9 xor eax,0xB992BAE5
00007FF62794DEB3 C1 C8 02 ror eax,0x02
00007FF62794DEB6 8B C8 mov ecx,eax
00007FF62794DEB8 C1 E1 10 shl ecx,0x10
00007FF62794DEBB 81 F1 7B BB F2 76 xor ecx,0x76F2BB7B
00007FF62794DEC1 33 C8 xor ecx,eax
00007FF62794DEC3 3B 0D 73 80 7B 02 cmp ecx,dword ptr ds:[0x00007FF62A105F3C] ;Array Count
00007FF62794DEC9 7D 14 jnl TslGame.00007FF62794DEDF
00007FF62794DECB 48 63 C1 movsxd rax,rcx
00007FF62794DECE 48 8D 0C 40 lea rcx,qword ptr ds:[rax+rax*2]
00007FF62794DED2 48 8B 05 57 80 7B 02 mov rax,qword ptr ds:[TslGame.00007FF62A105F30] ;ArrayList
00007FF62794DED9 48 8D 14 C8 lea rdx,qword ptr ds:[rax+rcx*8]
00007FF62794DEDD EB 03 jmp TslGame.00007FF62794DEE2
00007FF62794DEDF 48 8B D3 mov rdx,rbx
00007FF62794DEE2 8B 42 08 mov eax,dword ptr ds:[rdx+0x08]
00007FF62794DEE5 C1 E8 1D shr eax,0x1D
00007FF62794DEE8 A8 01 test al,0x01
00007FF62794DEEA 75 08 jne TslGame.00007FF62794DEF4
00007FF62794DEEC B0 01 mov al,0x01
00007FF62794DEEE EB 06 jmp TslGame.00007FF62794DEF6
00007FF62794DEF0 33 DB xor ebx,ebx
00007FF62794DEF2 8B FB mov edi,ebx
00007FF62794DEF4 32 C0 xor al,al
00007FF62794DEF6 84 C0 test al,al
这段代码是将Actor中的index取出来在缓冲表内找到对应的对象,判断这个Actor是否有效
2、缓冲表数据结构
typedef struct _tag_WidgetNode {
UINT64 uActor;
FLOAT flag;
DWORD dwEmpty[3];
}WIDGET_NODE_ACTOR, *PWIDGET_NODE_ACTOR;
直接用for循环就可以遍历出整个表,可能会存在空的,因此要判断下uActor字段是否为空
3、暴力搜索定位缓冲表
由于这个表的为缓冲性质,所以游戏会分配块较大的内存,通过观察这块内存大小为0x30000,可以利用这个特征进行内存遍历暴力搜索。
UINT64 GetCacheActorList() {
UINT64 uScanMemory = 0x10000;
while (uScanMemory < 0x700000000000) {
MEMORY_BASIC_INFORMATION mbi = { 0 };
if (VirtualQuery((PVOID)uScanMemory, &mbi, sizeof(mbi)) == sizeof(mbi)) {
if ((mbi.State & MEM_COMMIT) && (mbi.Protect == PAGE_READWRITE) && (mbi.RegionSize == 0x3000000)) {
PWIDGET_NODE_ACTOR pWidgetNode = (PWIDGET_NODE_ACTOR)mbi.BaseAddress;
#ifdef _DEBUG_MSG
DbgPrintf("Check Memory Block [0x%llX] %.2f,%.2f", (UINT64)mbi.BaseAddress, pWidgetNode[0].flag, pWidgetNode[1].flag);
#endif
if ((pWidgetNode[0].flag == 2.0f) && (pWidgetNode[1].flag == 32.0f)) {
mWidgetBaseList = (UINT64)mbi.BaseAddress;
#ifdef _DEBUG_MSG
DbgPrintf("Scan Widget List Base [%llX] Done!", mWidgetBaseList);
#endif
break;
}
}
uScanMemory = uScanMemory + mbi.RegionSize;
}
}
return mWidgetBaseList;
}