
أمثلة فريدا المصنوعة يدويًا
وأيضًا أمثلة المخرجات

{
"scope": "source.js",
"completions": [
{"trigger": "fridainterceptor", "contents": "Interceptor.attach(\n ptr,\n {\n onEnter:function(args) {\n\n },\n onLeave: function(retval) {\n\n }\n }\n)"},
{"trigger": "fridaperform", "contents": "function main(){\n console.log('main()');\n}\n\nconsole.log('script loaded');\nJava.perform(main);"},
{"trigger": "fridause", "contents": "var kls = Java.use('kls');"},
{"trigger": "fridahex", "contents": "hexdump(\n ptr,\n {\n offset: 0,\n length: ptr_size\n }\n);" },
{"trigger": "fridabacktrace", "contents": "console.log('called from:\\n' +\n Thread.backtrace(this.context, Backtracer.ACCURATE)\n .map(DebugSymbol.fromAddress).join('\\n') + '\\n'\n);"},
{"trigger": "fridamods", "contents": "var mods = Process.enumerateModules().filter(function(mod){\n return mod.name.includes(\"<name>\");\n});"},
{"trigger": "fridaexport", "contents": "Module.findExportByName(null, \"<export_name>\");"},
{"trigger": "fridabase", "contents": "Module.findBaseAddress(name);"},
{"trigger": "fridaoverload", "contents": "kls.method_name.overload().implementation=function(){}"}
]
}
لسرد الاختصارات :ab
قم بالتوسيع بكتابة key ثم <Space>
</details>
<details>
<summary>JEB</summary>
مُولِّد خطاف (hook) لطرق Java باستخدام اختصار لوحة المفاتيح
1. `curl -o ~/$JEB$/scripts/FridaCodeGenerator.py https://raw.githubusercontent.com/iddoeldor/frida-snippets/master/scripts/FridaCodeGenerator.py`
2. ضع المؤشر على توقيع طريقة Java
3. اضغط `Ctrl+Shift+Z`
4. يتم نسخ الكود إلى الحافظة النظامية (باستخدام `xclip`)
</details>
<hr />
#### جلب مفاتيح SSL```js
var keylog_callback = new NativeCallback((ssl, line) => {
send(Memory.readCString(line));
}, 'void', ['pointer', 'pointer']);
if (ObjC.available) {
var CALLBACK_OFFSET = 0x2A8
if (Memory.readDouble(Module.findExportByName('CoreFoundation', 'kCFCoreFoundationVersionNumber')) >= 1751.108) {
CALLBACK_OFFSET = 0x2B8
}
Interceptor.attach(Module.findExportByName('libboringssl.dylib', 'SSL_CTX_set_info_callback'), {
onEnter(args) {
ptr(args[0]).add(CALLBACK_OFFSET).writePointer(keylog_callback)
}
})
} else if (Java.available) {
var set_keylog_callback = new NativeFunction(Module.findExportByName('libssl.so', 'SSL_CTX_set_keylog_callback'), 'void', ['pointer', 'pointer']);
Interceptor.attach(Module.findExportByName('libssl.so', 'SSL_CTX_new'), {
onLeave(retval) {
set_keylog_callback(retval, keylog_callback)
}
})
}
Process .getModuleByName({ linux: 'libc.so', darwin: 'libSystem.B.dylib', windows: 'ws2_32.dll' }[Process.platform]) .enumerateExports().filter(ex => ex.type === 'function' && ['connect', 'recv', 'send', 'read', 'write'].some(prefix => ex.name.indexOf(prefix) === 0)) .forEach(ex => { Interceptor.attach(ex.address, { onEnter: function (args) { var fd = args[0].toInt32(); var socktype = Socket.type(fd); if (socktype !== 'tcp' && socktype !== 'tcp6') return; var address = Socket.peerAddress(fd); if (address === null) return; console.log(fd, ex.name, address.ip + ':' + address.port); } }) })
<details>
<summary>مثال الإخراج</summary>
مثال Android```sh
# wrap the script above inside Java.perform
$ frida -Uf com.example.app -l script.js --no-pause
[Android Model-X::com.example.app]-> 117 write 5.0.2.1:5242
117 read 5.0.2.1:5242
135 write 5.0.2.1:4244
135 read 5.0.2.1:4244
135 read 5.0.2.1:4244
مثال على اعتراض libc#open & تسجيل التتبع الخلفي إذا تم فتح ملف معين.```js
Interceptor.attach(Module.findExportByName("/system/lib/libc.so", "open"), {
onEnter: function(args) {
this.flag = false;
var filename = Memory.readCString(ptr(args[0]));
console.log('filename =', filename)
if (filename.endsWith(".xml")) {
this.flag = true;
var backtrace = Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n\t");
console.log("file name [ " + Memory.readCString(ptr(args[0])) + " ]\nBacktrace:" + backtrace);
}
},
onLeave: function(retval) {
if (this.flag) // passed from onEnter
console.warn("\nretval: " + retval);
}
});
#### **🚀 CVEs**
* [CVE-2023-36745](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36745) - ثغرة تنفيذ التعليمات البرمجية عن بُعد في Microsoft Exchange Server
* [CVE-2023-38146](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-38146) - ثغرة تنفيذ التعليمات البرمجية عن بُعد في Windows Themes
* [CVE-2023-36884](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36884) - ثغرة تنفيذ التعليمات البرمجية عن بُعد في Office وWindows HTML
* [CVE-2023-36584](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36584) - ثغرة تجاوز ميزة الأمان Mark of the Web في Windows
* [CVE-2023-36802](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36802) - ثغرة ارتفاع الامتيازات في Microsoft Streaming Service Proxy
* [CVE-2023-36761](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-36761) - ثغرة إفشاء المعلومات في Microsoft Word
##### ◉ Kernel```js
var fds = {}; // for f in /proc/`pidof $APP`/fd/*; do echo $f': 'readlink $f; done
Interceptor.attach(Module.findExportByName(null, 'open'), {
onEnter: function (args) {
var fname = args[0].readCString();
if (fname.endsWith('.jar')) {
this.flag = true;
this.fname = fname;
}
},
onLeave: function (retval) {
if (this.flag) {
fds[retval] = this.fname;
}
}
});
['read', 'pread', 'readv'].forEach(fnc => {
Interceptor.attach(Module.findExportByName(null, fnc), {
onEnter: function (args) {
var fd = args[0];
if (fd in fds)
console.log(`${fnc}: ${fds[fd]}
\t${Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n\t')}`);
}
});
});

import frida from frida_tools.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):
# print("⚡ output: pid={}, fd={}, data={}".format(pid, fd, repr(data)))
# fd=0 (input) fd=1(stdout) fd=2(stderr)
if fd != 2:
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)
<details>
<summary>مثال الاستخدام</summary>
سرد محتويات الدليل:```python
def ls(folder):
cmd = Shell(['/bin/sh', '-c', 'ls -la ' + folder], None)
cmd.exec()
for chunk in cmd.output:
print(chunk.strip().decode())
سحب الثنائي من iOS```python cmd = Shell(['/bin/sh', '-c', 'cat /System/Library/PrivateFrameworks/Example.framework/example'], None) cmd.exec() with open('/tmp/example', 'wb+') as f: f.writelines(cmd.output)
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### قائمة الوحدات```js
Process.enumerateModulesSync()
.filter(function(m){ return m['path'].toLowerCase().indexOf('app') !=-1 ; })
.forEach(function(m) {
console.log(JSON.stringify(m, null, ' '));
// to list exports use Module.enumerateExportsSync(m.name)
});
قائمة الوحدات والصادرات```js sudo frida Process --no-pause --eval 'var x={};Process.enumerateModulesSync().forEach(function(m){x[m.name] = Module.enumerateExportsSync(m.name)});x' -q | less +F
<details>
<summary>مثال الإخراج</summary>
</details>```js
{
"name": "app_process64",
"base": "0x6313a1c000",
"size": 40960,
"path": "/system/bin/app_process64"
}
{
"name": "libappfuse.so",
"base": "0x749ab96000",
"size": 53248,
"path": "/system/lib64/libappfuse.so"
}
{
"name": "[email protected]",
"base": "0x749b448000",
"size": 90112,
"path": "/system/lib64/[email protected]"
}
{
"name": "[email protected]",
"base": "0x749ac9e000",
"size": 94208,
"path": "/system/lib64/[email protected]"
}
{
"name": "[email protected]",
"base": "0x74981e0000",
"size": 98304,
"path": "/system/lib64/[email protected]"
}
{
"name": "[email protected]",
"base": "0x73fb4cc000",
"size": 40960,
"path": "/vendor/lib64/hw/[email protected]"
}
{
"name": "[email protected]",
"base": "0x73fb51f000",
"size": 90112,
"path": "/system/lib64/vndk-sp-29/[email protected]"
}
{
"name": "[email protected]",
"base": "0x73fb542000",
"size": 94208,
"path": "/system/lib64/vndk-sp-29/[email protected]"
}
{
"name": "base.odex",
"base": "0x73ab4cd000",
"size": 16965632,
"path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/oat/arm64/base.odex"
}
{
"name": "libfrida-gadget.so",
"base": "0x73a2c05000",
"size": 22876160,
"path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libfrida-gadget.so"
}
{
"name": "libmain.so",
"base": "0x73fb894000",
"size": 73728,
"path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libmain.so"
}
{
"name": "libunity.so",
"base": "0x739bf88000",
"size": 24461312,
"path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libunity.so"
}
{
"name": "libil2cpp.so",
"base": "0x7396fe6000",
"size": 25272320,
"path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libil2cpp.so"
}
{
"name": "DynamiteLoader.odex",
"base": "0x73b7ee4000",
"size": 376832,
"path": "/data/user_de/0/com.google.android.gms/app_chimera/m/00000278/oat/arm64/DynamiteLoader.odex"
}
{
"name": "base.odex",
"base": "0x72f2ee3000",
"size": 166838272,
"path": "/data/app/com.google.android.gms-j7RpxBsNAd3ttAYEdp2ahg==/oat/arm64/base.odex"
}
{
"name": "base.odex",
"base": "0x7396e6d000",
"size": 28672,
"path": "/data/app/com.google.android.trichromelibrary_432418133-X7Kc2Mqi-VXkY12N59kGug==/oat/arm64/base.odex"
}
{
"name": "base.odex",
"base": "0x724f15e000",
"size": 13225984,
"path": "/data/app/com.google.android.webview-w6i6OBFZ7T_wK4W4TpDAiQ==/oat/arm64/base.odex"
}
{
"name": "libmonochrome.so",
"base": "0x73b8592000",
"size": 76673024,
"path": "/data/app/com.google.android.webview-w6i6OBFZ7T_wK4W4TpDAiQ==/base.apk!/lib/arm64-v8a/libmonochrome.so"
}
{
"name": "libnativeNoodleNews.so",
"base": "0x723add3000",
"size": 962560,
"path": "/data/app/com.noodlecake.altosadventure-O2YLuwCOq7LbWSkRHkRLcg==/lib/arm64/libnativeNoodleNews.so"
}
{
"name": "libconscrypt_gmscore_jni.so",
"base": "0x7206629000",
"size": 1130496,
"path": "/data/app/com.google.android.gms-j7RpxBsNAd3ttAYEdp2ahg==/base.apk!/lib/arm64-v8a/libconscrypt_gmscore_jni.so"
}
Interceptor.attach(Module.findExportByName('libsqlite.so', 'sqlite3_prepare16_v2'), { onEnter: function(args) { console.log('DB: ' + Memory.readUtf16String(args[0]) + '\tSQL: ' + Memory.readUtf16String(args[1])); } });
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### system property get```js
Interceptor.attach(Module.findExportByName(null, '__system_property_get'), {
onEnter: function (args) {
this._name = args[0].readCString();
this._value = args[1];
},
onLeave: function (retval) {
console.log(JSON.stringify({
result_length: retval,
name: this._name,
val: this._value.readCString()
}));
}
});
var LAST_MSG = ''; Java.perform(() => { Interceptor.attach(Module.findExportByName('libbinder.so', 'ioctl'), { onEnter: function(args) { var binder_write_read_ptr = args[2]; if (args[1] == 0xC0306201) { // BINDER_WRITE_READ var binder_write_read = { // 'fd': args[0].toInt32(), 'write_size': binder_write_read_ptr.readU64(), 'write_consumed': binder_write_read_ptr.add(Process.pointerSize).readU64(), 'write_buffer': binder_write_read_ptr.add(Process.pointerSize * 2).readPointer(), } if (binder_write_read.write_size > 0) { var ptr = binder_write_read.write_buffer.add(binder_write_read.write_consumed + 4); switch (binder_write_read.write_buffer.readU32() & 0xff) { case 0: // BC_TRANSACTION case 1: // BC_REPLY var binder_transaction_data = { 'target': { 'handle': ptr.readU32(), 'ptr': ptr.readPointer() }, 'cookie': ptr.add(8).readPointer(), 'code': ptr.add(16).readU32(), 'flags': ptr.add(20).readU32(), 'sender_pid': ptr.add(24).readS32(), 'sender_euid': ptr.add(28).readU32(), 'data_size': ptr.add(32).readU64(), 'offsets_size': ptr.add(40).readU64(), 'data': { 'ptr': { 'buffer': ptr.add(48).readPointer(), 'offsets': ptr.add(56).readPointer() }, 'buf': ptr.add(48).readByteArray(8) } } var _log = hexdump(binder_transaction_data.data.ptr.buffer, { length: binder_transaction_data.data_size, ansi: true }); if (LAST_MSG.toString() != _log.toString()) { console.log(JSON.stringify(binder_transaction_data, null, 2)); console.log(_log); } break; } } } } }); });
<details>
<summary>مثال الإخراج</summary>```sh
{
"target": {
"handle": 16,
"ptr": "0x10"
},
"cookie": "0x0",
"code": 22,
"flags": 16,
"sender_pid": 0,
"sender_euid": 0,
"data_size": "68",
"offsets_size": "0",
"data": {
"ptr": {
"buffer": "0x78dce3dcf0",
"offsets": "0x0"
},
"buf": {}
}
}
0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
78dce3dcf0 04 00 40 01 1d 00 00 00 61 00 6e 00 64 00 72 00 [email protected].
78dce3dd00 6f 00 69 00 64 00 2e 00 6e 00 65 00 74 00 2e 00 o.i.d...n.e.t...
78dce3dd10 77 00 69 00 66 00 69 00 2e 00 49 00 57 00 69 00 w.i.f.i...I.W.i.
78dce3dd20 66 00 69 00 4d 00 61 00 6e 00 61 00 67 00 65 00 f.i.M.a.n.a.g.e.
78dce3dd30 72 00 00 00 r...
يمكن استخدام registerNativeMethods كتقنية لمكافحة الهندسة العكسية لمكتبات .so الأصلية، على سبيل المثال إخفاء الرموز قدر الإمكان، وتعمية الرموز المُصدرة، وإضافة بعض الحماية على جسر JNI.
source```js
var RevealNativeMethods = function() {
var pSize = Process.pointerSize;
var env = Java.vm.getEnv();
var RegisterNatives = 215, FindClassIndex = 6; // search "215" @ https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html
var jclassAddress2NameMap = {};
function getNativeAddress(idx) {
return env.handle.readPointer().add(idx * pSize).readPointer();
}
// intercepting FindClass to populate Map<address, jclass>
Interceptor.attach(getNativeAddress(FindClassIndex), {
onEnter: function(args) {
jclassAddress2NameMap[args[0]] = args[1].readCString();
}
});
// RegisterNative(jClass*, .., JNINativeMethod methods[nMethods], uint nMethods) // https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#977
Interceptor.attach(getNativeAddress(RegisterNatives), {
onEnter: function(args) {
for (var i = 0, nMethods = parseInt(args[3]); i < nMethods; i++) {
/
https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
/
var structSize = pSize * 3; // = sizeof(JNINativeMethod)
var methodsPtr = ptr(args[2]);
var signature = methodsPtr.add(i * structSize + pSize).readPointer();
var fnPtr = methodsPtr.add(i * structSize + (pSize * 2)).readPointer(); // void fnPtr
var jClass = jclassAddress2NameMap[args[0]].split('/');
var methodName = methodsPtr.add(i * structSize).readPointer().readCString();
console.log('\x1b[3' + '6;01' + 'm', JSON.stringify({
module: DebugSymbol.fromAddress(fnPtr)['moduleName'], // https://www.frida.re/docs/javascript-api/#debugsymbol
package: jClass.slice(0, -1).join('.'),
class: jClass[jClass.length - 1],
method: methodName, // methodsPtr.readPointer().readCString(), // char* name
signature: signature.readCString(), // char* signature TODO Java bytecode signature parser { Z: 'boolean', B: 'byte', C: 'char', S: 'short', I: 'int', J: 'long', F: 'float', D: 'double', L: 'fully-qualified-class;', '[': 'array' }
address: fnPtr
}), '\x1b[39;49;00m');
}
}
});
}
Java.perform(RevealNativeMethods);
@OldVersion```js
var fIntercepted = false;
function revealNativeMethods() {
if (fIntercepted === true) {
return;
}
var jclassAddress2NameMap = {};
var androidRunTimeSharedLibrary = "libart.so"; // may change between devices
Module.enumerateSymbolsSync(androidRunTimeSharedLibrary).forEach(function(symbol){
switch (symbol.name) {
case "_ZN3art3JNI21RegisterNativeMethodsEP7_JNIEnvP7_jclassPK15JNINativeMethodib":
/*
$ c++filt "_ZN3art3JNI21RegisterNativeMethodsEP7_JNIEnvP7_jclassPK15JNINativeMethodib"
art::JNI::RegisterNativeMethods(_JNIEnv*, _jclass*, JNINativeMethod const*, int, bool)
*/
var RegisterNativeMethodsPtr = symbol.address;
console.log("RegisterNativeMethods is at " + RegisterNativeMethodsPtr);
Interceptor.attach(RegisterNativeMethodsPtr, {
onEnter: function(args) {
var methodsPtr = ptr(args[2]);
var methodCount = parseInt(args[3]);
for (var i = 0; i < methodCount; i++) {
var pSize = Process.pointerSize;
/*
https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
*/
var structSize = pSize * 3; // JNINativeMethod contains 3 pointers
var namePtr = Memory.readPointer(methodsPtr.add(i * structSize));
var sigPtr = Memory.readPointer(methodsPtr.add(i * structSize + pSize));
var fnPtrPtr = Memory.readPointer(methodsPtr.add(i * structSize + (pSize * 2)));
// output schema: className#methodName(arguments)returnVal@address
console.log(
// package & class, replacing forward slash with dot for convenience
jclassAddress2NameMap[args[0]].replace(/\//g, '.') +
'#' + Memory.readCString(namePtr) + // method
Memory.readCString(sigPtr) + // signature (arguments & return type)
'@' + fnPtrPtr // C side address
);
}
},
onLeave: function (ignoredReturnValue) {}
});
break;
case "_ZN3art3JNI9FindClassEP7_JNIEnvPKc": // art::JNI::FindClass
Interceptor.attach(symbol.address, {
onEnter: function(args) {
if (args[1] != null) {
jclassAddress2NameMap[args[0]] = Memory.readCString(args[1]);
}
},
onLeave: function (ignoredReturnValue) {}
});
break;
}
});
fIntercepted = true;
}
Java.perform(revealNativeMethods);
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)
<details>
<summary>جدول أنواع الرموز</summary>
<pre>
"A" قيمة الرمز مطلقة، ولن يتم تغييرها عن طريق الربط الإضافي.
"B" الرمز موجود في قسم البيانات غير المهيأة (المعروف باسم BSS).
"C" الرمز شائع. الرموز الشائعة هي بيانات غير مهيأة.
عند الربط، قد تظهر عدة رموز شائعة بنفس الاسم.
إذا تم تعريف الرمز في أي مكان، يتم التعامل مع الرموز الشائعة كمراجع غير معرفة.
"D" الرمز موجود في قسم البيانات المهيأة.
"G" الرمز موجود في قسم بيانات مهيأة للكائنات الصغيرة.
تسمح بعض تنسيقات ملفات الكائنات بالوصول الأكثر كفاءة إلى كائنات البيانات الصغيرة، مثل متغير int عام
مقابل مصفوفة عامة كبيرة.
"I" الرمز هو مرجع غير مباشر لرمز آخر.
هذا امتداد GNU لتنسيق ملف كائن a.out والذي نادرًا ما يستخدم.
"N" الرمز هو رمز تصحيح.
"R" الرمز موجود في قسم بيانات للقراءة فقط.
"S" الرمز موجود في قسم بيانات غير مهيأة للكائنات الصغيرة.
"T" الرمز موجود في قسم النص (الكود).
"U" الرمز غير معرف.
"V" الرمز هو كائن ضعيف. عندما يتم ربط رمز معرف ضعيف مع رمز معرف عادي،
يتم استخدام الرمز المعرف العادي بدون خطأ.
عندما يتم ربط رمز غير معرف ضعيف والرمز غير معرف، تصبح قيمة الرمز الضعيف
صفرًا بدون خطأ.
"W" الرمز هو رمز ضعيف لم يتم وضع علامة محددة عليه كرمز كائن ضعيف.
عندما يتم ربط رمز معرف ضعيف مع رمز معرف عادي،
يتم استخدام الرمز المعرف العادي بدون خطأ.
عندما يتم ربط رمز غير معرف ضعيف والرمز غير معرف، يتم تحديد قيمة الرمز
بطريقة خاصة بالنظام بدون خطأ.
في بعض الأنظمة، تشير الأحرف الكبيرة إلى أنه تم تحديد قيمة افتراضية.
"-" الرمز هو رمز stabs في ملف كائن a.out.
في هذه الحالة، القيم التالية المطبوعة هي حقل stabs الآخر، حقل stabs desc، ونوع stab.
تُستخدم رموز stabs للاحتفاظ بمعلومات التصحيح.
"?" نوع الرمز غير معروف، أو خاص بتنسيق ملف الكائن.
</pre>
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### تعداد الفئات المحملة
واحفظه في ملف باسم `pkg.classes````bash
$ frida -U com.pkg -qe 'Java.perform(function(){Java.enumerateLoadedClasses({"onMatch":function(c){console.log(c);}});});' -o pkg.classes
احصل على طرق وأعضاء الفصل.```js Object.getOwnPropertyNames(Java.use('com.company.CustomClass').proto).join('\n\t')
إذا كان هناك تضارب في الأسماء، فإن الطريقة والعضو لهما نفس الاسم، فسيتم إضافة شرطة سفلية إلى العضو. [source](https://github.com/frida/frida-java/pull/21)```js
let fieldJsName = env.stringFromJni(fieldName);
while (jsMethods.hasOwnProperty(fieldJsName)) {
fieldJsName = '_' + fieldJsName;
}
سيتم إيقاف WiFi عند إنشاء أول نشاط.```js var WifiManager = Java.use("android.net.wifi.WifiManager"); Java.use("android.app.Activity").onCreate.overload("android.os.Bundle").implementation = function(bundle) { var wManager = Java.cast(this.getSystemService("wifi"), WifiManager); console.log('isWifiEnabled ?', wManager.isWifiEnabled()); wManager.setWifiEnabled(false); this.$init(bundle); }
<details>
<summary>مثال على الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### تعيين الوكيل
سيقوم بتعيين وكيل على مستوى النظام باستخدام عنوان IP والمنفذ المقدمين.```js
var ActivityThread = Java.use('android.app.ActivityThread');
var ConnectivityManager = Java.use('android.net.ConnectivityManager');
var ProxyInfo = Java.use('android.net.ProxyInfo');
var proxyInfo = ProxyInfo.$new('192.168.1.10', 8080, ''); // change to null in order to disable the proxy.
var context = ActivityThread.currentApplication().getApplicationContext();
var connectivityManager = Java.cast(context.getSystemService('connectivity'), ConnectivityManager);
connectivityManager.setGlobalProxy(proxyInfo);
يمكن أيضًا ربط وتغيير IMEI.```js function getIMEI(){ console.log('IMEI =', Java.use("android.telephony.TelephonyManager").$new().getDeviceId()); } Java.perform(getIMEI)
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### Hook io InputStream
قم بربط `InputputStream` وطباعة المخزن المؤقت بصيغة `ascii` مع حد الأحرف وقائمة الاستثناء.```js
function binaryToHexToAscii(array, readLimit) {
var result = [];
// read 100 bytes #performance
readLimit = readLimit || 100;
for (var i = 0; i < readLimit; ++i) {
result.push(String.fromCharCode( // hex2ascii part
parseInt(
('0' + (array[i] & 0xFF).toString(16)).slice(-2), // binary2hex part
16
)
));
}
return result.join('');
}
function hookInputStream() {
Java.use('java.io.InputStream')['read'].overload('[B').implementation = function(b) {
// execute original and save return value
var retval = this.read(b);
var resp = binaryToHexToAscii(b);
// conditions to not print garbage packets
var reExcludeList = new RegExp(['Mmm'/*, 'Ping' /*, ' Yo'*/].join('|'));
if ( ! reExcludeList.test(resp) ) {
console.log(resp);
}
var reIncludeList = new RegExp(['AAA', 'BBB', 'CCC'].join('|'));
if ( reIncludeList.test(resp) ) {
send( binaryToHexToAscii(b, 1200) );
}
return retval;
};
}
Java.perform(hookInputStream);
// 0 = // https://developer.android.com/reference/android/widget/Toast#LENGTH_LONG Java.scheduleOnMainThread(() => { Java.use("android.widget.Toast") .makeText(Java.use("android.app.ActivityThread").currentApplication().getApplicationContext(), Java.use("java.lang.StringBuilder").$new("Text to Toast here"), 0).show(); });
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### انتظار الشرط
الانتظار حتى يتم تحميل DLL معين في تطبيق Unity، يمكن تنفيذ التبديل الساخن.```javascript
var awaitForCondition = function(callback) {
var int = setInterval(function() {
if (Module.findExportByName(null, "mono_get_root_domain")) {
clearInterval(int);
callback();
return;
}
}, 0);
}
function hook() {
Interceptor.attach(Module.findExportByName(null, "mono_assembly_load_from_full"), {
onEnter: function(args) {
this._dll = Memory.readUtf8String(ptr(args[1]));
console.log('[*]', this._dll);
},
onLeave: function(retval) {
if (this._dll.endsWith("Assembly-CSharp.dll")) {
console.log(JSON.stringify({
retval: retval,
name: this._dll
}, null, 2));
}
}
});
}
Java.perform(awaitForCondition(hook));
سجل عندما يغير WebView عنوان URL.```js Java.use("android.webkit.WebView").loadUrl.overload("java.lang.String").implementation = function (s) { send(s.toString()); this.loadUrl.overload("java.lang.String").call(this, s); };
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### طباعة سلاسل وقت التشغيل
خطاف `toString` من StringBuilder/Buffer وطباعة تتبع المكدس.```js
Java.perform(function() {
['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]();
if (ret.indexOf('') != -1) {
// print stacktrace if return value contains specific string
Java.perform(function() {
var jAndroidLog = Java.use("android.util.Log"), jException = Java.use("java.lang.Exception");
console.log( jAndroidLog.getStackTraceString( jException.$new() ) );
});
}
send('[' + i + '] ' + ret);
return ret;
}
});
});
Java.perform(function() { var shared_pref_class = Java.use('android.app.SharedPreferencesImpl$EditorImpl');
shared_pref_class.putString.overload('java.lang.String', 'java.lang.String').implementation = function(k, v) {
console.log('Shared preference updated: ', k, '=', v);
return this.putString(k, v);
}
shared_pref_class.putInt.overload('java.lang.String', 'int').implementation = function(k, v) {
console.log('Shared preference updated: ', k, '=', v);
return this.putInt(k, v);
}
shared_pref_class.putFloat.overload('java.lang.String', 'float').implementation = function(k, v) {
console.log('Shared preference updated: ', k, '=', v);
return this.putFloat(k, v);
}
shared_pref_class.putBoolean.overload('java.lang.String', 'boolean').implementation = function(k, v) {
console.log('Shared preference updated: ', k, '=', v);
return this.putBoolean(k, v);
}
shared_pref_class.putLong.overload('java.lang.String', 'long').implementation = function(k, v) {
console.log('Shared preference updated: ', k, '=', v);
return this.putLong(k, v);
}
shared_pref_class.putStringSet.overload('java.lang.String', java.util.Set).implementation = function(k, v) {
console.log('Shared preference updated: ', k, '=', v);
return this.putStringSet(k, v);
}
});
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### مقارنة السلاسل```js
Java.perform(function() {
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;
}
});
ربط الطريقة الأصلية بواسطة اسم الوحدة وعنوان الطريقة وطباعة الوسائط.```js var moduleName = "libfoo.so"; var nativeFuncAddr = 0x1234; // $ nm --demangle --dynamic libfoo.so | grep "Class::method("
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)) { console.log("ret: " + retval); var baseAddr = Module.findBaseAddress(moduleName); Interceptor.attach(baseAddr.add(nativeFuncAddr), { onEnter: function(args) { console.log("[-] hook invoked"); console.log(JSON.stringify({ a1: args[1].toInt32(), a2: Memory.readUtf8String(Memory.readPointer(args[2])), a3: Boolean(args[3]) }, null, '\t')); } }); } } });
<details>
<summary>مثال الإخراج</summary>
مهام قيد الإنجاز
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### مُنشئ Hook```js
Java.use('java.lang.StringBuilder').$init.overload('java.lang.String').implementation = function(stringArgument) {
console.log("c'tor");
return this.$init(stringArgument);
};
`java.lang.reflect.Method#invoke(Object obj, Object... args, boolean bool)````javascript Java.use('java.lang.reflect.Method').invoke.overload('java.lang.Object', '[Ljava.lang.Object;', 'boolean').implementation = function(a,b,c) { console.log('hooked!', a, b, c); return this.invoke(a,b,c); };
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### فئة Trace
طريقة تتبع الفئة، مع ألوان جميلة وخيارات للطباعة بصيغة JSON وتتبع المكدس.
TODO إضافة تتبع للـ c'tor.```js
var Color = {
RESET: "\x1b[39;49;00m", Black: "0;01", Blue: "4;01", Cyan: "6;01", Gray: "7;11", Green: "2;01", Purple: "5;01", Red: "1;01", Yellow: "3;01",
Light: {
Black: "0;11", Blue: "4;11", Cyan: "6;11", Gray: "7;01", Green: "2;11", Purple: "5;11", Red: "1;11", Yellow: "3;11"
}
};
/**
*
* @param input.
* If an object is passed it will print as json
* @param kwargs options map {
* -l level: string; log/warn/error
* -i indent: boolean; print JSON prettify
* -c color: @see ColorMap
* }
*/
var LOG = function (input, kwargs) {
kwargs = kwargs || {};
var logLevel = kwargs['l'] || 'log', colorPrefix = '\x1b[3', colorSuffix = 'm';
if (typeof input === 'object')
input = JSON.stringify(input, null, kwargs['i'] ? 2 : null);
if (kwargs['c'])
input = colorPrefix + kwargs['c'] + colorSuffix + input + Color.RESET;
console[logLevel](https://github.com/iddoeldor/frida-snippets/blob/HEAD/input);
};
var printBacktrace = function () {
Java.perform(function() {
var android_util_Log = Java.use('android.util.Log'), java_lang_Exception = Java.use('java.lang.Exception');
// getting stacktrace by throwing an exception
LOG(android_util_Log.getStackTraceString(java_lang_Exception.$new()), { c: Color.Gray });
});
};
function traceClass(targetClass) {
var hook;
try {
hook = Java.use(targetClass);
} catch (e) {
console.error("trace class failed", e);
return;
}
var methods = hook.class.getDeclaredMethods();
hook.$dispose();
var parsedMethods = [];
methods.forEach(function (method) {
var methodStr = method.toString();
var methodReplace = methodStr.replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1];
parsedMethods.push(methodReplace);
});
uniqBy(parsedMethods, JSON.stringify).forEach(function (targetMethod) {
traceMethod(targetClass + '.' + targetMethod);
});
}
function traceMethod(targetClassMethod) {
try {
var delim = targetClassMethod.lastIndexOf('.');
if (delim === -1)
return;
var targetClass = targetClassMethod.slice(0, delim);
var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length);
var hook = Java.use(targetClass);
var overloadCount = hook[targetMethod].overloads.length;
LOG({ tracing: targetClassMethod, overloaded: overloadCount }, { c: Color.Green });
for (var i = 0; i < overloadCount; i++) {
hook[targetMethod].overloads[i].implementation = function () {
var log = { '#': targetClassMethod, args: [] };
for (var j = 0; j < arguments.length; j++) {
var arg = arguments[j];
// quick&dirty fix for java.io.StringWriter char[].toString() impl because frida prints [object Object]
if (j === 0 && arguments[j]) {
if (arguments[j].toString() === '[object Object]') {
var s = [];
for (var k = 0, l = arguments[j].length; k < l; k++) {
s.push(arguments[j][k]);
}
arg = s.join('');
}
}
log.args.push({ i: j, o: arg, s: arg ? arg.toString(): 'null'});
}
var retval;
try {
retval = this[targetMethod].apply(this, arguments); // might crash (Frida bug?)
log.returns = { val: retval, str: retval ? retval.toString() : null };
} catch (e) {
console.error(e);
}
LOG(log, { c: Color.Blue });
return retval;
}
}
} catch(error) {
LOG({ tracing: targetClassMethod, "overloaded": 0}, { c: Color.Red });
}
}
// remove duplicates from array
function uniqBy(array, key) {
var seen = {};
return array.filter(function (item) {
var k = key(item);
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
});
}
var Main = function() {
Java.perform(function () { // avoid java.lang.ClassNotFoundException
[
// "java.io.File",
'java.net.Socket'
].forEach(traceClass);
Java.use('java.net.Socket').isConnected.overload().implementation = function () {
LOG('Socket.isConnected.overload', { c: Color.Light.Cyan });
printBacktrace();
return true;
}
});
};
Java.perform(Main);
ANDROID_ID فريد في كل تطبيق على أندرويد.```javascript function getContext() { return Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(); }
function logAndroidId() { console.log('[-]', Java.use('android.provider.Settings$Secure').getString(getContext(), 'android_id')); }
<details>
<summary>مثال على الإخراج</summary>
https://stackoverflow.com/a/54818023/2655092
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### تغيير الموقع```js
Java.perform(() => {
var Location = Java.use('android.location.Location');
Location.getLatitude.implementation = function() {
return LATITUDE;
}
Location.getLongitude.implementation = function() {
return LONGITUDE;
}
})
تجاوز منع التقاط الشاشة سؤال على Stackoverflow```javascript Java.perform(function() { Java.use('android.view.SurfaceView').setSecure.overload('boolean').implementation = function(flag){ console.log('[1] flag:', flag); this.call(false); }; var LayoutParams = Java.use('android.view.WindowManager$LayoutParams'); Java.use('android.view.ViewWindow').setFlags.overload('int', 'int').implementation = function(flags, mask){ console.log('flag secure: ', LayoutParams.FLAG_SECURE.value); console.log('before:', flags); flags = (flags.value & ~LayoutParams.FLAG_SECURE.value); console.log('after:', flags); this.call(this, flags, mask); }; });
<details>
<summary>مثال الإخراج</summary>
https://stackoverflow.com/a/54818023/2655092
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### تحديث Shared Preferences```javascript
function notifyNewSharedPreference() {
Java.use('android.app.SharedPreferencesImpl$EditorImpl').putString.overload('java.lang.String', 'java.lang.String').implementation = function(k, v) {
console.log('[SharedPreferencesImpl]', k, '=', v);
return this.putString(k, v);
}
}
function hookOverloads(className, func) { var clazz = Java.use(className); var overloads = clazz[func].overloads; for (var i in overloads) { if (overloads[i].hasOwnProperty('argumentTypes') || overloads[i]['argumentTypes'] != undefined) { var parameters = [];
var curArgumentTypes = overloads[i].argumentTypes, args = [], argLog = '[';
for (var j in curArgumentTypes) {
var cName = curArgumentTypes[j].className;
parameters.push(cName);
argLog += "'(" + cName + ") ' + v" + j + ",";
args.push('v' + j);
}
argLog += ']';
var script = "var ret = this." + func + '(' + args.join(',') + ") || '';\n"
+ "console.log(JSON.stringify(" + argLog + "));\n"
+ "return ret;"
args.push(script);
clazz[func].overload.apply(this, parameters).implementation = Function.apply(null, args);
}
} }
Java.perform(function() { hookOverloads('java.lang.StringBuilder', '$init'); })
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### تسجيل مستقبل البث```javascript
Java.perform(() => {
const MyBroadcastReceiver = Java.registerClass({
name: 'MyBroadcastReceiver',
superClass: Java.use('android.content.BroadcastReceiver'),
methods: {
onReceive: [{
returnType: 'void',
argumentTypes: ['android.content.Context', 'android.content.Intent'],
implementation: function(context, intent) {
// ..
}
}]
},
});
let ctx = Java.use('android.app.ActivityThread').currentApplication().getApplicationContext();
ctx.registerReceiver(MyBroadcastReceiver.$new(), Java.use('android.content.IntentFilter').$new('com.example.JAVA_TO_AGENT'));
});
function listClassesImplementsInterface(aInterface) { let classLoaders = Java.enumerateClassLoadersSync() Java.enumerateLoadedClassesSync().forEach(className => { for (let i = 0; i < classLoaders.length; i++) { let classLoader = classLoaders[i] Java.classFactory.loader = classLoader try { let jclass = Java.use(className).class let ifaces = jclass.getInterfaces().toString() jclass = null if (ifaces.indexOf(aInterface) != -1) { console.log(JSON.stringify({ name: className, loader: classLoader.toString(), interfaces: ifaces })) break // we found one ClassLoader, that's enough } } catch (e) { // continue to next ClassLoader } } }) }
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### زيادة عدد الخطوات```js
Java.perform(() => {
var customSensorEventListener = null;
var curSteps = 0;
var totalNumberOfRequiredSteps = 10000;
function incSteps() {
Java.perform(() => {
var sEvent = Java.use('android.hardware.SensorEvent').$new(1);
sEvent.values.values = Java.array('float', [curSteps]); // https://developer.android.com/reference/android/hardware/SensorEvent#values
sEvent.timestamp = Java.use('java.lang.Long').$new(Java.use('java.lang.System').nanoTime());
sEvent.accuracy = Java.use('java.lang.Integer').$new(3); // https://developer.android.com/reference/android/hardware/SensorManager#SENSOR_STATUS_ACCURACY_HIGH
customSensorEventListener.onSensorChanged(sEvent);
if (curSteps < totalNumberOfRequiredSteps) {
setTimeout(() => {
curSteps += 50;
incSteps();
}, 1500)
}
});
}
Java.choose('.CustomSensorEventListener', { // class that implements SensorEventListener
onMatch: function (instance) {
customSensorEventListener = instance;
},
onComplete: function () {
incSteps();
}
});
});
var m = 'libsystem_trace.dylib'; // bool os_log_type_enabled(os_log_t oslog, os_log_type_t type); var isEnabledFunc = Module.findExportByName(m, 'os_log_type_enabled'); // _os_log_impl(void *dso, os_log_t log, os_log_type_t type, const char *format, uint8_t *buf, unsigned int size); var logFunc = Module.findExportByName(m, '_os_log_impl');
// Enable all logs Interceptor.attach(isEnabledFunc, { onLeave: function (ret) { ret.replace(0x1); } });
Interceptor.attach(logFunc, { onEnter: function (a) { /* OS_ENUM(os_log_type, uint8_t, OS_LOG_TYPE_DEFAULT = 0x00, OS_LOG_TYPE_INFO = 0x01, OS_LOG_TYPE_DEBUG = 0x02, OS_LOG_TYPE_ERROR = 0x10, OS_LOG_TYPE_FAULT = 0x11); */ var type = a[2]; var format = a[3]; if (type !== 0x2) { console.log(JSON.stringify({ type: type, format: format.readCString(), //buf: a[4].readPointer().readCString() // TODO }, null, 2)); } } })
<details>
<summary>مثال على الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### مربع تنبيه iOS```js
var UIAlertController = ObjC.classes.UIAlertController;
var UIAlertAction = ObjC.classes.UIAlertAction;
var UIApplication = ObjC.classes.UIApplication;
var handler = new ObjC.Block({ retType: 'void', argTypes: ['object'], implementation: function () {} });
ObjC.schedule(ObjC.mainQueue, function () {
var alert = UIAlertController.alertControllerWithTitle_message_preferredStyle_('Frida', 'Hello from Frida', 1);
var defaultAction = UIAlertAction.actionWithTitle_style_handler_('OK', 0, handler);
alert.addAction_(defaultAction);
// Instead of using `ObjC.choose()` and looking for UIViewController instances on the heap, we have direct access through UIApplication:
UIApplication.sharedApplication().keyWindow().rootViewController().presentViewController_animated_completion_(alert, true, NULL);
})
سجل كل فتح ملف```js Interceptor.attach(ObjC.classes.NSFileManager['- fileExistsAtPath:'].implementation, { onEnter: function (args) { console.log('open' , ObjC.Object(args[2]).toString()); } });
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### فئة Observe```js
function observeClass(name) {
var k = ObjC.classes[name];
k.$ownMethods.forEach(function(m) {
var impl = k[m].implementation;
console.log('Observing ' + name + ' ' + m);
Interceptor.attach(impl, {
onEnter: function(a) {
this.log = [];
this.log.push('(' + a[0] + ',' + Memory.readUtf8String(a[1]) + ') ' + name + ' ' + m);
if (m.indexOf(':') !== -1) {
var params = m.split(':');
params[0] = params[0].split(' ')[1];
for (var i = 0; i < params.length - 1; i++) {
try {
this.log.push(params[i] + ': ' + new ObjC.Object(a[2 + i]).toString());
} catch (e) {
this.log.push(params[i] + ': ' + a[2 + i].toString());
}
}
}
this.log.push(
Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress)
.join('\n')
);
},
onLeave: function(r) {
try {
this.log.push('RET: ' + new ObjC.Object(r).toString());
} catch (e) {
this.log.push('RET: ' + r.toString());
}
console.log(this.log.join('\n') + '\n');
}
});
});
}
`observeClass('Someclass$innerClass');```` Observing Someclass$innerClass - func Observing Someclass$innerClass - empty (0x174670040,parameterName) Someclass$innerClass - func 0x10048dd6c libfoo!0x3bdd6c 0x1005a5dd0 libfoo!0x4d5dd0 0x1832151c0 libdispatch.dylib!_dispatch_client_callout 0x183215fb4 libdispatch.dylib!dispatch_once_f RET: 0xabcdef
</details>
<br>[⬆ Back to top](#table-of-contents)
#### العثور على UUID لتطبيق iOS
احصل على UUID لمسار محدد عند التوصيل بتطبيق من خلال قراءة ملف plist تحت كل حاوية تطبيق.```js
var PLACEHOLDER = '{UUID}';
function extractUUIDfromPath(path) {
var bundleIdentifier = String(ObjC.classes.NSBundle.mainBundle().objectForInfoDictionaryKey_('CFBundleIdentifier'));
var path_prefix = path.substr(0, path.indexOf(PLACEHOLDER));
var plist_metadata = '/.com.apple.mobile_container_manager.metadata.plist';
var errorPtr = Memory.alloc(Process.pointerSize);
Memory.writePointer(errorPtr, NULL);
var folders = ObjC.classes.NSFileManager.defaultManager().contentsOfDirectoryAtPath_error_(path_prefix, errorPtr);
var error = Memory.readPointer(errorPtr);
if (errorPtr)
console.error( new ObjC.Object( error ) );
for (var i = 0, l = folders.count(); i < l; i++) {
var uuid = folders.objectAtIndex_(i);
var metadata = path_prefix + uuid + plist_metadata;
var dict = ObjC.classes.NSMutableDictionary.alloc().initWithContentsOfFile_(metadata);
var enumerator = dict.keyEnumerator();
var key;
while ((key = enumerator.nextObject()) !== null) {
if (key == 'MCMMetadataIdentifier') {
var appId = String(dict.objectForKey_(key));
if (appId.indexOf(bundleIdentifier) != -1) {
return path.replace(PLACEHOLDER, uuid);
}
}
}
}
}
console.log( extractUUIDfromPath('/var/mobile/Containers/Data/Application/' + PLACEHOLDER + '/Documents') );
طباعة خريطة الأعضاء (مع القيم) لكل مثيل من الفئة```js ObjC.choose(ObjC.classes[clazz], { onMatch: function (obj) { console.log('onMatch: ', obj); Object.keys(obj.$ivars).forEach(function(v) { console.log('\t', v, '=', obj.$ivars[v]); }); }, onComplete: function () { console.log('onComplete', arguments.length); } });
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### التسلسل الهرمي للفئات
Object.keys(ObjC.classes) ستدرج جميع فئات Objective C المتاحة،
ولكن في الواقع سيعيد هذا جميع الفئات المحملة في العملية الحالية، بما في ذلك أطر النظام.
إذا أردنا شيء مثل weak_classdump، لإدراج الفئات من الملف التنفيذي نفسه فقط، فإن وقت تشغيل Objective C يوفر بالفعل مثل هذه الوظيفة [objc_copyClassNamesForImage](#https://developer.apple.com/documentation/objectivec/1418485-objc_copyclassnamesforimage?language=objc)```js
var objc_copyClassNamesForImage = new NativeFunction(
Module.findExportByName(null, 'objc_copyClassNamesForImage'),
'pointer',
['pointer', 'pointer']
);
var free = new NativeFunction(Module.findExportByName(null, 'free'), 'void', ['pointer']);
var classes = new Array(count);
var p = Memory.alloc(Process.pointerSize);
Memory.writeUInt(p, 0);
var path = ObjC.classes.NSBundle.mainBundle().executablePath().UTF8String();
var pPath = Memory.allocUtf8String(path);
var pClasses = objc_copyClassNamesForImage(pPath, p);
var count = Memory.readUInt(p);
for (var i = 0; i < count; i++) {
var pClassName = Memory.readPointer(pClasses.add(i * Process.pointerSize));
classes[i] = Memory.readUtf8String(pClassName);
}
free(pClasses);
var tree = {};
classes.forEach(function(name) {
var clazz = ObjC.classes[name];
var chain = [name];
while (clazz = clazz.$superClass) {
chain.unshift(clazz.$className);
}
var node = tree;
chain.forEach(function(clazz) {
node[clazz] = node[clazz] || {};
node = node[clazz];
});
});
send(tree);
ربط `objc_msgSend````py import frida, sys
f = open('/tmp/log', 'w')
def on_message(msg, _data): f.write(msg['payload']+'\n')
frida_script = """ Interceptor.attach(Module.findExportByName('/usr/lib/libobjc.A.dylib', 'objc_msgSend'), { onEnter: function(args) { var m = Memory.readCString(args[1]); if (m != 'length' && !m.startsWith('_fastC')) send(m); } }); """ device = frida.get_usb_device() pid = device.spawn(["com.example"]) # or .get_frontmost_application() session = device.attach(pid) script = session.create_script(frida_script) script.on('message', on_message) script.load() device.resume(pid) sys.stdin.read()
```sh
$ sort /tmp/log | uniq -c | sort -n
لتقليل الوظائف المتعلقة بواجهة المستخدم، أستخدم الخطوات التالية:
-o /tmp/log1<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### تفريغ مقاطع الذاكرة```js
Process.enumerateRanges('rw-', {
onMatch: function (range) {
var fname = `/sdcard/${range.base}_dump`;
var f = new File(fname, 'wb');
f.write(instance.base.readByteArray(instance.size));
f.flush();
f.close();
console.log(`base=${range.base} size=${range.size} prot=${range.protection} fname=${fname}`);
},
onComplete: function () {}
});
function memscan(str) { Process.enumerateModulesSync().filter(m => m.path.startsWith('/data')).forEach(m => { var pattern = str.split('').map(letter => letter.charCodeAt(0).toString(16)).join(' '); try { var res = Memory.scanSync(m.base, m.size, pattern); if (res.length > 0) console.log(JSON.stringify({m, res})); } catch (e) { console.warn(e); } }); }
[No content provided to translate.]```js
var memscn = function (str) {
Process.enumerateModulesSync().forEach(function (m) {
var pattern = str.split('').map(function (l) { return l.charCodeAt(0).toString(16) }).join(' ');
try {
var res = Memory.scanSync(m.base, m.size, pattern);
if (res.length > 0)
console.log(JSON.stringify({m, res}, null , 2));
} catch (e) {
console.warn(e);
}
});
}
var _module = Process.findModuleByName('myModule'); var base = ptr(_module.base); var startTraceOffset = 0xabcd1234, numInstructionsToTrace = 50; var startTrace = base.add(startTraceOffset), endTrace = startTrace.add(4 * (numInstructionsToTrace - 1));
Interceptor.attach(ObjC.classes.CustomClass['- func'].implementation, {
onEnter: function (args) {
var tid = Process.getCurrentThreadId();
this.tid = tid;
console.warn(onEnter [ ${tid} ]);
Stalker.follow(tid, {
transform: function (iterator) {
var instruction;
while ((instruction = iterator.next()) !== null) {
// condition to putCallout
if (instruction.address <= endTrace && instruction.address >= startTrace) {
// print instruction & registers values
iterator.putCallout(function(context) {
var offset = ptr(context.pc).sub(base);
var inst = Instruction.parse(context.pc).toString();
var modified_inst = inst;
inst.replace(/,/g, '').split(' ').forEach(op => {
if (op.startsWith('x'))
modified_inst = modified_inst.replace(op, context[op]);
else if (op.startsWith('w'))
modified_inst = modified_inst.replace(op, context[op.replace('w', 'x')]);
});
modified_inst = '\x1b[35;01m' + modified_inst + '\x1b[0m';
console.log(x8=${context.x8} x25=${context.x25} x0=${context.x0} x21=${context.x21})
console.log(${offset} ${inst} # ${modified_inst});
});
}
iterator.keep();
}
}
})
},
onLeave: function (retval) {
console.log(onLeave [ ${this.tid} ]);
// cleanup
Stalker.unfollow(this.tid);
Stalker.garbageCollect();
}
})
<details>
<summary>مثال للإخراج</summary>
mul x5, x2, x21 # mul 0x3, 0x4, 0x5
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### Cpp demangler```sh
$ npm i frida-compile demangler-js -g
أضف إلى السكربت الخاص بك```js const demangle = require('demangler-js').demangle; ... Module.enumerateExportsSync('library.so') .filter(x => x.name.startsWith('_Z')) .forEach(x => { Interceptor.attach(x.address, { onEnter: function (args) { console.log('[-] ' + demangle(x.name)); } }); });
تجميع```sh
$ frida-compile script.js -o out.js
run```sh $ frida -Uf com.app -l out.js
<details>
<summary>مثال على المخرجات</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### الخطاف المبكر
تعيين الخطافات قبل DT_INIT_ARRAY ( [المصدر](https://cs.android.com/android/platform/superproject/+/master:bionic/linker/linker_soinfo.cpp;l=386;drc=android-8.0.0_r1?q=call_constructor&ss=android%2Fplatform%2Fsuperproject) )```js
let base;
let do_dlopen = null;
let call_ctor = null;
const target_lib_name = 'targetlib.so';
Process.findModuleByName('linker64').enumerateSymbols().forEach(sym => {
if (sym.name.indexOf('do_dlopen') >= 0) {
do_dlopen = sym.address;
} else if (sym.name.indexOf('call_constructor') >= 0) {
call_ctor = sym.address;
}
})
Interceptor.attach(do_dlopen, function (args) {
if (args[0].readUtf8String().indexOf(target_lib_name) >= 0) {
Interceptor.attach(call_ctor, function () {
const module = Process.findModuleByName(target_lib_name);
base = module.base;
console.log('loading', target_lib_name, '- base @', base);
// DoStuff
})
}
})
المصدر: iGio90
مثال على استخراج خصائص جهاز iOS بطريقة سريعة وغير رسمية```js var UIDevice = ObjC.classes.UIDevice.currentDevice(); UIDevice.$ownMethods .filter(function(method) { return method.indexOf(':') == -1 /* filter out methods with parameters / && method.indexOf('+') == -1 / filter out public methods */ }) .forEach(function(method) { console.log(method, ':', UIDevicemethod) }) console.log('executablePath =', ObjC.classes.NSBundle.mainBundle().executablePath().toString());
☁️ IP الخاص بي: 127.0.0.1
🔒 تشفير المرور: [تمكين]
📡 فحص الشبكة: [ تمكين ]
❌ خروج
للاختيار استخدم: مفاتيح الأسهم ^, ↵ أدخل, esc رجوع```js
if (ObjC.available) {
var processInfo = ObjC.classes.NSProcessInfo.processInfo();
var versionString = processInfo.operatingSystemVersionString().toString();
// E.g. "Version 13.5 (Build 17F75)"
var ver = versionString.split(' ');
var version = ver[1];
// E.g. 13.5
console.log("iOS version: " + version);
}
function screenshot() { ObjC.schedule(ObjC.mainQueue, function() { var getNativeFunction = function (ex, retVal, args) { return new NativeFunction(Module.findExportByName('UIKit', ex), retVal, args); }; var api = { UIWindow: ObjC.classes.UIWindow, UIGraphicsBeginImageContextWithOptions: getNativeFunction('UIGraphicsBeginImageContextWithOptions', 'void', [['double', 'double'], 'bool', 'double']), UIGraphicsBeginImageContextWithOptions: getNativeFunction('UIGraphicsBeginImageContextWithOptions', 'void', [['double', 'double'], 'bool', 'double']), UIGraphicsEndImageContext: getNativeFunction('UIGraphicsEndImageContext', 'void', []), UIGraphicsGetImageFromCurrentImageContext: getNativeFunction('UIGraphicsGetImageFromCurrentImageContext', 'pointer', []), UIImagePNGRepresentation: getNativeFunction('UIImagePNGRepresentation', 'pointer', ['pointer']) }; var view = api.UIWindow.keyWindow(); var bounds = view.bounds(); var size = bounds[1]; api.UIGraphicsBeginImageContextWithOptions(size, 0, 0); view.drawViewHierarchyInRect_afterScreenUpdates_(bounds, true);
var image = api.UIGraphicsGetImageFromCurrentImageContext();
api.UIGraphicsEndImageContext();
var png = new ObjC.Object(api.UIImagePNGRepresentation(image));
send('screenshot', Memory.readByteArray(png.bytes(), png.length()));
}); }
rpc.exports = { takescreenshot: screenshot }
> **⚠️ تحذير**: هذا العمل قيد التطوير، يُرجى عدم استخدامه في بيئة الإنتاج بعد!```py
...
def save_screenshot(d):
f = open('/tmp/screenshot.png', 'wb')
f.write(d)
f.close()
def on_message(msg, data):
save_screenshot(data)
script.exports.takescreenshot()
# open screenshot & invoke rpc via input
# <Ctrl+C> will take screenshot, open it with eog & wait for export function name to invoke via input
def on_message(msg, data):
if 'payload' in msg:
if msg['payload'] == 'screenshot':
i = '/tmp/screenshot.png'
f = open(i, 'wb')
f.write(data)
f.close()
subprocess.call(['eog', i])
while True:
try:
time.sleep(1)
except KeyboardInterrupt:
script.exports.takescreenshot()
try:
getattr(script.exports, input())()
except (KeyboardInterrupt, frida.core.RPCException) as e:
print('[!]', e)
Interceptor.attach(ObjC.classes.NMSSHChannel['- execute:error:timeout:'].implementation, {
onEnter: function(args) {
this.cmd = ObjC.Object(args[2]).toString();
this.timeout = args[4];
},
onLeave: function(retv) {
console.log(CMD: ${ObjC.Object(args[2]).toString()} Timeout: ${args[4]} Ret: ${retv});
}
});
<details>
<summary>مثال الإخراج</summary>
TODO
</details>
<br>[⬆ العودة إلى الأعلى](#table-of-contents)
#### المهام القادمة
- إضافة صور GIF وأمثلة
- إضافة روابط إلى /scripts
- توسيع إزالة تثبيت SSL العالمية لـ [ios](https://codeshare.frida.re/@dki/ios10-ssl-bypass/) [andoid 1](https://github.com/Fuzion24/JustTrustMe/blob/master/app/src/main/java/just/trust/me/Main.java) [android
$ frida --codeshare FrenchYeti/android-file-system-access-hook -f com.example.app --no-pausenull إلى خاصية implementation.#include #include
extern "C" { void* create_stdstr(char data, int size) { std::string s = new std::string(); (*s).assign(data, size); return s; } }
| الاسم | طريقة HTTP | نقطة النهاية | اسم الطريقة |
| ---- | ----------- | -------- | ----------- |
| Add | `POST` | `/add` | `Add` |
| Copy | `POST` | `/copy?fromPID=` | `Copy` |
| Lookup | `GET` | `/lookup?item=itemID` | `Lookup` |
| Last | `GET` | `/last` | `Last` |
| Length | `GET` | `/length` | `Length` |
| Pop | `POST` | `/pop` | `Pop` |
| Remove | `DELETE` | `/remove?item=itemID` | `Remove` |
| Shift | `POST` | `/shift` | `Shift` |
تعرض وحدة المصفوفة:```sh
$ ./android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++ a.cpp -o a -shared -static-libstdc++ && adb push a /data/local/tmp/a
#### تحميل وحدة C
* https://frida.re/docs/javascript-api/#cmodule
* https://frida.re/news/2019/09/18/frida-12-7-released/```sh
$ ./aarch64-linux-android21-clang /tmp/b.c -o /tmp/a -shared ../sysroot/usr/lib/aarch64-linux-android/21/liblog.so && adb push /tmp/a /data/local/tmp/a
Synful قابل للتوسعة ويوفر بنية قائمة على المكونات الإضافية تسمح بتطوير الأداة بشكل أكبر والتكيف مع بيئات مختلفة، بهدف أساسي هو تحقيق أكبر قدر ممكن من الوظائف المفيدة لاختبارات الاختراق في العالم الحقيقي، مع الحفاظ على مستوى عالٍ من التخفي. تتضمن المكونات الإضافية الحالية لـ Synful: Keylogging، PowerShell Injection، Port Scanner، Reverse Shell، TCP Proxy، SAM / SECRETS Dump، File / Screenshot Exfiltration، و Session Lock / Unlock.```c #include <stdio.h> #include <stdlib.h> #include <android/log.h>
#define TAG "TEST1" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, VA_ARGS) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, VA_ARGS)
void test(void) { FILE* fp = popen("ls -l /sdcard 2>&1", "r"); if (fp == NULL) LOGE("executing cmd failed"); char b[256]; while (fgets(b, sizeof(b), fp) != NULL) { LOGI("%s", b); } pclose(fp); }
قد تكون سمعت عن الجملة الشهيرة (الشائعة بين المهندسين والمتسللين): «لا تكرر العجلة». ولكن عندما يصل فحص الأمان إلى طريق مسدود ولا تجد ثغرات أو نقاط ضعف، ولا توجد خيارات أخرى، فهذا هو الوقت المناسب لإعادة اختراع العجلة والتوصل إلى تقنيات هجوم جديدة، لأنه في كثير من الأحيان قد يؤدي إصلاح برمجي واحد أو اثنين إلى خفض تصنيف خطورة الثغرة، لكنه لا يعالج السبب الجذري.```sh
$ frida -Uf com.app --no-pause --enable-jit -e "Module.load('/data/local/tmp/a')"
[ ] -> new NativeFunction(Module.findExportByName('a', 'test'), 'void', [])()
اعتراض funcPtr وتسجيل من يقرأ/يكتب في x2 عن طريق إزالة الأذونات باستخدام mprotect.```js
Process.setExceptionHandler(function(exp) {
console.warn(JSON.stringify(Object.assign(exp, { _lr: DebugSymbol.fromAddress(exp.context.lr), _pc: DebugSymbol.fromAddress(exp.context.pc) }), null, 2));
Memory.protect(exp.memory.address, Process.pointerSize, 'rw-');
// can also use new NativeFunction(Module.findExportByName(null, 'mprotect'), 'int', ['pointer', 'uint', 'int'])(parseInt(this.context.x2), 2, 0)
return true; // goto PC
});
Interceptor.attach(funcPtr, { onEnter: function (args) { console.log('onEnter', JSON.stringify({ x2: this.context.x2, mprotect_ret: Memory.protect(this.context.x2, 2, '---'), errno: this.errno }, null, 2)); }, onLeave: function (retval) { console.log('onLeave'); } });
<details>
<summary>مثال على الإخراج</summary>```
[iOS Device::com.app]-> onEnter {
"x2": "0x1c145c6e0",
"mprotect_ret": true,
"errno": 2
}
{
"type": "access-violation",
"address": "0x1853b0198",
"memory": {
"operation": "read",
"address": "0x1c145c6e0"
},
"context": {
"lr": "0x100453358",
"fp": "0x16fb2e860",
"x28": "0x0",
"x27": "0x0",
"x26": "0x104312600",
"x25": "0x0",
"x24": "0x0",
"x23": "0x0",
"x22": "0x0",
"x21": "0xb000000422bbda03",
"x20": "0x1c4a22560",
"x19": "0xb000000422bbda03",
"x18": "0x0",
"x17": "0x100d25290",
"x16": "0x1853b0190",
"x15": "0x0",
"x14": "0x5",
"x13": "0xe5a1c4119597",
"x12": "0x10e80ca30",
"x11": "0x180000003f",
"x10": "0x10e80ca00",
"x9": "0x1020ad7c3",
"x8": "0x0",
"x7": "0x0",
"x6": "0x0",
"x5": "0x0",
"x4": "0xb000000422bbda03",
"x3": "0x1c4a22560",
"x2": "0x1c145c6e0",
"x1": "0x1020ad7c3",
"x0": "0x1c145c6e0",
"sp": "0x16fb2e790",
"pc": "0x1853b0198"
},
"nativeContext": "0x16fc42b24"
}
onLeave
var cookieJar = {}; var cookies = ObjC.classes.NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies(); for (var i = 0, l = cookies.count(); i < l; i++) { var cookie = cookies'- objectAtIndex:'; cookieJar[cookie.Name()] = cookie.Value().toString(); // "- expiresDate".toString() } console.log(JSON.stringify(cookieJar, null, 2));
<details>
<summary>مثال الإخراج</summary>```js
{
"key1": "value 1",
"key2": "value 2"
}