WG基础必知十三条

14 篇文章 7 订阅
14 篇文章 25 订阅

一、什么是基址?

我们可以想象一棵苹果树,树有根,树上也有苹果,

某个苹果对应某个偏移,而树根就是基址,通过基址往上找就能找到某个苹果

而找到的这个苹果,相对于有个偏移。通过基址+偏移就能确定是哪个苹果。

例如:基址=00401000 偏移是20,代表1号苹果,那OD里:dd [00401000]+20 就能找到这个1号苹果。

dd命令 是以内存地址的方式查看数据。

二、为什么要找基址?

因为游戏退出基址不会变化,只有游戏更新后才会变化,

而要是用找到的内存地址,例如:血的内存地址,游戏退出是会变化的,不方便我们编写辅助调用。

三、用什么工具适合找基址和偏移?

Ollydbg(简称OD)-反汇编
Cheat Engine(简称CE)-游戏作弊修改器

强烈推荐这两款游戏数据分析高手都必备的工具。

四、偏移最多有多少级?

最少偏移就是一个基址代表一个数据,例如:dd 00401000 就是血数量
最多偏移可以是无穷大,分析过最多的是20多偏移。

例如:dd [00401000]+20 20就是一级偏移
而类推:
dd [[00401000]+20]+30 30就是二级偏移

五、什么是CALL?

CALL就是相当于易语言里的子程序,相当于C++里面的函数。

每个CALL都有用途,很多独立的功能都可以封装在CALL里,这样调用这个CALL也就调用了对应封装的功能。

CALL有“参数”,也有“返回值”

“参数”可以是没有,也可以是多个。

六、如何识别CALL有多少个参数?

实战举例说明:

这个CALL:

0042FC9F > $ E8 ECCF0000 CALL start.0043CC90 //内存地址是0043CC90

进入CALL里面,OD里是用enter回车键进入:

0043CC90 /$ 55 PUSH EBP
0043CC91 |. 8BEC MOV EBP,ESP
0043CC93 |. 83EC 10 SUB ESP,10
0043CC96 |. A1 10F84500 MOV EAX,DWORD PTR DS:[45F810]
0043CC9B |. 8365 F8 00 AND DWORD PTR SS:[EBP-8],0
0043CC9F |. 8365 FC 00 AND DWORD PTR SS:[EBP-4],0
0043CCA3 |. 53 PUSH EBX
0043CCA4 |. 57 PUSH EDI
0043CCA5 |. BF 4EE640BB MOV EDI,BB40E64E
0043CCAA |. 3BC7 CMP EAX,EDI
0043CCAC |. BB 0000FFFF MOV EBX,FFFF0000
0043CCB1 |. 74 0D JE SHORT start.0043CCC0
0043CCB3 |. 85C3 TEST EBX,EAX
0043CCB5 |. 74 09 JE SHORT start.0043CCC0
0043CCB7 |. F7D0 NOT EAX
0043CCB9 |. A3 14F84500 MOV DWORD PTR DS:[45F814],EAX
0043CCBE |. EB 60 JMP SHORT start.0043CD20
0043CCC0 |> 56 PUSH ESI
0043CCC1 |. 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
0043CCC4 |. 50 PUSH EAX ; /pFileTime
0043CCC5 |. FF15 74C14400 CALL DWORD PTR DS:[<&KERNEL32.GetSystemT>; \GetSystemTimeAsFileTime
0043CCCB |. 8B75 FC MOV ESI,DWORD PTR SS:[EBP-4]
0043CCCE |. 3375 F8 XOR ESI,DWORD PTR SS:[EBP-8]
0043CCD1 |. FF15 70C24400 CALL DWORD PTR DS:[<&KERNEL32.GetCurrent>; [GetCurrentProcessId
0043CCD7 |. 33F0 XOR ESI,EAX
0043CCD9 |. FF15 7CC24400 CALL DWORD PTR DS:[<&KERNEL32.GetCurrent>; [GetCurrentThreadId
0043CCDF |. 33F0 XOR ESI,EAX
0043CCE1 |. FF15 B4C14400 CALL DWORD PTR DS:[<&KERNEL32.GetTickCou>; [GetTickCount
0043CCE7 |. 33F0 XOR ESI,EAX
0043CCE9 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
0043CCEC |. 50 PUSH EAX ; /pPerformanceCount
0043CCED |. FF15 70C14400 CALL DWORD PTR DS:[<&KERNEL32.QueryPerfo>; \QueryPerformanceCounter
0043CCF3 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]
0043CCF6 |. 3345 F0 XOR EAX,DWORD PTR SS:[EBP-10]
0043CCF9 |. 33F0 XOR ESI,EAX
0043CCFB |. 3BF7 CMP ESI,EDI
0043CCFD |. 75 07 JNZ SHORT start.0043CD06
0043CCFF |. BE 4FE640BB MOV ESI,BB40E64F
0043CD04 |. EB 0B JMP SHORT start.0043CD11
0043CD06 |> 85F3 TEST EBX,ESI
0043CD08 |. 75 07 JNZ SHORT start.0043CD11
0043CD0A |. 8BC6 MOV EAX,ESI
0043CD0C |. C1E0 10 SHL EAX,10
0043CD0F |. 0BF0 OR ESI,EAX
0043CD11 |> 8935 10F84500 MOV DWORD PTR DS:[45F810],ESI
0043CD17 |. F7D6 NOT ESI
0043CD19 |. 8935 14F84500 MOV DWORD PTR DS:[45F814],ESI
0043CD1F |. 5E POP ESI
0043CD20 |> 5F POP EDI
0043CD21 |. 5B POP EBX
0043CD22 |. C9 LEAVE
0043CD23 . C3 RETN //注意看这个retn返回命令,直接retn返回说明该CALL没参数。

=================================================

再举例 说明有参数的识别:

0040C0B6 |. 6A FF PUSH -1 //参数
0040C0B8 |. 53 PUSH EBX //参数
0040C0B9 |. 50 PUSH EAX //参数 可以看这里有多少个push 代表有多少个参数。是在CALL的前面
0040C0BA |. 8D8C24 D00000>LEA ECX,DWORD PTR SS:[ESP+D0]
0040C0C1 |. C68424 180100>MOV BYTE PTR SS:[ESP+118],4
0040C0C9 |. E8 02C2FFFF CALL start.004082D0 //这个CALL,进入里面

得到:

004082D0 /$ 53 PUSH EBX
004082D1 |. 8B5C24 08 MOV EBX,DWORD PTR SS:[ESP+8]
004082D5 |. 55 PUSH EBP
004082D6 |. 8B6C24 10 MOV EBP,DWORD PTR SS:[ESP+10]
004082DA |. 396B 14 CMP DWORD PTR DS:[EBX+14],EBP
004082DD |. 56 PUSH ESI
004082DE |. 57 PUSH EDI
004082DF |. 8BF1 MOV ESI,ECX
004082E1 |. 73 05 JNB SHORT start.004082E8
004082E3 |. E8 ACE70300 CALL start.00446A94
004082E8 |> 8B7B 14 MOV EDI,DWORD PTR DS:[EBX+14]
004082EB |. 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C]
004082EF |. 2BFD SUB EDI,EBP
004082F1 |. 3BC7 CMP EAX,EDI
004082F3 |. 73 02 JNB SHORT start.004082F7
004082F5 |. 8BF8 MOV EDI,EAX
004082F7 |> 3BF3 CMP ESI,EBX
004082F9 |. 75 1F JNZ SHORT start.0040831A
004082FB |. 6A FF PUSH -1
004082FD |. 03FD ADD EDI,EBP
004082FF |. 57 PUSH EDI
00408300 |. 8BCE MOV ECX,ESI
00408302 |. E8 99E6FFFF CALL start.004069A0
00408307 |. 55 PUSH EBP
00408308 |. 6A 00 PUSH 0
0040830A |. 8BCE MOV ECX,ESI
0040830C |. E8 8FE6FFFF CALL start.004069A0
00408311 |. 5F POP EDI
00408312 |. 8BC6 MOV EAX,ESI
00408314 |. 5E POP ESI
00408315 |. 5D POP EBP
00408316 |. 5B POP EBX
00408317 |. C2 0C00 RETN 0C //看这里 是返回 0c 是16机制,转成10进制 12/4=3个参数 为什么要除以4,因为1个push 占用4个字节 3个push就是3*4=12字节

七、如何调试CALL可能对应的功能?

当你在找某个CALL数据的时候,例如:吃药CALL,

吃药CALL相关的CALL你可以通过 :

1.无参数CALL,可以直接OD里,右键-二进制-用NOP填充 该CALL,填充后,回游戏看是否能吃药,能的话,说明与吃药CALL不相干。

2.有参数CALL,可以直接修改CALL,OD里按空格键修改反汇编,修改为add esp,4 4代表1个参数,如果是三个参数的话,就修改为:add esp,0c 这样使堆栈平衡了,游戏才不会出错,然后也是回游戏看是否能吃药,能的话,说明也是与吃药CALL不相干的CALL。

八、知道了有参数CALL的参数数据,如何调试CALL效果?

可以通过“代码注入器”这个工具来调试CALL效果。

举例 有参数CALL:

push eax
push edx
call 00401000

//上CALL有2个参数,通过PUSH看出来的,这2个参数的值假设分别是
push 1
push 2

那我们在代码注入器如何来写汇编的呢?

具体是:

push 1
push 2
call 00401000

然后按下 注入远程代码 就能看效果了。

无参数CALL直接写call 00401000即可。

九、能达到CALL效果,但游戏出错怎么办?

用代码注入器测试能达到CALL效果,但游戏出错了,这如何解决?

这通常是由于有参数的CALL,有个堆栈不平衡导致的,

那如何恢复堆栈平衡呢?

举例 有参数CALL:

push 1
push 2
call 00401000

这个CALL有2个参数,代码注入器能达到效果,但会出错,

这时候要加上堆栈平衡汇编语句

具体是:

push 1
push 2
call 00401000
add esp,8

1个参数是4字节,2个参数是8字节,所以是add esp,8

这样就不会达到CALL效果同时游戏出错了。

十、游戏数据分析“汇编”很重要吗?

汇编看得懂就行,例如:mov eax,ebx 是什么意思?
mov eax,[00401000] 是什么意思?

你能看懂就OK了。

十一、什么是内存挂,什么是变态挂,什么是脱机挂?

内存挂就是获取游戏里面的CALL数据,主要以调用游戏数据为主。

变态挂就是修改游戏里面的数据,例如:像单机游戏一样修改数据,或者修改汇编,达到游戏本没的功能。主要以修改游戏数据以及汇编为主。

脱机挂就是向服务器发送封包数据,可以不用开客户端也能挂机。主要以封包数据为主。

十二、发送封包的函数都有哪些?OD如何下断?

send
sendto
WSASend
WSASendTo

这四个是常用的发送封包函数,OD里获取CALL数据的时候相当有用。

OD下断点就是:

bp send
bp sendto
bp WSASend
bp WSASendTo

不同的游戏可能用了不同的发送封包函数,在实际的实践当中,可以灵活运用。

列出2个最常用函数原型:

int send(
__in SOCKET s, //封包ID
__in const char *buf, //封包数据
__in int len, //封包大小
__in int flags //标志位
);

====================

int WSASend(
__in SOCKET s, //封包ID
__in LPWSABUF lpBuffers, //封包数据
__in DWORD dwBufferCount, //封包数量
__out LPDWORD lpNumberOfBytesSent, //封包大小
__in DWORD dwFlags, //标志位
__in LPWSAOVERLAPPED lpOverlapped, //指向WSAOVERLAPPED结构指针
__in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
//完成例程的指针
);

以上了解了解就ok。

十三、什么是OD死码,如何设立?为什么要设立?

==============================================
什么是OD死码?

OD死码指的就是OD反汇编中游戏更新后也不变的汇编。

==============================================

如何设立?

规则:最多8条汇编,因为OD里ctrl+s搜的时候最多只能8条

哪些汇编不能用于OD死码:call 内存地址
jz/jnz/je(等跳转语句) 内存地址
mov eax,[ecx+0abc] 偏移abc比较大的不可以。
mov eax,[esp+30] 汇编里有ESP堆栈寄存器的不可以,后面跟的偏移+30会变化

为什么要设立?

因为游戏更新基址,较大的偏移会变化,为了方便,所以设立OD死码,
方便快速获取游戏更新后的相关数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值