Compare commits

...

80 Commits

Author SHA1 Message Date
13d89b020d 更新 hookssl.js 2024-03-07 00:24:13 +08:00
34735c3e0e 创建 baidunetdisk.js 2024-03-07 00:24:09 +08:00
866701b499 更新 main.py 2024-03-07 00:24:06 +08:00
f47e9cb306 更新 main.py 2023-11-09 17:08:12 +08:00
8c4cd61081 更新 main.py 2023-11-07 14:18:03 +08:00
cfefd337b9 删除 url_request.js 2023-11-06 17:02:31 +08:00
af1a9e1859 更新 test.py 2023-11-06 17:02:29 +08:00
6c7278a064 删除 test.js 2023-11-06 17:02:27 +08:00
58c81f32e5 创建 url_request.js 2023-11-06 17:02:24 +08:00
67623951ce 创建 test.js 2023-11-06 17:02:22 +08:00
8960406388 创建 monitor_request.js 2023-11-06 17:02:18 +08:00
51bf1e5a6f 创建 hookssl.js 2023-11-06 17:02:16 +08:00
0e75201906 创建 hook_qqmusic.js 2023-11-06 17:02:14 +08:00
8aa5351ccc 创建 hook_conversions.js 2023-11-06 17:02:12 +08:00
1e80a8067b 删除 hookssl.js 2023-11-06 17:02:09 +08:00
df7b021ea0 删除 hook_qqmusic.js 2023-11-06 17:02:07 +08:00
86f1a339d0 删除 hook_conversions.js 2023-11-06 17:02:04 +08:00
b8e653e57d 更新 main.py 2023-11-06 17:01:58 +08:00
9ec56ced34 更新 main.py 2023-10-24 19:54:40 +08:00
e949fdc3e5 创建 hook_qqmusic.js 2023-10-24 19:54:38 +08:00
7167780f0f 创建 url_request.js 2023-10-19 11:26:26 +08:00
dd6a0f4018 创建 test.js 2023-10-19 11:26:24 +08:00
64e5f9c6d9 更新 main.py 2023-10-19 11:26:22 +08:00
f16dd8cae1 更新 hook_conversions.js 2023-10-19 11:26:18 +08:00
e358abc840 更新 files_utils.py 2023-10-18 15:13:04 +08:00
054d36b04d 更新 main.py 2023-10-18 15:13:01 +08:00
424ff95d2b 更新 hook_conversions.js 2023-10-18 15:12:58 +08:00
8405b06e9a 更新 main.py 2023-10-18 09:59:43 +08:00
115626622b 更新 hook_conversions.js 2023-10-18 09:59:41 +08:00
7a34565a64 更新 main.py 2023-10-17 09:48:24 +08:00
9de27d332d 更新 hook_conversions.js 2023-10-16 19:13:06 +08:00
deb6e8fb4c 创建 navi.pcap 2023-10-16 18:38:23 +08:00
fc56cd8c54 创建 hookssl.js 2023-10-16 18:38:21 +08:00
7dc4eb24fd 更新 hook_conversions.js 2023-10-16 18:38:20 +08:00
358c51a054 更新 main.py 2023-10-13 11:12:10 +08:00
db7b6cb54a 更新 hook_conversions.js 2023-10-13 11:12:07 +08:00
b1b381b7a6 更新 test.py 2023-10-11 16:45:37 +08:00
7dd5c0d661 更新 files_utils.py 2023-10-11 16:45:35 +08:00
4b174c9f3e 更新 command.py 2023-10-11 16:45:33 +08:00
0892550341 更新 main.py 2023-10-11 16:45:31 +08:00
1613f15825 更新 hook_conversions.js 2023-10-11 16:45:27 +08:00
0370063b48 删除 hook.log 2023-10-11 16:45:25 +08:00
239f2b1de4 更新 frida抓包.md 2023-10-11 15:14:17 +08:00
df79d971f4 创建 hook.log 2023-10-11 15:14:15 +08:00
b1164af03a 创建 hook_conversions.js 2023-10-11 15:14:12 +08:00
c0a5ef2486 创建 main.py 2023-10-11 15:14:10 +08:00
75d28434ee 创建 __init__.py 2023-10-11 15:14:08 +08:00
aec778ff41 创建 command.py 2023-10-11 15:14:06 +08:00
21aa528f08 创建 files_utils.py 2023-10-11 15:14:05 +08:00
29fc054c02 更新 test.py 2023-10-11 15:14:01 +08:00
9e8761d7a4 删除 tiktok.pcap 2023-10-11 15:13:58 +08:00
dd3e023690 删除 com.vmall.client.pcap 2023-10-11 15:13:54 +08:00
64d25ac27d 创建 requirements.txt 2023-09-26 16:30:30 +08:00
4cb52cd56e 创建 tiktok.pcap 2023-09-25 17:31:57 +08:00
0226485c31 删除 VMALL-1695632341.log 2023-09-25 17:19:56 +08:00
19333bc43a 创建 com.vmall.client.pcap 2023-09-25 17:11:32 +08:00
e74d6554e9 创建 VMALL-1695632341.log 2023-09-25 17:11:29 +08:00
528b0d8885 创建 script.js 2023-09-25 17:11:27 +08:00
23640b607a 创建 r0capture.py 2023-09-25 17:11:24 +08:00
649dd5ac89 创建 myhexdump.py 2023-09-25 17:11:23 +08:00
27631b814a 更新 frida抓包.md 2023-09-25 17:09:40 +08:00
c8b014e457 更新 frida抓包.md 2023-09-25 15:29:07 +08:00
b46444dea2 创建 frida抓包.md 2023-09-25 15:23:19 +08:00
8fc63ad9c0 删除 X.js 2023-09-25 15:14:00 +08:00
26622767e6 更新 test.py 2023-09-25 15:13:57 +08:00
2311f5ad29 删除 SettingServiceImpl.js 2023-09-25 15:13:54 +08:00
1c199de379 删除 RegionMockConfig.js 2023-09-25 15:13:53 +08:00
c8e27de06b 删除 AppLogReaperServiceImpl.js 2023-09-25 15:13:51 +08:00
132bc23c8c 删除 AppLog.js 2023-09-25 15:13:49 +08:00
0059733ffd 更新 misc.xml 2023-09-25 15:13:47 +08:00
d8e7976afc 创建 .DS_Store 2023-09-25 15:13:45 +08:00
cf74259b5e 更新 hook.iml 2023-09-25 15:13:44 +08:00
e0f14d46ea 更新 hook.iml 2023-09-04 17:31:02 +08:00
1d88394e2b 更新 misc.xml 2023-09-04 17:30:59 +08:00
c0f2b7110c 创建 AppLog.js 2023-09-04 17:30:55 +08:00
017ef1ef56 创建 AppLogReaperServiceImpl.js 2023-09-04 17:30:52 +08:00
e9c1de8fe5 创建 RegionMockConfig.js 2023-09-04 17:30:50 +08:00
d251f3e86c 创建 SettingServiceImpl.js 2023-09-04 17:30:45 +08:00
7e54e08c90 更新 test.py 2023-09-04 17:30:42 +08:00
ff00478296 创建 X.js 2023-09-04 17:30:39 +08:00
21 changed files with 2230 additions and 25 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

4
.idea/hook.iml generated
View File

@@ -3,8 +3,10 @@
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
<excludeFolder url="file://$MODULE_DIR$/venv 3.11" />
<excludeFolder url="file://$MODULE_DIR$/venv 3.9" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="Python 3.9 (hook) (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
.idea/misc.xml generated
View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (hook)" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (hook) (2)" project-jdk-type="Python SDK" />
</project>

65
frida抓包.md Normal file
View File

@@ -0,0 +1,65 @@
# frida抓包
## 环境和工具准备:
- python 3.x
- r0capture
- frida / frida-tools
- apkshell
## r0capture
```shell
git clone https://github.com/r0ysue/r0capture
```
## frida
frida-server下载地址
```
https://github.com/frida/frida/releases
```
虚拟环境安装frida和frida- tools
```shell
pip install frida
```
```shell
pip install frida-tools
```
使用Frida查看包进程
```shell
frida-ps -U | grep "包名"
```
## 运行 r0capture.py
```bash
python r0capture.py -U 前面记录的目标应用包名 -p xxx.pcap
```
```
python3 r0capture/r0capture.py -U com.vmall.client -p com.vmall.client.pcap
```
其中 -p 参数用来保存抓包结果,.pcap 是数据报存储格式,包括 Wireshark 在内的很多主流抓包软件都可以生成或者导入 pcap 数据包并分析
如果中途提示 hexdump 名称错误pip 安装一下即可
```bash
pip install hexdump
```
# hook appsflyer conversions
```
frida -U -l <jshook代码> -f <packageName>
```

76
main.py Normal file
View File

@@ -0,0 +1,76 @@
import frida
import modules.command
import modules.files_utils
import sys
import time
FIRST_WRITE = True # 全局变量,用于跟踪是否是首次写入
def on_message(message, data):
print(message)
# modules.files_utils.write_log(message)
# print(message)
# if message['type'] == 'send':
# print(message['payload'])
def attach_method(is_spawn):
if type(is_spawn) == bool:
if is_spawn:
return True
else:
return False
else:
print(f"is_spawn type error,please check is_spawn type.")
def main(package_name,script_path,is_spawn):
# 从Python发送数据到Frida的JavaScript脚本
print(f"script_path: {script_path}")
js_code = modules.files_utils.read_javascript(script_path)
# print(js_code)
modules.command.start_frida()
# modules.command.clearCache(package_name)
# 连接到USB设备
device = frida.get_usb_device()
print(device)
if attach_method(is_spawn):
pid = device.spawn(package_name)
print(f"进程pid: {pid}")
process = device.attach(pid)
script = process.create_script(js_code)
# script.on("message", on_message)
script.load()
# data_to_send = {'data': 'Hello from Python!'}
# script.post({'type': 'input_data', 'payload': data_to_send})
device.resume(pid) # 加载完脚本后, 恢复进程运行
sys.stdin.read()
else:
# 列出设备上的所有进程
pid = None
processes = device.enumerate_processes()
for process in processes:
if process.name == attach_process_name:
pid = process.pid
print(f"pid: {process.pid},App Name: {process.name}")
# 如果你想附加到一个特定的进程并注入一个脚本:
if pid is not None:
session = device.attach(pid)
script = session.create_script(js_code)
script.on('message', on_message)
script.load()
else:
print(f"get process error")
if __name__ == '__main__':
# 是否以spawn模式运行
is_spawn = True
# 目标进程名
attach_process_name = "百度网盘"
# 目标包名
package_name = "com.baidu.netdisk"
# 注入的脚本路径
# script_path = "scripts/hook_conversions.js"
script_path = "scripts/baidunetdisk.js"
main(package_name,script_path, is_spawn)

0
modules/__init__.py Normal file
View File

98
modules/command.py Normal file
View File

@@ -0,0 +1,98 @@
import subprocess
import logging
import time
import json
from modules.files_utils import get_path
def run_adb_command(command_list):
process = subprocess.Popen(command_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
output = stdout.decode().strip()
status_code = process.returncode
error = stderr.decode().strip()
return output, status_code, error
def start_frida():
if is_frida_running():
return
else:
output, status_code, error = run_adb_command(['adb', 'shell', 'su', '-c', '/data/local/tmp/frica'])
if status_code == 0:
print(output)
logging.info(f"start frida output: {output}")
return True
else:
print(error)
logging.error(f"start error,error:{error}")
return False
def is_frida_running():
output, status_code, error = run_adb_command(['adb', 'shell', 'ps', '|', 'grep', 'frica'])
print(output)
return 'frica' in output
def get_main_activity_for_package(package_name):
output, status_code, error = run_adb_command(['adb', 'shell', 'dumpsys', 'package', package_name])
if status_code != 0:
print(f"Error getting main activity: {error}")
return None
else:
# print(f"output: {output},output type: {type(output)}")
return find_mainActivity(output,package_name)
def find_mainActivity(output,package_name):
activity = []
start_append = False
lines = [line.strip() for line in output.split("\n")]
for line in lines:
if "Activity Resolver Table:" in line:
activity.append(line)
if "Non-Data Actions:" in line:
activity.append(line)
start_append = True
elif "android.intent.category.LAUNCHER" in line:
activity.append(line)
break
elif start_append == True:
activity.append(line)
for main_ac in activity:
if package_name in main_ac:
tmp = main_ac.split()
print(tmp[1])
return tmp[1]
# lines = output.split('\n')
# print(f"lines: \n{lines},lines type: {type(lines)}")
# last_line_indent = 0
# for line in lines:
# stripped = line.lstrip()
# indent = len(line) - len(stripped)
# print(indent)
def clearCache(package_name):
if stopApp(package_name):
output, status_code, error = run_adb_command(['adb', 'shell', 'pm', 'clear', package_name])
if status_code == 0:
print(f"clear cache status_code: {status_code}\noutput: {output}")
return True
else:
print(error)
print(f"clear cache error: {error}")
return False
else:
print("stopApp error")
def stopApp(package_name):
print(f"强行停止{package_name}")
output, status_code, error = run_adb_command(['adb', 'shell', 'am', 'force-stop', package_name])
if status_code == 0:
print(f"status_code: {status_code}\noutput: {output}")
return True
else:
print(error)
logging.error(f"stop APP error: {error}")
return False

23
modules/files_utils.py Normal file
View File

@@ -0,0 +1,23 @@
import os
# 获取当前Python脚本的绝对路径
def get_path(script_name):
script_directory = os.path.dirname(os.path.abspath(__file__))
parent_directory = os.path.dirname(script_directory)
# 使用os.path.join构建hook_conversions.js的完整路径
script_path = os.path.join(parent_directory,script_name)
print(script_path)
return script_path
def read_javascript(script_path):
with open(script_path, "r") as file:
script_code = file.read()
return script_code
def write_log(messages):
global FIRST_WRITE
print(f"FIRST_WRITE: {FIRST_WRITE}")
with open("frida_log.log", "a") as log_file:
if FIRST_WRITE: # 如果是首次写入
log_file.write("\n\n\n") # 空出三行
FIRST_WRITE = False # 更新状态,表明已经写过了
log_file.write(str(messages) + "\n")

BIN
navi.pcap Normal file

Binary file not shown.

479
r0capture/myhexdump.py Normal file
View File

@@ -0,0 +1,479 @@
# -*- coding: utf-8 -*-
# !/usr/bin/env python
# -*- coding: latin-1 -*-
# <-- removing this magic comment breaks Python 3.4 on Windows
"""
1. Dump binary data to the following text format:
00000000: 00 00 00 5B 68 65 78 64 75 6D 70 5D 00 00 00 00 ...[hexdump]....
00000010: 00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........
It is similar to the one used by:
Scapy
00 00 00 5B 68 65 78 64 75 6D 70 5D 00 00 00 00 ...[hexdump]....
00 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF .."3DUfw........
Far Manager
000000000: 00 00 00 5B 68 65 78 64 ¦ 75 6D 70 5D 00 00 00 00 [hexdump]
000000010: 00 11 22 33 44 55 66 77 ¦ 88 99 AA BB CC DD EE FF ?"3DUfwˆ™ª»ÌÝîÿ
2. Restore binary data from the formats above as well
as from less exotic strings of raw hex
"""
__version__ = '3.3'
__author__ = 'anatoly techtonik <techtonik@gmail.com>'
__license__ = 'Public Domain'
__history__ = \
"""
3.3 (2015-01-22)
* accept input from sys.stdin if "-" is specified
for both dump and restore (issue #1)
* new normalize_py() helper to set sys.stdout to
binary mode on Windows
3.2 (2015-07-02)
* hexdump is now packaged as .zip on all platforms
(on Linux created archive was tar.gz)
* .zip is executable! try `python hexdump-3.2.zip`
* dump() now accepts configurable separator, patch
by Ian Land (PR #3)
3.1 (2014-10-20)
* implemented workaround against mysterious coding
issue with Python 3 (see revision 51302cf)
* fix Python 3 installs for systems where UTF-8 is
not default (Windows), thanks to George Schizas
(the problem was caused by reading of README.txt)
3.0 (2014-09-07)
* remove unused int2byte() helper
* add dehex(text) helper to convert hex string
to binary data
* add 'size' argument to dump() helper to specify
length of chunks
2.0 (2014-02-02)
* add --restore option to command line mode to get
binary data back from hex dump
* support saving test output with `--test logfile`
* restore() from hex strings without spaces
* restore() now raises TypeError if input data is
not string
* hexdump() and dumpgen() now don't return unicode
strings in Python 2.x when generator is requested
1.0 (2013-12-30)
* length of address is reduced from 10 to 8
* hexdump() got new 'result' keyword argument, it
can be either 'print', 'generator' or 'return'
* actual dumping logic is now in new dumpgen()
generator function
* new dump(binary) function that takes binary data
and returns string like "66 6F 72 6D 61 74"
* new genchunks(mixed, size) function that chunks
both sequences and file like objects
0.5 (2013-06-10)
* hexdump is now also a command line utility (no
restore yet)
0.4 (2013-06-09)
* fix installation with Python 3 for non English
versions of Windows, thanks to George Schizas
0.3 (2013-04-29)
* fully Python 3 compatible
0.2 (2013-04-28)
* restore() to recover binary data from a hex dump in
native, Far Manager and Scapy text formats (others
might work as well)
* restore() is Python 3 compatible
0.1 (2013-04-28)
* working hexdump() function for Python 2
"""
import binascii # binascii is required for Python 3
import sys
# --- constants
PY3K = sys.version_info >= (3, 0)
# --- workaround against Python consistency issues
def normalize_py():
''' Problem 001 - sys.stdout in Python is by default opened in
text mode, and writes to this stdout produce corrupted binary
data on Windows
python -c "import sys; sys.stdout.write('_\n_')" > file
python -c "print(repr(open('file', 'rb').read()))"
'''
if sys.platform == "win32":
# set sys.stdout to binary mode on Windows
import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
# --- - chunking helpers
def chunks(seq, size):
'''Generator that cuts sequence (bytes, memoryview, etc.)
into chunks of given size. If `seq` length is not multiply
of `size`, the lengh of the last chunk returned will be
less than requested.
>>> list( chunks([1,2,3,4,5,6,7], 3) )
[[1, 2, 3], [4, 5, 6], [7]]
'''
d, m = divmod(len(seq), size)
for i in range(d):
yield seq[i * size:(i + 1) * size]
if m:
yield seq[d * size:]
def chunkread(f, size):
'''Generator that reads from file like object. May return less
data than requested on the last read.'''
c = f.read(size)
while len(c):
yield c
c = f.read(size)
def genchunks(mixed, size):
'''Generator to chunk binary sequences or file like objects.
The size of the last chunk returned may be less than
requested.'''
if hasattr(mixed, 'read'):
return chunkread(mixed, size)
else:
return chunks(mixed, size)
# --- - /chunking helpers
def dehex(hextext):
"""
Convert from hex string to binary data stripping
whitespaces from `hextext` if necessary.
"""
if PY3K:
return bytes.fromhex(hextext)
else:
hextext = "".join(hextext.split())
return hextext.decode('hex')
def dump(binary, size=2, sep=' '):
'''
Convert binary data (bytes in Python 3 and str in
Python 2) to hex string like '00 DE AD BE EF'.
`size` argument specifies length of text chunks
and `sep` sets chunk separator.
'''
hexstr = binascii.hexlify(binary)
if PY3K:
hexstr = hexstr.decode('ascii')
return sep.join(chunks(hexstr.upper(), size))
def dumpgen(data, only_str):
'''
Generator that produces strings:
'00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................'
'''
generator = genchunks(data, 16)
for addr, d in enumerate(generator):
line = ""
if not only_str:
# 00000000:
line = '%08X: ' % (addr * 16)
# 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
dumpstr = dump(d)
line += dumpstr[:8 * 3]
if len(d) > 8: # insert separator if needed
line += ' ' + dumpstr[8 * 3:]
# ................
# calculate indentation, which may be different for the last line
pad = 2
if len(d) < 16:
pad += 3 * (16 - len(d))
if len(d) <= 8:
pad += 1
line += ' ' * pad
for byte in d:
# printable ASCII range 0x20 to 0x7E
if not PY3K:
byte = ord(byte)
if 0x20 <= byte <= 0x7E:
line += chr(byte)
else:
line += '.'
yield line
def hexdump(data, result='print', only_str=False):
'''
Transform binary data to the hex dump text format:
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[x] data argument as a binary string
[x] data argument as a file like object
Returns result depending on the `result` argument:
'print' - prints line by line
'return' - returns single string
'generator' - returns generator that produces lines
'''
if PY3K and type(data) == str:
raise TypeError('Abstract unicode data (expected bytes sequence)')
gen = dumpgen(data, only_str=only_str)
if result == 'generator':
return gen
elif result == 'return':
return '\n'.join(gen)
elif result == 'print':
for line in gen:
print(line)
else:
raise ValueError('Unknown value of `result` argument')
def restore(dump):
'''
Restore binary data from a hex dump.
[x] dump argument as a string
[ ] dump argument as a line iterator
Supported formats:
[x] hexdump.hexdump
[x] Scapy
[x] Far Manager
'''
minhexwidth = 2 * 16 # minimal width of the hex part - 00000... style
bytehexwidth = 3 * 16 - 1 # min width for a bytewise dump - 00 00 ... style
result = bytes() if PY3K else ''
if type(dump) != str:
raise TypeError('Invalid data for restore')
text = dump.strip() # ignore surrounding empty lines
for line in text.split('\n'):
# strip address part
addrend = line.find(':')
if 0 < addrend < minhexwidth: # : is not in ascii part
line = line[addrend + 1:]
line = line.lstrip()
# check dump type
if line[2] == ' ': # 00 00 00 ... type of dump
# check separator
sepstart = (2 + 1) * 7 + 2 # ('00'+' ')*7+'00'
sep = line[sepstart:sepstart + 3]
if sep[:2] == ' ' and sep[2:] != ' ': # ...00 00 00 00...
hexdata = line[:bytehexwidth + 1]
elif sep[2:] == ' ': # ...00 00 | 00 00... - Far Manager
hexdata = line[:sepstart] + line[sepstart + 3:bytehexwidth + 2]
else: # ...00 00 00 00... - Scapy, no separator
hexdata = line[:bytehexwidth]
line = hexdata
result += dehex(line)
return result
def runtest(logfile=None):
'''Run hexdump tests. Requires hexfile.bin to be in the same
directory as hexdump.py itself'''
class TeeOutput(object):
def __init__(self, stream1, stream2):
self.outputs = [stream1, stream2]
# -- methods from sys.stdout / sys.stderr
def write(self, data):
for stream in self.outputs:
if PY3K:
if 'b' in stream.mode:
data = data.encode('utf-8')
stream.write(data)
stream.flush()
def tell(self):
raise IOError
def flush(self):
for stream in self.outputs:
stream.flush()
# --/ sys.stdout
if logfile:
openlog = open(logfile, 'wb')
# copy stdout and stderr streams to log file
savedstd = sys.stderr, sys.stdout
sys.stderr = TeeOutput(sys.stderr, openlog)
sys.stdout = TeeOutput(sys.stdout, openlog)
def echo(msg, linefeed=True):
sys.stdout.write(msg)
if linefeed:
sys.stdout.write('\n')
expected = '''\
00000000: 00 00 00 5B 68 65 78 64 75 6D 70 5D 00 00 00 00 ...[hexdump]....
00000010: 00 11 22 33 44 55 66 77 88 99 0A BB CC DD EE FF .."3DUfw........\
'''
# get path to hexfile.bin
# this doesn't work from .zip
# import os.path as osp
# hexfile = osp.dirname(osp.abspath(__file__)) + '/hexfile.bin'
# this doesn't work either
# hexfile = osp.dirname(sys.modules[__name__].__file__) + '/hexfile.bin'
# this works
import pkgutil
bin = pkgutil.get_data('hexdump', 'data/hexfile.bin')
# varios length of input data
hexdump(b'zzzz' * 12)
hexdump(b'o' * 17)
hexdump(b'p' * 24)
hexdump(b'q' * 26)
# allowable character set filter
hexdump(b'line\nfeed\r\ntest')
hexdump(b'\x00\x00\x00\x5B\x68\x65\x78\x64\x75\x6D\x70\x5D\x00\x00\x00\x00'
b'\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\x0A\xBB\xCC\xDD\xEE\xFF')
print('---')
# dumping file-like binary object to screen (default behavior)
hexdump(bin)
print('return output')
hexout = hexdump(bin, result='return')
assert hexout == expected, 'returned hex didn\'t match'
print('return generator')
hexgen = hexdump(bin, result='generator')
assert next(hexgen) == expected.split('\n')[0], 'hex generator 1 didn\'t match'
assert next(hexgen) == expected.split('\n')[1], 'hex generator 2 didn\'t match'
# binary restore test
bindata = restore(
'''
00000000: 00 00 00 5B 68 65 78 64 75 6D 70 5D 00 00 00 00 ...[hexdump]....
00000010: 00 11 22 33 44 55 66 77 88 99 0A BB CC DD EE FF .."3DUfw........
''')
echo('restore check ', linefeed=False)
assert bin == bindata, 'restore check failed'
echo('passed')
far = \
'''
000000000: 00 00 00 5B 68 65 78 64 ¦ 75 6D 70 5D 00 00 00 00 [hexdump]
000000010: 00 11 22 33 44 55 66 77 ¦ 88 99 0A BB CC DD EE FF ?"3DUfwˆ™ª»ÌÝîÿ
'''
echo('restore far format ', linefeed=False)
assert bin == restore(far), 'far format check failed'
echo('passed')
scapy = '''\
00 00 00 5B 68 65 78 64 75 6D 70 5D 00 00 00 00 ...[hexdump]....
00 11 22 33 44 55 66 77 88 99 0A BB CC DD EE FF .."3DUfw........
'''
echo('restore scapy format ', linefeed=False)
assert bin == restore(scapy), 'scapy format check failed'
echo('passed')
if not PY3K:
assert restore('5B68657864756D705D') == '[hexdump]', 'no space check failed'
assert dump('\\\xa1\xab\x1e', sep='').lower() == '5ca1ab1e'
else:
assert restore('5B68657864756D705D') == b'[hexdump]', 'no space check failed'
assert dump(b'\\\xa1\xab\x1e', sep='').lower() == '5ca1ab1e'
print('---[test file hexdumping]---')
import os
import tempfile
hexfile = tempfile.NamedTemporaryFile(delete=False)
try:
hexfile.write(bin)
hexfile.close()
hexdump(open(hexfile.name, 'rb'))
finally:
os.remove(hexfile.name)
if logfile:
sys.stderr, sys.stdout = savedstd
openlog.close()
def main():
from optparse import OptionParser
parser = OptionParser(usage='''
%prog [binfile|-]
%prog -r hexfile
%prog --test [logfile]''', version=__version__)
parser.add_option('-r', '--restore', action='store_true',
help='restore binary from hex dump')
parser.add_option('--test', action='store_true', help='run hexdump sanity checks')
options, args = parser.parse_args()
if options.test:
if args:
runtest(logfile=args[0])
else:
runtest()
elif not args or len(args) > 1:
parser.print_help()
sys.exit(-1)
else:
## dump file
if not options.restore:
# [x] memory effective dump
if args[0] == '-':
if not PY3K:
hexdump(sys.stdin)
else:
hexdump(sys.stdin.buffer)
else:
hexdump(open(args[0], 'rb'))
## restore file
else:
# prepare input stream
if args[0] == '-':
instream = sys.stdin
else:
if PY3K:
instream = open(args[0])
else:
instream = open(args[0], 'rb')
# output stream
# [ ] memory efficient restore
if PY3K:
sys.stdout.buffer.write(restore(instream.read()))
else:
# Windows - binary mode for sys.stdout to prevent data corruption
normalize_py()
sys.stdout.write(restore(instream.read()))
if __name__ == '__main__':
main()
# [x] file restore from command line utility
# [ ] write dump with LF on Windows for consistency
# [ ] encoding param for hexdump()ing Python 3 str if anybody requests that
# [ ] document chunking API
# [ ] document hexdump API
# [ ] blog about sys.stdout text mode problem on Windows

374
r0capture/r0capture.py Normal file
View File

@@ -0,0 +1,374 @@
# Copyright 2017 Google Inc. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Decrypts and logs a process's SSL traffic.
Hooks the functions SSL_read() and SSL_write() in a given process and logs the
decrypted data to the console and/or to a pcap file.
Typical usage example:
ssl_log("wget", "log.pcap", True)
Dependencies:
frida (https://www.frida.re/):
sudo pip install frida
hexdump (https://bitbucket.org/techtonik/hexdump/) if using verbose output:
sudo pip install hexdump
"""
__author__ = "geffner@google.com (Jason Geffner)"
__version__ = "2.0"
"""
# r0capture
ID: r0ysue
安卓应用层抓包通杀脚本
https://github.com/r0ysue/r0capture
## 简介
- 仅限安卓平台测试安卓7、8、9、10 可用
- 无视所有证书校验或绑定,无视任何证书;
- 通杀TCP/IP四层模型中的应用层中的全部协议
- 通杀协议包括Http,WebSocket,Ftp,Xmpp,Imap,Smtp,Protobuf等等、以及它们的SSL版本
- 通杀所有应用层框架包括HttpUrlConnection、Okhttp1/3/4、Retrofit/Volley等等
"""
# Windows版本需要安装库
# pip install 'win_inet_pton'
# pip install hexdump
import argparse
import os
import pprint
import random
import signal
import socket
import struct
import sys
import time
from pathlib import Path
import frida
from loguru import logger
try:
if os.name == 'nt':
import win_inet_pton
except ImportError:
# win_inet_pton import error
pass
try:
import myhexdump as hexdump # pylint: disable=g-import-not-at-top
except ImportError:
pass
try:
from shutil import get_terminal_size as get_terminal_size
except:
try:
from backports.shutil_get_terminal_size import get_terminal_size as get_terminal_size
except:
pass
try:
import click
except:
class click:
@staticmethod
def secho(message=None, **kwargs):
print(message)
@staticmethod
def style(**kwargs):
raise Exception("unsupported style")
banner = """
--------------------------------------------------------------------------------------------
.oooo. .
d8P'`Y8b .o8
oooo d8b 888 888 .ooooo. .oooo. oo.ooooo. .o888oo oooo oooo oooo d8b .ooooo.
`888""8P 888 888 d88' `"Y8 `P )88b 888' `88b 888 `888 `888 `888""8P d88' `88b
888 888 888 888 .oP"888 888 888 888 888 888 888 888ooo888
888 `88b d88' 888 .o8 d8( 888 888 888 888 . 888 888 888 888 .o
d888b `Y8bd8P' `Y8bod8P' `Y888""8o 888bod8P' "888" `V88V"V8P' d888b `Y8bod8P'
888
o888o
https://github.com/r0ysue/r0capture
--------------------------------------------------------------------------------------------\n
"""
def show_banner():
colors = ['bright_red', 'bright_green', 'bright_blue', 'cyan', 'magenta']
try:
click.style('color test', fg='bright_red')
except:
colors = ['red', 'green', 'blue', 'cyan', 'magenta']
try:
columns = get_terminal_size().columns
if columns >= len(banner.splitlines()[1]):
for line in banner.splitlines():
click.secho(line, fg=random.choice(colors))
except:
pass
# ssl_session[<SSL_SESSION id>] = (<bytes sent by client>,
# <bytes sent by server>)
ssl_sessions = {}
def ssl_log(process, pcap=None, host=False, verbose=False, isUsb=False, ssllib="", isSpawn=True, wait=0):
"""Decrypts and logs a process's SSL traffic.
Hooks the functions SSL_read() and SSL_write() in a given process and logs
the decrypted data to the console and/or to a pcap file.
Args:
process: The target process's name (as a string) or process ID (as an int).
pcap: The file path to which the pcap file should be written.
verbose: If True, log the decrypted traffic to the console.
Raises:
NotImplementedError: Not running on a Linux or macOS system.
"""
# if platform.system() not in ("Darwin", "Linux"):
# raise NotImplementedError("This function is only implemented for Linux and "
# "macOS systems.")
def log_pcap(pcap_file, ssl_session_id, function, src_addr, src_port,
dst_addr, dst_port, data):
"""Writes the captured data to a pcap file.
Args:
pcap_file: The opened pcap file.
ssl_session_id: The SSL session ID for the communication.
function: The function that was intercepted ("SSL_read" or "SSL_write").
src_addr: The source address of the logged packet.
src_port: The source port of the logged packet.
dst_addr: The destination address of the logged packet.
dst_port: The destination port of the logged packet.
data: The decrypted packet data.
"""
t = time.time()
if ssl_session_id not in ssl_sessions:
ssl_sessions[ssl_session_id] = (random.randint(0, 0xFFFFFFFF),
random.randint(0, 0xFFFFFFFF))
client_sent, server_sent = ssl_sessions[ssl_session_id]
if function == "SSL_read":
seq, ack = (server_sent, client_sent)
else:
seq, ack = (client_sent, server_sent)
for writes in (
# PCAP record (packet) header
("=I", int(t)), # Timestamp seconds
("=I", int((t * 1000000) % 1000000)), # Timestamp microseconds
("=I", 40 + len(data)), # Number of octets saved
("=i", 40 + len(data)), # Actual length of packet
# IPv4 header
(">B", 0x45), # Version and Header Length
(">B", 0), # Type of Service
(">H", 40 + len(data)), # Total Length
(">H", 0), # Identification
(">H", 0x4000), # Flags and Fragment Offset
(">B", 0xFF), # Time to Live
(">B", 6), # Protocol
(">H", 0), # Header Checksum
(">I", src_addr), # Source Address
(">I", dst_addr), # Destination Address
# TCP header
(">H", src_port), # Source Port
(">H", dst_port), # Destination Port
(">I", seq), # Sequence Number
(">I", ack), # Acknowledgment Number
(">H", 0x5018), # Header Length and Flags
(">H", 0xFFFF), # Window Size
(">H", 0), # Checksum
(">H", 0)): # Urgent Pointer
pcap_file.write(struct.pack(writes[0], writes[1]))
pcap_file.write(data)
if function == "SSL_read":
server_sent += len(data)
else:
client_sent += len(data)
ssl_sessions[ssl_session_id] = (client_sent, server_sent)
def on_message(message, data):
"""Callback for errors and messages sent from Frida-injected JavaScript.
Logs captured packet data received from JavaScript to the console and/or a
pcap file. See https://www.frida.re/docs/messages/ for more detail on
Frida's messages.
Args:
message: A dictionary containing the message "type" and other fields
dependent on message type.
data: The string of captured decrypted data.
"""
if message["type"] == "error":
logger.info(f"{message}")
os.kill(os.getpid(), signal.SIGTERM)
return
if len(data) == 1:
logger.info(f'{message["payload"]["function"]}')
logger.info(f'{message["payload"]["stack"]}')
return
p = message["payload"]
if verbose:
src_addr = socket.inet_ntop(socket.AF_INET,
struct.pack(">I", p["src_addr"]))
dst_addr = socket.inet_ntop(socket.AF_INET,
struct.pack(">I", p["dst_addr"]))
session_id = p['ssl_session_id']
logger.info(f"SSL Session: {session_id}")
logger.info("[%s] %s:%d --> %s:%d" % (
p["function"],
src_addr,
p["src_port"],
dst_addr,
p["dst_port"]))
gen = hexdump.hexdump(data, result="generator",only_str=True)
str_gen = ''.join(gen)
logger.info(f"{str_gen}")
logger.info(f"{p['stack']}")
if pcap:
log_pcap(pcap_file, p["ssl_session_id"], p["function"], p["src_addr"],
p["src_port"], p["dst_addr"], p["dst_port"], data)
if isUsb:
try:
device = frida.get_usb_device()
except:
device = frida.get_remote_device()
else:
if host:
manager = frida.get_device_manager()
device = manager.add_remote_device(host)
else:
device = frida.get_local_device()
if isSpawn:
pid = device.spawn([process])
time.sleep(1)
session = device.attach(pid)
time.sleep(1)
device.resume(pid)
else:
print("attach")
session = device.attach(process)
if wait > 0:
print(f"wait for {wait} seconds")
time.sleep(wait)
# session = frida.attach(process)
# pid = device.spawn([process])
# pid = process
# session = device.attach(pid)
# device.resume(pid)
if pcap:
pcap_file = open(pcap, "wb", 0)
for writes in (
("=I", 0xa1b2c3d4), # Magic number
("=H", 2), # Major version number
("=H", 4), # Minor version number
("=i", time.timezone), # GMT to local correction
("=I", 0), # Accuracy of timestamps
("=I", 65535), # Max length of captured packets
("=I", 228)): # Data link type (LINKTYPE_IPV4)
pcap_file.write(struct.pack(writes[0], writes[1]))
with open(Path(__file__).resolve().parent.joinpath("./script.js"), encoding="utf-8") as f:
_FRIDA_SCRIPT = f.read()
# _FRIDA_SCRIPT = session.create_script(content)
# print(_FRIDA_SCRIPT)
script = session.create_script(_FRIDA_SCRIPT)
script.on("message", on_message)
script.load()
if ssllib != "":
script.exports.setssllib(ssllib)
print("Press Ctrl+C to stop logging.")
def stoplog(signum, frame):
print('You have stoped logging.')
session.detach()
if pcap:
pcap_file.flush()
pcap_file.close()
exit()
signal.signal(signal.SIGINT, stoplog)
signal.signal(signal.SIGTERM, stoplog)
sys.stdin.read()
if __name__ == "__main__":
show_banner()
class ArgParser(argparse.ArgumentParser):
def error(self, message):
print("ssl_logger v" + __version__)
print("by " + __author__)
print("Modified by BigFaceCat")
print("Error: " + message)
print()
print(self.format_help().replace("usage:", "Usage:"))
self.exit(0)
parser = ArgParser(
add_help=False,
description="Decrypts and logs a process's SSL traffic.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=r"""
Examples:
%(prog)s -pcap ssl.pcap openssl
%(prog)s -verbose 31337
%(prog)s -pcap log.pcap -verbose wget
%(prog)s -pcap log.pcap -ssl "*libssl.so*" com.bigfacecat.testdemo
""")
args = parser.add_argument_group("Arguments")
args.add_argument("-pcap", '-p', metavar="<path>", required=False,
help="Name of PCAP file to write")
args.add_argument("-host", '-H', metavar="<192.168.1.1:27042>", required=False,
help="connect to remote frida-server on HOST")
args.add_argument("-verbose", "-v", required=False, action="store_const", default=True,
const=True, help="Show verbose output")
args.add_argument("process", metavar="<process name | process id>",
help="Process whose SSL calls to log")
args.add_argument("-ssl", default="", metavar="<lib>",
help="SSL library to hook")
args.add_argument("--isUsb", "-U", default=False, action="store_true",
help="connect to USB device")
args.add_argument("--isSpawn", "-f", default=False, action="store_true",
help="if spawned app")
args.add_argument("-wait", "-w", type=int, metavar="<seconds>", default=0,
help="Time to wait for the process")
parsed = parser.parse_args()
logger.add(f"{parsed.process.replace('.','_')}-{int(time.time())}.log", rotation="500MB", encoding="utf-8", enqueue=True, retention="10 days")
ssl_log(
int(parsed.process) if parsed.process.isdigit() else parsed.process,
parsed.pcap,
parsed.host,
parsed.verbose,
isUsb=parsed.isUsb,
isSpawn=parsed.isSpawn,
ssllib=parsed.ssl,
wait=parsed.wait
)

339
r0capture/script.js Normal file
View File

@@ -0,0 +1,339 @@
/**
* Initializes 'addresses' dictionary and NativeFunctions.
*/
"use strict";
rpc.exports = {
setssllib: function (name) {
console.log("setSSLLib => " + name);
libname = name;
initializeGlobals();
return;
}
};
var addresses = {};
var SSL_get_fd = null;
var SSL_get_session = null;
var SSL_SESSION_get_id = null;
var getpeername = null;
var getsockname = null;
var ntohs = null;
var ntohl = null;
var SSLstackwrite = null;
var SSLstackread = null;
var libname = "*libssl*";
function uuid(len, radix) {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
var uuid = [], i;
radix = radix || chars.length;
if (len) {
// Compact form
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
} else {
// rfc4122, version 4 form
var r;
// rfc4122 requires these characters
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}
function return_zero(args) {
return 0;
}
function initializeGlobals() {
var resolver = new ApiResolver("module");
var exps = [
[Process.platform == "darwin" ? "*libboringssl*" : "*libssl*", ["SSL_read", "SSL_write", "SSL_get_fd", "SSL_get_session", "SSL_SESSION_get_id"]], // for ios and Android
[Process.platform == "darwin" ? "*libsystem*" : "*libc*", ["getpeername", "getsockname", "ntohs", "ntohl"]]
];
// console.log(exps)
for (var i = 0; i < exps.length; i++) {
var lib = exps[i][0];
var names = exps[i][1];
for (var j = 0; j < names.length; j++) {
var name = names[j];
// console.log("exports:" + lib + "!" + name)
var matches = resolver.enumerateMatchesSync("exports:" + lib + "!" + name);
if (matches.length == 0) {
if (name == "SSL_get_fd") {
addresses["SSL_get_fd"] = 0;
continue;
}
throw "Could not find " + lib + "!" + name;
}
else if (matches.length != 1) {
// Sometimes Frida returns duplicates.
var address = 0;
var s = "";
var duplicates_only = true;
for (var k = 0; k < matches.length; k++) {
if (s.length != 0) {
s += ", ";
}
s += matches[k].name + "@" + matches[k].address;
if (address == 0) {
address = matches[k].address;
}
else if (!address.equals(matches[k].address)) {
duplicates_only = false;
}
}
if (!duplicates_only) {
throw "More than one match found for " + lib + "!" + name + ": " + s;
}
}
addresses[name] = matches[0].address;
}
}
if (addresses["SSL_get_fd"] == 0) {
SSL_get_fd = return_zero;
} else {
SSL_get_fd = new NativeFunction(addresses["SSL_get_fd"], "int", ["pointer"]);
}
SSL_get_session = new NativeFunction(addresses["SSL_get_session"], "pointer", ["pointer"]);
SSL_SESSION_get_id = new NativeFunction(addresses["SSL_SESSION_get_id"], "pointer", ["pointer", "pointer"]);
getpeername = new NativeFunction(addresses["getpeername"], "int", ["int", "pointer", "pointer"]);
getsockname = new NativeFunction(addresses["getsockname"], "int", ["int", "pointer", "pointer"]);
ntohs = new NativeFunction(addresses["ntohs"], "uint16", ["uint16"]);
ntohl = new NativeFunction(addresses["ntohl"], "uint32", ["uint32"]);
}
initializeGlobals();
function ipToNumber(ip) {
var num = 0;
if (ip == "") {
return num;
}
var aNum = ip.split(".");
if (aNum.length != 4) {
return num;
}
num += parseInt(aNum[0]) << 0;
num += parseInt(aNum[1]) << 8;
num += parseInt(aNum[2]) << 16;
num += parseInt(aNum[3]) << 24;
num = num >>> 0;//这个很关键,不然可能会出现负数的情况
return num;
}
/**
* Returns a dictionary of a sockfd's "src_addr", "src_port", "dst_addr", and
* "dst_port".
* @param {int} sockfd The file descriptor of the socket to inspect.
* @param {boolean} isRead If true, the context is an SSL_read call. If
* false, the context is an SSL_write call.
* @return {dict} Dictionary of sockfd's "src_addr", "src_port", "dst_addr",
* and "dst_port".
*/
function getPortsAndAddresses(sockfd, isRead) {
var message = {};
var src_dst = ["src", "dst"];
for (var i = 0; i < src_dst.length; i++) {
if ((src_dst[i] == "src") ^ isRead) {
var sockAddr = Socket.localAddress(sockfd)
}
else {
var sockAddr = Socket.peerAddress(sockfd)
}
if (sockAddr == null) {
// 网络超时or其他原因可能导致socket被关闭
message[src_dst[i] + "_port"] = 0
message[src_dst[i] + "_addr"] = 0
} else {
message[src_dst[i] + "_port"] = (sockAddr.port & 0xFFFF)
message[src_dst[i] + "_addr"] = ntohl(ipToNumber(sockAddr.ip.split(":").pop()))
}
}
return message;
}
/**
* Get the session_id of SSL object and return it as a hex string.
* @param {!NativePointer} ssl A pointer to an SSL object.
* @return {dict} A string representing the session_id of the SSL object's
* SSL_SESSION. For example,
* "59FD71B7B90202F359D89E66AE4E61247954E28431F6C6AC46625D472FF76336".
*/
function getSslSessionId(ssl) {
var session = SSL_get_session(ssl);
if (session == 0) {
return 0;
}
var len = Memory.alloc(4);
var p = SSL_SESSION_get_id(session, len);
len = Memory.readU32(len);
var session_id = "";
for (var i = 0; i < len; i++) {
// Read a byte, convert it to a hex string (0xAB ==> "AB"), and append
// it to session_id.
session_id +=
("0" + Memory.readU8(p.add(i)).toString(16).toUpperCase()).substr(-2);
}
return session_id;
}
Interceptor.attach(addresses["SSL_read"],
{
onEnter: function (args) {
var message = getPortsAndAddresses(SSL_get_fd(args[0]), true);
message["ssl_session_id"] = getSslSessionId(args[0]);
message["function"] = "SSL_read";
message["stack"] = SSLstackread;
this.message = message;
this.buf = args[1];
},
onLeave: function (retval) {
retval |= 0; // Cast retval to 32-bit integer.
if (retval <= 0) {
return;
}
send(this.message, Memory.readByteArray(this.buf, retval));
}
});
Interceptor.attach(addresses["SSL_write"],
{
onEnter: function (args) {
var message = getPortsAndAddresses(SSL_get_fd(args[0]), false);
message["ssl_session_id"] = getSslSessionId(args[0]);
message["function"] = "SSL_write";
message["stack"] = SSLstackwrite;
send(message, Memory.readByteArray(args[1], parseInt(args[2])));
},
onLeave: function (retval) {
}
});
if (Java.available) {
Java.perform(function () {
function storeP12(pri, p7, p12Path, p12Password) {
var X509Certificate = Java.use("java.security.cert.X509Certificate")
var p7X509 = Java.cast(p7, X509Certificate);
var chain = Java.array("java.security.cert.X509Certificate", [p7X509])
var ks = Java.use("java.security.KeyStore").getInstance("PKCS12", "BC");
ks.load(null, null);
ks.setKeyEntry("client", pri, Java.use('java.lang.String').$new(p12Password).toCharArray(), chain);
try {
var out = Java.use("java.io.FileOutputStream").$new(p12Path);
ks.store(out, Java.use('java.lang.String').$new(p12Password).toCharArray())
} catch (exp) {
console.log(exp)
}
}
//在服务器校验客户端的情形下帮助dump客户端证书并保存为p12的格式证书密码为r0ysue
Java.use("java.security.KeyStore$PrivateKeyEntry").getPrivateKey.implementation = function () {
var result = this.getPrivateKey()
var packageName = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext().getPackageName();
storeP12(this.getPrivateKey(), this.getCertificate(), '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12', 'r0ysue');
var message = {};
message["function"] = "dumpClinetCertificate=>" + '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12' + ' pwd: r0ysue';
message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
var data = Memory.alloc(1);
send(message, Memory.readByteArray(data, 1))
return result;
}
Java.use("java.security.KeyStore$PrivateKeyEntry").getCertificateChain.implementation = function () {
var result = this.getCertificateChain()
var packageName = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext().getPackageName();
storeP12(this.getPrivateKey(), this.getCertificate(), '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12', 'r0ysue');
var message = {};
message["function"] = "dumpClinetCertificate=>" + '/sdcard/Download/' + packageName + uuid(10, 16) + '.p12' + ' pwd: r0ysue';
message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
var data = Memory.alloc(1);
send(message, Memory.readByteArray(data, 1))
return result;
}
//SSLpinning helper 帮助定位证书绑定的关键代码a
Java.use("java.io.File").$init.overload('java.io.File', 'java.lang.String').implementation = function (file, cert) {
var result = this.$init(file, cert)
var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
if (file.getPath().indexOf("cacert") >= 0 && stack.indexOf("X509TrustManagerExtensions.checkServerTrusted") >= 0) {
var message = {};
message["function"] = "SSLpinning position locator => " + file.getPath() + " " + cert;
message["stack"] = stack;
var data = Memory.alloc(1);
send(message, Memory.readByteArray(data, 1))
}
return result;
}
Java.use("java.net.SocketOutputStream").socketWrite0.overload('java.io.FileDescriptor', '[B', 'int', 'int').implementation = function (fd, bytearry, offset, byteCount) {
var result = this.socketWrite0(fd, bytearry, offset, byteCount);
var message = {};
message["function"] = "HTTP_send";
message["ssl_session_id"] = "";
message["src_addr"] = ntohl(ipToNumber((this.socket.value.getLocalAddress().toString().split(":")[0]).split("/").pop()));
message["src_port"] = parseInt(this.socket.value.getLocalPort().toString());
message["dst_addr"] = ntohl(ipToNumber((this.socket.value.getRemoteSocketAddress().toString().split(":")[0]).split("/").pop()));
message["dst_port"] = parseInt(this.socket.value.getRemoteSocketAddress().toString().split(":").pop());
message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
var ptr = Memory.alloc(byteCount);
for (var i = 0; i < byteCount; ++i)
Memory.writeS8(ptr.add(i), bytearry[offset + i]);
send(message, Memory.readByteArray(ptr, byteCount))
return result;
}
Java.use("java.net.SocketInputStream").socketRead0.overload('java.io.FileDescriptor', '[B', 'int', 'int', 'int').implementation = function (fd, bytearry, offset, byteCount, timeout) {
var result = this.socketRead0(fd, bytearry, offset, byteCount, timeout);
var message = {};
message["function"] = "HTTP_recv";
message["ssl_session_id"] = "";
message["src_addr"] = ntohl(ipToNumber((this.socket.value.getRemoteSocketAddress().toString().split(":")[0]).split("/").pop()));
message["src_port"] = parseInt(this.socket.value.getRemoteSocketAddress().toString().split(":").pop());
message["dst_addr"] = ntohl(ipToNumber((this.socket.value.getLocalAddress().toString().split(":")[0]).split("/").pop()));
message["dst_port"] = parseInt(this.socket.value.getLocalPort());
message["stack"] = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
if (result > 0) {
var ptr = Memory.alloc(result);
for (var i = 0; i < result; ++i)
Memory.writeS8(ptr.add(i), bytearry[offset + i]);
send(message, Memory.readByteArray(ptr, result))
}
return result;
}
if (parseFloat(Java.androidVersion) > 8) {
Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
var result = this.write(bytearry, int1, int2);
SSLstackwrite = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
return result;
}
Java.use("com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
var result = this.read(bytearry, int1, int2);
SSLstackread = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
return result;
}
}
else {
Java.use("com.android.org.conscrypt.OpenSSLSocketImpl$SSLOutputStream").write.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
var result = this.write(bytearry, int1, int2);
SSLstackwrite = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
return result;
}
Java.use("com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream").read.overload('[B', 'int', 'int').implementation = function (bytearry, int1, int2) {
var result = this.read(bytearry, int1, int2);
SSLstackread = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()).toString();
return result;
}
}
}
)
}

8
requirements.txt Normal file
View File

@@ -0,0 +1,8 @@
colorama==0.4.6
frida==16.0.19
frida-tools==12.2.1
loguru==0.7.2
prompt-toolkit==3.0.38
Pygments==2.15.1
typing_extensions==4.6.3
wcwidth==0.2.6

21
scripts/baidunetdisk.js Normal file
View File

@@ -0,0 +1,21 @@
console.log("Script loaded successfully");
Java.perform(function () {
var Request = Java.use("okhttp3.Request");
// Hook Request的toString方法
Request.toString.implementation = function () {
// 调用原始的toString方法并保存结果
var result = this.toString();
// 打印结果
console.log("Request.toString result: " + result);
// 返回原始方法调用的结果
return result;
};
});

197
scripts/hook_conversions.js Normal file
View File

@@ -0,0 +1,197 @@
log_info("Script loaded successfully");
// hook_okhttp_client()
if (Java.available) {
hook_json()
let class_name = "okhttp3.OkHttpClient"
if (check_class(class_name)){
hook_okhttp_client()
}
Java.perform(function () {
log_info("start hook java.net.URL");
var URL = Java.use('java.net.URL');
URL.$init.overload('java.lang.String').implementation = function (spec) {
// console.log("URL request:" + spec)
log_info("URL request: " + spec)
if (spec.includes("appsflyer")) {
// console.log("URL request: " + spec);
if (spec.includes("conversions")) {
var stackTrace = Java.use('java.lang.Exception').$new().getStackTrace().toString();
// console.log(stackTrace);
}
}
return this.$init(spec);
};
});
}
function printMethods(className) {
log_info("start print methods.")
var jclass = Java.use(className);
var methods = jclass.class.getDeclaredMethods();
console.log("Printing methods of " + className + ":\n");
methods.forEach(function (method) {
// console.log(method);
log_info("The methods under the class" + className + " are: " + method);
});
}
function hook_okhttp_client() {
if (Java.available) {
Java.perform(function () {
log_info("start hook_okhttp_client.")
try {
var OkHttpClient = Java.use("okhttp3.OkHttpClient");
OkHttpClient.newCall.overload('okhttp3.Request').implementation = function (request) {
var requestUrl = request.url();
if (requestUrl) {
console.log("OkHttp Request URL: " + requestUrl.toString());
} else {
console.log("OkHttp Request URL is not available");
}
console.log("OkHttp Request Headers: " + request.headers().toString());
if (request.method() == "POST") {
console.log("OkHttp Request Body: " + request.body().contentType().toString());
}
var call = this.newCall(request);
var response = call.execute();
console.log("OkHttp Response: " + response.body().string());
return call;
};
} catch (e) {
console.log("Error hooking OkHttp: " + e);
}
});
}
}
function hook_HttpURLConnection_stream() {
console.log("start hook_HttpURLConnection_stream")
if (Java.available) {
Java.perform(function () {
var HttpURLConnection = Java.use("java.net.HttpURLConnection");
HttpURLConnection.getOutputStream.implementation = function () {
var outputStream = this.getOutputStream();
var OutputStreamWrapper = Java.use("java.io.OutputStream");
var newOutputStream = Java.registerClass({
name: "CustomOutputStream",
superClass: OutputStreamWrapper,
methods: {
write: function (buffer, byteOffset, byteCount) {
var data = Array.prototype.slice.call(buffer.slice(byteOffset, byteOffset + byteCount));
console.log("Request data: " + String.fromCharCode.apply(null, data));
outputStream.write(buffer, byteOffset, byteCount);
}
}
});
return newOutputStream.$new(outputStream);
};
HttpURLConnection.getInputStream.implementation = function () {
var inputStream = this.getInputStream();
var InputStreamWrapper = Java.use("java.io.InputStream");
var newInputStream = Java.registerClass({
name: "CustomInputStream",
superClass: InputStreamWrapper,
methods: {
read: function (buffer, byteOffset, byteCount) {
var bytesRead = inputStream.read(buffer, byteOffset, byteCount);
if (bytesRead != -1) {
var data = Array.prototype.slice.call(buffer.slice(byteOffset, byteOffset + bytesRead));
console.log("Response data: " + String.fromCharCode.apply(null, data));
}
return bytesRead;
}
}
});
return newInputStream.$new(inputStream);
};
});
}
}
function hook_retrofit() {
Java.perform(function () {
var retrofitBuilder = Java.use("retrofit2.Retrofit$Builder");
retrofitBuilder.build.implementation = function () {
var retrofit = this.build();
var httpClient = retrofit.callFactory().clone();
httpClient.interceptors().add(new Java.use('okhttp3.Interceptor')({
intercept: function (chain) {
console.log("HTTP Request -> " + chain.request().toString())
var response = chain.proceed(chain.request());
console.log("HTTP Response -> " + response.toString());
return response;
}
}))
return retrofit.newBuilder()
.callFactory(httpClient)
.build();
}
});
}
function hook_json() {
Java.perform(function () {
var JSONObject = Java.use('org.json.JSONObject');
JSONObject.toString.overload().implementation = function () {
var result = this.toString.call(this);
// get_conversions(result)
// log_info("Serialized JSONObject: " + result)
return result;
};
});
}
function log_info(messages) {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-based
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const milliseconds = String(now.getMilliseconds()).padStart(3, '0');
const timestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}:${milliseconds}`;
console.log(`${timestamp} - ${messages}`);
send(`${timestamp} - ${messages}`);
}
function check_class(class_name) {
var classFound = false; // 默认为未找到
Java.enumerateLoadedClasses({
onMatch: function(currentClassName) {
if (currentClassName === class_name) {
classFound = true; // 如果找到了类则设置为true
}
},
onComplete: function() {
if (classFound) {
log_info(class_name + " has been loaded!");
} else {
log_info(class_name + " has not been loaded yet.");
}
}
});
return classFound;
}
recv('input_data', function(payload) {
console.log(typeof(payload))
console.log(JSON.stringify(payload))
console.log('Received data from Python: ' + payload.payload.data);
});

40
scripts/hook_qqmusic.js Normal file
View File

@@ -0,0 +1,40 @@
log_info("Script loaded successfully");
if (Java.available) {
hook_json()
Java.perform(function () {
log_info("start hook java.net.URL");
var URL = Java.use('java.net.URL');
URL.$init.overload('java.lang.String').implementation = function (spec) {
log_info("URL request: " + spec)
return this.$init(spec);
};
});
}
function log_info(messages) {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-based
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const milliseconds = String(now.getMilliseconds()).padStart(3, '0');
const timestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}:${milliseconds}`;
console.log(`${timestamp} - ${messages}`);
send(`${timestamp} - ${messages}`);
}
function hook_json() {
Java.perform(function () {
var JSONObject = Java.use('org.json.JSONObject');
JSONObject.toString.overload().implementation = function () {
var result = this.toString.call(this);
// get_conversions(result)
log_info("Serialized JSONObject: " + result)
return result;
};
});
}

362
scripts/hookssl.js Normal file
View File

@@ -0,0 +1,362 @@
console.log("Script loaded successfully");
Java.perform(function() {
/*
hook list:
1.SSLcontext
2.okhttp
3.webview
4.XUtils
5.httpclientandroidlib
6.JSSE
7.network\_security\_config (android 7.0+)
8.Apache Http client (support partly)
9.OpenSSLSocketImpl
10.TrustKit
11.Cronet
*/
// Attempts to bypass SSL pinning implementations in a number of
// ways. These include implementing a new TrustManager that will
// accept any SSL certificate, overriding OkHTTP v3 check()
// method etc.
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier');
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var quiet_output = false;
// Helper method to honor the quiet flag.
function quiet_send(data) {
if (quiet_output) {
return;
}
send(data)
}
// Implement a new TrustManager
// ref: https://gist.github.com/oleavr/3ca67a173ff7d207c6b8c3b0ca65a9d8
// Java.registerClass() is only supported on ART for now(201803). 所以android 4.4以下不兼容,4.4要切换成ART使用.
/*
06-07 16:15:38.541 27021-27073/mi.sslpinningdemo W/System.err: java.lang.IllegalArgumentException: Required method checkServerTrusted(X509Certificate[], String, String, String) missing
06-07 16:15:38.542 27021-27073/mi.sslpinningdemo W/System.err: at android.net.http.X509TrustManagerExtensions.<init>(X509TrustManagerExtensions.java:73)
at mi.ssl.MiPinningTrustManger.<init>(MiPinningTrustManger.java:61)
06-07 16:15:38.543 27021-27073/mi.sslpinningdemo W/System.err: at mi.sslpinningdemo.OkHttpUtil.getSecPinningClient(OkHttpUtil.java:112)
at mi.sslpinningdemo.OkHttpUtil.get(OkHttpUtil.java:62)
at mi.sslpinningdemo.MainActivity$1$1.run(MainActivity.java:36)
*/
var X509Certificate = Java.use("java.security.cert.X509Certificate");
var TrustManager;
try {
TrustManager = Java.registerClass({
name: 'org.wooyun.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function(chain, authType) {},
checkServerTrusted: function(chain, authType) {},
getAcceptedIssuers: function() {
// var certs = [X509Certificate.$new()];
// return certs;
return [];
}
}
});
} catch (e) {
quiet_send("registerClass from X509TrustManager >>>>>>>> " + e.message);
}
// Prepare the TrustManagers array to pass to SSLContext.init()
var TrustManagers = [TrustManager.$new()];
try {
// Prepare a Empty SSLFactory
var TLS_SSLContext = SSLContext.getInstance("TLS");
TLS_SSLContext.init(null, TrustManagers, null);
var EmptySSLFactory = TLS_SSLContext.getSocketFactory();
} catch (e) {
quiet_send(e.message);
}
send('Custom, Empty TrustManager ready');
// Get a handle on the init() on the SSLContext class
var SSLContext_init = SSLContext.init.overload(
'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
// Override the init method, specifying our new TrustManager
SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
quiet_send('Overriding SSLContext.init() with the custom TrustManager');
SSLContext_init.call(this, null, TrustManagers, null);
};
/*** okhttp3.x unpinning ***/
// Wrap the logic in a try/catch as not all applications will have
// okhttp as part of the app.
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
quiet_send('OkHTTP 3.x Found');
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {
quiet_send('OkHTTP 3.x check() called. Not throwing an exception.');
}
} catch (err) {
// If we dont have a ClassNotFoundException exception, raise the
// problem encountered.
if (err.message.indexOf('ClassNotFoundException') === 0) {
throw new Error(err);
}
}
// Appcelerator Titanium PinningTrustManager
// Wrap the logic in a try/catch as not all applications will have
// appcelerator as part of the app.
try {
var PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
send('Appcelerator Titanium Found');
PinningTrustManager.checkServerTrusted.implementation = function() {
quiet_send('Appcelerator checkServerTrusted() called. Not throwing an exception.');
}
} catch (err) {
// If we dont have a ClassNotFoundException exception, raise the
// problem encountered.
if (err.message.indexOf('ClassNotFoundException') === 0) {
throw new Error(err);
}
}
/*** okhttp unpinning ***/
try {
var OkHttpClient = Java.use("com.squareup.okhttp.OkHttpClient");
OkHttpClient.setCertificatePinner.implementation = function(certificatePinner) {
// do nothing
quiet_send("OkHttpClient.setCertificatePinner Called!");
return this;
};
// Invalidate the certificate pinnet checks (if "setCertificatePinner" was called before the previous invalidation)
var CertificatePinner = Java.use("com.squareup.okhttp.CertificatePinner");
CertificatePinner.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(p0, p1) {
// do nothing
quiet_send("okhttp Called! [Certificate]");
return;
};
CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function(p0, p1) {
// do nothing
quiet_send("okhttp Called! [List]");
return;
};
} catch (e) {
quiet_send("com.squareup.okhttp not found");
}
/*** WebView Hooks ***/
/* frameworks/base/core/java/android/webkit/WebViewClient.java */
/* public void onReceivedSslError(Webview, SslErrorHandler, SslError) */
var WebViewClient = Java.use("android.webkit.WebViewClient");
WebViewClient.onReceivedSslError.implementation = function(webView, sslErrorHandler, sslError) {
quiet_send("WebViewClient onReceivedSslError invoke");
//执行proceed方法
sslErrorHandler.proceed();
return;
};
WebViewClient.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function(a, b, c, d) {
quiet_send("WebViewClient onReceivedError invoked");
return;
};
WebViewClient.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function() {
quiet_send("WebViewClient onReceivedError invoked");
return;
};
/*** JSSE Hooks ***/
/* libcore/luni/src/main/java/javax/net/ssl/TrustManagerFactory.java */
/* public final TrustManager[] getTrustManager() */
/* TrustManagerFactory.getTrustManagers maybe cause X509TrustManagerExtensions error */
// var TrustManagerFactory = Java.use("javax.net.ssl.TrustManagerFactory");
// TrustManagerFactory.getTrustManagers.implementation = function(){
// quiet_send("TrustManagerFactory getTrustManagers invoked");
// return TrustManagers;
// }
var HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
/* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */
/* public void setDefaultHostnameVerifier(HostnameVerifier) */
HttpsURLConnection.setDefaultHostnameVerifier.implementation = function(hostnameVerifier) {
quiet_send("HttpsURLConnection.setDefaultHostnameVerifier invoked");
return null;
};
/* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */
/* public void setSSLSocketFactory(SSLSocketFactory) */
HttpsURLConnection.setSSLSocketFactory.implementation = function(SSLSocketFactory) {
quiet_send("HttpsURLConnection.setSSLSocketFactory invoked");
return null;
};
/* libcore/luni/src/main/java/javax/net/ssl/HttpsURLConnection.java */
/* public void setHostnameVerifier(HostnameVerifier) */
HttpsURLConnection.setHostnameVerifier.implementation = function(hostnameVerifier) {
quiet_send("HttpsURLConnection.setHostnameVerifier invoked");
return null;
};
/*** Xutils3.x hooks ***/
//Implement a new HostnameVerifier
var TrustHostnameVerifier;
try {
TrustHostnameVerifier = Java.registerClass({
name: 'org.wooyun.TrustHostnameVerifier',
implements: [HostnameVerifier],
method: {
verify: function(hostname, session) {
return true;
}
}
});
} catch (e) {
//java.lang.ClassNotFoundException: Didn't find class "org.wooyun.TrustHostnameVerifier"
quiet_send("registerClass from hostnameVerifier >>>>>>>> " + e.message);
}
try {
var RequestParams = Java.use('org.xutils.http.RequestParams');
RequestParams.setSslSocketFactory.implementation = function(sslSocketFactory) {
sslSocketFactory = EmptySSLFactory;
return null;
}
RequestParams.setHostnameVerifier.implementation = function(hostnameVerifier) {
hostnameVerifier = TrustHostnameVerifier.$new();
return null;
}
} catch (e) {
quiet_send("Xutils hooks not Found");
}
/*** httpclientandroidlib Hooks ***/
try {
var AbstractVerifier = Java.use("ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier");
AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String', '[Ljava.lang.String', 'boolean').implementation = function() {
quiet_send("httpclientandroidlib Hooks");
return null;
}
} catch (e) {
quiet_send("httpclientandroidlib Hooks not found");
}
/***
android 7.0+ network_security_config TrustManagerImpl hook
apache httpclient partly
***/
var TrustManagerImpl = Java.use("com.android.org.conscrypt.TrustManagerImpl");
// try {
// var Arrays = Java.use("java.util.Arrays");
// //apache http client pinning maybe baypass
// //https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#471
// TrustManagerImpl.checkTrusted.implementation = function (chain, authType, session, parameters, authType) {
// quiet_send("TrustManagerImpl checkTrusted called");
// //Generics currently result in java.lang.Object
// return Arrays.asList(chain);
// }
//
// } catch (e) {
// quiet_send("TrustManagerImpl checkTrusted nout found");
// }
try {
// Android 7+ TrustManagerImpl
TrustManagerImpl.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
quiet_send("TrustManagerImpl verifyChain called");
// Skip all the logic and just return the chain again :P
//https://www.nccgroup.trust/uk/about-us/newsroom-and-events/blogs/2017/november/bypassing-androids-network-security-configuration/
// https://github.com/google/conscrypt/blob/c88f9f55a523f128f0e4dace76a34724bfa1e88c/platform/src/main/java/org/conscrypt/TrustManagerImpl.java#L650
return untrustedChain;
}
} catch (e) {
quiet_send("TrustManagerImpl verifyChain nout found below 7.0");
}
// OpenSSLSocketImpl
try {
var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, authMethod) {
quiet_send('OpenSSLSocketImpl.verifyCertificateChain');
}
quiet_send('OpenSSLSocketImpl pinning')
} catch (err) {
quiet_send('OpenSSLSocketImpl pinner not found');
}
// Trustkit
try {
var Activity = Java.use("com.datatheorem.android.trustkit.pinning.OkHostnameVerifier");
Activity.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(str) {
quiet_send('Trustkit.verify1: ' + str);
return true;
};
Activity.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(str) {
quiet_send('Trustkit.verify2: ' + str);
return true;
};
quiet_send('Trustkit pinning')
} catch (err) {
quiet_send('Trustkit pinner not found')
}
try {
//cronet pinner hook
//weibo don't invoke
var netBuilder = Java.use("org.chromium.net.CronetEngine$Builder");
//https://developer.android.com/guide/topics/connectivity/cronet/reference/org/chromium/net/CronetEngine.Builder.html#enablePublicKeyPinningBypassForLocalTrustAnchors(boolean)
netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.implementation = function(arg) {
//weibo not invoke
console.log("Enables or disables public key pinning bypass for local trust anchors = " + arg);
//true to enable the bypass, false to disable.
var ret = netBuilder.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true);
return ret;
};
netBuilder.addPublicKeyPins.implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) {
console.log("cronet addPublicKeyPins hostName = " + hostName);
//var ret = netBuilder.addPublicKeyPins.call(this,hostName, pinsSha256,includeSubdomains, expirationDate);
//this 是调用 addPublicKeyPins 前的对象吗? Yes,CronetEngine.Builder
return this;
};
} catch (err) {
console.log('[-] Cronet pinner not found')
}
});

View File

@@ -0,0 +1,32 @@
log_info("Script loaded successfully");
Java.perform(function () {
var OkHttpClient = Java.use('okhttp3.OkHttpClient');
var Request = Java.use('okhttp3.Request');
OkHttpClient.newCall.implementation = function (request) {
var url = request.url().toString();
var method = request.method();
var body = request.body();
var size = body != null ? body.contentLength() / 1024 : 0;
console.log("Method: " + method + "\nURL: " + url + "\nSize: " + size + " kb");
return this.newCall(request);
};
});
function log_info(messages) {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-based
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const milliseconds = String(now.getMilliseconds()).padStart(3, '0');
const timestamp = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}:${milliseconds}`;
console.log(`${timestamp} - ${messages}`);
send(`${timestamp} - ${messages}`);
}

20
scripts/test.js Normal file
View File

@@ -0,0 +1,20 @@
Java.perform(function() {
var ByteArrayOutputStream = Java.use('java.io.ByteArrayOutputStream');
var HttpsURLConnection = Java.use('javax.net.ssl.HttpsURLConnection');
HttpsURLConnection.getOutputStream.implementation = function() {
var outputStream = this.getOutputStream();
// 创建一个新的 ByteArrayOutputStream 实例,以便于我们读取数据。
var byteArrayOutputStream = ByteArrayOutputStream.$new();
outputStream.write.overload('[B').implementation = function(buffer) {
byteArrayOutputStream.write(buffer);
console.log("[*] Data written to URL:", this.getURL().toString());
console.log("[*] Data:", byteArrayOutputStream.toString('UTF-8'));
return outputStream.write(buffer);
};
return outputStream;
};
});

82
scripts/url_request.js Normal file
View File

@@ -0,0 +1,82 @@
Java.perform(function() {
var URL = Java.use("java.net.URL");
var HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
var HttpURLConnection = Java.use("java.net.HttpURLConnection");
var OutputStreamWriter = Java.use("java.io.OutputStreamWriter");
var BufferedReader = Java.use("java.io.BufferedReader");
var InputStreamReader = Java.use("java.io.InputStreamReader");
var OutputStream = Java.use('java.io.OutputStream');
var OkHttpClient = Java.use('okhttp3.OkHttpClient');
URL.$init.overload('java.lang.String').implementation = function(url) {
console.log("[*] URL init:", url.toString());
return this.$init(url);
};
HttpsURLConnection.setDoOutput.implementation = function(value) {
console.log("[*]HttpsURLConnection setDoOutput:", value);
return this.setDoOutput(value);
};
HttpsURLConnection.setRequestProperty.implementation = function(key, value) {
console.log("[*] setRequestProperty:", key, value);
return this.setRequestProperty(key, value);
};
HttpsURLConnection.getOutputStream.implementation = function() {
console.log("[*] getOutputStream");
return this.getOutputStream();
};
HttpURLConnection.setRequestProperty.implementation = function(key, value) {
console.log("[*] setRequestProperty:", key, value);
return this.setRequestProperty(key, value);
};
HttpURLConnection.setDoOutput.implementation = function(value) {
console.log("[*]HttpURLConnection setDoOutput:", value);
return this.setDoOutput(value);
};
// HttpURLConnection.getOutputStream.implementation = function() {
// console.log("[*] getOutputStream");
// var outputStream = this.getOutputStream();
//
// outputStream.write.overload('[B').implementation = function(buffer) {
// console.log("[*] Data written:", Java.array('byte', buffer).toString());
// return this.write(buffer);
// };
// return outputStream;
// };
// OutputStream.write.overload('[B').implementation = function(buffer) {
// console.log("[*] Data written:", Java.array('byte', buffer).toString());
// return this.write(buffer);
// };
BufferedReader.readLine.overload().implementation = function() {
var line = this.readLine();
// console.log("[*] BufferedReader.readLine:", line);
return line;
};
InputStreamReader.$init.overload('java.io.InputStream').implementation = function(stream) {
console.log("[*] InputStreamReader.init:", stream);
return this.$init(stream);
};
OkHttpClient.newCall.overload('okhttp3.Request').implementation = function(request) {
console.log("[*] Request URL:", request.url().toString());
console.log("[*] Request Headers:", request.headers().toString());
if (request.method() == "POST") {
console.log("[*] Request Body:", request.body().toString());
}
return this.newCall(request);
};
});

33
test.py
View File

@@ -1,24 +1,11 @@
import frida
import frida,sys
import modules.files_utils
def is_frida_running(device):
try:
# 获取设备上的所有进程
processes = device.enumerate_processes()
# 检查是否存在名为 'frida-server' 的进程
for process in processes:
print(process)
if process.name == 'frida':
return True
return False
except Exception as e:
print(f"Error: {e}")
return False
device = frida.get_usb_device(timeout=3)
if is_frida_running(device):
print("Frida is running on the device.")
else:
print("Frida is not running on the device.")
js_code = modules.files_utils.read_javascript("scripts/hook_conversions.js")
device = frida.get_usb_device()
pid = device.spawn(["com.naviapp"]) # 以挂起方式创建进程
process = device.attach(pid)
script = process.create_script(js_code)
script.load()
device.resume(pid) # 加载完脚本, 恢复进程运行
sys.stdin.read()