搜索背包物品基址

在游戏中,背包中包含了各种药品和装备等游戏道具,通过搜索背包基址,进而遍历背包,得到各种背包物品信息是非常重要的。

背包中的物品数量是一个比较容易更改的属性,我们通过改变物品的数量,用 CE 工具来定位物品数量的虚拟地址,然后有两种思路来定位物品数量的基址:

  1. 对物品数量虚拟地址下硬件访问断点,看是谁访问了这个地址量,看是哪里改写了这个地址
  2. 对物品数量虚拟地址下硬件写入断点,改变物品数

一、笑傲江湖背包基址分析(x32)

1 通过硬件访问断点追溯背包基址

首先我们用 CE 搜索出背包特定物品数量的虚拟地址,然后对其下一个硬件访问断点,打开背包,在如下出断下:

00A5A4E8 | C78424 9C000000  | mov dword ptr ss:[esp+9C],FFFFFFFF      |
00A5A4F3 | E8 28DB0800      | call xajh.AE8020                        |
00A5A4F8 | 83C4 20          | add esp,20                              |
00A5A4FB | 837F 70 01       | cmp dword ptr ds:[edi+70],1             | 11 edi 的值一直变化

因为游戏在循环遍历背包中不同物品的信息并将其显示在频幕上,所以上面代码中的 edi 值一直变化,我们往上追溯 edi

00A5A47D | 8BBC24 84000000  | mov edi,dword ptr ss:[esp+84]           | 22 edi 来源于本call的第一个参数

00A5AA57 | 52               | push edx                                |
00A5AA58 | 51               | push ecx                                |
00A5AA59 | 53               | push ebx                                |
00A5AA5A | 50               | push eax                                | 33 第一个参数为 eax

00A5AA25 | 8B4C24 2C        | mov ecx,dword ptr ss:[esp+2C]           |
00A5AA29 | 6A 00            | push 0                                  |
00A5AA2B | 53               | push ebx                                | 物品的位置
00A5AA2C | E8 BF03B0FF      | call xajh.55ADF0                        | 44 eax 来源于此 call
00A5AA31 | 85C0             | test eax,eax                            |

经分析,随着 ebx 不断 +1,返回的 eax 值不断 +4,表明正在遍历背包,因此推测 eax 为背包中物品的地址,由于我们需要追踪背包基址,因此我们需要跟进 call 里面继续追踪 eax 的来源:

0055ADF0 | 8B4424 04        | mov eax,dword ptr ss:[esp+4]            |
0055ADF4 | 85C0             | test eax,eax                            |
0055ADF6 | 7C 1D            | jl xajh.55AE15                          |
0055ADF8 | 3B41 28          | cmp eax,dword ptr ds:[ecx+28]           |
0055ADFB | 7D 18            | jge xajh.55AE15                         |
0055ADFD | 807C24 08 00     | cmp byte ptr ss:[esp+8],0               |
0055AE02 | 8B49 24          | mov ecx,dword ptr ds:[ecx+24]           | 77 ecx==438AC898
0055AE05 | 8D0C81           | lea ecx,dword ptr ds:[ecx+eax*4]        | 66 ecx==5597BFB0
0055AE08 | 8B01             | mov eax,dword ptr ds:[ecx]              | 55 ecx==5597BFE4
0055AE0A | 74 0B            | je xajh.55AE17                          |
0055AE0C | C701 00000000    | mov dword ptr ds:[ecx],0                |
0055AE12 | C2 0800          | ret 8                                   |
0055AE15 | 33C0             | xor eax,eax                             |
0055AE17 | C2 0800          | ret 8                                   |

这是一个公用 call,不止用于遍历背包,ecx 的值一直在变化,eax 为遍历的位置,由于背包比其他的容器要大,观察 eax 值的取值范围来分辨是否在遍历背包,如果判断错误则会追踪到其他的路径,导致追踪错误,跳出公用 call 后继续追踪 ecx

00A5AA25 | 8B4C24 2C        | mov ecx,dword ptr ss:[esp+2C]           | 88 [esp+2C] 为局部变量

00A5A91C | 8D4F 08          | lea ecx,dword ptr ds:[edi+8]            | 1010 edi==438AC890
00A5A91F | 6A 01            | push 1                                  |
00A5A921 | 894C24 34        | mov dword ptr ss:[esp+34],ecx           | 99

00A5A87F | E8 9C3BA5FF      | call xajh.4AE420                        | 1313 eax 来源于此call
00A5A884 | 8B40 08          | mov eax,dword ptr ds:[eax+8]            | 1212 eax==2C5D7EC0
00A5A887 | 8B78 14          | mov edi,dword ptr ds:[eax+14]           | 1111 eax==38926A20

004AE420 | A1 D8825201      | mov eax,dword ptr ds:[15282D8]          | 1616 追到基址
004AE425 | 85C0             | test eax,eax                            |
004AE427 | 74 0E            | je xajh.4AE437                          |
004AE429 | 8B40 24          | mov eax,dword ptr ds:[eax+24]           | 1515 eax==01529788
004AE42C | 85C0             | test eax,eax                            |
004AE42E | 74 07            | je xajh.4AE437                          |
004AE430 | 8B80 90000000    | mov eax,dword ptr ds:[eax+90]           | 1414 eax==0BDC0FB8
004AE436 | C3               | ret                                     |
004AE437 | 33C0             | xor eax,eax                             |
004AE439 | C3               | ret                                     |

组合背包物品数量基址:[[[[[[[15282D8]+24]+90]+8]+14]+8+24]+eax*4]+70

其中 eax 为背包中物品的位置,因此可以得到背包基址:[[[[[[15282D8]+24]+90]+8]+14]+8+24]

我们查看背包基址的内存:

5597BFB0  411B38A8  ¨8.A  &"p酻"
5597BFB4  54750538  8.uT  
5597BFB8  411B35F0  ð5.A  &"P怲"
5597BFBC  5474CBD8  ØËtT  
5597BFC0  411B3FE8  è?.A  &"P怲"
5597BFC4  411B3250  P2.A  &"P怲"
5597BFC8  411B3338  83.A  &"P怲"
5597BFCC  411B3990  .9.A  &"P怲"
5597BFD0  00000000  ....  
5597BFD4  00000000  ....  

背包基址里面存放的是物品的地址,为了验证背包基址是否正确,我们通过挪动背包中的物品,则其对应的基址也会移动到相应的位置。

下面我们继续分析背包集中中物品地址的结构,很容易得到如下信息:
+48:最大物品数量
+70:物品数量

但是看不到物品名称,一般来说物品结构体中都会包含物体名称,我们通过 CE 工具来对其进行定位,我们首先用工具将要搜索的物品名称进行转码:

由于这个游戏中文使用的是 UNICODE 编码,将其复制到 CE 中,并将搜索类型更改为 字节数组,并在尾部添加 00 00 字符串结束符:

将搜索出来的字节数组类型全部改为 UNICODE 字符串,然后挨个更改名字,看哪个数据会影响游戏显示:

找到该地址后和物品结构体中的值一一比对,找到值相等或相近的,进行分析,不难得出物品名字偏移:
[+D8]+4:药品物品名称
[+E8]+4:装备物品名称

当物品偏移 [+D8]+4 的值为 1 的时候,表明这件物品是一件装备。

2 通过硬件写入断点追溯背包基址

我们之前用 硬件访问断点 追溯血量基址的时候发现并没有追踪到人物的基址,而是通过硬件写入断点才追溯到正确的人物基址,那物品背包基址是不是也通过硬件写入断点来追溯基址会比较好呢?我们来试一下。

首先对物品数量虚拟地址下硬件写入断点,然后拆分物品使得物品数量发生变化,断下后进行溯源:

00554CD1 | 75 10            | jne xajh.554CE3                         |
00554CD3 | 0141 70          | add dword ptr ds:[ecx+70],eax           | 11 ecx==411B3990
00554CD6 | 8B51 70          | mov edx,dword ptr ds:[ecx+70]           |
00554CD9 | 8B41 48          | mov eax,dword ptr ds:[ecx+48]           |

0055AE83 | 8BCE             | mov ecx,esi                             | 22

0055AE68 | 8BF9             | mov edi,ecx                             | 55
0055AE6A | 7C 36            | jl xajh.55AEA2                          |
0055AE6C | 3B5F 28          | cmp ebx,dword ptr ds:[edi+28]           | edi+28:"氶粆"
0055AE6F | 7D 31            | jge xajh.55AEA2                         |
0055AE71 | 8B47 24          | mov eax,dword ptr ds:[edi+24]           | 44 edi==438AC898
0055AE74 | 56               | push esi                                |
0055AE75 | 8B3498           | mov esi,dword ptr ds:[eax+ebx*4]        | 33 eax==5597BFB0

0055B33D | 8BCE             | mov ecx,esi                             | 66

0055B2F9 | 8BF1             | mov esi,ecx                             | 77

0052B20D | 8BCB             | mov ecx,ebx                             | 88

0052B1F5 | 3BD0             | cmp edx,eax                             |
0052B1F7 | 8D5A 08          | lea ebx,dword ptr ds:[edx+8]            | 99 edx==438AC890
0052B1FA | 75 72            | jne xajh.52B26E                         |

0052B1CD | E8 CEB5FFFF      | call xajh.5267A0                        | 1111 eax来源于这个call
0052B1D2 | 0FB64C24 23      | movzx ecx,byte ptr ss:[esp+23]          |
0052B1D7 | 51               | push ecx                                |
0052B1D8 | 8BCB             | mov ecx,ebx                             |
0052B1DA | 8BD0             | mov edx,eax                             | 1010
0052B1DC | E8 BFB5FFFF      | call xajh.5267A0                        |

我们进入 call 里面追踪 eax

005267A0 | 8B4424 04        | mov eax,dword ptr ss:[esp+4]            |
005267A4 | 83F8 14          | cmp eax,14                              |
005267A7 | 77 07            | ja xajh.5267B0                          |
005267A9 | 8B4481 0C        | mov eax,dword ptr ds:[ecx+eax*4+C]      | 1212 ecx==38926A20
005267AD | C2 0400          | ret 4                                   |
005267B0 | 33C0             | xor eax,eax                             |
005267B2 | C2 0400          | ret 4                                   |

此处是一个公用的函数,我们之前通过拆分物品来改变物品数量,但是此处不断地断下,我们无法通过改变物品数量来使其断下,但是我们发现 ecx 的值是不变的,我们继续跟踪就跳出了这个 call,来到下面的位置:

0052B1CB | 8BCB             | mov ecx,ebx                             | 1313

跳出公用函数后,此处又只有当拆分物品时才会断下,而且 ecx 的值没有变化,我们可以继续追踪:

0052A5B0 | 55               | push ebp                                |
0052A5B1 | 8BEC             | mov ebp,esp                             |
0052A5B3 | 83E4 F8          | and esp,FFFFFFF8                        |
0052A5B6 | 6A FF            | push FFFFFFFF                           |
0052A5B8 | 68 AEF80F01      | push xajh.10FF8AE                       |
0052A5BD | 64:A1 00000000   | mov eax,dword ptr fs:[0]                |
0052A5C3 | 50               | push eax                                |
0052A5C4 | 64:8925 00000000 | mov dword ptr fs:[0],esp                |
0052A5CB | 81EC D0010000    | sub esp,1D0                             |
0052A5D1 | 53               | push ebx                                |
0052A5D2 | 8BD9             | mov ebx,ecx                             | 1414

ecx 追溯到函数头部发现来源于上层 call,但是回到上层发现 ecx 的值不对,路线跟错了,是哪里除了问题吗?原来其实 0052A5B0 这个地址并不是函数头部,还有其他地址跳到了这里,我们直接右键这条语句,然后点击查找引用看是哪条语句引用了这里,果然有一条语句跳转到 0052A5B0 这个地址,我们跟过去:

00DBA5E0 | E8 3B3E6FFF      | call xajh.4AE420                        | 1616 eax 来源于此call
00DBA5E5 | 85C0             | test eax,eax                            |
00DBA5E7 | 75 05            | jne xajh.DBA5EE                         |
00DBA5E9 | 33C0             | xor eax,eax                             |
00DBA5EB | C2 0400          | ret 4                                   |
00DBA5EE | 8B48 08          | mov ecx,dword ptr ds:[eax+8]            | 1515 eax==2C5D7EC0
00DBA5F1 | 85C9             | test ecx,ecx                            |
00DBA5F3 | 74 F4            | je xajh.DBA5E9                          |
00DBA5F5 | E9 B6FF76FF      | jmp xajh.52A5B0                         |

继续进入 call 追溯 eax

004AE420 | A1 D8825201      | mov eax,dword ptr ds:[15282D8]          | 1818 追到基址
004AE425 | 85C0             | test eax,eax                            |
004AE427 | 74 0E            | je xajh.4AE437                          |
004AE429 | 8B40 24          | mov eax,dword ptr ds:[eax+24]           | 1717
004AE42C | 85C0             | test eax,eax                            |
004AE42E | 74 07            | je xajh.4AE437                          |
004AE430 | 8B80 90000000    | mov eax,dword ptr ds:[eax+90]           | 1616
004AE436 | C3               | ret                                     |
004AE437 | 33C0             | xor eax,eax                             |
004AE439 | C3               | ret                                     |

这也是一个公用 call,频繁中断,我们无法拆分物品,但已经追踪到了基址,不用再追踪寄存器的值了,接下来我们组合物品数量基址:[[[[[[[15282D8]+24]+90]+8]+eax*4+C]+8+24]+ebx*4]+70

eax 的取值有2、3、4 和 5,而结合我们之前的分析结果,eax=2 的时候是背包基址,ebx为背包中的物品位置。

我们发现通过硬件写入断点追溯出来的背包基址当中有两个变量,对于 eax 的取值我们只能进行推测验证来确定了,所以硬件写入断点行不通的时候,不妨试试硬件访问断点

posted @ 2025-04-21 21:53  lostin9772  阅读(9)  评论(0)    收藏  举报