吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 25745|回复: 139
收起左侧

[Android 原创] 记一次基于frida的手游透视实现

    [复制链接]
从0开始的小小怪 发表于 2020-3-25 15:46
本帖最后由 从0开始的小小怪 于 2020-3-25 15:59 编辑

0x0 前言

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


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

0x1 工具的使用

​                frida的使用基于python, 所以在开始前先安装好最新版的python.然后执行pip install fridapip 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-server

启动frida-server

​                                                                                                                                        图1: 启动frida-server

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

检测连接

检测连接

​                                                                                                                                        图2: 检测连接情况

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

frida工作正常

frida工作正常

预先修改数据测试

预先修改数据测试

​                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)#绘图

​                最终实现的效果如图:

1.png 2.png

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]

免费评分

参与人数 42威望 +2 吾爱币 +140 热心值 +36 收起 理由
wabc666 + 2 + 1 牛逼啊,frida还能做外挂,真实奇思妙想!
睡懒觉的猫 + 1 + 1 谢谢@Thanks!
pangxie1991 + 1 谢谢@Thanks!
jiaodian + 1 + 1 鼓励转贴优秀软件安全工具和文档!
Anekys + 1 + 1 谢谢@Thanks!
九重桂妖 + 1 用心讨论,共获提升!
shenshouaowu + 1 用心讨论,共获提升!
pareto + 1 + 1 用心讨论,共获提升!
ylbhs + 1 + 1 谢谢@Thanks!
LoveMiku233 + 1 + 1 谢谢@Thanks!
qtfreet00 + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
西枫游戏 + 1 + 1 不一样的使用方法 牛逼
q75092585 + 1 我很赞同!
wanghaisheng + 1 + 1 用心讨论,共获提升!
Small_Google + 1 + 1 用心讨论,共获提升!
sunnylds7 + 1 + 1 热心回复!
hikansakuratan + 1 + 1 鼓励转贴优秀软件安全工具和文档!
zhp_king + 1 我很赞同!
小学生 + 1 + 1 楼主真行家,成品丢我一个
gunxsword + 1 + 1 从有想法到实现这种效果...2天...牛逼...
jimmyzang + 1 + 1 我很赞同!
lynxtang + 1 + 1 谢谢@Thanks!
Black_山猫 + 1 用心讨论,共获提升!
m0nst3r + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
wangyoo + 1 谢谢@Thanks!
v0id_alphc + 1 + 1 牛逼兄弟
S-tony + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Lucifer_BW + 1 + 1 热心回复!
unbeaten + 1 + 1 谢谢@Thanks!
暗夜杀神 + 1 + 1 谢谢@Thanks!
wyyynioo + 1 谢谢@Thanks!
zqy10008 + 1 用心讨论,共获提升!
AsktaoMS + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
挑灯看花 + 1 我有一个大胆的想法
axuan666 + 1 我很赞同!
CrazyNut + 3 + 1 用心讨论,共获提升!
LASTandGAME + 1 + 1 鼓励转贴优秀软件安全工具和文档!
Capitalwell + 1 + 1 我很赞同!
干烧鱼蛋炒饭 + 1 + 1 我很赞同!
丶咖啡猫丶 + 1 + 1 热心回复!
Pholhx + 1 + 1 谢谢@Thanks!
clockworklun + 2 + 1 鼓励转贴优秀软件安全工具和文档!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

老凡尘 发表于 2020-3-27 12:26

留下你的邮箱发给你
LASTandGAME 发表于 2020-3-25 16:54
赤座灯里 发表于 2020-3-25 16:03
本帖最后由 赤座灯里 于 2020-3-25 16:43 编辑

可以试试用rpc远程调用,js里定义导出函数,用rpc.exports的字典进行声明,函数只用来读内存返回坐标数据,然后在python里循环调用该函数取出坐标直接绘制,应该可以解决问题
那年夏天52 发表于 2020-3-25 16:01
这个好啊,顶
LoongKing 发表于 2020-3-26 10:53
@腾讯安全 建议发offer
SunerC 发表于 2020-3-25 16:26
企鹅觉得很淦
jy03344125 发表于 2020-3-25 16:36
有点复杂…先慢慢看看
imyxuan 发表于 2020-3-25 16:37
有点给力
EV99 发表于 2020-3-25 16:40
收藏一波
Capitalwell 发表于 2020-3-25 16:48
原来透视这样实现的呀
Dream_Peng 发表于 2020-3-25 17:00
楼主 基于这个东东可以写自动化后台脚本不?
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-5 05:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表