快捷搜索:  汽车  科技

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)Memory.readInt()指令是读取指针所指的地址取int类型的值 ptr(0xc404bf30)的意思是将0xc404bf30转化为native指针 在frida的内存操作都是基于这个native指针来进行的. 上面两图我们可以看到工具能够正常工作.我们在这里主要使用frida的内存操作指令 而不使用拦截器. 首先我们配合gg修改器附加一个进程进行指令的测试 我们选用一个进程 我挑的进程的pid为10080 使用frida -p 10080 -U附加或者查看该进程的包名使用frida -n xxx -U附加 附加后我们用gg修改器选一个地址 修改为一个数字 frida读取验证一下:图1: 启动frida-server之后将该窗口最小化 开启另一个窗口输入frida-ps -U命令检测模块是否正常连接 如图所示则一切正常:图2: 检测连接情况

0x0 前言

之前在接触到frida之后就对这个工具印象特别深刻 虽说每次调试都得需要电脑的辅助调控 但是胜在轻量级且不用总是重启 接口的使用也比较方便. 因为在之前见过有人使用gg修改器配合软件的绘制来进行对鹅肠的某款moba手游进行方框透视 所有突然来了灵感 尝试使用frida读取内存 并且实现同时对读取的数据用python绘制.


在这里我对所有敏感的特征码进行了删减处理 只进行技术的交流 不传播脚本的使用.

0x1 工具的使用

frida的使用基于python 所以在开始前先安装好最新版的python.然后执行pip install frida和pip install frida-tools 就安装好frida了. 此外还需要有adb工具 具体的基础使用不在这里赘述 百度上有很多. 在frida的官网下载frida-server并且使用adb push命令将其置于data/local/tmp目录下 并且赋予777权限.

工具准备就绪后如图依次输入指令adb shell su ./data/local/tmp/frida-server命令运行frida-server:

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)(1)

图1: 启动frida-server

之后将该窗口最小化 开启另一个窗口输入frida-ps -U命令检测模块是否正常连接 如图所示则一切正常:

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)(2)

图2: 检测连接情况

我们在这里主要使用frida的内存操作指令 而不使用拦截器. 首先我们配合gg修改器附加一个进程进行指令的测试 我们选用一个进程 我挑的进程的pid为10080 使用frida -p 10080 -U附加或者查看该进程的包名使用frida -n xxx -U附加 附加后我们用gg修改器选一个地址 修改为一个数字 frida读取验证一下:

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)(3)

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)(4)

Memory.readInt()指令是读取指针所指的地址取int类型的值 ptr(0xc404bf30)的意思是将0xc404bf30转化为native指针 在frida的内存操作都是基于这个native指针来进行的. 上面两图我们可以看到工具能够正常工作.

我们的绘图操作使用python的tkinter包. 相关的参考资料可以如下:

0x2 js代码对数据读取

主要的js代码如下:

复制代码 隐藏代码 //js code function readP(firstAddr pos){//设置偏移并且读取数据 for(var i=0;i<=9;i ){//十名玩家 var base = ptr(firstAddr[i]); pos[2*i] = Memory.readInt(base.add(xOffset));//读取x轴 pos[2*i 1] = Memory.readInt(base.add(yOffset));//读取y轴 } } var pattern = 'xx';//特征匹配 var base = ptr(0x7f000000);//扫描起点 var firstAddr = []; Memory.scan(base 0x10000000 pattern { onMatch: function(address size){//匹配之后执行的回调函数 var vJudg = Memory.readInt(ptr(address).add(xOffset));//读取判断 if(vJudg>redMin&&vJudg<redMax) firstAddr.push(address); if(vJudg>blueMin&&vJudg<blueMax) firstAddr.push(address); } onComplete:function(){// console.log('scan finish'); } }); Thread.sleep(2)//一定要等待扫描线程结束后才继续往下 否则报错 var pos = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]; var time;//需要设置脚本运行时间 否则报传输错误 未知原因 while(time--){ Thread.sleep(0.2); readP(firstAddr pos); send(pos.toString());//传送数据 }

js代码主要的流程是先扫描特征码 然后基于特征码偏移找到玩家的坐标数据 之后将读取的坐标数据以字符串的形式传递给python代码. 首先特征码的查找是必要的 其次对于内存的读取有一个坑 玩家要不断点击移动按钮内存才会刷新 倘若拖动摇杆则会造成内存无法刷新的问题 具体解决方案我查了很多资料也没有找到原因. 希望有大佬可以指点一下.

0x3 python接收js数据并完成绘图

我对python的功能进行了分类 主要的原因在于无论采用多线程还是多进程 tkinter在绘图的过程中要么画不出图像 要么报main thread is not in main loop的错误 所以我索性将绘图另外放置一个脚本之中 开两个shell进行工作 数据的传输使用socket进行传输. 接收数据的服务端代码如下:

复制代码 隐藏代码 #file1.py import frida import sys import socket server = socket.socket() server.bind(('192.168.0.104' 8900))#局域网ip地址 server.listen(1) serObj address = server.accept() package_id = 'com.xxx' # 游戏包名 device = frida.get_usb_device(timeout=10)#我的电脑要设置timeout 否则连接不上 原因未知 session = device.attach(package_id) scr = """ /*****************/ """ def on_message(message data): serObj.send(message['payload'].encode('utf-8')) script = session.create_script(scr) script.on("message" on_message) script.load()

这个py文件主要完成了js数据的接收和转发至绘图脚本的工作. 绘图脚本代码如下:

复制代码 隐藏代码 import mttkinter import time from mttkinter import * import sys import socket global color def ScreenPos(gamePos): for i in range(0 10): gamePos[2*i] = (gamePos[2*i]/108850*600) 300 gamePos[2*i 1] = -(gamePos[2*i 1]/108850*600) 300 return gamePos def StringToInt(s): gamePos = s.split(' ') for i in range(0 20): gamePos[i] = int(gamePos[i]) return gamePos def DrawPoint(canvas screenPos): length = 5 for i in range(0 10): if color[i]==1: canvas.create_rectangle(screenPos[i*2]-length 460 screenPos[i*2 1]-length 150 screenPos[i*2] length 460 screenPos[i*2 1] length 150 fill = 'red') else: canvas.create_rectangle(screenPos[i*2]-length 460 screenPos[i*2 1]-length 150 screenPos[i*2] length 460 screenPos[i*2 1] length 150 fill = 'blue') def Draw(re_data canvas tk): gamePos = StringToInt(re_data) screenPos = ScreenPos(gamePos) canvas.create_rectangle(440 130 1080 770 fill = 'white') DrawPoint(canvas screenPos) tk.update() def Check(gamePos): for i in range(0 10): if gamePos[2*i]>0: color[i]=1#red color = [0 0 0 0 0 0 0 0 0 0]#颜色区分 tk = mttkinter.mtTkinter.Tk() tk.geometry(' 0 0') tk.overrideredirect(True) canvas = mttkinter.mtTkinter.Canvas(tk width = 1920 height = 1080) canvas.pack() client = socket.socket() client.connect(('192.168.0.104' 8900))#连接服务端 re_data = client.recv(1024).decode('utf-8') Check(StringToInt(re_data))#数据校验 while True: re_data = client.recv(1024).decode('utf-8') Draw(re_data canvas tk)#绘图

最终实现的效果如图:

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)(5)

手游救赎猎手和端游救赎猎手对比(记一次基于frida的手游透视实现)(6)

0x4 最后

从开始有这个想法到最后的勉强算成功花了两天的时间 真的是踩了无数的坑 也学到了挺多的东西. 令我印象最深刻的还是js读出内存不更新以及画图的问题 我到现在也搞不懂 难道是frida还对读过的内存进行了缓存吗 移动摇杆就是不更新内存 只有点击才有反应. 还有python的绘图 一边传数据一边画图按理说用多线程就可以解决的 可多线程多进程都试过才发现不行. 最后绘图的帧率很低 一卡一卡的 人物坐标莫名其妙会飘 手机也很热 也就做研究可以试试 实际的使用根本不行=.=

以下是我个人觉得比较好的相关参考资料:

[<FONT color='blue'>frida文档</FONT>][https://frida.re/docs/javascript-api/]

[<FONT color='blue'>frida入门教程</FONT>][https://www.jianshu.com/p/b833fba1bffe]

[<FONT color='blue'>tkinter画图</FONT>][https://www.cnblogs.com/OctoptusLian/p/6366351.html]

猜您喜欢: