CE+OD实例——查找人物包裹信息

 

要想学会外挂制作先得学会找基址,这里我就做个实例了
首先我们用CE来找出是什么指令修改了我们包裹中物品的数量(怎么找我就不说了,不懂的看CCB老大的教程)

找到指令是

0048F0AB   mov   dword ptr [ecx+14], edx

用OD打开武林elementclient.exe,Ctrl+G转到表达式0048F0AB...

可以看到这条指令是在一个函数中

0048F0A0 /$ 8B4424 04   mov   eax, dword ptr [esp+4]
0048F0A4 |. 8B51 14     mov   edx, dword ptr [ecx+14]
0048F0A7 |. 03D0       add   edx, eax
0048F0A9 |. 8BC2       mov   eax, edx
0048F0AB |. 8951 14     mov   dword ptr [ecx+14], edx
0048F0AE |. 85C0       test   eax, eax
0048F0B0 |. 7D 07       jge   short 0048F0B9
0048F0B2 |. C741 14 00000>mov   dword ptr [ecx+14], 0
0048F0B9 |> 8B41 18     mov   eax, dword ptr [ecx+18]
0048F0BC |. 8B51 14     mov   edx, dword ptr [ecx+14]
0048F0BF |. 3BD0       cmp   edx, eax
0048F0C1 |. 7E 03       jle   short 0048F0C6
0048F0C3 |. 8941 14     mov   dword ptr [ecx+14], eax
0048F0C6 |> 8B41 14     mov   eax, dword ptr [ecx+14]
0048F0C9 /. C2 0400     retn   4

我们在开始的地方F2下断,F8单步步过看看每条指令都做了些什么...

粗略的看一下,可以发现,当前CALL传入的参数1也就是[ESP+4]是-1,也就是我们使用了这个物品(比如吃药),[ECX+14]是存放的当前物品的数量,而[ECX+18]上存放的当前物品堆叠上限...因为是16进制的,所以大家要习惯看这些数值...

再看看程序流程,基本可以看出这个函数的功能是判断当前使用的物品是否超出1~99这个范围,也就是判断是否用完了或者是捡满了...

那么找包裹物品的地址,我们就要找出ECX的值是怎么来的!!!

OK,Ctrl+F9执行到返回,我们来看看是哪条指令调用了这个CALL...

返回到指令

0048908D |. E8 0E600000   call   0048F0A0

老习惯,我们上下拖动大致看看这段指令有多长...(其实主要是大概要回溯多长,因为我们要找ECX的值)

00489060 /$ 53         push   ebx
00489061 |. 8B5C24 08   mov   ebx, dword ptr [esp+8]
00489065 |. 56         push   esi
00489066 |. 57         push   edi
00489067 |. 85DB       test   ebx, ebx
00489069 |. 8BF9       mov   edi, ecx
0048906B |. 7C 3E       jl     short 004890AB
0048906D |. 3B5F 10     cmp   ebx, dword ptr [edi+10]
00489070 |. 7D 39       jge   short 004890AB
00489072 |. 8B47 0C     mov   eax, dword ptr [edi+C]
00489075 |. 8B3498     mov   esi, dword ptr [eax+ebx*4]
00489078 |. 85F6       test   esi, esi
0048907A |. 75 08       jnz   short 00489084
0048907C |. 5F         pop   edi
0048907D |. 5E         pop   esi
0048907E |. B0 01       mov   al, 1
00489080 |. 5B         pop   ebx
00489081 |. C2 0800     retn   8
00489084 |> 8B4C24 14   mov   ecx, dword ptr [esp+14]
00489088 |. F7D9       neg   ecx
0048908A |. 51         push   ecx
0048908B |. 8BCE       mov   ecx, esi
0048908D |. E8 0E600000   call   0048F0A0

先看看指令,发现ECX=ESI,往上ESI=[EAX+EBX*4],OK!!!我们在

00489075 |. 8B3498     mov   esi, dword ptr [eax+ebx*4]

处下断...

发现EBX的值实际上就是我们点击包裹的格子序号(当然,人家是从0开始计数的...)

恩,有门...再就是找EAX的值是怎么来的了...

往上看,EAX=[EDI+C],EDI=ECX...

没办法,ECX是由上一级函数传入的,好吧,继续Ctrl+F9...

转到指令

00457724 |. E8 37190300   call   00489060

还是上下看看...有点长,中间还有好几个CALL,郁闷...

004576B0 /$ 8B4424 04   mov   eax, dword ptr [esp+4]
004576B4 |. 53         push   ebx
004576B5 |. 55         push   ebp
004576B6 |. 56         push   esi
004576B7 |. 8B70 0C     mov   esi, dword ptr [eax+C]
004576BA |. 8BD9       mov   ebx, ecx
004576BC |. 33C9       xor   ecx, ecx
004576BE |. 57         push   edi
004576BF |. 8A0E       mov   cl, byte ptr [esi]
004576C1 |. 51         push   ecx
004576C2 |. 8BCB       mov   ecx, ebx
004576C4 |. E8 C7860000   call   0045FD90                
004576C9 |. 8BE8       mov   ebp, eax
004576CB |. 85ED       test   ebp, ebp
004576CD |. 0F84 AC000000 je     0045777F
004576D3 |. 33D2       xor   edx, edx
004576D5 |. 6A 00       push   0
004576D7 |. 8A56 01     mov   dl, byte ptr [esi+1]
004576DA |. 8BCD       mov   ecx, ebp
004576DC |. 52         push   edx
004576DD |. E8 EE0F0300   call   004886D0
004576E2 |. 8BF8       mov   edi, eax
004576E4 |. 85FF       test   edi, edi
004576E6 |. 0F84 93000000 je     0045777F
004576EC |. 8B46 02     mov   eax, dword ptr [esi+2]
004576EF |. 8B4F 08     mov   ecx, dword ptr [edi+8]
004576F2 |. 3BC8       cmp   ecx, eax
004576F4 |. 0F85 85000000 jnz   0045777F
004576FA |. 6A 00       push   0                     ; /Arg3 = 00000000
004576FC |. 6A 00       push   0                     ; |Arg2 = 00000000
004576FE |. 50         push   eax                     ; |Arg1
004576FF |. 8BCB       mov   ecx, ebx                 ; |
00457701 |. E8 9A4A0200   call   0047C1A0                 ; /elementc.0047C1A0
00457706 |. 8B07       mov   eax, dword ptr [edi]
00457708 |. 8BCF       mov   ecx, edi
0045770A |. FF50 1C     call   dword ptr [eax+1C]
0045770D |. 66:8B46 06   mov   ax, word ptr [esi+6]
00457711 |. 66:85C0     test   ax, ax
00457714 |. 74 3C       je     short 00457752
00457716 |. 33C9       xor   ecx, ecx
00457718 |. 25 FFFF0000   and   eax, 0FFFF
0045771D |. 8A4E 01     mov   cl, byte ptr [esi+1]
00457720 |. 50         push   eax
00457721 |. 51         push   ecx
00457722 |. 8BCD       mov   ecx, ebp
00457724 |. E8 37190300   call   00489060

打起精神,记住我们要找的是ECX的值...

仔细看,就可以看出,ECX=EBP,而EBP=EAX

004576DA |. 8BCD       mov   ecx, ebp

004576C9 |. 8BE8       mov   ebp, eax

从函数开始下断,我们看看是什么指令修改了EAX的值...

恩,mov ebp, eax上面有个CALL,大家都应该知道对于高级语言,编译器一般习惯于将返回值放如EAX中的吧...

二话不说,先进call 0045FD90里面看看是个什么情况...

0045FD90 /$ 8B4424 04   mov   eax, dword ptr [esp+4]
0045FD94 |. 83F8 04     cmp   eax, 4                   ; Switch (cases 0..4)
0045FD97 |. 77 34       ja     short 0045FDCD
0045FD99 |. FF2485 D4FD45>jmp   dword ptr [eax*4+45FDD4]
0045FDA0 |> 8B81 3C080000 mov   eax, dword ptr [ecx+83C]       ; Case 0 of switch 0045FD94
0045FDA6 |. C2 0400     retn   4
0045FDA9 |> 8B81 40080000 mov   eax, dword ptr [ecx+840]       ; Case 1 of switch 0045FD94
0045FDAF |. C2 0400     retn   4
0045FDB2 |> 8B81 44080000 mov   eax, dword ptr [ecx+844]       ; Case 2 of switch 0045FD94
0045FDB8 |. C2 0400     retn   4
0045FDBB |> 8B81 78080000 mov   eax, dword ptr [ecx+878]       ; Case 3 of switch 0045FD94
0045FDC1 |. C2 0400     retn   4
0045FDC4 |> 8B81 7C080000 mov   eax, dword ptr [ecx+87C]       ; Case 4 of switch 0045FD94
0045FDCA |. C2 0400     retn   4
0045FDCD |> 33C0       xor   eax, eax                 ; Default case of switch 0045FD94
0045FDCF /. C2 0400     retn   4
0045FDD2     8BFF       mov   edi, edi
0045FDD4   . A0FD4500     dd     elementc.0045FDA0           ; 分支表 被用于 0045FD99
0045FDD8   . A9FD4500     dd     elementc.0045FDA9
0045FDDC   . B2FD4500     dd     elementc.0045FDB2
0045FDE0   . BBFD4500     dd     elementc.0045FDBB
0045FDE4   . C4FD4500     dd     elementc.0045FDC4

发现是个分支处理的函数,至于吃药是怎么分支的,我们先出去看看这个参数[ESP+4]和ECX的值是怎么来的...

004576BF |. 8A0E       mov   cl, byte ptr [esi]
004576C1 |. 51         push   ecx
004576C2 |. 8BCB       mov   ecx, ebx
004576C4 |. E8 C7860000   call   0045FD90

下断,可以知道push ecx的时候ECX是0,而mov ecx,ebx的时候不知道大家看出来什么没有...

当时我就觉得这个EBX的值很熟,后来一想,这个值不就是人物属性地址[[8BCB44]+1C]+24的值么...

而且,吃药的时候,那个CALL要传入的参数始终是0...

至此,所有的我们需要的信息都找到了...

那我们就可以总结了...

[[[[8BCB44]+1C]+24]+83C]+10 的值是角色包裹最大容量...

[[[[8BCB44]+1C]+24]+83C]+C 是角色包裹首地址...

[[[[[8BCB44]+1C]+24]+83C]+C]+4*格子序号 是格子物品首地址...

[[[[[[8BCB44]+1C]+24]+83C]+C]+4*格子序号]+14 是此格物品的数量...

[[[[[[8BCB44]+1C]+24]+83C]+C]+4*格子序号]+18 是此格物品的堆叠上限...

授人以鱼,不如授人以渔...关于其他的地址需要大家举一反三

你可能感兴趣的:(c,语言,byte,编译器)