免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
如果看不懂、不知道现在做的什么,那就跟着做完看效果
现在的代码都是依据数据包来写的,如果看不懂代码,就说明没看懂数据包
内容参考于: 易道云信息技术研究院VIP课
上一个内容:86.解析游戏技能数据包中的内容
下方说的指针意思是内存地址
到这基本上都是进行的数据包的分析,可以感觉出分析数据包不如做逆向好玩,逆向是一个有明确反馈的东西,就是只要找到线索找到它出现的时机,也就能找到要找的东西,但是数据包的分析,数据包的分析是从刚开始到分析到最后不知道怎么分析出来,也不知道能不能分析出来,很可能做到最后被一两个数据包给卡主了,也会因为这一两个数据包导致我们无法达成利用数据包这个事情,很可能这个软件分析好了,然后换了一个软件就分析不出来了,这时不要放弃慢慢搞。
然后上一个内容里发现了技能都是英文的,然后装备的名字也是英文的,这是为了做多语言,就是做了一个游戏如果火了,在国外要英文的,在我们国家要中文的,如果把这些文字在代码里写死了,比如写死了中文,然后在国外火了要英文就要重新把中文改成英文然后把代码重新编译,这样就很麻烦,然后游戏里它就写一个编码,就是在数据包中看到的那些英文,通过这些英文去找游戏里的语言包,然后通过语言包显示文字信息,这样不同的国家只需要写语言包,不需要动游戏代码,就能实现多个语言,然后我们要逆向的是找游戏什么时候查的语言包,查语言包的算法,这是逆向的要的结果,然后是这个事情它会什么时候出现,出现的点第一个技能创建时查表,也就是接收18 28这个数据包的时候创建的技能,然后是鼠标放到技能上显示名字的时候查语言包(表),然后如果使用的是技能创建的时候查表,它会把技能的名字放到一个变量里,然后鼠标放到技能上的时候会显示技能名字,这时的技能名字是通过访问变量而不是访问查表,这时就无法通过鼠标放到技能上显示技能名字去找查语言包的操作,然后如果是鼠标放到技能上显示名字时是查的语言包,这个时候在显示的位置往上追就能看到它把英文当参数传给函数的操作,所以要区分这两种情况,不然会找不到。
然后现在是无法确认游戏它是什么时候查的语言包。
首先从技能名字下手
下图红框技能的名字,冲斩
![]()
然后使用 Cheat Engine 工具看冲斩的地址,使用 Cheat Engine 附加游戏
![]()
然后搜索字符串
![]()
会搜出多个
![]()
把它们都添加到列表
![]()
然后修改值,双击下图1位置,就可以弹出改变数值窗口了
![]()
然后发现游戏中的技能名变成了4冲斩
![]()
这说明下图红框位置是技能名
![]()
然后看是什么访问了它
![]()
然后鼠标放到下图游戏中红框位置,就可以看到什么访问了它们
![]()
然后鼠标单击1然后再单击2然后鼠标在3位置右击就可以弹出 复制信息到剪贴板了,后面要用要把它们4个全部复制一下
![]()
然后全部记录下来
![]()
然后关闭 Cheat Engine打开x96dbg
![]()
以管理员方式启动
![]()
然后点附加
![]()
然后选中游戏,点附加
![]()
然后首先第一个是0x102960C4位置,下图打断点(鼠标双击下断点)发现它是一个长断的函数,这样正常,这种显示内容的函数肯定是通用的,然后再次双击取消断点,然后按f9让游戏运行起来
![]()
然后下一个条件断点
![]()
条件是eax,eax通过Cheat Engine得知它是技能名字的地址
![]()
下好条件断点之后,鼠标放到游戏下图红框的位置就可以触发断点了
![]()
然后它的入参,下图红框位置是技能id,但是技能id前面加了desc_,然后通过这个可以猜测游戏是在显示的时候去查的语言包
![]()
然后看它附近的代码,下图绿框,可以看到eax的值是从一个数组(数组的写法就是 eax+ecx*4,这样有+*的操作基本都是数组)中得到的
![]()
然后eax的值与ecx的值,是从esp加一个数字得到的,esp是与栈有关,也就是可能是局部变量也可能是参数
![]()
然后函数的头部,附近并没有局部变量的写法esp+4、esp+8这样的写法是局部比那里,所以eax与ecx的值是从上一层来的
![]()
然后断点住
![]()
取消断点
![]()
按ctrl+f9再按f8来到上一层,如果不取消断点就按ctrl+f9再按f8会很乱
![]()
然后到了下图的函数就没法用条件断点了,只能硬看了,也不是硬看,既然它是常断的函数,就说名做的是是一样的,应该看哪个断点住的都行,下图绿框可以看到eax 是序号,ecx是this指针
![]()
然后现在知道了eax+ecx*4,eax是this指针,ecx 是参数
![]()
然后this指针是传递过来的,eax是通过函数返回值得到的,如下图红框
![]()
下图得到数组下标
![]()
然后现在知道数组下标是在0x102962B3位置调用的0x10295FB0函数得到的,然后0x10295FB0函数里用到了ebx,所以接下来找ebx怎么得
![]()
然后在下图位置打断点,然后复制ebx的值,这个值后面分析要用 069244C8
![]()
复制完ebx的值,在下图位置断点住,然后取消断点
![]()
然后按ctrl+f9再按f8来到上一层,然后在上一层的函数打断点并断点住,然后看到eax是ebx的值,这时断点住如果eax并不是ebx的值那就下一个条件断点
![]()
然后eax 的值来自于esp+38位置,然后当前函数并没有局部变量的操作,所以esp是参数
![]()
然后按ctrl+f9再按f8来到上一层,这是一个函数指针
![]()
然后通过条件断点,看到ebx是我们要的指针
![]()
然后ebx的值是从eax来的,如下图,eax的值是一个函数的返回值
![]()
然后跟丢了,然后重新来,然后回到0x102960C4位置,把ebx的值记下来0B2991B8
![]()
然后按ctrl+f9再按f8,来到下图位置
![]()
然后下条件断点找 0B2991B8
![]()
然后在条件断点的状态下按ctrl+f9在按f8来到下图位置
![]()
然后再下条件断点,继续找0x0B2991B8,这里是eax满足条件
![]()
然后再条件断点住的状态下按ctrl+f9再按f8,然后就来到了下图位置0x02556b7f位置
![]()
然后继续下条件断点找0x0B2991B8,这里是ebx
![]()
然后再条件断点的状态下按ctrl+f9再按f8,然后就来到了下图位置
![]()
然后发现在这根据0x0B2991B8下条件断点 eax、ecx、edx、ebx都断不下来,所以是走过了,然后回到0x02556b7f位置,然后发现又来到这个位置了,如下图,这次是一路按着技能给的ebx的值找的,然后这时换个思路,不用根据技能的名字找了,根据npc的名字,第一次跟丢了就来到了下图位置,第一次没有截图,但确实是有这个事
![]()
然后再次回到0x102960C4位置
![]()
然后找一个npc
![]()
记录它的ebx的值 0B2991B8,按ctrl+f9再按f8发现它还是回来到下图位置
![]()
按ctrl+f9再按f8这里与之前的一样
![]()
到这可以发现与之前的代码不一样了
![]()
然后这里的ebx的值是我们要找的
![]()
然后按ctrl+f9再按f8来到下图位置,这里都是在条件断点断下来的情况下按ctrl+f9再按f8,后面就省略提示在 条件断点断下来,然后取消断点了,直接说按ctrl+f9再按f8这样操作了,只要记得有按ctrl+f9再按f8的就要 条件断点断下来,然后取消断点之后再按
![]()
然后这里eax是我们要找的值
![]()
eax的值如下图,来自于esp+13C太大了,所以来自于参数
![]()
然后继续按ctrl+f9再按f8,然后来到了下图位置
![]()
我们要找的值在eax,eax的值来自于esp+18,esp+18e很小,很大几率是局部变量,然后来到当前函数头部
![]()
并没有在栈里看到与我们要的数据相似的值
![]()
然后再函数头部一路f8,看看我们的值在哪来的,然后看到在下图红框位置第一次出现我们要的值,0x3E1B765位置调用的0x3F1A680函数
![]()
然后这个函数的参数是固定的,一直都是76 00 00 00 84 02 00 00 所以这个函数我们可以利用它
![]()
为什么说可以利用它,它没有用ecx、edx这种this地址,它是一个c代码,然后它的参数,是76 00 00 00 84 02 00 00 这个东西,我们完全可以模拟它,去调用0x3F1A680函数然后得到语言包,然后游戏基址很难找很绕,应该通过0x3F1A680这个函数可以把所有基址都给找出来
![]()
然后发现了上面有一个函数,这个函数的参数是一个内存地址,也就是我们的 76 00 00 00 84 02 00 00 这个东西,但是现在并不是76 00 00 00 84 02 00 00 这个东西,从下图可以看出来
![]()
执行完函数之后,得到了76 00 00 00 84 02 00 00 这个东西,所以都用伪造了,直接申请8字节内存然后把内存地址给不0x3F1C060函数,然后就能得到获取语言包的基址了
![]()
这个函数里面没有用ecx(this指针),所以是可以直接调用的
![]()
总结
调用0x3F1C060函数得到一个序号,然后把这个序号作为入参去调用0x3F1A680函数,调用完0x3F1A680函数就得到了npc名字表,然后用0x3F1A680函数返回值作为this指针去调用0x10295FB0函数得到序号,有了序号之后再根据0x10291F60函数里去找名字的算法,得到名字
分析的关键代码
得到基址
03E1B750 | 68 4C120304 | push fxgamelogic.403124C | 403124C:"TextManager"
03E1B755 | 50 | push eax |
03E1B756 | 8D4C24 64 | lea ecx,dword ptr ss:[esp+64] | [esp+64]:&"manm_080509xx.ini"
03E1B75A | 51 | push ecx |
03E1B75B | E8 00091000 | call fxgamelogic.3F1C060 |
03E1B760 | 8D5424 68 | lea edx,dword ptr ss:[esp+68] | [esp+68]:FxModule_GetFuncCreator+1A3FF
03E1B764 | 52 | push edx |
03E1B765 | E8 16EF0F00 | call fxgamelogic.3F1A680 | 返回值是语言包基址
03E1B76A | 83C4 10 | add esp,10 |
03E1B76D | 85C0 | test eax,eax |
得到序号
102962A0 | 51 | push ecx |
102962A1 | 53 | push ebx |
102962A2 | 8BD8 | mov ebx,eax |
102962A4 | 807B 29 00 | cmp byte ptr ds:[ebx+29],0 |
102962A8 | C74424 04 00000000 | mov dword ptr ss:[esp+4],0 |
102962B0 | 57 | push edi | edi:"npc_zqm001_0084"
102962B1 | 75 0A | jne fxgui.102962BD |
102962B3 | E8 F8FCFFFF | call fxgui.10295FB0 |
102962B8 | 85C0 | test eax,eax |
102962BA | 7D 10 | jge fxgui.102962CC |
102962BC | 57 | push edi | edi:"npc_zqm001_0084"
102962BD | 8BCE | mov ecx,esi |
102962BF | E8 9CBCFFFF | call fxgui.10291F60 |
102962C4 | 83C4 04 | add esp,4 |
102962C7 | 8BC6 | mov eax,esi |
102962C9 | 5B | pop ebx |
102962CA | 59 | pop ecx |
102962CB | C3 | ret |
102962CC | 50 | push eax |
102962CD | 56 | push esi |
102962CE | 8BCB | mov ecx,ebx |
102962D0 | E8 7BFDFFFF | call fxgui.10296050 |
102962D5 | 8BC6 | mov eax,esi |
102962D7 | 5B | pop ebx |
102962D8 | 59 | pop ecx |
102962D9 | C3 | ret |