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