From 04a6173d9231f2c934bbc13e45506755ede0162e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=83=B3=E8=A6=81=E6=88=90=E4=B8=BARapStar=E5=90=97?= =?UTF-8?q?=EF=BC=9F?= Date: Thu, 24 Sep 2020 15:11:47 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9ABase=20Demo=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 20 +++- config.py | 9 +- main.py | 196 ++++++++----------------------------- parse.js | 6 +- requirements.txt | 31 ++++++ source/fastapi_docs.png | Bin 0 -> 29204 bytes source/post_body_hints.png | Bin 0 -> 31125 bytes source/test.png | Bin 0 -> 31519 bytes utils/__init__.py | 62 ++++++++++++ utils/generate_function.py | 145 +++++++++++++++++++++++++++ 10 files changed, 301 insertions(+), 168 deletions(-) create mode 100644 requirements.txt create mode 100644 source/fastapi_docs.png create mode 100644 source/post_body_hints.png create mode 100644 source/test.png create mode 100644 utils/__init__.py create mode 100644 utils/generate_function.py diff --git a/README.md b/README.md index d18b238..d3e5dc9 100644 --- a/README.md +++ b/README.md @@ -11,28 +11,40 @@

-> 基于FastAPI实现的Frida-Rpc工具 +> 基于`FastAPI`实现的`Frida-RPC`工具,只需开发好相对应app的`Frida-Js`脚本,即可自动生成相应的基于`FastAPI`的`Frida-RPC`工具 ### 🏠 [Homepage](暂无) ### ✨ [Demo](暂无) +Do By You Self! + +## 实现原理 + +`Python`执行`PyexecJs`通过`Js的AST树`结构获取`Frida-Js`脚本中`rpc.exports`的方法以及对应方法的参数个数,根据方法名和参数个数通过`types.FunctionDef`从`Python AST字节码`来动态生成新的`Function对象`,并且结合`pydantic`的`create_model`自动生成的参数模型注册到`FastAPI的路由系统`中,实现`Frida-RPC`的功能。 + ## Install ```sh -暂无 +1. git clone git@github.com:lateautumn4lin/arida.git + +2. conda create -n arida python==3.8 + +3. conda install --yes --file requirements.txt ``` ## Usage ```sh -暂无 +1. uvicorn main:app --reload + +2. watch 127.0.0.1:8000/docs ``` ## Run tests ```sh -暂无 +uvicorn main:app --reload ``` ## 参考资料 diff --git a/config.py b/config.py index 6202a60..a713f2b 100644 --- a/config.py +++ b/config.py @@ -9,10 +9,5 @@ @License : (C)Copyright 2020 @Desc : None ''' - -apps_config = [ - { - "package_name": "com.kuaiduizuoye.scan", - "script_name": "kuaiduizuoye.js" - } -] +from pathlib import Path +PRASE_PATH = Path(__file__).absolute().parent / "parse.js" diff --git a/main.py b/main.py index d7a34cc..3027509 100644 --- a/main.py +++ b/main.py @@ -9,66 +9,32 @@ @License : (C)Copyright 2020 @Desc : None ''' +from pathlib import Path from pydantic import BaseModel, Field, create_model -from typing import NewType -from ast import * -import types from fastapi import APIRouter -import subprocess import time import frida -from frida import ServerNotRunningError +from starlette.applications import Starlette from fastapi import FastAPI from loguru import logger -import execjs +from utils.generate_function import generate_function +from utils import ( + name_transform, + detect_frida_state, + start_frida_server, + get_app_info +) +from config import * -app = FastAPI() -_parse_path = "parse.js" +# 配置相关函数的参数类型列表 +function_params_hints = { + "encryptData": [0, 0, 0, 0, "", 0, 0, 0, 0, 0, 0] +} +# app相关信息 +_frida_js_path = Path(__file__).absolute().parent/"apps/kuaiduizuoye.js" _package_name = "com.kuaiduizuoye.scan" -_frida_js_path = f"apps/kuaiduizuoye.js" - - -def get_app_info(): - with open(_parse_path, encoding="utf-8") as f, open(_frida_js_path, encoding="utf-8") as f1: - ctx = execjs.compile(f.read()) - result = ctx.call( - 'parse', f1.read() - ) - return result - - -def on_message(message, data): - if message['type'] == 'send': - logger.info("[**] {0}".format(message['payload'])) - else: - logger.info(f"log:{message}") - - -def detect_frida_state(): - logger.info("Begin Detect Frida State") - shell = 'adb shell su -c "ps -ef|grep frida"' - p = subprocess.Popen( - shell, - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) - stdout, stderr = p.communicate() - stdout = stdout.decode('utf-8') - return ("frida-server" in stdout) - - -def start_frida_server(): - logger.info("Begin Start Frida Server") - shell = 'adb shell su -c "./data/local/tmp/frida-server &"' - subprocess.Popen( - shell, - shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT - ) - +# frida注入 if not detect_frida_state(): # 启动frida-server,增加延迟防止附加失败 start_frida_server() @@ -77,111 +43,29 @@ session = frida.get_usb_device().attach(_package_name) script = session.create_script( open(_frida_js_path, encoding="utf-8").read() ) -script.on('message', on_message) -logger.info('[*] Start attach') script.load() -Url = create_model("User", **{"origin_url": "asdasd"}) -function_ast = FunctionDef( - lineno=2, - col_offset=0, - name='generate_url', - args=arguments( - args=[ - arg( - lineno=2, - col_offset=17, - arg='item', - annotation=Name(lineno=2, col_offset=22, - id='Url', ctx=Load()), - ), - ], - posonlyargs=[], - vararg=None, - kwonlyargs=[], - kw_defaults=[], - kwarg=None, - defaults=[], - ), - body=[ - Expr( - lineno=3, - col_offset=4, - value=Call( - lineno=3, - col_offset=4, - func=Name(lineno=3, col_offset=4, - id='print', ctx=Load()), - args=[Name(lineno=3, col_offset=10, - id='Url', ctx=Load())], - keywords=[], - ), - ), - Assign( - lineno=4, - col_offset=4, - targets=[Name(lineno=4, col_offset=4, - id='res', ctx=Store())], - value=Call( - lineno=4, - col_offset=10, - func=Attribute( - lineno=4, - col_offset=10, - value=Attribute( - lineno=4, - col_offset=10, - value=Name(lineno=4, col_offset=10, - id='script', ctx=Load()), - attr='exports', - ctx=Load(), - ), - attr='generate_url', - ctx=Load(), - ), - args=[ - Attribute( - lineno=4, - col_offset=38, - value=Name(lineno=4, col_offset=38, - id='item', ctx=Load()), - attr='origin_url', - ctx=Load(), - ), - ], - keywords=[], - ), - ), - Return( - lineno=5, - col_offset=4, - value=Name(lineno=5, col_offset=11, id='res', ctx=Load()), - ), - ], - decorator_list=[], - returns=None, -) -module_ast = Module(body=[function_ast], type_ignores=[]) -module_code = compile(module_ast, "<>", "exec") -function_code = [ - c for c in module_code.co_consts if isinstance(c, types.CodeType)][0] -test = types.FunctionType( - function_code, - { - "script": script, - "Url": Url, - "print": print - } -) -test.__annotations__ = {"item": Url} - -router = APIRouter() -for k, v in get_app_info().items(): - router.add_api_route("/generate_url", test, methods=["POST"]) - break -app.include_router(router) -# @app.post('/generate_url') -# def generate_url(item: c): -# res = script.exports.generate_url(item.origin_url) -# return res +def init_app() -> Starlette: + app = FastAPI() + # 每个app创建特有路由 + router = APIRouter() + for api_name, params in get_app_info(parse_path=PRASE_PATH, frida_js_path=_frida_js_path).items(): + params_dict = dict(zip(params, function_params_hints[api_name])) if ( + api_name in function_params_hints) else dict.fromkeys(params, "bb") + model_name = f"{api_name}Model" + Model = create_model(model_name, **params_dict) + new_api_name = name_transform(api_name) + func = generate_function( + new_api_name, + script, + model_name, + Model + ) + router.add_api_route(f"/{new_api_name}", func, methods=["POST"]) + # 全局添加各app路由类 + app.include_router(router) + return app + + +app = init_app() diff --git a/parse.js b/parse.js index d6016ee..3231029 100644 --- a/parse.js +++ b/parse.js @@ -19,7 +19,11 @@ function parse(code) { // 处理function,获取函数名以及对应参数 FunctionDeclaration(path) { let params = path.node; - functions.set(params.id.name, params.params.length) + var lst = new Array(); + for (let i = 0; i < params.params.length; i++) { + lst.push(params.params[i].name) + } + functions.set(params.id.name, lst) } } babel.transform(code, { diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d5c66ec --- /dev/null +++ b/requirements.txt @@ -0,0 +1,31 @@ +# This file may be used to create an environment using: +# $ conda create --name --file +# platform: win-64 +autopep8=1.5.4=py_0 +ca-certificates=2020.7.22=0 +certifi=2020.6.20=py38_0 +click=7.1.2=pypi_0 +colorama=0.4.3=pypi_0 +fastapi=0.61.1=pypi_0 +frida=12.11.17=pypi_0 +h11=0.9.0=pypi_0 +loguru=0.5.3=pypi_0 +openssl=1.1.1g=he774522_1 +pip=20.2.2=py38_0 +pycodestyle=2.6.0=py_0 +pydantic=1.6.1=pypi_0 +pyexecjs=1.5.1=pypi_0 +python=3.8.0=hff0d562_2 +setuptools=49.6.0=py38_0 +six=1.15.0=pypi_0 +sqlite=3.33.0=h2a8f88b_0 +starlette=0.13.6=pypi_0 +toml=0.10.1=py_0 +uvicorn=0.11.8=pypi_0 +vc=14.1=h0510ff6_4 +vs2015_runtime=14.16.27012=hf0eaf9b_3 +websockets=8.1=pypi_0 +wheel=0.35.1=py_0 +win32-setctime=1.0.2=pypi_0 +wincertstore=0.2=py38_0 +zlib=1.2.11=h62dcd97_4 diff --git a/source/fastapi_docs.png b/source/fastapi_docs.png new file mode 100644 index 0000000000000000000000000000000000000000..ec7145d88ac7d03be150d833f79f8c3498122ac0 GIT binary patch literal 29204 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 Jk>CHQ;y)U&yB`1m literal 0 HcmV?d00001 diff --git a/source/post_body_hints.png b/source/post_body_hints.png new file mode 100644 index 0000000000000000000000000000000000000000..12c5d774067292fe14a77cd2d01fb566649a771c GIT binary patch literal 31125 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 RyASu|TQ|>*IUD?c`VU=(xq1Kq literal 0 HcmV?d00001 diff --git a/source/test.png b/source/test.png new file mode 100644 index 0000000000000000000000000000000000000000..984189900bc850477e2c903038990c68a9d2c5d4 GIT binary patch literal 31519 zcmeFZd0bQHx;9MffK$b46)jV(Rjisj}3-Pb+*xHr)6gGC=NvaqoDVAr=_?YFR)hqthJzhl9C@J`_P_4VN8J=A``9TrvH zwj%Jy+?X!|zO=BY&RJ|YHV^#0FyY%!l!e9eB=f)bhE6z~wXncE*!9(y2hT=IjJ%xa zQJjNT{iNx&!wV1EaCmn>{G7r9!NY47kGwqXH=GŽ#De(g{AE++l)cfLC>JF^g< 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 Dict[str, List[str]]: + with open(parse_path, encoding="utf-8") as f, open(frida_js_path, encoding="utf-8") as f1: + ctx = execjs.compile(f.read()) + result = ctx.call( + 'parse', f1.read() + ) + return result + + +def name_transform(name: str) -> str: + split_idx = 0 + for idx, s in enumerate(name): + if s.isupper(): + split_idx = idx + return f"{(name[:split_idx]).lower()}_{(name[split_idx:]).lower()}" + + +def detect_frida_state() -> str: + logger.info("Begin Detect Frida State") + shell = 'adb shell su -c "ps -ef|grep frida"' + p = subprocess.Popen( + shell, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) + stdout, stderr = p.communicate() + stdout = stdout.decode('utf-8') + return ("frida-server" in stdout) + + +def start_frida_server() -> NoReturn: + logger.info("Begin Start Frida Server") + shell = 'adb shell su -c "./data/local/tmp/frida-server &"' + subprocess.Popen( + shell, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) diff --git a/utils/generate_function.py b/utils/generate_function.py new file mode 100644 index 0000000..0b248af --- /dev/null +++ b/utils/generate_function.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +''' +@File : generate_function.py +@Time : 2020/09/24 10:23:37 +@Author : Lateautumn4lin +@Version : 1.0 +@Contact : Lateautumn4lin +@License : (C)Copyright 2020 +@Desc : None +''' +import types +from ast import * +from typing import Callable +from pydantic import BaseModel +from frida.core import Script + + +def generate_function( + func_name: str, + script: Script, + model_name: str, + model: BaseModel +) -> Callable: + function_ast = FunctionDef( + lineno=2, + col_offset=0, + name=func_name, + args=arguments( + args=[ + arg( + lineno=2, + col_offset=17, + arg='item', + annotation=Name(lineno=2, col_offset=23, + id=model_name, ctx=Load()), + ), + ], + vararg=None, + kwonlyargs=[], + kw_defaults=[], + kwarg=None, + defaults=[], + posonlyargs=[] + ), + body=[ + # Expr( + # lineno=3, + # col_offset=4, + # value=Call( + # lineno=3, + # col_offset=4, + # func=Name(lineno=3, col_offset=4, + # id='print', ctx=Load()), + # args=[ + # Call( + # lineno=3, + # col_offset=10, + # func=Name(lineno=3, col_offset=10, + # id='dict', ctx=Load()), + # args=[Name(lineno=3, col_offset=15, + # id='item', ctx=Load())], + # keywords=[], + # ), + # ], + # keywords=[], + # ), + # ), + Assign( + lineno=3, + col_offset=4, + targets=[Name(lineno=3, col_offset=4, + id='res', ctx=Store())], + value=Call( + lineno=3, + col_offset=10, + func=Attribute( + lineno=3, + col_offset=10, + value=Attribute( + lineno=3, + col_offset=10, + value=Name(lineno=3, col_offset=10, + id='script', ctx=Load()), + attr='exports', + ctx=Load(), + ), + attr=func_name, + ctx=Load(), + ), + args=[ + Starred( + lineno=4, + col_offset=38, + value=Call( + lineno=4, + col_offset=39, + func=Attribute( + lineno=4, + col_offset=39, + value=Call( + lineno=4, + col_offset=39, + func=Name( + lineno=4, col_offset=39, id='dict', ctx=Load()), + args=[ + Name(lineno=4, col_offset=44, id='item', ctx=Load())], + keywords=[], + ), + attr='values', + ctx=Load(), + ), + args=[], + keywords=[], + ), + ctx=Load(), + ), + ], + keywords=[], + ), + ), + Return( + lineno=4, + col_offset=4, + value=Name(lineno=4, col_offset=11, id='res', ctx=Load()), + ), + ], + decorator_list=[], + returns=None, + ) + module_ast = Module(body=[function_ast], type_ignores=[]) + module_code = compile(module_ast, "<>", "exec") + function_code = [ + c for c in module_code.co_consts if isinstance(c, types.CodeType)][0] + function = types.FunctionType( + function_code, + { + "script": script, + model_name: model, + "print": print, + "dict": dict + } + ) + function.__annotations__ = {"item": model} + return function