scripts directory
This commit is contained in:
parent
b7ad44fc54
commit
05e330fcae
@ -8,7 +8,7 @@
|
||||
- [Hook JNI by address](#hook-jni-by-address)
|
||||
- [Print all runtime strings & Stacktrace](#print-runtime-strings)
|
||||
- [Find iOS application UUID](#find-ios-application-uuid)
|
||||
- [Execute shell command](https://github.com/iddoeldor/frida-snippets/blob/master/exec_shell_cmd.py)
|
||||
- [Execute shell command](https://github.com/iddoeldor/frida-snippets/blob/master/scripts/exec_shell_cmd.py)
|
||||
- [TODO list](#todos)
|
||||
|
||||
#### Enumerate loaded classes
|
||||
|
@ -1,83 +0,0 @@
|
||||
# Check for native library calls and return a stacktrace
|
||||
import sys
|
||||
import frida
|
||||
from pprint import pprint
|
||||
|
||||
|
||||
def on_message(m, _data):
|
||||
if m['type'] == 'send':
|
||||
print(m['payload'])
|
||||
else:
|
||||
if m['type'] == 'error':
|
||||
pprint(m)
|
||||
exit(2)
|
||||
|
||||
|
||||
jscode = """
|
||||
Java.perform(function() {
|
||||
|
||||
var SystemDef = Java.use('java.lang.System');
|
||||
|
||||
var RuntimeDef = Java.use('java.lang.Runtime');
|
||||
|
||||
var exceptionClass = Java.use('java.lang.Exception');
|
||||
|
||||
var SystemLoad_1 = SystemDef.load.overload('java.lang.String');
|
||||
|
||||
var SystemLoad_2 = SystemDef.loadLibrary.overload('java.lang.String');
|
||||
|
||||
var RuntimeLoad_1 = RuntimeDef.load.overload('java.lang.String');
|
||||
|
||||
var RuntimeLoad_2 = RuntimeDef.loadLibrary.overload('java.lang.String');
|
||||
|
||||
var ThreadDef = Java.use('java.lang.Thread');
|
||||
|
||||
var ThreadObj = ThreadDef.$new();
|
||||
|
||||
SystemLoad_1.implementation = function(library) {
|
||||
send("[1] Loading dynamic library => " + library);
|
||||
stackTrace();
|
||||
return SystemLoad_1.call(this, library);
|
||||
}
|
||||
|
||||
SystemLoad_2.implementation = function(library) {
|
||||
send("[2] Loading dynamic library => " + library);
|
||||
stackTrace();
|
||||
SystemLoad_2.call(this, library);
|
||||
return;
|
||||
}
|
||||
|
||||
RuntimeLoad_1.implementation = function(library) {
|
||||
send("[3] Loading dynamic library => " + library);
|
||||
stackTrace();
|
||||
RuntimeLoad_1.call(this, library);
|
||||
return;
|
||||
}
|
||||
|
||||
RuntimeLoad_2.implementation = function(library) {
|
||||
send("[4] Loading dynamic library => " + library);
|
||||
stackTrace();
|
||||
RuntimeLoad_2.call(this, library);
|
||||
return;
|
||||
}
|
||||
|
||||
function stackTrace() {
|
||||
var stack = ThreadObj.currentThread().getStackTrace();
|
||||
for (var i = 0; i < stack.length; i++) {
|
||||
send(i + " => " + stack[i].toString());
|
||||
}
|
||||
send("--------------------------------------------------------------------------");
|
||||
}
|
||||
|
||||
});
|
||||
"""
|
||||
APP = 'com.app'
|
||||
device = frida.get_usb_device()
|
||||
pid = device.spawn([APP])
|
||||
session = device.attach(pid)
|
||||
script = session.create_script(jscode)
|
||||
print("[*] Intercepting [{}]".format(pid))
|
||||
script.on('message', on_message)
|
||||
script.load()
|
||||
device.resume(APP)
|
||||
sys.stdin.read()
|
@ -1,119 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import frida
|
||||
|
||||
APP_NAME = 'com.package.name'
|
||||
|
||||
|
||||
def on_message(message, _ignored_data):
|
||||
if message['type'] == 'send':
|
||||
if type(message['payload']) == dict:
|
||||
os.makedirs(os.path.dirname('./dump/{}/'.format(APP_NAME)), exist_ok=True) # create sub folder if not exist
|
||||
with open('./dump/{}/{}'.format(APP_NAME, message['payload']['file']), 'w') as d:
|
||||
for element in message['payload']['content']:
|
||||
d.write(chr(element % 256))
|
||||
d.close()
|
||||
print('[*] Successfully dumped to {0}'.format(message['payload']['file']))
|
||||
else:
|
||||
print('[*] {0}'.format(message['payload'].encode('utf-8')))
|
||||
else:
|
||||
print(message)
|
||||
|
||||
|
||||
js_code = """
|
||||
Java.perform(function() {
|
||||
var openedfile = "";
|
||||
var data = {
|
||||
"file": "",
|
||||
"content": []
|
||||
};
|
||||
var isOpen = false;
|
||||
var index = 0;
|
||||
|
||||
var fos = Java.use('java.io.FileOutputStream');
|
||||
|
||||
var fos_construct_2 = fos.$init.overload('java.lang.String');
|
||||
var fos_construct_3 = fos.$init.overload('java.io.File');
|
||||
var fos_construct_4 = fos.$init.overload('java.lang.String', 'boolean');
|
||||
var fos_construct_5 = fos.$init.overload('java.io.File', 'boolean');
|
||||
|
||||
var fos_write_1 = fos.write.overload('[B', 'int', 'int');
|
||||
|
||||
var fos_close = fos.close;
|
||||
|
||||
function dump(data) {
|
||||
send("Got " + data["content"].length + " bytes!");
|
||||
var tmp_name = openedfile.split("/");
|
||||
tmp_name = tmp_name[tmp_name.length - 1];
|
||||
data["file"] = tmp_name;
|
||||
send(data);
|
||||
data["content"] = [];
|
||||
index = 0;
|
||||
}
|
||||
|
||||
fos_construct_2.implementation = function(file) {
|
||||
var filename = file;
|
||||
if (openedfile != filename) {
|
||||
openedfile = filename;
|
||||
send("File opened for write " + filename);
|
||||
isOpen = true;
|
||||
}
|
||||
return fos_construct_2.call(this, file);
|
||||
}
|
||||
|
||||
fos_construct_3.implementation = function(file) {
|
||||
var filename = file.getAbsolutePath();
|
||||
if (openedfile != filename) {
|
||||
openedfile = filename;
|
||||
send("File opened for write " + filename);
|
||||
isOpen = true;
|
||||
}
|
||||
return fos_construct_3.call(this, file);
|
||||
}
|
||||
|
||||
fos_construct_4.implementation = function(file, true_false) {
|
||||
var filename = file;
|
||||
if (openedfile != filename) {
|
||||
openedfile = filename;
|
||||
send("File opened for write " + filename);
|
||||
isOpen = true;
|
||||
}
|
||||
return fos_construct_4.call(this, file, true_false);
|
||||
}
|
||||
|
||||
fos_construct_5.implementation = function(file, true_false) {
|
||||
var filename = file.getAbsolutePath();
|
||||
if (openedfile != filename) {
|
||||
openedfile = filename;
|
||||
send("File opened for write " + filename);
|
||||
isOpen = true;
|
||||
}
|
||||
return fos_construct_5.call(this, file, true_false);
|
||||
}
|
||||
|
||||
fos_write_1.implementation = function(arr, offset, length) {
|
||||
var i = 0;
|
||||
for (i = offset; i < length; i = i + 1) {
|
||||
data["content"][index] = arr[i];
|
||||
index = index + 1;
|
||||
}
|
||||
return fos_write_1.call(this, arr, offset, length);
|
||||
}
|
||||
|
||||
fos_close.implementation = function() {
|
||||
dump(data);
|
||||
return fos_close.call(this);
|
||||
}
|
||||
|
||||
});
|
||||
"""
|
||||
|
||||
device = frida.get_usb_device()
|
||||
pid = device.spawn([APP_NAME])
|
||||
session = device.attach(pid)
|
||||
script = session.create_script(js_code)
|
||||
print("[*] Intercepting [{}]".format(pid))
|
||||
script.on('message', on_message)
|
||||
script.load()
|
||||
device.resume(APP_NAME)
|
||||
sys.stdin.read()
|
@ -1,75 +0,0 @@
|
||||
"""
|
||||
Execute shell command
|
||||
For example, list directory contents:
|
||||
def ls(folder):
|
||||
cmd = Shell(['/bin/sh', '-c', 'ls -la ' + folder], None)
|
||||
cmd.exec()
|
||||
for chunk in cmd.output:
|
||||
print(chunk.strip().decode())
|
||||
"""
|
||||
import frida
|
||||
from frida.application import Reactor
|
||||
import threading
|
||||
import click
|
||||
|
||||
|
||||
class Shell(object):
|
||||
def __init__(self, argv, env):
|
||||
self._stop_requested = threading.Event()
|
||||
self._reactor = Reactor(run_until_return=lambda reactor: self._stop_requested.wait())
|
||||
|
||||
self._device = frida.get_usb_device()
|
||||
self._sessions = set()
|
||||
|
||||
self._device.on("child-added", lambda child: self._reactor.schedule(lambda: self._on_child_added(child)))
|
||||
self._device.on("child-removed", lambda child: self._reactor.schedule(lambda: self._on_child_removed(child)))
|
||||
self._device.on("output", lambda pid, fd, data: self._reactor.schedule(lambda: self._on_output(pid, fd, data)))
|
||||
|
||||
self.argv = argv
|
||||
self.env = env
|
||||
self.output = [] # stdout will pushed into array
|
||||
|
||||
def exec(self):
|
||||
self._reactor.schedule(lambda: self._start())
|
||||
self._reactor.run()
|
||||
|
||||
def _start(self):
|
||||
click.secho("✔ spawn(argv={})".format(self.argv), fg='green', dim=True)
|
||||
pid = self._device.spawn(self.argv, env=self.env, stdio='pipe')
|
||||
self._instrument(pid)
|
||||
|
||||
def _stop_if_idle(self):
|
||||
if len(self._sessions) == 0:
|
||||
self._stop_requested.set()
|
||||
|
||||
def _instrument(self, pid):
|
||||
click.secho("✔ attach(pid={})".format(pid), fg='green', dim=True)
|
||||
session = self._device.attach(pid)
|
||||
session.on("detached", lambda reason: self._reactor.schedule(lambda: self._on_detached(pid, session, reason)))
|
||||
click.secho("✔ enable_child_gating()", fg='green', dim=True)
|
||||
session.enable_child_gating()
|
||||
# print("✔ resume(pid={})".format(pid))
|
||||
self._device.resume(pid)
|
||||
self._sessions.add(session)
|
||||
|
||||
def _on_child_added(self, child):
|
||||
click.secho("⚡ child_added: {}".format(child), fg='green', dim=True)
|
||||
self._instrument(child.pid)
|
||||
|
||||
@staticmethod
|
||||
def _on_child_removed(child):
|
||||
click.secho("⚡ child_removed: {}".format(child), fg='green', dim=True)
|
||||
|
||||
def _on_output(self, pid, fd, data):
|
||||
# if len(data) > 0:
|
||||
# print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data)))
|
||||
self.output.append(data)
|
||||
|
||||
def _on_detached(self, pid, session, reason):
|
||||
click.secho("⚡ detached: pid={}, reason='{}'".format(pid, reason), fg='green', dim=True)
|
||||
self._sessions.remove(session)
|
||||
self._reactor.schedule(self._stop_if_idle, delay=0.5)
|
||||
|
||||
@staticmethod
|
||||
def _on_message(pid, message):
|
||||
click.secho("⚡ message: pid={}, payload={}".format(pid, message), fg='green', dim=True)
|
@ -1,73 +0,0 @@
|
||||
### How to access inner class static field
|
||||
```
|
||||
package tech.yusi.fridademo;
|
||||
|
||||
public class Jingdong {
|
||||
private int intResult;
|
||||
|
||||
private final static class a {
|
||||
final static Jingdong a = new Jingdong();
|
||||
}
|
||||
|
||||
|
||||
public Jingdong() {
|
||||
intResult = 0;
|
||||
}
|
||||
|
||||
public static Jingdong a() {
|
||||
return a.a;
|
||||
}
|
||||
|
||||
public static int a(int arg0, int arg1) {
|
||||
return arg0 + arg1;
|
||||
}
|
||||
|
||||
|
||||
public String a(String arg0, String arg1) {
|
||||
return arg0 + arg1;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import frida,sys
|
||||
|
||||
rdev = frida.get_remote_device()
|
||||
session = rdev.attach("tech.yusi.fridademo")
|
||||
|
||||
def on_message(message ,data):
|
||||
if message['type'] == 'send':
|
||||
print(message['payload'])
|
||||
elif message['type'] == 'error':
|
||||
print(message['stack'])
|
||||
else:
|
||||
print(message)
|
||||
|
||||
jscode = """
|
||||
send(Java.available);
|
||||
Java.perform(function () {
|
||||
var JingdongA = Java.use("tech.yusi.fridademo.Jingdong$a");
|
||||
var Jingdong = JingdongA.a;
|
||||
send(Jingdong.fieldType);
|
||||
|
||||
var JingdongInstance = Jingdong.value;
|
||||
var ret = JingdongInstance.a("G8", "4tar");
|
||||
send(ret);
|
||||
|
||||
});
|
||||
"""
|
||||
|
||||
script = session.create_script(jscode)
|
||||
script.on("message" , on_message)
|
||||
script.load()
|
||||
|
||||
try:
|
||||
sys.stdin.read()
|
||||
except KeyboardInterrupt as e:
|
||||
session.detach()
|
||||
sys.exit(0)
|
||||
```
|
||||
|
@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Download latest frida-server, extract, push & run on android device/emulator
|
||||
# adb 1.0.32, jq 1.5, xz 5.1, wget 1.17.1
|
||||
# sudo apt install wget jq xz
|
||||
|
||||
# PARCH = phone architecture
|
||||
# if oneliner [[ == "armeabi-v7a" ]] is a dirty fix because frida's release for armeabi-v7a is just "arm"
|
||||
|
||||
# TODO fix adb root which does not work on phones, only emulators, use `adb shell su` instead
|
||||
|
||||
PARCH=`adb shell getprop ro.product.cpu.abi`;\
|
||||
[[ "${PARCH}" == "armeabi-v7a" ]] && PARCH="arm";\
|
||||
wget -q -O - https://api.github.com/repos/frida/frida/releases \
|
||||
| jq '.[0] | .assets[] | select(.browser_download_url | match("server(.*?)android-'${PARCH}'*\\.xz")).browser_download_url' \
|
||||
| xargs wget -q --show-progress $1 \
|
||||
&& unxz frida-server* \
|
||||
&& adb root \
|
||||
&& adb push frida-server* /data/local/tmp/frida-server \
|
||||
&& adb shell "chmod 755 /data/local/tmp/frida-server" \
|
||||
&& adb shell "/data/local/tmp/frida-server &"
|
@ -1,23 +0,0 @@
|
||||
Java.perform(function() {
|
||||
// string compare
|
||||
var str = Java.use('java.lang.String'), objectClass = 'java.lang.Object';
|
||||
str.equals.overload(objectClass).implementation = function(obj) {
|
||||
var response = str.equals.overload(objectClass).call(this, obj);
|
||||
if (obj) {
|
||||
if (obj.toString().length > 5) {
|
||||
send(str.toString.call(this) + ' == ' + obj.toString() + ' ? ' + response);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
// log AbstractStringBuilder.toString()
|
||||
['java.lang.StringBuilder', 'java.lang.StringBuffer'].forEach(function(clazz, i) {
|
||||
console.log('[?] ' + i + ' = ' + clazz);
|
||||
var func = 'toString';
|
||||
Java.use(clazz)[func].implementation = function() {
|
||||
var ret = this[func]();
|
||||
send('[' + i + '] ' + ret);
|
||||
return ret;
|
||||
};
|
||||
});
|
||||
});
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* By http://github.com/LotemBY *
|
||||
|
||||
This is a frida script for unpinning and reversing of ObjC applications.
|
||||
Intercept method's which match regex.
|
||||
|
||||
You may change the following regex arrays to match your needs:
|
||||
*/
|
||||
|
||||
// The list of regexs for the moudle name
|
||||
var moduleKeyWords = [/.*/]; // (It is not recommended to search all the moudles)
|
||||
|
||||
// The list of regexs for the method name
|
||||
var methodKeyWords = [/cert/i, /trust/i, /ssl/i, /verify/i, /509/];
|
||||
|
||||
// The list of regexs for the method to override their return value with "1"
|
||||
var overrideKeyWords = [];
|
||||
|
||||
/*
|
||||
To run this script with frida on iPhone, follow these steps:
|
||||
1. Make sure the iPhone is jailbreaked
|
||||
2. Download the frida server from Cydia (package: re.frida.server)
|
||||
3. Connect the iPhone to your computer with USB and open the application
|
||||
4. Type in console "frida-ps -U" to get the list of running proccess on the iPhone, and find the proccess name of your app
|
||||
5. Type in console "frida -U <APP PROCCESS NAME> -l <PATH TO THIS SCRIPT>" to run this script
|
||||
6. Now you should use the app to trigger some of the intercepted methods
|
||||
*/
|
||||
var onCompleteCallback = function (retval) {};
|
||||
setImmediate(function () {
|
||||
if (!ObjC.available) {
|
||||
console.log("[-] Objective-C Runtime is not available!");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("=======================================================\n");
|
||||
console.log("[*] Searching methods...");
|
||||
|
||||
var moduleUsed = false;
|
||||
|
||||
Process.enumerateModules({
|
||||
onMatch: function(module) {
|
||||
|
||||
if (!matchesRegex(moduleKeyWords, module.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
moduleUsed = false;
|
||||
Module.enumerateSymbols(module.name, {
|
||||
onMatch: function(exp) {
|
||||
if (matchesRegex(methodKeyWords, exp.name)) {
|
||||
if (!moduleUsed) {
|
||||
console.log("[*] In module \"" + module.name + "\"");
|
||||
moduleUsed = true;
|
||||
}
|
||||
console.log("\t[*] Matching method: \"" + exp.name + "\", Address: " + Module.findExportByName(module.name, exp.name));
|
||||
|
||||
if (intercept(module.name, exp.name)) {
|
||||
console.log("\t\t[+] Now intercepting " + exp.name);
|
||||
} else {
|
||||
console.log("\t\t[-] Could not intercept " + exp.name);
|
||||
}
|
||||
}
|
||||
},
|
||||
onComplete: onCompleteCallback
|
||||
});
|
||||
},
|
||||
onComplete: onCompleteCallback
|
||||
});
|
||||
|
||||
console.log("[*] Completed!");
|
||||
console.log("=======================================================\n\n");
|
||||
});
|
||||
|
||||
// Return if 'str' match any of the regexs in the array 'regexList'
|
||||
function matchesRegex(regexList, str) {
|
||||
regexList.forEach(function(el) {
|
||||
if (str.search(el) != -1)
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to intercept a method by moudle name and function name.
|
||||
// Return 'true' on success and 'false' on failor.
|
||||
function intercept(module, func) {
|
||||
try {
|
||||
Interceptor.attach(Module.findExportByName(module, func), {
|
||||
onEnter: function(args) {
|
||||
console.log("[*] Method CALL:\t\"" + func + "\" called!");
|
||||
},
|
||||
onLeave: function (retval) {
|
||||
console.log("[*] Method RETURN:\t\"" + func + "\" (return value: " + retval + ")");
|
||||
|
||||
if (matchesRegex(overrideKeyWords, func)) {
|
||||
console.log("[!] CHANGED RETURN VALUE of method:\t\"" + func + "\" (new value: " + 1 + ")");
|
||||
retval.replace(1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
def on_message(m, _data):
|
||||
if m['type'] == 'send':
|
||||
print(m['payload'])
|
||||
elif m['type'] == 'error':
|
||||
print(m)
|
||||
|
||||
|
||||
def switch(argument_key, idx):
|
||||
"""
|
||||
c/c++ variable type to javascript reader switch implementation
|
||||
# TODO handle other arguments, [long, longlong..]
|
||||
:param argument_key: variable type
|
||||
:param idx: index in symbols array
|
||||
:return: javascript to read the type of variable
|
||||
"""
|
||||
argument_key = argument_key.replace(' ', '')
|
||||
return '%d: %s' % (idx, {
|
||||
'int': 'args[%d].toInt32(),',
|
||||
'unsignedint': 'args[%d].toInt32(),',
|
||||
'std::string': 'Memory.readUtf8String(Memory.readPointer(args[%d])),',
|
||||
'bool': 'Boolean(args[%d]),'
|
||||
}[argument_key] % idx)
|
||||
|
||||
|
||||
def list_symbols_from_object_files(module_id):
|
||||
import subprocess
|
||||
return subprocess.getoutput('nm --demangle --dynamic %s' % module_id)
|
||||
|
||||
|
||||
def parse_nm_output(nm_stdout, symbols):
|
||||
for line in nm_stdout.splitlines():
|
||||
split = line.split()
|
||||
open_parenthesis_idx = line.find('(')
|
||||
raw_arguments = [] if open_parenthesis_idx == -1 else line[open_parenthesis_idx + 1:-1]
|
||||
if len(raw_arguments) > 0: # ignore methods without arguments
|
||||
raw_argument_list = raw_arguments.split(',')
|
||||
symbols.append({
|
||||
'address': split[0],
|
||||
'type': split[1], # @see Symbol Type Table
|
||||
'name': split[2][:split[2].find('(')], # method name
|
||||
'args': raw_argument_list
|
||||
})
|
||||
|
||||
|
||||
def get_js_script(method, module_id):
|
||||
js_script = """
|
||||
var moduleName = "{{moduleName}}", nativeFuncAddr = {{methodAddress}};
|
||||
Interceptor.attach(Module.findExportByName(null, "dlopen"), {
|
||||
onEnter: function(args) {
|
||||
this.lib = Memory.readUtf8String(args[0]);
|
||||
console.log("[*] dlopen called with: " + this.lib);
|
||||
},
|
||||
onLeave: function(retval) {
|
||||
if (this.lib.endsWith(moduleName)) {
|
||||
Interceptor.attach(Module.findBaseAddress(moduleName).add(nativeFuncAddr), {
|
||||
onEnter: function(args) {
|
||||
console.log("[*] hook invoked", JSON.stringify({{arguments}}, null, '\t'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
"""
|
||||
replace_map = {
|
||||
'{{moduleName}}': module_id,
|
||||
'{{methodAddress}}': '0x' + method['address'],
|
||||
'{{arguments}}': '{' + ''.join([switch(method['args'][i], i + 1) for i in range(len(method['args']))]) + '}'
|
||||
}
|
||||
for k, v in replace_map.items():
|
||||
js_script = js_script.replace(k, v)
|
||||
print('[+] JS Script:\n', js_script)
|
||||
return js_script
|
||||
|
||||
|
||||
def main(app_id, module_id, method):
|
||||
"""
|
||||
$ python3.x+ script.py --method SomeClass::someMethod --app com.company.app --module libfoo.so
|
||||
:param app_id: application identifier / bundle id
|
||||
:param module_id: shared object identifier / known suffix, will iterate loaded modules (@see dlopen)
|
||||
:param method: method/symbol name
|
||||
:return: hook native method and print arguments when invoked
|
||||
"""
|
||||
# TODO extract all app's modules via `adb shell -c 'ls -lR /data/app/' + app_if + '*' | grep "\.so"`
|
||||
|
||||
nm_stdout = list_symbols_from_object_files(module_id)
|
||||
|
||||
symbols = []
|
||||
parse_nm_output(nm_stdout, symbols)
|
||||
|
||||
selection_idx = None
|
||||
for idx, symbol in enumerate(symbols):
|
||||
if method is None: # if --method flag is not passed
|
||||
print("%4d) %s (%d)" % (idx, symbol['name'], len(symbol['args'])))
|
||||
elif method == symbol['name']:
|
||||
selection_idx = idx
|
||||
break
|
||||
if selection_idx is None:
|
||||
if method is None:
|
||||
selection_idx = input("Enter symbol number: ")
|
||||
else:
|
||||
print('[+] Method not found, remove method flag to get list of methods to select from, `nm` stdout:')
|
||||
print(nm_stdout)
|
||||
exit(2)
|
||||
|
||||
method = symbols[int(selection_idx)]
|
||||
print('[+] Selected method: %s' % method['name'])
|
||||
print('[+] Method arguments: %s' % method['args'])
|
||||
|
||||
from frida import get_usb_device
|
||||
device = get_usb_device()
|
||||
pid = device.spawn([app_id])
|
||||
session = device.attach(pid)
|
||||
script = session.create_script(get_js_script(method, module_id))
|
||||
script.on('message', on_message)
|
||||
script.load()
|
||||
device.resume(app_id)
|
||||
# keep hook alive
|
||||
from sys import stdin
|
||||
stdin.read()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from argparse import ArgumentParser
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('--app', help='app identifier "com.company.app"')
|
||||
parser.add_argument('--module', help='loaded module name "libfoo.2.so"')
|
||||
parser.add_argument('--method', help='method name "SomeClass::someMethod", if empty it will print select-list')
|
||||
args = parser.parse_args()
|
||||
main(args.app, args.module, args.method)
|
||||
|
||||
|
||||
"""
|
||||
Symbol Type Table:
|
||||
"A" The symbol's value is absolute, and will not be changed by further linking.
|
||||
"B" The symbol is in the uninitialized data section (known as BSS).
|
||||
"C" The symbol is common. Common symbols are uninitialized data.
|
||||
When linking, multiple common symbols may appear with the same name.
|
||||
If the symbol is defined anywhere, the common symbols are treated as undefined references.
|
||||
"D" The symbol is in the initialized data section.
|
||||
"G" The symbol is in an initialized data section for small objects.
|
||||
Some object file formats permit more efficient access to small data objects, such as a global int variable as
|
||||
opposed to a large global array.
|
||||
"I" The symbol is an indirect reference to another symbol.
|
||||
This is a GNU extension to the a.out object file format which is rarely used.
|
||||
"N" The symbol is a debugging symbol.
|
||||
"R" The symbol is in a read only data section.
|
||||
"S" The symbol is in an uninitialized data section for small objects.
|
||||
"T" The symbol is in the text (code) section.
|
||||
"U" The symbol is undefined.
|
||||
"V" The symbol is a weak object. When a weak defined symbol is linked with a normal defined symbol,
|
||||
the normal defined symbol is used with no error.
|
||||
When a weak undefined symbol is linked and the symbol is not defined, the value of the weak symbol becomes
|
||||
zero with no error.
|
||||
"W" The symbol is a weak symbol that has not been specifically tagged as a weak object symbol.
|
||||
When a weak defined symbol is linked with a normal defined symbol,
|
||||
the normal defined symbol is used with no error.
|
||||
When a weak undefined symbol is linked and the symbol is not defined, the value of the symbol is determined
|
||||
in a system-specific manner without error.
|
||||
On some systems, uppercase indicates that a default value has been specified.
|
||||
"-" The symbol is a stabs symbol in an a.out object file.
|
||||
In this case, the next values printed are the stabs other field, the stabs desc field, and the stab type.
|
||||
Stabs symbols are used to hold debugging information.
|
||||
"?" The symbol type is unknown, or object file format specific.
|
||||
"""
|
Loading…
Reference in New Issue
Block a user