feat:Base Demo实现
This commit is contained in:
parent
80727fb0f8
commit
04a6173d92
20
README.md
20
README.md
@ -11,28 +11,40 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
> 基于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
|
||||
```
|
||||
|
||||
## 参考资料
|
||||
|
@ -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"
|
||||
|
190
main.py
190
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}
|
||||
|
||||
|
||||
def init_app() -> Starlette:
|
||||
app = FastAPI()
|
||||
# 每个app创建特有路由
|
||||
router = APIRouter()
|
||||
for k, v in get_app_info().items():
|
||||
router.add_api_route("/generate_url", test, methods=["POST"])
|
||||
break
|
||||
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.post('/generate_url')
|
||||
# def generate_url(item: c):
|
||||
# res = script.exports.generate_url(item.origin_url)
|
||||
# return res
|
||||
app = init_app()
|
||||
|
6
parse.js
6
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, {
|
||||
|
31
requirements.txt
Normal file
31
requirements.txt
Normal file
@ -0,0 +1,31 @@
|
||||
# This file may be used to create an environment using:
|
||||
# $ conda create --name <env> --file <this 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
|
BIN
source/fastapi_docs.png
Normal file
BIN
source/fastapi_docs.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
source/post_body_hints.png
Normal file
BIN
source/post_body_hints.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
source/test.png
Normal file
BIN
source/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
62
utils/__init__.py
Normal file
62
utils/__init__.py
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- encoding: utf-8 -*-
|
||||
'''
|
||||
@File : __init__.py
|
||||
@Time : 2020/09/24 11:11:38
|
||||
@Author : Lateautumn4lin
|
||||
@Version : 1.0
|
||||
@Contact : Lateautumn4lin
|
||||
@License : (C)Copyright 2020
|
||||
@Desc : None
|
||||
'''
|
||||
from typing import (
|
||||
Dict,
|
||||
List,
|
||||
NoReturn
|
||||
)
|
||||
from pathlib import PosixPath
|
||||
import subprocess
|
||||
from loguru import logger
|
||||
import execjs
|
||||
|
||||
|
||||
def get_app_info(parse_path: PosixPath, frida_js_path: PosixPath) -> 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
|
||||
)
|
145
utils/generate_function.py
Normal file
145
utils/generate_function.py
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user