feat:Base Demo实现
This commit is contained in:
parent
80727fb0f8
commit
04a6173d92
20
README.md
20
README.md
@ -11,28 +11,40 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
> 基于FastAPI实现的Frida-Rpc工具
|
> 基于`FastAPI`实现的`Frida-RPC`工具,只需开发好相对应app的`Frida-Js`脚本,即可自动生成相应的基于`FastAPI`的`Frida-RPC`工具
|
||||||
|
|
||||||
### 🏠 [Homepage](暂无)
|
### 🏠 [Homepage](暂无)
|
||||||
|
|
||||||
### ✨ [Demo](暂无)
|
### ✨ [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
|
## Install
|
||||||
|
|
||||||
```sh
|
```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
|
## Usage
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
暂无
|
1. uvicorn main:app --reload
|
||||||
|
|
||||||
|
2. watch 127.0.0.1:8000/docs
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run tests
|
## Run tests
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
暂无
|
uvicorn main:app --reload
|
||||||
```
|
```
|
||||||
|
|
||||||
## 参考资料
|
## 参考资料
|
||||||
|
@ -9,10 +9,5 @@
|
|||||||
@License : (C)Copyright 2020
|
@License : (C)Copyright 2020
|
||||||
@Desc : None
|
@Desc : None
|
||||||
'''
|
'''
|
||||||
|
from pathlib import Path
|
||||||
apps_config = [
|
PRASE_PATH = Path(__file__).absolute().parent / "parse.js"
|
||||||
{
|
|
||||||
"package_name": "com.kuaiduizuoye.scan",
|
|
||||||
"script_name": "kuaiduizuoye.js"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
190
main.py
190
main.py
@ -9,66 +9,32 @@
|
|||||||
@License : (C)Copyright 2020
|
@License : (C)Copyright 2020
|
||||||
@Desc : None
|
@Desc : None
|
||||||
'''
|
'''
|
||||||
|
from pathlib import Path
|
||||||
from pydantic import BaseModel, Field, create_model
|
from pydantic import BaseModel, Field, create_model
|
||||||
from typing import NewType
|
|
||||||
from ast import *
|
|
||||||
import types
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
import subprocess
|
|
||||||
import time
|
import time
|
||||||
import frida
|
import frida
|
||||||
from frida import ServerNotRunningError
|
from starlette.applications import Starlette
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from loguru import logger
|
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"
|
_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():
|
if not detect_frida_state():
|
||||||
# 启动frida-server,增加延迟防止附加失败
|
# 启动frida-server,增加延迟防止附加失败
|
||||||
start_frida_server()
|
start_frida_server()
|
||||||
@ -77,111 +43,29 @@ session = frida.get_usb_device().attach(_package_name)
|
|||||||
script = session.create_script(
|
script = session.create_script(
|
||||||
open(_frida_js_path, encoding="utf-8").read()
|
open(_frida_js_path, encoding="utf-8").read()
|
||||||
)
|
)
|
||||||
script.on('message', on_message)
|
|
||||||
logger.info('[*] Start attach')
|
|
||||||
script.load()
|
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()
|
router = APIRouter()
|
||||||
for k, v in get_app_info().items():
|
for api_name, params in get_app_info(parse_path=PRASE_PATH, frida_js_path=_frida_js_path).items():
|
||||||
router.add_api_route("/generate_url", test, methods=["POST"])
|
params_dict = dict(zip(params, function_params_hints[api_name])) if (
|
||||||
break
|
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)
|
app.include_router(router)
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
# @app.post('/generate_url')
|
app = init_app()
|
||||||
# def generate_url(item: c):
|
|
||||||
# res = script.exports.generate_url(item.origin_url)
|
|
||||||
# return res
|
|
||||||
|
6
parse.js
6
parse.js
@ -19,7 +19,11 @@ function parse(code) {
|
|||||||
// 处理function,获取函数名以及对应参数
|
// 处理function,获取函数名以及对应参数
|
||||||
FunctionDeclaration(path) {
|
FunctionDeclaration(path) {
|
||||||
let params = path.node;
|
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, {
|
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