feat:Base Demo实现

This commit is contained in:
想要成为RapStar吗? 2020-09-24 15:11:47 +08:00
parent 80727fb0f8
commit 04a6173d92
10 changed files with 301 additions and 168 deletions

View File

@ -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
``` ```
## 参考资料 ## 参考资料

View File

@ -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"
}
]

196
main.py
View File

@ -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}
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 init_app() -> Starlette:
# def generate_url(item: c): app = FastAPI()
# res = script.exports.generate_url(item.origin_url) # 每个app创建特有路由
# return res 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()

View File

@ -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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
source/post_body_hints.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
source/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

62
utils/__init__.py Normal file
View 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
View 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