├── README.md ├── android.html ├── bsides-frida.apk ├── exercise ├── exercise.c ├── javascript-api.html └── template.py /README.md: -------------------------------------------------------------------------------- 1 | # FridaWorkshop 2 | Break Apps with Frida workshop material 3 | 4 | The slides can be downloaded from https://github.com/DigitalInterruption/DigitalInterruption.github.io/blob/master/Prototyping%20and%20reverse%20engineering%20with%20frida_hacklu.pdf 5 | -------------------------------------------------------------------------------- /android.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Android - Frida • A world-class dynamic instrumentation framework 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 60 |
61 | 67 | 87 |
88 |
89 | 90 | 91 |
92 |
93 | 94 |
95 | 2004 |
2005 | 2006 |
2007 | 2298 |
2299 | 2300 | 2301 |
2302 |
2303 |
2304 | Improve this page 2305 |
2306 |

Android

2307 |

In this tutorial we show how to do function tracing on your Android device.

2308 | 2309 |

Setting up your Android device

2310 | 2311 |

Before you start, you will need to root your device in case you haven’t done so 2312 | already. Also note that most of our testing has involved Android 4.4, and while 2313 | we do support 4.2 all the way through 6.0, there’s for now limited support for 2314 | ART and we would recommend that you start out with a Dalvik-powered ARM device 2315 | or emulator for the time being.

2316 | 2317 |

You will also need the adb tool from the Android SDK.

2318 | 2319 |

First off, download the latest frida-server for Android from our releases 2320 | page and get it running on your 2321 | device:

2322 | 2323 |
$ adb root # might be required
2324 | $ adb push frida-server /data/local/tmp/ 
2325 | $ adb shell "chmod 755 /data/local/tmp/frida-server"
2326 | $ adb shell "/data/local/tmp/frida-server &"
2327 | 2328 |

For the last step, make sure you start frida-server as root, i.e. if you are 2329 | doing this on a rooted device, you might need to su and run it from that 2330 | shell.

2331 | 2332 |

Next, make sure adb can see your device:

2333 | 2334 |
$ adb devices -l
2335 | 2336 |

This will also ensure that the adb daemon is running on your desktop, which 2337 | allows Frida to discover and communicate with your device regardless of whether 2338 | you’ve got it hooked up through USB or WiFi.

2339 | 2340 |

A quick smoke-test

2341 | 2342 |

Now, on your desktop it’s time to make sure the basics are working. Run:

2343 | 2344 |
$ frida-ps -U
2345 | 2346 |

This should give you a process list along the lines of:

2347 | 2348 |
  PID NAME
2349 |  1590 com.facebook.katana
2350 | 13194 com.facebook.katana:providers
2351 | 12326 com.facebook.orca
2352 | 13282 com.twitter.android
2353 | …
2354 | 2355 |

Great, we’re good to go then!

2356 | 2357 |

Tracing open() calls in Chrome

2358 | 2359 |

Alright, let’s have some fun. Fire up the Chrome app on your device and return 2360 | to your desktop and run:

2361 | 2362 |
$ frida-trace -U -i open com.android.chrome
2363 | Uploading data...
2364 | open: Auto-generated handler …/linker/open.js
2365 | open: Auto-generated handler …/libc.so/open.js
2366 | Started tracing 2 functions. Press Ctrl+C to stop.
2367 | 2368 |

Now just play around with the Chrome app and you should start seeing open() 2369 | calls flying in:

2370 | 2371 |
1392 ms	open()
2372 | 1403 ms	open()
2373 | 1420 ms	open()
2374 | 2375 |

You can now live-edit the aforementioned JavaScript files as you read 2376 | man open, and start diving deeper and deeper into your Android apps.

2377 | 2378 |

Building your own tools

2379 | 2380 |

While the CLI tools like frida, frida-trace, etc., are definitely 2381 | quite useful, there might be times when you’d like to build your own tools 2382 | harnessing the powerful Frida APIs. For that we would 2383 | recommend reading the chapters on Functions and 2384 | Messages, and anywhere you see frida.attach() just 2385 | substitute that with frida.get_usb_device().attach().

2386 | 2387 | 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 | 2400 | 2401 | 2402 | 2403 | 2404 | 2405 | 2406 | 2407 | 2408 | 2409 | 2410 | 2411 | 2412 | 2413 | 2414 | 2415 | 2416 | 2417 | 2418 | 2419 | 2420 | 2421 | 2422 | 2423 | 2424 | 2425 |
2426 |
2427 | 2428 | 2429 | 2430 | 2431 | 2432 |
2433 |
2434 | 2435 | 2436 | 2437 | 2438 | 2439 |
2440 |
2441 |
2442 | 2443 | 2444 |
2445 |
2446 | 2447 |
2448 |
2449 | 2450 | 2451 | 2463 | 2464 | 2465 | 2466 | 2467 | 2468 | 2480 | 2481 | 2482 | 2483 | 2484 | 2485 | -------------------------------------------------------------------------------- /bsides-frida.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalInterruption/FridaWorkshop/b28c41186cf6cc59beafaa71ebacbbe0f20fdaa0/bsides-frida.apk -------------------------------------------------------------------------------- /exercise: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DigitalInterruption/FridaWorkshop/b28c41186cf6cc59beafaa71ebacbbe0f20fdaa0/exercise -------------------------------------------------------------------------------- /exercise.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define MESSAGE_NUM 5 8 | char* encryptString(char*,char*,size_t); 9 | char* getKey(int); 10 | void decryptAllMessage(); 11 | int checkPassword(); 12 | int getMessage(char*); 13 | void printAllEncryptedMessages(); 14 | 15 | struct messages{ 16 | char* key; 17 | char* encryptedString; 18 | size_t len; 19 | }message[MESSAGE_NUM]; 20 | 21 | 22 | int main() 23 | { 24 | srand(time(NULL)); 25 | char readString[255]; 26 | for(int i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | JavaScript API - Frida • A world-class dynamic instrumentation framework 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 60 |
61 | 67 | 87 |
88 |
89 | 90 | 91 |
92 |
93 | 94 |
95 | 2004 |
2005 | 2006 |
2007 | 2298 |
2299 | 2300 | 2301 |
2302 |
2303 |
2304 | Improve this page 2305 |
2306 |

JavaScript API

2307 |

Table of contents

2308 |
    2309 |
  1. Global
  2. 2310 |
  3. console
  4. 2311 |
  5. rpc
  6. 2312 |
  7. Frida
  8. 2313 |
  9. Process
  10. 2314 |
  11. Module
  12. 2315 |
  13. Memory
  14. 2316 |
  15. MemoryAccessMonitor
  16. 2317 |
  17. Thread
  18. 2318 |
  19. Int64
  20. 2319 |
  21. UInt64
  22. 2320 |
  23. NativePointer
  24. 2321 |
  25. NativeFunction
  26. 2322 |
  27. NativeCallback
  28. 2323 |
  29. Socket
  30. 2324 |
  31. Stream
  32. 2325 |
  33. File
  34. 2326 |
  35. Interceptor
  36. 2327 |
  37. Stalker
  38. 2328 |
  39. ApiResolver
  40. 2329 |
  41. DebugSymbol
  42. 2330 |
  43. Instruction
  44. 2331 |
  45. ObjC
  46. 2332 |
  47. Java
  48. 2333 |
  49. WeakRef
  50. 2334 |
2335 | 2336 |

Global

2337 | 2338 |
    2339 |
  • 2340 |

    hexdump(target[, options]): generate a hexdump from the provided 2341 | ArrayBuffer or NativePointer target, optionally with options for 2342 | customizing the output.

    2343 | 2344 |

    For example:

    2345 |
  • 2346 |
2347 | 2348 |
var libc = Module.findBaseAddress('libc.so');
2349 | var buf = Memory.readByteArray(libc, 64);
2350 | console.log(hexdump(buf, {
2351 |   offset: 0,
2352 |   length: 64,
2353 |   header: true,
2354 |   ansi: true
2355 | }));
2356 | 2357 |
           0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
2358 | 00000000  7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  .ELF............
2359 | 00000010  03 00 28 00 01 00 00 00 00 00 00 00 34 00 00 00  ..(.........4...
2360 | 00000020  34 a8 04 00 00 00 00 05 34 00 20 00 08 00 28 00  4.......4. ...(.
2361 | 00000030  1e 00 1d 00 06 00 00 00 34 00 00 00 34 00 00 00  ........4...4...
2362 | 2363 |
    2364 |
  • 2365 |

    int64(v): short-hand for new Int64(v)

    2366 |
  • 2367 |
  • 2368 |

    uint64(v): short-hand for new UInt64(v)

    2369 |
  • 2370 |
  • 2371 |

    ptr(s): short-hand for new NativePointer(s)

    2372 |
  • 2373 |
  • 2374 |

    NULL: short-hand for ptr("0")

    2375 |
  • 2376 |
  • 2377 |

    recv([type, ]callback): request callback to be called on the next 2378 | message received from your Frida-based application. Optionally type may 2379 | be specified to only receive a message where the type field is set to 2380 | type.

    2381 | 2382 |

    This will only give you one message, so you need to call recv() again 2383 | to receive the next one.

    2384 |
  • 2385 |
  • 2386 |

    send(message[, data]): send the JavaScript object message to your 2387 | Frida-based application (it must be serializable to JSON). If you also have 2388 | some raw binary data that you’d like to send along with it, e.g. you dumped 2389 | some memory using Memory#readByteArray, then you may pass this through the 2390 | optional data argument. This requires it to either be an ArrayBuffer or an 2391 | array of integers between 0 and 255.

    2392 |
  • 2393 |
2394 | 2395 |
2396 |
Performance considerations
2397 |

2398 | While send() is asynchronous, the total overhead of sending a single 2399 | message is not optimized for high frequencies, so that means Frida leaves 2400 | it up to you to batch multiple values into a single send()-call, 2401 | based on whether low delay or high throughput is desired. 2402 |

2403 |
2404 | 2405 |
    2406 |
  • 2407 |

    setTimeout(fn, delay): call fn after delay milliseconds. Returns an 2408 | id that can be passed to clearTimeout to cancel it.

    2409 |
  • 2410 |
  • 2411 |

    clearTimeout(id): cancel id returned by call to setTimeout

    2412 |
  • 2413 |
  • 2414 |

    setInterval(fn, delay): call fn every delay milliseconds. Returns an 2415 | id that can be passed to clearInterval to cancel it.

    2416 |
  • 2417 |
  • 2418 |

    clearInterval(id): cancel id returned by call to setInterval

    2419 |
  • 2420 |
2421 | 2422 |

console

2423 | 2424 |
    2425 |
  • 2426 |

    console.log(line), console.warn(line), console.error(line): 2427 | write line to the console of your Frida-based application. The exact 2428 | behavior depends on where frida-core 2429 | is integrated. 2430 | For example, this output goes to stdout or stderr when using Frida 2431 | through frida-python, 2432 | qDebug when using 2433 | frida-qml, etc.

    2434 | 2435 |

    Arguments that are ArrayBuffer objects will be substituted by the result of 2436 | hexdump() with default options.

    2437 |
  • 2438 |
2439 | 2440 |

rpc

2441 | 2442 |
    2443 |
  • rpc.exports: empty object that you can either replace or insert into to 2444 | expose an RPC-style API to your application. The key specifies the method 2445 | name and the value is your exported function. This function may either 2446 | return a plain value for returning that to the caller immediately, or a 2447 | Promise for returning asynchronously.
  • 2448 |
2449 | 2450 |
2451 |

For example:

2452 |
2453 | 2454 |
'use strict';
2455 | 
2456 | rpc.exports = {
2457 |     add: function (a, b) {
2458 |         return a + b;
2459 |     },
2460 |     sub: function (a, b) {
2461 |         return new Promise(resolve => {
2462 |             setTimeout(() => {
2463 |                 resolve(a - b);
2464 |             }, 100);
2465 |         });
2466 |     }
2467 | };
2468 | 2469 |
2470 |

From an application using the Node.js bindings this API would be consumed 2471 | like this:

2472 |
2473 | 2474 |
'use strict';
2475 | 
2476 | const co = require('co');
2477 | const frida = require('frida');
2478 | const load = require('frida-load');
2479 | 
2480 | let session, script;
2481 | co(function *() {
2482 |     const source = yield load(require.resolve('./agent.js'));
2483 |     session = yield frida.attach("iTunes");
2484 |     script = yield session.createScript(source);
2485 |     script.events.listen('message', onMessage);
2486 |     yield script.load();
2487 |     const api = yield script.getExports();
2488 |     console.log(yield api.add(2, 3));
2489 |     console.log(yield api.sub(5, 3));
2490 | })
2491 | .catch(onError);
2492 | 
2493 | function onError(error) {
2494 |     console.error(error.stack);
2495 | }
2496 | 
2497 | function onMessage(message, data) {
2498 |     if (message.type === 'send') {
2499 |         console.log(message.payload);
2500 |     } else if (message.type === 'error') {
2501 |         console.error(message.stack);
2502 |     }
2503 | }
2504 | 2505 |
2506 |

The Python version would be very similar:

2507 |
2508 | 2509 |
import codecs
2510 | import frida
2511 | 
2512 | def on_message(message, data):
2513 |     if message['type'] == 'send':
2514 |         print(message['payload'])
2515 |     elif message['type'] == 'error':
2516 |         print(message['stack'])
2517 | 
2518 | session = frida.attach('iTunes')
2519 | with codecs.open('./agent.js', 'r', 'utf-8') as f:
2520 |     source = f.read()
2521 | script = session.create_script(source)
2522 | script.on('message', on_message)
2523 | script.load()
2524 | print(script.exports.add(2, 3))
2525 | print(script.exports.sub(5, 3))
2526 | session.detach()
2527 | 2528 |

In the example above we used script.on('message', on_message) to monitor for any messages from the injected process, JavaScript side. There are other notifications that you can watch for as well on both the script and session. If you want to be notified when the target process exits, use session.on('detached', your_function).

2529 | 2530 |

Frida

2531 | 2532 |
    2533 |
  • Frida.version: property containing the current Frida version
  • 2534 |
2535 | 2536 |

Process

2537 | 2538 |
    2539 |
  • 2540 |

    Process.arch: property containing the string ia32, x64, arm 2541 | or arm64

    2542 |
  • 2543 |
  • 2544 |

    Process.platform: property containing the string windows, 2545 | darwin, linux or qnx

    2546 |
  • 2547 |
  • 2548 |

    Process.pageSize: property containing the size of a virtual memory page 2549 | (in bytes) as a JavaScript number. This is used to make your scripts more 2550 | portable.

    2551 |
  • 2552 |
  • 2553 |

    Process.pointerSize: property containing the size of a pointer 2554 | (in bytes) as a JavaScript number. This is used to make your scripts more 2555 | portable.

    2556 |
  • 2557 |
  • 2558 |

    Process.isDebuggerAttached(): returns a boolean indicating whether a 2559 | debugger is currently attached

    2560 |
  • 2561 |
  • 2562 |

    Process.getCurrentThreadId(): get this thread’s OS-specific id as a 2563 | JavaScript number

    2564 |
  • 2565 |
  • 2566 |

    Process.enumerateThreads(callbacks): enumerate all threads, 2567 | where callbacks is an object specifying:

    2568 | 2569 |
      2570 |
    • onMatch: function (thread): called with thread object containing: 2571 |
        2572 |
      • id: OS-specific id
      • 2573 |
      • state: string specifying either running, stopped, waiting, 2574 | uninterruptible or halted
      • 2575 |
      • context: object with the keys pc and sp, which are 2576 | NativePointer objects specifying EIP/RIP/PC and ESP/RSP/SP, 2577 | respectively, for ia32/x64/arm. Other processor-specific keys 2578 | are also available, e.g. eax, rax, r0, x0, etc.
      • 2579 |
      2580 | 2581 |

      This function may return the string stop to cancel the enumeration 2582 | early.

      2583 |
    • 2584 |
    • onComplete: function (): called when all threads have been enumerated
    • 2585 |
    2586 |
  • 2587 |
  • 2588 |

    Process.enumerateThreadsSync(): synchronous version of 2589 | enumerateThreads() that returns the threads in an array.

    2590 |
  • 2591 |
  • 2592 |

    Process.findModuleByAddress(address), 2593 | Process.getModuleByAddress(address), 2594 | Process.findModuleByName(name), 2595 | Process.getModuleByName(name): 2596 | return an object with details about the module whose address or name 2597 | matches the one specified. In the event that no such module could be found, 2598 | the find-prefixed functions return null whilst the get-prefixed 2599 | functions throw an exception. See Process.enumerateModules() for 2600 | details about which fields are included.

    2601 |
  • 2602 |
  • 2603 |

    Process.enumerateModules(callbacks): enumerate modules loaded right now, 2604 | where callbacks is an object specifying:

    2605 | 2606 |
      2607 |
    • onMatch: function (module): called with module object containing: 2608 |
        2609 |
      • name: canonical module name as a string
      • 2610 |
      • base: base address as a NativePointer
      • 2611 |
      • size: size in bytes
      • 2612 |
      • path: full filesystem path as a string
      • 2613 |
      2614 | 2615 |

      This function may return the string stop to cancel the enumeration 2616 | early.

      2617 |
    • 2618 |
    • onComplete: function (): called when all modules have been enumerated
    • 2619 |
    2620 |
  • 2621 |
  • 2622 |

    Process.enumerateModulesSync(): synchronous version of 2623 | enumerateModules() that returns the modules in an array.

    2624 |
  • 2625 |
  • 2626 |

    Process.findRangeByAddress(address), getRangeByAddress(address): 2627 | return an object with details about the range containing address. In the 2628 | event that no such range could be found, findRangeByAddress() returns 2629 | null whilst getRangeByAddress() throws an exception. See 2630 | Process.enumerateRanges() for details about which fields are included.

    2631 |
  • 2632 |
  • 2633 |

    Process.enumerateRanges(protection|specifier, callbacks): enumerate memory 2634 | ranges satisfying protection given as a string of the form: rwx, where 2635 | rw- means “must be at least readable and writable”. Alternatively you may 2636 | provide a specifier object with a protection key whose value is as 2637 | aforementioned, and a coalesce key set to true if you’d like neighboring 2638 | ranges with the same protection to be coalesced (the default is false; 2639 | i.e. keeping the ranges separate). callbacks is an object specifying:

    2640 | 2641 |
      2642 |
    • onMatch: function (range): called with range object containing: 2643 |
        2644 |
      • base: base address as a NativePointer
      • 2645 |
      • size: size in bytes
      • 2646 |
      • protection: protection string (see above)
      • 2647 |
      • 2648 |

        file: (when available) file mapping details as an object 2649 | containing:

        2650 | 2651 |
          2652 |
        • path: full filesystem path as a string
        • 2653 |
        • offset: offset in bytes
        • 2654 |
        2655 |
      • 2656 |
      2657 | 2658 |

      This function may return the string stop to cancel the enumeration 2659 | early.

      2660 |
    • 2661 |
    • onComplete: function (): called when all memory ranges have been 2662 | enumerated
    • 2663 |
    2664 |
  • 2665 |
  • 2666 |

    Process.enumerateRangesSync(protection|specifier): synchronous version of 2667 | enumerateRanges() that returns the ranges in an array.

    2668 |
  • 2669 |
  • 2670 |

    Process.enumerateMallocRanges(callbacks): just like enumerateRanges(), 2671 | but for individual memory allocations known to the system heap.

    2672 |
  • 2673 |
  • 2674 |

    Process.enumerateMallocRangesSync(protection): synchronous version of 2675 | enumerateMallocRanges() that returns the ranges in an array.

    2676 |
  • 2677 |
2678 | 2679 |

Module

2680 | 2681 |
    2682 |
  • 2683 |

    Module.enumerateImports(name, callbacks): enumerate imports of module with 2684 | the name as seen in Process#enumerateModules. callbacks is an object 2685 | specifying:

    2686 | 2687 |
      2688 |
    • onMatch: function (imp): called with imp object containing: 2689 |
        2690 |
      • type: string specifying either function or variable
      • 2691 |
      • name: import name as a string
      • 2692 |
      • module: module name as a string
      • 2693 |
      • address: absolute address as a NativePointer
      • 2694 |
      2695 | 2696 |

      Only the name field is guaranteed to be present for all imports. The 2697 | platform-specific backend will do its best to resolve the other fields 2698 | even beyond what the native metadata provides, but there is no guarantee 2699 | that it will succeed. This function may return the string stop to 2700 | cancel the enumeration early.

      2701 |
    • 2702 |
    • onComplete: function (): called when all imports have been 2703 | enumerated
    • 2704 |
    2705 |
  • 2706 |
  • 2707 |

    Module.enumerateImportsSync(name): synchronous version of 2708 | enumerateImports() that returns the imports in an array.

    2709 |
  • 2710 |
  • 2711 |

    Module.enumerateExports(name, callbacks): enumerate exports of module with 2712 | the name as seen in Process#enumerateModules. callbacks is an object 2713 | specifying:

    2714 | 2715 |
      2716 |
    • onMatch: function (exp): called with exp object containing: 2717 |
        2718 |
      • type: string specifying either function or variable
      • 2719 |
      • name: export name as a string
      • 2720 |
      • address: absolute address as a NativePointer
      • 2721 |
      2722 | 2723 |

      This function may return the string stop to cancel the enumeration 2724 | early.

      2725 |
    • 2726 |
    • onComplete: function (): called when all exports have been 2727 | enumerated
    • 2728 |
    2729 |
  • 2730 |
  • 2731 |

    Module.enumerateExportsSync(name): synchronous version of 2732 | enumerateExports() that returns the exports in an array.

    2733 |
  • 2734 |
  • 2735 |

    Module.enumerateRanges(name, protection, callbacks): just like 2736 | Process#enumerateRanges, except it’s scoped to the specified module 2737 | name.

    2738 |
  • 2739 |
  • 2740 |

    Module.enumerateRangesSync(name, protection): synchronous version of 2741 | enumerateRanges() that returns the ranges in an array.

    2742 |
  • 2743 |
  • 2744 |

    Module.findBaseAddress(name): returns the base address of the name 2745 | module, or null if the module isn’t loaded

    2746 |
  • 2747 |
  • 2748 |

    Module.findExportByName(module|null, exp): returns the absolute address of 2749 | the export named exp in module. If the module isn’t known you may pass 2750 | null instead of its name, but this can be a costly search and should be 2751 | avoided.

    2752 |
  • 2753 |
2754 | 2755 |

Memory

2756 | 2757 |
    2758 |
  • 2759 |

    Memory.scan(address, size, pattern, callbacks): scan memory for 2760 | occurences of pattern in the memory range given by address and size.

    2761 | 2762 |
      2763 |
    • 2764 |

      pattern must be of the form “13 37 ?? ff” to match 0x13 followed by 2765 | 0x37 followed by any byte followed by 0xff

      2766 |
    • 2767 |
    • 2768 |

      callbacks is an object with:

      2769 | 2770 |
        2771 |
      • 2772 |

        onMatch: function (address, size): called with address 2773 | containing the address of the occurence as a NativePointer and 2774 | size specifying the size as a JavaScript number.

        2775 | 2776 |

        This function may return the string stop to cancel the memory 2777 | scanning early.

        2778 |
      • 2779 |
      • 2780 |

        onError: function (reason): called with reason when there was a 2781 | memory access error while scanning

        2782 |
      • 2783 |
      • 2784 |

        onComplete: function (): called when the memory range has been 2785 | fully scanned

        2786 |
      • 2787 |
      2788 |
    • 2789 |
    2790 |
  • 2791 |
  • 2792 |

    Memory.scanSync(address, size, pattern): synchronous version of scan() 2793 | that returns the matches in an array.

    2794 |
  • 2795 |
  • 2796 |

    Memory.alloc(size): allocate size bytes of memory on the heap. The 2797 | returned object is a NativePointer and the heap memory will be released 2798 | when all JavaScript handles to it are gone. This means you need to keep 2799 | a reference to it while the pointer is being used by code outside the 2800 | JavaScript runtime.

    2801 |
  • 2802 |
  • 2803 |

    Memory.copy(dst, src, n): just like memcpy.

    2804 |
  • 2805 |
  • 2806 |

    Memory.dup(address, size): short-hand for Memory.alloc() followed by 2807 | Memory.copy().

    2808 |
  • 2809 |
  • 2810 |

    Memory.protect(address, size, protection): update protection on a region 2811 | of memory, where protection is a string of the same format as 2812 | Process.enumerateRanges().

    2813 | 2814 |

    For example:

    2815 |
  • 2816 |
2817 | 2818 |
Memory.protect(ptr("0x1234"), 4096, 'rw-');
2819 | 2820 |
    2821 |
  • 2822 |

    Memory.readPointer(address): read a pointer from address and return 2823 | it as a NativePointer.

    2824 | 2825 |

    A JavaScript exception will be thrown if address isn’t readable.

    2826 |
  • 2827 |
  • 2828 |

    Memory.writePointer(address, ptr): write ptr to address.

    2829 | 2830 |

    A JavaScript exception will be thrown if address isn’t writable.

    2831 |
  • 2832 |
  • 2833 |

    Memory.readS8(address), Memory.readU8(address), 2834 | Memory.readS16(address), Memory.readU16(address), 2835 | Memory.readS32(address), Memory.readU32(address), 2836 | Memory.readShort(address), Memory.readUShort(address), 2837 | Memory.readInt(address), Memory.readUInt(address), 2838 | Memory.readFloat(address), Memory.readDouble(address): 2839 | read a signed or unsigned 8/16/32/etc. or float/double value from 2840 | address and return it as a JavaScript number.

    2841 | 2842 |

    A JavaScript exception will be thrown if address isn’t readable.

    2843 |
  • 2844 |
  • 2845 |

    Memory.writeS8(address, value), Memory.writeU8(address, value), 2846 | Memory.writeS16(address, value), Memory.writeU16(address, value), 2847 | Memory.writeS32(address, value), Memory.writeU32(address, value), 2848 | Memory.writeShort(address, value), Memory.writeUShort(address, value), 2849 | Memory.writeInt(address, value), Memory.writeUInt(address, value), 2850 | Memory.writeFloat(address, value), Memory.writeDouble(address, value): 2851 | write the JavaScript number value to the signed or unsigned 2852 | 8/16/32/etc. or float/double value at address.

    2853 | 2854 |

    A JavaScript exception will be thrown if address isn’t writable.

    2855 |
  • 2856 |
  • 2857 |

    Memory.readS64(address), Memory.readU64(address), 2858 | Memory.readLong(address), Memory.readULong(address): 2859 | read a signed or unsigned 64-bit, or long-sized, value from address` and 2860 | return it as an Int64/UInt64 object.

    2861 | 2862 |

    A JavaScript exception will be thrown if address isn’t readable.

    2863 |
  • 2864 |
  • 2865 |

    Memory.writeS64(address, value), Memory.writeU64(address, value), 2866 | Memory.writeLong(address, value), Memory.writeULong(address, value): 2867 | write the Int64/UInt64 value to the signed or unsigned 64-bit, or 2868 | long-sized, value at address.

    2869 | 2870 |

    A JavaScript exception will be thrown if address isn’t writable.

    2871 |
  • 2872 |
  • 2873 |

    Memory.readByteArray(address, length): read length bytes from address 2874 | and return it as an ArrayBuffer. This buffer may be efficiently transferred 2875 | to your Frida-based application by passing it as the second argument to 2876 | send().

    2877 | 2878 |

    A JavaScript exception will be thrown if any of the length bytes read from 2879 | address isn’t readable.

    2880 |
  • 2881 |
  • 2882 |

    Memory.writeByteArray(address, bytes): write bytes to address, where 2883 | the former is either an ArrayBuffer, typically returned from 2884 | Memory.readByteArray(), or an array of integers between 0 and 255. For 2885 | example: [ 0x13, 0x37, 0x42 ].

    2886 | 2887 |

    A JavaScript exception will be thrown if any of the bytes written to 2888 | address isn’t writable.

    2889 |
  • 2890 |
  • 2891 |

    Memory.readCString(address[, size = -1]), 2892 | Memory.readUtf8String(address[, size = -1]), 2893 | Memory.readUtf16String(address[, length = -1]), 2894 | Memory.readAnsiString(address[, size = -1]): 2895 | read the bytes at address as an ASCII, UTF-8, UTF-16 or ANSI string. 2896 | Supply the optional size argument if you know the size of the string 2897 | in bytes, or omit it or specify -1 if the string is NUL-terminated. 2898 | Likewise you may supply the optional length argument if you know the 2899 | length of the string in characters.

    2900 | 2901 |

    A JavaScript exception will be thrown if any of the size / length bytes 2902 | read from address isn’t readable.

    2903 | 2904 |

    Note that readAnsiString() is only available (and relevant) on Windows.

    2905 |
  • 2906 |
  • 2907 |

    Memory.writeUtf8String(address, str), 2908 | Memory.writeUtf16String(address, str), 2909 | Memory.writeAnsiString(address, str): 2910 | encode and write the JavaScript string to address (with NUL-terminator).

    2911 | 2912 |

    A JavaScript exception will be thrown if any of the bytes written to 2913 | address isn’t writable.

    2914 | 2915 |

    Note that writeAnsiString() is only available (and relevant) on Windows.

    2916 |
  • 2917 |
  • 2918 |

    Memory.allocUtf8String(str), 2919 | Memory.allocUtf16String(str), 2920 | Memory.allocAnsiString(str): 2921 | allocate, encode and write out str as a UTF-8/UTF-16/ANSI string on the 2922 | heap. The returned object is a NativePointer. See Memory#alloc for 2923 | details about its lifetime.

    2924 |
  • 2925 |
2926 | 2927 |

MemoryAccessMonitor

2928 | 2929 |
2930 |
MemoryAccessMonitor is only available on Windows for now
2931 |

2932 | We would love to support this on the other platforms too, so if you find 2933 | this useful and would like to help out, please get in touch. 2934 |

2935 |
2936 | 2937 |
    2938 |
  • 2939 |

    MemoryAccessMonitor.enable(ranges, callbacks): monitor one or more memory 2940 | ranges for access, and notify on the first access of each contained memory 2941 | page. ranges is either a single range object or an array of such objects, 2942 | each of which contains:

    2943 | 2944 |
      2945 |
    • base: base address as a NativePointer
    • 2946 |
    • size: size in bytes
    • 2947 |
    2948 | 2949 |

    callbacks is an object specifying:

    2950 | 2951 |
      2952 |
    • onAccess: function (details): called synchronously with details 2953 | object containing: 2954 |
        2955 |
      • operation: the kind of operation that triggered the access, as a 2956 | string specifying either read, write or execute
      • 2957 |
      • from: address of instruction performing the access as a 2958 | NativePointer
      • 2959 |
      • address: address being accessed as a NativePointer
      • 2960 |
      • rangeIndex: index of the accessed range in the ranges provided to 2961 | MemoryAccessMonitor.enable()
      • 2962 |
      • pageIndex: index of the accessed memory page inside the specified 2963 | range
      • 2964 |
      • pagesCompleted: overall number of pages which have been accessed 2965 | so far (and are no longer being monitored)
      • 2966 |
      • pagesTotal: overall number of pages that were initially monitored
      • 2967 |
      2968 |
    • 2969 |
    2970 |
  • 2971 |
  • 2972 |

    MemoryAccessMonitor.disable(): stop monitoring the remaining memory ranges 2973 | passed to MemoryAccessMonitor.enable()

    2974 |
  • 2975 |
2976 | 2977 |

Thread

2978 | 2979 |
    2980 |
  • 2981 |

    Thread.backtrace([context, backtracer]): generate a backtrace for the 2982 | current thread, returned as an array of NativePointer objects.

    2983 | 2984 |

    If you call this from Interceptor’s onEnter or onLeave callbacks you 2985 | should provide this.context for the optional context argument, as it 2986 | will give you a more accurate backtrace. Omitting context means the 2987 | backtrace will be generated from the current stack location, which may 2988 | not give you a very good backtrace due to V8’s stack frames. 2989 | The optional backtracer argument specifies the kind of backtracer to use, 2990 | and must be either Backtracer.FUZZY or Backtracer.ACCURATE, where the 2991 | latter is the default if not specified. The accurate kind of backtracers 2992 | rely on debugger-friendly binaries or presence of debug information to do a 2993 | good job, whereas the fuzzy backtracers perform forensics on the stack in 2994 | order to guess the return addresses, which means you will get false 2995 | positives, but it will work on any binary.

    2996 |
  • 2997 |
2998 | 2999 |
var f = Module.findExportByName("libcommonCrypto.dylib",
3000 |     "CCCryptorCreate");
3001 | Interceptor.attach(f, {
3002 |     onEnter: function (args) {
3003 |         console.log("CCCryptorCreate called from:\n" +
3004 |             Thread.backtrace(this.context, Backtracer.ACCURATE)
3005 |             .map(DebugSymbol.fromAddress).join("\n") + "\n");
3006 |     }
3007 | });
3008 | 3009 |
    3010 |
  • Thread.sleep(delay): suspend execution of the current thread for delay 3011 | seconds specified as a JavaScript number. For example 0.05 to sleep for 3012 | 50 ms.
  • 3013 |
3014 | 3015 |

Int64

3016 | 3017 |
    3018 |
  • 3019 |

    new Int64(v): create a new Int64 from v, which is either a JavaScript 3020 | Number or a string containing a value in decimal, or hexadecimal if prefixed 3021 | with “0x”. You may use the int64(v) short-hand for brevity.

    3022 |
  • 3023 |
  • 3024 |

    add(rhs), sub(rhs), 3025 | and(rhs), or(rhs), 3026 | xor(rhs): 3027 | make a new Int64 with this Int64 plus/minus/and/or/xor rhs, which may 3028 | either be a JavaScript number or another Int64

    3029 |
  • 3030 |
  • 3031 |

    shr(n), shl(n): 3032 | make a new Int64 with this Int64 shifted right/left by n bits

    3033 |
  • 3034 |
  • 3035 |

    compare(rhs): returns an integer comparison result just like 3036 | String#localeCompare()

    3037 |
  • 3038 |
  • 3039 |

    toNumber(): cast this Int64 to a JavaScript Number

    3040 |
  • 3041 |
  • 3042 |

    toString([radix = 10]): convert to a string of optional radix (defaults to 3043 | 10)

    3044 |
  • 3045 |
3046 | 3047 |

UInt64

3048 | 3049 |
    3050 |
  • 3051 |

    new UInt64(v): create a new UInt64 from v, which is either a JavaScript 3052 | Number or a string containing a value in decimal, or hexadecimal if prefixed 3053 | with “0x”. You may use the uint64(v) short-hand for brevity.

    3054 |
  • 3055 |
  • 3056 |

    add(rhs), sub(rhs), 3057 | and(rhs), or(rhs), 3058 | xor(rhs): 3059 | make a new UInt64 with this UInt64 plus/minus/and/or/xor rhs, which may 3060 | either be a JavaScript number or another UInt64

    3061 |
  • 3062 |
  • 3063 |

    shr(n), shl(n): 3064 | make a new UInt64 with this UInt64 shifted right/left by n bits

    3065 |
  • 3066 |
  • 3067 |

    compare(rhs): returns an integer comparison result just like 3068 | String#localeCompare()

    3069 |
  • 3070 |
  • 3071 |

    toNumber(): cast this UInt64 to a JavaScript Number

    3072 |
  • 3073 |
  • 3074 |

    toString([radix = 10]): convert to a string of optional radix (defaults to 3075 | 10)

    3076 |
  • 3077 |
3078 | 3079 |

NativePointer

3080 | 3081 |
    3082 |
  • 3083 |

    new NativePointer(s): create a new NativePointer from the string s 3084 | containing a memory address in either decimal, or hexadecimal if prefixed 3085 | with “0x”. You may use the ptr(s) short-hand for brevity.

    3086 |
  • 3087 |
  • 3088 |

    isNull(): returns a boolean allowing you to conveniently check if a 3089 | pointer is NULL

    3090 |
  • 3091 |
  • 3092 |

    add(rhs), sub(rhs), 3093 | and(rhs), or(rhs), 3094 | xor(rhs): 3095 | make a new NativePointer with this NativePointer plus/minus/and/or/xor 3096 | rhs, which may either be a JavaScript number or another NativePointer

    3097 |
  • 3098 |
  • 3099 |

    shr(n), shl(n): 3100 | make a new NativePointer with this NativePointer shifted right/left by n 3101 | bits

    3102 |
  • 3103 |
  • 3104 |

    equals(rhs): returns a boolean indicating whether rhs is equal to 3105 | this one; i.e. it has the same pointer value

    3106 |
  • 3107 |
  • 3108 |

    compare(rhs): returns an integer comparison result just like 3109 | String#localeCompare()

    3110 |
  • 3111 |
  • 3112 |

    toInt32(): cast this NativePointer to a signed 32-bit integer

    3113 |
  • 3114 |
  • 3115 |

    toString([radix = 16]): convert to a string of optional radix (defaults to 3116 | 16)

    3117 |
  • 3118 |
  • 3119 |

    toMatchPattern(): returns a string containing a Memory.scan()-compatible 3120 | match pattern for this pointer’s raw value

    3121 |
  • 3122 |
3123 | 3124 |

NativeFunction

3125 | 3126 |
    3127 |
  • 3128 |

    new NativeFunction(address, returnType, argTypes[, abi]): create a new 3129 | NativeFunction to call the function at address (specified with a 3130 | NativePointer), where returnType specifies the return type, and the 3131 | argTypes array specifies the argument types. You may optionally also 3132 | specify abi if not system default. For variadic functions, add a '...' 3133 | entry to argTypes between the fixed arguments and the variadic ones.

    3134 | 3135 |

    Structs & Classes by Value

    3136 | 3137 |

    As for structs or classes passed by value, instead of a string provide an 3138 | array containing the struct’s field types following each other. You may nest 3139 | these as deep as desired for representing structs inside structs. Note that 3140 | the returned object is also a NativePointer, and can thus be passed to 3141 | Interceptor#attach.

    3142 | 3143 |

    This must match the struct/class exactly, so if you have a struct with three 3144 | ints, you must pass ['int', 'int', 'int'].

    3145 | 3146 |

    For a class that has virtual methods, the first parameter will be a pointer 3147 | to the vtable.

    3148 | 3149 |

    For C++ scenarios involving a return value that is larger than 3150 | Process.pointerSize, a NativePointer to preallocated space must be passed 3151 | in as the first parameter. (This scenario is common in WebKit, for example.)

    3152 | 3153 |

    Example:

    3154 |
  • 3155 |
3156 | 3157 |
// LargeObject HandyClass::friendlyFunctionName();
3158 | var friendlyFunctionName = new NativeFunction(friendlyFunctionPtr, 'void', ['pointer', 'pointer']);
3159 | var returnValue = Memory.alloc(sizeOfLargeObject);
3160 | friendlyFunctionName(returnValue, thisPtr);
3161 | 3162 |
### Supported Types
3163 | 
3164 | -   void
3165 | -   pointer
3166 | -   int
3167 | -   uint
3168 | -   long
3169 | -   ulong
3170 | -   char
3171 | -   uchar
3172 | -   float
3173 | -   double
3174 | -   int8
3175 | -   uint8
3176 | -   int16
3177 | -   uint16
3178 | -   int32
3179 | -   uint32
3180 | -   int64
3181 | -   uint64
3182 | 
3183 | ### Supported ABIs
3184 | 
3185 | -   default
3186 | 
3187 | -   Windows 32-bit:
3188 |     -   sysv
3189 |     -   stdcall
3190 |     -   thiscall
3191 |     -   fastcall
3192 |     -   mscdecl
3193 | 
3194 | - Windows 64-bit:
3195 |     -   win64
3196 | 
3197 | - UNIX x86:
3198 |     -   sysv
3199 |     -   unix64
3200 | 
3201 | - UNIX ARM:
3202 |     -   sysv
3203 |     -   vfp
3204 | 
3205 | 3206 |

NativeCallback

3207 | 3208 |
    3209 |
  • new NativeCallback(func, returnType, argTypes[, abi]): create a new 3210 | NativeCallback implemented by the JavaScript function func, where 3211 | returnType specifies the return type, and the argTypes array specifies 3212 | the argument types. You may also specify the abi if not system default. 3213 | See NativeFunction for details about supported types and abis. 3214 | Note that the returned object is also a NativePointer, and can thus be 3215 | passed to Interceptor#replace.
  • 3216 |
3217 | 3218 |

Socket

3219 | 3220 |
    3221 |
  • 3222 |

    Socket.type(handle): inspect the OS socket handle and return its type 3223 | as a string which is either tcp, udp, tcp6, udp6, unix:stream, 3224 | unix:dgram, or null if invalid or unknown.

    3225 |
  • 3226 |
  • 3227 |

    Socket.localAddress(handle), 3228 | Socket.peerAddress(handle): 3229 | inspect the OS socket handle and return its local or peer address, or 3230 | null if invalid or unknown.

    3231 | 3232 |

    The object returned has the fields:

    3233 | 3234 |
      3235 |
    • ip: (IP sockets) IP address as a string.
    • 3236 |
    • port: (IP sockets) Port number as a JavaScript number.
    • 3237 |
    • path: (UNIX sockets) UNIX path as a string.
    • 3238 |
    3239 |
  • 3240 |
3241 | 3242 |

Stream

3243 | 3244 |
    3245 |
  • 3246 |

    new UnixInputStream(fd[, options]), 3247 | new UnixOutputStream(fd[, options]), 3248 | new Win32InputStream(handle[, options]), 3249 | new Win32OutputStream(handle[, options]): create a new stream object 3250 | from the file descriptor fd (UNIX) or file HANDLE handle (Windows). 3251 | You may also supply an options object with autoClose set to true to 3252 | make the stream close the underlying OS resource when the stream is 3253 | released, either through close() or future garbage-collection.

    3254 | 3255 |

    All methods of the returned object are fully asynchronous and return a 3256 | Promise object.

    3257 |
  • 3258 |
  • 3259 |

    close(): close the stream, releasing resources related to it. Once the 3260 | stream is closed, all other operations will fail. Closing a stream multiple 3261 | times is allowed and will not result in an error.

    3262 |
  • 3263 |
  • 3264 |

    InputStream#read(size): read up to size bytes from the stream. The 3265 | returned Promise receives an ArrayBuffer up to size bytes long. End of 3266 | stream is signalled through an empty buffer.

    3267 |
  • 3268 |
  • 3269 |

    InputStream#readAll(size): keep reading from the stream until exactly 3270 | size bytes have been consumed. The returned Promise receives an 3271 | ArrayBuffer that is exactly size bytes long. Premature error or end of 3272 | stream results in the Promise getting rejected with an error, where the 3273 | Error object has a partialData property containing the incomplete data.

    3274 |
  • 3275 |
  • 3276 |

    OutputStream#write(data): try to write data to the stream. The data 3277 | value is either an ArrayBuffer or an array of integers between 0 and 255. 3278 | The returned Promise receives a Number specifying how many bytes of 3279 | data were written to the stream.

    3280 |
  • 3281 |
  • 3282 |

    OutputStream#writeAll(data): keep writing to the stream until all of 3283 | data has been written. The data value is either an ArrayBuffer or an 3284 | array of integers between 0 and 255. Premature error or end of stream 3285 | results in an error, where the Error object has a partialSize property 3286 | specifying how many bytes of data were written to the stream before the 3287 | error occurred.

    3288 |
  • 3289 |
3290 | 3291 |

File

3292 | 3293 |
    3294 |
  • 3295 |

    new File(filePath, mode): open or create the file at filePath with 3296 | the mode string specifying how it should be opened. For example "wb" 3297 | to open the file for writing in binary mode (this is the same format as 3298 | fopen() from the C standard library).

    3299 |
  • 3300 |
  • 3301 |

    write(data): synchronously write data to the file, where data is 3302 | either a string or a buffer as returned by Memory#readByteArray

    3303 |
  • 3304 |
  • 3305 |

    flush(): flush any buffered data to the underlying file

    3306 |
  • 3307 |
  • 3308 |

    close(): close the file. You should call this function when you’re done 3309 | with the file. Any remaining buffered data will automatically be flushed 3310 | before closure.

    3311 |
  • 3312 |
3313 | 3314 |

Interceptor

3315 | 3316 |
    3317 |
  • 3318 |

    Interceptor.attach(target, callbacks): intercept calls to function at 3319 | target. This is a NativePointer specifying the address of the function 3320 | you would like to intercept calls to. Note that on 32-bit ARM this address 3321 | must have its least significant bit set to 0 for ARM functions, and 1 for 3322 | Thumb functions. Frida takes care of this detail for you if you get the 3323 | address from a Frida API (for example Module.findExportByName()).

    3324 | 3325 |

    The callbacks argument is an object containing one or more of:

    3326 | 3327 |
      3328 |
    • 3329 |

      onEnter: function (args): callback function given one argument 3330 | args that can be used to read or write arguments as an array of 3331 | NativePointer objects.

      3332 |
    • 3333 |
    • 3334 |

      onLeave: function (retval): callback function given one argument 3335 | retval that is a NativePointer-derived object containing the raw 3336 | return value. 3337 | You may call retval.replace(1337) to replace the return value with 3338 | the integer 1337, or retval.replace(ptr("0x1234")) to replace with 3339 | a pointer. 3340 | Note that this object is recycled across onLeave calls, so do not 3341 | store and use it outside your callback. Make a deep copy if you need 3342 | to store the contained value, e.g.: ptr(retval.toString()).

      3343 |
    • 3344 |
    3345 | 3346 |

    You may also intercept arbitrary instructions by passing a function instead 3347 | of the callbacks object. This function has the same signature as 3348 | onEnter, but the args argument passed to it will only give you sensible 3349 | values if the intercepted instruction is at the beginning of a function or 3350 | at a point where registers/stack have not yet deviated from that point.

    3351 | 3352 |

    Returns a listener object that you can call detach() on.

    3353 | 3354 |

    Note that these functions will be invoked with this bound to a 3355 | per-invocation (thread-local) object where you can store arbitrary data, 3356 | which is useful if you want to read an argument in onEnter and act on it 3357 | in onLeave.

    3358 | 3359 |

    For example:

    3360 |
  • 3361 |
3362 | 3363 |
Interceptor.attach(Module.findExportByName("libc.so", "read"), {
3364 |     onEnter: function (args) {
3365 |         this.fileDescriptor = args[0].toInt32();
3366 |     },
3367 |     onLeave: function (retval) {
3368 |         if (retval.toInt32() > 0) {
3369 |             /* do something with this.fileDescriptor */
3370 |         }
3371 |     }
3372 | });
3373 | 3374 |
    3375 |
  • 3376 |

    Additionally, the object contains some useful properties:

    3377 | 3378 |
      3379 |
    • 3380 |

      returnAddress: return address as a NativePointer

      3381 |
    • 3382 |
    • 3383 |

      context: object with the keys pc and sp, which are 3384 | NativePointer objects specifying EIP/RIP/PC and ESP/RSP/SP, 3385 | respectively, for ia32/x64/arm. Other processor-specific keys 3386 | are also available, e.g. eax, rax, r0, x0, etc. 3387 | You may also update register values by assigning to these keys.

      3388 |
    • 3389 |
    • 3390 |

      errno: (UNIX) current errno value (you may replace it)

      3391 |
    • 3392 |
    • 3393 |

      lastError: (Windows) current OS error value (you may replace it)

      3394 |
    • 3395 |
    • 3396 |

      threadId: OS thread ID

      3397 |
    • 3398 |
    • 3399 |

      depth: call depth of relative to other invocations

      3400 |
    • 3401 |
    3402 |
  • 3403 |
3404 | 3405 |
3406 |
Performance considerations
3407 |

3408 | The callbacks provided have a significant impact on performance. If you only 3409 | need to inspect arguments but do not care about the return value, or the 3410 | other way around, make sure you omit the callback that you don't need; i.e. 3411 | avoid putting your logic in onEnter and leaving onLeave in 3412 | there as an empty callback. 3413 |

3414 |

3415 | On an iPhone 5S the base overhead when providing just onEnter might be 3416 | something like 6 microseconds, and 11 microseconds with both onEnter 3417 | and onLeave provided. 3418 |

3419 |

3420 | Also be careful about intercepting calls to functions that are called a 3421 | bazillion times per second; while send() is asynchronous, the total 3422 | overhead of sending a single message is not optimized for high frequencies, 3423 | so that means Frida leaves it up to you to batch multiple values into a 3424 | single send()-call, based on whether low delay or high throughput 3425 | is desired. 3426 |

3427 |
3428 | 3429 |
    3430 |
  • 3431 |

    Interceptor.detachAll(): detach all previously attached callbacks.

    3432 |
  • 3433 |
  • 3434 |

    Interceptor.replace(target, replacement): replace function at target 3435 | with implementation at replacement. This is typically used if you want 3436 | to fully or partially replace an existing function’s implementation. Use 3437 | NativeCallback to implement a replacement in JavaScript. Note that 3438 | replacement will be kept alive until Interceptor#revert is called. 3439 | If you want to chain to the original implementation you can synchronously 3440 | call target through a NativeFunction inside your implementation, which 3441 | will bypass and go directly to the original implementation.

    3442 | 3443 |

    Here’s an example:

    3444 |
  • 3445 |
3446 | 3447 |
var openPtr = Module.findExportByName("libc.so", "open");
3448 | var open = new NativeFunction(openPtr, 'int', ['pointer', 'int']);
3449 | Interceptor.replace(openPtr, new NativeCallback(function (pathPtr, flags) {
3450 |     var path = Memory.readUtf8String(pathPtr);
3451 |     log("Opening '" + path + "'");
3452 |     var fd = open(pathPtr, flags);
3453 |     log("Got fd: " + fd);
3454 |     return fd;
3455 | }, 'int', ['pointer', 'int']));
3456 | 3457 |
    3458 |
  • Interceptor.revert(target): revert function at target to the previous 3459 | implementation.
  • 3460 |
3461 | 3462 |

Stalker

3463 | 3464 |
    3465 |
  • 3466 |

    Stalker.follow([threadId, options]): start stalking threadId (or the 3467 | current thread if omitted), optionally with options for enabling events.

    3468 | 3469 |

    For example:

    3470 |
  • 3471 |
3472 | 3473 |
Stalker.follow(Process.getCurrentThreadId(), {
3474 |   events: {
3475 |     call: true, // CALL instructions: yes please
3476 |     ret: false, // RET instructions: no thanks
3477 |     exec: false // all instructions: no thanks
3478 |   },
3479 |   onReceive: function (events) {
3480 |     // Called with `events` containing a binary blob which is one or more
3481 |     // GumEvent structs.  See `gumevent.h` for the format. This is obviously a
3482 |     // terrible API that is subject to change once a better trade-off between
3483 |     // ease-of-use and performance has been found.
3484 |   },
3485 |   onCallSummary: function (summary) {
3486 |     // Called with `summary` being a key-value mapping of call target to number
3487 |     // of calls, in the current time window. You would typically implement this
3488 |     // instead of `onReceive` for efficiency.
3489 |   }
3490 | });
3491 | 3492 |
3493 |
Performance considerations
3494 |

3495 | The callbacks provided have a significant impact on performance. If you only 3496 | need periodic call summaries but do not care about the raw events, or the 3497 | other way around, make sure you omit the callback that you don't need; i.e. 3498 | avoid putting your logic in onCallSummary and leaving 3499 | onReceive in there as an empty callback. 3500 |

3501 |
3502 | 3503 |
    3504 |
  • 3505 |

    Stalker.unfollow([threadId]): stop stalking threadId (or the current 3506 | thread if omitted).

    3507 |
  • 3508 |
  • 3509 |

    Stalker.garbageCollect(): free accumulated memory at a safe point after 3510 | Stalker#unfollow. This is needed to avoid race-conditions where the 3511 | thread just unfollowed is executing its last instructions.

    3512 |
  • 3513 |
  • 3514 |

    Stalker.addCallProbe(address, callback): call callback (see 3515 | Interceptor#attach#onEnter for signature) synchronously when a CALL is 3516 | made to address. Returns an id that can be passed to 3517 | Stalker#removeCallProbe later.

    3518 |
  • 3519 |
  • 3520 |

    Stalker.removeCallProbe: remove a call probe added by 3521 | Stalker#addCallProbe.

    3522 |
  • 3523 |
  • 3524 |

    Stalker.trustThreshold: an integer specifying how many times a piece of 3525 | code needs to be executed before it is assumed it can be trusted to not 3526 | mutate. 3527 | Specify -1 for no trust (slow), 0 to trust code from the get-go, and N to 3528 | trust code after it has been executed N times. Defaults to 1.

    3529 |
  • 3530 |
  • 3531 |

    Stalker.queueCapacity: an integer specifying the capacity of the event 3532 | queue in number of events. Defaults to 16384 events.

    3533 |
  • 3534 |
  • 3535 |

    Stalker.queueDrainInterval: an integer specifying the time in milliseconds 3536 | between each time the event queue is drained. Defaults to 250 ms, which 3537 | means that the event queue is drained four times per second.

    3538 |
  • 3539 |
3540 | 3541 |

ApiResolver

3542 | 3543 |
    3544 |
  • 3545 |

    new ApiResolver(type): create a new resolver of the given type, allowing 3546 | you to quickly find functions by name, with globs permitted. Precisely which 3547 | resolvers are available depends on the current platform and runtimes loaded 3548 | in the current process. As of the time of writing, the available resolvers 3549 | are:

    3550 | 3551 |
      3552 |
    • module: Resolves exported and imported functions of shared libraries 3553 | currently loaded. Always available.
    • 3554 |
    • objc: Resolves Objective-C methods of classes currently loaded. 3555 | Available on macOS and iOS in processes that have the Objective-C 3556 | runtime loaded. Use ObjC.available to check at runtime, or 3557 | wrap your new ApiResolver('objc') call in a try-catch.
    • 3558 |
    3559 | 3560 |

    The resolver will load the minimum amount of data required on creation, and 3561 | lazy-load the rest depending on the queries it receives. It is thus 3562 | recommended to use the same instance for a batch of queries, but recreate it 3563 | for future batches to avoid looking at stale data.

    3564 |
  • 3565 |
  • 3566 |

    enumerateMatches(query, callbacks): perform the resolver-specific query 3567 | string, where callbacks is an object specifying:

    3568 | 3569 |
      3570 |
    • 3571 |

      onMatch: function (match): called for each match, where match is an 3572 | object with name and address keys.

      3573 |
    • 3574 |
    • 3575 |

      onComplete: function (): called when all matches have been enumerated.

      3576 |
    • 3577 |
    3578 |
  • 3579 |
3580 | 3581 |
var resolver = new ApiResolver('module');
3582 | resolver.enumerateMatches('exports:*!open*', {
3583 |   onMatch: function (match) {
3584 |     /*
3585 |      * Where `match` contains an object like this one:
3586 |      *
3587 |      * {
3588 |      *     name: '/usr/lib/libSystem.B.dylib!opendir$INODE64',
3589 |      *     address: ptr('0x7fff870135c9')
3590 |      * }
3591 |      */
3592 |   },
3593 |   onComplete: function () {
3594 |   }
3595 | });
3596 | 3597 |
var resolver = new ApiResolver('objc');
3598 | resolver.enumerateMatches('-[NSURL* *HTTP*]', {
3599 |   onMatch: function (match) {
3600 |     /*
3601 |      * Where `match` contains an object like this one:
3602 |      *
3603 |      * {
3604 |      *     name: '-[NSURLRequest valueForHTTPHeaderField:]',
3605 |      *     address: ptr('0x7fff94183e22')
3606 |      * }
3607 |      */
3608 |   },
3609 |   onComplete: function () {
3610 |   }
3611 | });
3612 | 3613 |
    3614 |
  • enumerateMatchesSync(query): synchronous version of enumerateMatches() 3615 | that returns the matches in an array.
  • 3616 |
3617 | 3618 |

DebugSymbol

3619 | 3620 |
    3621 |
  • 3622 |

    DebugSymbol.fromAddress(address), DebugSymbol.fromName(name): 3623 | look up debug information for address/name and return it as an object 3624 | containing:

    3625 | 3626 |
      3627 |
    • address: Address that this symbol is for, as a NativePointer.
    • 3628 |
    • name: Name of the symbol, as a string.
    • 3629 |
    • moduleName: Module name owning this symbol, as a string.
    • 3630 |
    • fileName: File name owning this symbol, as a string.
    • 3631 |
    • lineNumber: Line number in fileName, as a JavaScript number.
    • 3632 |
    3633 | 3634 |

    You may also call toString() on it, which is very useful when combined 3635 | with Thread.backtrace():

    3636 |
  • 3637 |
3638 | 3639 |
var f = Module.findExportByName("libcommonCrypto.dylib",
3640 |     "CCCryptorCreate");
3641 | Interceptor.attach(f, {
3642 |     onEnter: function (args) {
3643 |         console.log("CCCryptorCreate called from:\n" +
3644 |             Thread.backtrace(this.context, Backtracer.ACCURATE)
3645 |             .map(DebugSymbol.fromAddress).join("\n") + "\n");
3646 |     }
3647 | });
3648 | 3649 |
    3650 |
  • 3651 |

    DebugSymbol.getFunctionByName(name): resolves a function name and 3652 | returns its address as a NativePointer. Returns the first if more than 3653 | one function is found. Throws an exception if the name cannot be resolved.

    3654 |
  • 3655 |
  • 3656 |

    DebugSymbol.findFunctionsNamed(name): resolves a function name and returns 3657 | its addresses as an array of NativePointer objects.

    3658 |
  • 3659 |
  • 3660 |

    DebugSymbol.findFunctionsMatching(glob): resolves function names matching 3661 | glob and returns their addresses as an array of NativePointer objects.

    3662 |
  • 3663 |
3664 | 3665 |

Instruction

3666 | 3667 |
    3668 |
  • 3669 |

    Instruction.parse(target): parse the instruction at the target address 3670 | in memory, represented by a NativePointer. 3671 | Note that on 32-bit ARM this address must have its least significant bit 3672 | set to 0 for ARM functions, and 1 for Thumb functions. Frida takes care 3673 | of this detail for you if you get the address from a Frida API (for 3674 | example Module.findExportByName()).

    3675 | 3676 |

    The object returned has the fields:

    3677 | 3678 |
      3679 |
    • address: Address (EIP) of this instruction, as a NativePointer.
    • 3680 |
    • next: Pointer to the next instruction, so you can parse() it.
    • 3681 |
    • size: Size of this instruction.
    • 3682 |
    • mnemonic: String representation of instruction mnemonic.
    • 3683 |
    • opStr: String representation of instruction operands.
    • 3684 |
    • toString(): Convert to a human-readable string.
    • 3685 |
    3686 |
  • 3687 |
3688 | 3689 |

ObjC

3690 | 3691 |
    3692 |
  • 3693 |

    ObjC.available: a boolean specifying whether the current process has an 3694 | Objective-C runtime loaded. Do not invoke any other ObjC properties or 3695 | methods unless this is the case.

    3696 |
  • 3697 |
  • 3698 |

    ObjC.api: an object mapping function names to NativeFunction instances 3699 | for direct access to a big portion of the Objective-C runtime API.

    3700 |
  • 3701 |
  • 3702 |

    ObjC.classes: an object mapping class names to ObjC.Object JavaScript 3703 | bindings for each of the currently registered classes. You can interact with objects by using dot notation and replacing colons with underscores, i.e.: [NSString stringWithString:@"Hello World"] becomes var NSString = ObjC.classes.NSString; NSString.stringWithString_("Hello World");. Note the underscore after the method name. Refer to iOS Examples section for more details.

    3704 |
  • 3705 |
  • 3706 |

    ObjC.protocols: an object mapping protocol names to ObjC.Protocol 3707 | JavaScript bindings for each of the currently registered protocols.

    3708 |
  • 3709 |
  • 3710 |

    ObjC.mainQueue: the GCD queue of the main thread

    3711 |
  • 3712 |
  • 3713 |

    ObjC.schedule(queue, work): schedule the JavaScript function work on 3714 | the GCD queue specified by queue. An NSAutoreleasePool is created just 3715 | before calling work, and cleaned up on return.

    3716 |
  • 3717 |
3718 | 3719 |
var NSSound = ObjC.classes.NSSound; /* macOS */
3720 | ObjC.schedule(ObjC.mainQueue, function () {
3721 |     var sound = NSSound.alloc().initWithContentsOfFile_byReference_("/Users/oleavr/.Trash/test.mp3", true);
3722 |     sound.play();
3723 | });
3724 | 3725 |
    3726 |
  • new ObjC.Object(handle[, protocol]): create a JavaScript binding given 3727 | the existing object at handle (a NativePointer). You may also specify 3728 | the protocol argument if you’d like to treat handle as an object 3729 | implementing a certain protocol only.
  • 3730 |
3731 | 3732 |
Interceptor.attach(myFunction.implementation, {
3733 |   onEnter: function(args) {
3734 |     // ObjC: args[0] = self, args[1] = selector, args[2-n] = arguments
3735 |     var myString = new ObjC.Object(args[2]);
3736 |     console.log("String argument: " + myString.toString());
3737 |   }
3738 | });
3739 | 3740 |
3741 |

This object has some special properties:

3742 | 3743 |
    3744 |
  • $kind: string specifying either instance, class or meta-class
  • 3745 |
  • $super: an ObjC.Object instance used for chaining up to super-class 3746 | method implementations
  • 3747 |
  • $superClass: super-class as an ObjC.Object instance
  • 3748 |
  • $class: class of this object as an ObjC.Object instance
  • 3749 |
  • $className: string containing the class name of this object
  • 3750 |
  • $protocols: object mapping protocol name to ObjC.Protocol instance 3751 | for each of the protocols that this object conforms to
  • 3752 |
  • $methods: array containing native method names exposed by this object’s 3753 | class and parent classes
  • 3754 |
  • $ownMethods: array containing native method names exposed by this object’s 3755 | class, not including parent classes
  • 3756 |
  • $ivars: object mapping each instance variable name to its current 3757 | value, allowing you to read and write each through access and assignment
  • 3758 |
3759 | 3760 |

There is also an equals(other) method for checking whether two instances 3761 | refer to the same underlying object.

3762 |
3763 | 3764 |
    3765 |
  • 3766 |

    new ObjC.Protocol(handle): create a JavaScript binding given the existing 3767 | protocol at handle (a NativePointer).

    3768 |
  • 3769 |
  • 3770 |

    new ObjC.Block(target): create a JavaScript binding given the existing 3771 | block at target (a NativePointer), or, to define a new block, target 3772 | should be an object specifying the type signature and JavaScript function to 3773 | call whenever the block is invoked. The function is specified with an 3774 | implementation key, and the signature is specified either through a 3775 | types key, or through the retType and argTypes keys. See 3776 | ObjC.registerClass() for details.

    3777 | 3778 |

    The most common use-case is hooking an existing block, which for a block 3779 | expecting two arguments would look something like:

    3780 |
  • 3781 |
3782 | 3783 |
const pendingBlocks = new Set();
3784 | 
3785 | Interceptor.attach(..., {
3786 |   onEnter(args) {
3787 |     const block = new ObjC.Block(args[4]);
3788 |     pendingBlocks.add(block); // Keep it alive
3789 |     const appCallback = block.implementation;
3790 |     block.implementation = (error, value) => {
3791 |       // Do your logging here
3792 |       const result = appCallback(error, value);
3793 |       pendingBlocks.delete(block);
3794 |       return result;
3795 |     };
3796 |   }
3797 | });
3798 | 3799 |
    3800 |
  • ObjC.implement(method, fn): create a JavaScript implementation compatible 3801 | with the signature of method, where the JavaScript function fn is used 3802 | as the implementation. Returns a NativeCallback that you may assign to an 3803 | ObjC method’s implementation property.
  • 3804 |
3805 | 3806 |
var NSSound = ObjC.classes.NSSound; /* macOS */
3807 | var oldImpl = NSSound.play.implementation;
3808 | NSSound.play.implementation = ObjC.implement(NSSound.play, function (handle, selector) {
3809 |     return oldImpl(handle, selector);
3810 | });
3811 | 
3812 | var NSView = ObjC.classes.NSView; /* macOS */
3813 | var drawRect = NSView['- drawRect:'];
3814 | var oldImpl = drawRect.implementation;
3815 | drawRect.implementation = ObjC.implement(drawRect, function (handle, selector) {
3816 |     oldImpl(handle, selector);
3817 | });
3818 | 3819 |
3820 |

As the implementation property is a NativeFunction and thus also a 3821 | NativePointer, you may also use Interceptor to hook functions:

3822 |
3823 | 3824 |
var NSSound = ObjC.classes.NSSound; /* macOS */
3825 | Interceptor.attach(NSSound.play.implementation, {
3826 |     onEnter: function () {
3827 |         send("[NSSound play]");
3828 |     }
3829 | });
3830 | 3831 |
    3832 |
  • 3833 |

    ObjC.registerProxy(properties): create a new class designed to act as a 3834 | proxy for a target object, where properties is an object specifying:

    3835 | 3836 |
      3837 |
    • protocols: (optional) Array of protocols this class conforms to.
    • 3838 |
    • methods: (optional) Object specifying methods to implement.
    • 3839 |
    • events: (optional) Object specifying callbacks for getting notified 3840 | about events. For now there’s just one event: 3841 |
        3842 |
      • forward: function (name): Called with name specifying the 3843 | method name that we’re about to forward a call to. This might be 3844 | where you’d start out with a temporary callback that just logs the 3845 | names to help you decide which methods to override.
      • 3846 |
      3847 |
    • 3848 |
    3849 |
  • 3850 |
3851 | 3852 |
const MyConnectionDelegateProxy = ObjC.registerProxy({
3853 |   protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
3854 |   methods: {
3855 |     '- connection:didReceiveResponse:': function (conn, resp) {
3856 |       /* fancy logging code here */
3857 |       /* this.data.foo === 1234 */
3858 |       this.data.target
3859 |           .connection_didReceiveResponse_(conn, resp);
3860 |     },
3861 |     '- connection:didReceiveData:': function (conn, data) {
3862 |       /* other logging code here */
3863 |       this.data.target
3864 |           .connection_didReceiveData_(conn, data);
3865 |     }
3866 |   },
3867 |   events: {
3868 |     forward: function (name) {
3869 |       console.log('*** forwarding: ' + name);
3870 |     }
3871 |   }
3872 | });
3873 | 
3874 | const method = ObjC.classes.NSURLConnection[
3875 |     '- initWithRequest:delegate:startImmediately:'];
3876 | Interceptor.attach(method.implementation, {
3877 |   onEnter: function (args) {
3878 |     args[3] = new MyConnectionDelegateProxy(args[3], {
3879 |       foo: 1234
3880 |     });
3881 |   }
3882 | });
3883 | 3884 |
    3885 |
  • 3886 |

    ObjC.registerClass(properties): create a new Objective-C class, where 3887 | properties is an object specifying:

    3888 | 3889 |
      3890 |
    • name: (optional) String specifying the name of the class; omit this 3891 | if you don’t care about the globally visible name and would like the 3892 | runtime to auto-generate one for you.
    • 3893 |
    • super: (optional) Super-class, or null to create a new root class; 3894 | omit to inherit from NSObject.
    • 3895 |
    • protocols: (optional) Array of protocols this class conforms to.
    • 3896 |
    • methods: (optional) Object specifying methods to implement.
    • 3897 |
    3898 |
  • 3899 |
3900 | 3901 |
const MyConnectionDelegateProxy = ObjC.registerClass({
3902 |   name: 'MyConnectionDelegateProxy',
3903 |   super: ObjC.classes.NSObject,
3904 |   protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
3905 |   methods: {
3906 |     '- init': function () {
3907 |       const self = this.super.init();
3908 |       if (self !== null) {
3909 |         ObjC.bind(self, {
3910 |           foo: 1234
3911 |         });
3912 |       }
3913 |       return self;
3914 |     },
3915 |     '- dealloc': function () {
3916 |       ObjC.unbind(this.self);
3917 |       this.super.dealloc();
3918 |     },
3919 |     '- connection:didReceiveResponse:': function (conn, resp) {
3920 |       /* this.data.foo === 1234 */
3921 |     },
3922 |     /*
3923 |      * But those previous methods are declared assuming that
3924 |      * either the super-class or a protocol we conform to has
3925 |      * the same method so we can grab its type information.
3926 |      * However, if that's not the case, you would write it
3927 |      * like this:
3928 |      */
3929 |     '- connection:didReceiveResponse:': {
3930 |       retType: 'void',
3931 |       argTypes: ['object', 'object'],
3932 |       implementation: function (conn, resp) {
3933 |       }
3934 |     },
3935 |     /* Or grab it from an existing class: */
3936 |     '- connection:didReceiveResponse:': {
3937 |       types: ObjC.classes
3938 |           .Foo['- connection:didReceiveResponse:'].types,
3939 |       implementation: function (conn, resp) {
3940 |       }
3941 |     },
3942 |     /* Or from an existing protocol: */
3943 |     '- connection:didReceiveResponse:': {
3944 |       types: ObjC.protocols.NSURLConnectionDataDelegate
3945 |           .methods['- connection:didReceiveResponse:'].types,
3946 |       implementation: function (conn, resp) {
3947 |       }
3948 |     },
3949 |     /* Or write the signature by hand if you really want to: */
3950 |     '- connection:didReceiveResponse:': {
3951 |       types: 'v32@0:8@16@24',
3952 |       implementation: function (conn, resp) {
3953 |       }
3954 |     }
3955 |   }
3956 | });
3957 | 
3958 | const proxy = MyConnectionDelegateProxy.alloc().init();
3959 | /* use `proxy`, and later: */
3960 | proxy.release();
3961 | 3962 |
    3963 |
  • 3964 |

    ObjC.registerProtocol(properties): create a new Objective-C protocol, 3965 | where properties is an object specifying:

    3966 | 3967 |
      3968 |
    • name: (optional) String specifying the name of the protocol; omit this 3969 | if you don’t care about the globally visible name and would like the 3970 | runtime to auto-generate one for you.
    • 3971 |
    • protocols: (optional) Array of protocols this protocol incorporates.
    • 3972 |
    • methods: (optional) Object specifying methods to declare.
    • 3973 |
    3974 |
  • 3975 |
3976 | 3977 |
const MyDataDelegate = ObjC.registerProtocol({
3978 |   name: 'MyDataDelegate',
3979 |   protocols: [ObjC.protocols.NSURLConnectionDataDelegate],
3980 |   methods: {
3981 |     /* You must specify the signature: */
3982 |     '- connection:didStuff:': {
3983 |       retType: 'void',
3984 |       argTypes: ['object', 'object']
3985 |     },
3986 |     /* Or grab it from a method of an existing class: */
3987 |     '- connection:didStuff:': {
3988 |       types: ObjC.classes
3989 |           .Foo['- connection:didReceiveResponse:'].types
3990 |     },
3991 |     /* Or from an existing protocol method: */
3992 |     '- connection:didStuff:': {
3993 |       types: ObjC.protocols.NSURLConnectionDataDelegate
3994 |           .methods['- connection:didReceiveResponse:'].types
3995 |     },
3996 |     /* Or write the signature by hand if you really want to: */
3997 |     '- connection:didStuff:': {
3998 |       types: 'v32@0:8@16@24'
3999 |     },
4000 |     /* You can also make a method optional (default is required): */
4001 |     '- connection:didStuff:': {
4002 |       retType: 'void',
4003 |       argTypes: ['object', 'object'],
4004 |       optional: true
4005 |     }
4006 |   }
4007 | });
4008 | 4009 |
    4010 |
  • 4011 |

    ObjC.bind(obj, data): bind some JavaScript data to an Objective-C 4012 | instance; see ObjC.registerClass() for an example.

    4013 |
  • 4014 |
  • 4015 |

    ObjC.unbind(obj): unbind previous associated JavaScript data from an 4016 | Objective-C instance; see ObjC.registerClass() for an example.

    4017 |
  • 4018 |
  • 4019 |

    ObjC.getBoundData(obj): look up previously bound data from an Objective-C 4020 | object.

    4021 |
  • 4022 |
  • 4023 |

    ObjC.choose(specifier, callbacks): enumerate live instances of classes 4024 | matching specifier by scanning the heap. specifier is either a class 4025 | selector or an object specifying a class selector and desired options. 4026 | The class selector is an ObjC.Object of a class, e.g. 4027 | ObjC.classes.UIButton. 4028 | When passing an object as the specifier you should provide the class 4029 | field with your class selector, and the subclasses field with a 4030 | boolean indicating whether you’re also interested in subclasses matching the 4031 | given class selector. The default is to also include subclasses. 4032 | The callbacks argument is an object specifying:

    4033 | 4034 |
      4035 |
    • 4036 |

      onMatch: function (instance): called once for each live instance found 4037 | with a ready-to-use instance just as if you would have called 4038 | new ObjC.Object(ptr("0x1234")) knowing that this particular 4039 | Objective-C instance lives at 0x1234.

      4040 | 4041 |

      This function may return the string stop to cancel the enumeration 4042 | early.

      4043 |
    • 4044 |
    • 4045 |

      onComplete: function (): called when all instances have been enumerated

      4046 |
    • 4047 |
    4048 |
  • 4049 |
  • 4050 |

    ObjC.chooseSync(specifier): synchronous version of choose() that returns 4051 | the instances in an array.

    4052 |
  • 4053 |
  • 4054 |

    ObjC.selector(name): convert the JavaScript string name to a selector

    4055 |
  • 4056 |
  • 4057 |

    ObjC.selectorAsString(sel): convert the selector sel to a JavaScript 4058 | string

    4059 |
  • 4060 |
4061 | 4062 |

Java

4063 | 4064 |
    4065 |
  • 4066 |

    Java.available: a boolean specifying whether the current process has the 4067 | a Java VM loaded, i.e. Dalvik or ART. Do not invoke any other Java 4068 | properties or methods unless this is the case.

    4069 |
  • 4070 |
  • 4071 |

    Java.enumerateLoadedClasses(callbacks): enumerate classes loaded right 4072 | now, where callbacks is an object specifying:

    4073 | 4074 |
      4075 |
    • 4076 |

      onMatch: function (className): called for each loaded class with 4077 | className that may be passed to use() to get a JavaScript wrapper.

      4078 |
    • 4079 |
    • 4080 |

      onComplete: function (): called when all classes have been enumerated.

      4081 |
    • 4082 |
    4083 |
  • 4084 |
  • 4085 |

    Java.enumerateLoadedClassesSync(): synchronous version of 4086 | enumerateLoadedClasses() that returns the class names in an array.

    4087 |
  • 4088 |
  • 4089 |

    Java.perform(fn): ensure that the current thread is attached to the VM 4090 | and call fn. (This isn’t necessary in callbacks from Java.)

    4091 |
  • 4092 |
4093 | 4094 |
Java.perform(function () {
4095 |     var Activity = Java.use("android.app.Activity");
4096 |     Activity.onResume.implementation = function () {
4097 |         send("onResume() got called! Let's call the original implementation");
4098 |         this.onResume();
4099 |     };
4100 | });
4101 | 4102 |
    4103 |
  • Java.use(className): dynamically get a JavaScript wrapper for 4104 | className that you can instantiate objects from by calling $new() on 4105 | it to invoke a constructor. Call $dispose() on an instance to clean it 4106 | up explicitly (or wait for the JavaScript object to get garbage-collected, 4107 | or script to get unloaded). Static and non-static methods are available, 4108 | and you can even replace a method implementation and throw an exception 4109 | from it:
  • 4110 |
4111 | 4112 |
Java.perform(function () {
4113 |     var Activity = Java.use("android.app.Activity");
4114 |     var Exception = Java.use("java.lang.Exception");
4115 |     Activity.onResume.implementation = function () {
4116 |         throw Exception.$new("Oh noes!");
4117 |     };
4118 | });
4119 | 4120 |
    4121 |
  • 4122 |

    Java.scheduleOnMainThread(fn): run fn on the main thread of the VM.

    4123 |
  • 4124 |
  • 4125 |

    Java.choose(className, callbacks): enumerate live instances of the 4126 | className class by scanning the Java heap, where callbacks is an 4127 | object specifying:

    4128 | 4129 |
      4130 |
    • 4131 |

      onMatch: function (instance): called once for each live instance found 4132 | with a ready-to-use instance just as if you would have called 4133 | Java.cast() with a raw handle to this particular instance.

      4134 | 4135 |

      This function may return the string stop to cancel the enumeration 4136 | early.

      4137 |
    • 4138 |
    • 4139 |

      onComplete: function (): called when all instances have been enumerated

      4140 |
    • 4141 |
    4142 |
  • 4143 |
  • 4144 |

    Java.cast(handle, klass): create a JavaScript wrapper given the existing 4145 | instance at handle of given class klass (as returned from 4146 | Java.use()). Such a wrapper also has a class property for getting a 4147 | wrapper for its class, and a $className property for getting a string 4148 | representation of its class-name.

    4149 |
  • 4150 |
4151 | 4152 |
var Activity = Java.use("android.app.Activity");
4153 | var activity = Java.cast(ptr("0x1234"), Activity);
4154 | 4155 |

WeakRef

4156 | 4157 |
    4158 |
  • 4159 |

    WeakRef.bind(value, fn): monitor value and call the fn callback as 4160 | soon as value has been garbage-collected, or the script is about to get 4161 | unloaded. Returns an id that you can pass to WeakRef.unbind() for 4162 | explicit cleanup.

    4163 | 4164 |

    This API is useful if you’re building a language-binding, where you need to 4165 | free native resources when a JS value is no longer needed.

    4166 |
  • 4167 |
  • 4168 |

    WeakRef.unbind(id): stop monitoring the value passed to 4169 | WeakRef.bind(value, fn), and call the fn callback immediately.

    4170 |
  • 4171 |
4172 | 4173 | 4174 | 4175 | 4176 | 4177 | 4178 | 4179 | 4180 | 4181 | 4182 | 4183 | 4184 | 4185 | 4186 | 4187 | 4188 | 4189 | 4190 | 4191 | 4192 | 4193 | 4194 | 4195 | 4196 | 4197 | 4198 | 4199 | 4200 | 4201 | 4202 | 4203 | 4204 | 4205 | 4206 | 4207 | 4208 | 4209 | 4210 | 4211 | 4212 | 4213 | 4214 | 4215 | 4216 | 4217 | 4218 | 4219 | 4220 | 4221 | 4222 | 4223 | 4224 | 4225 | 4226 | 4227 | 4228 | 4229 | 4230 | 4231 | 4232 | 4233 | 4234 | 4235 | 4236 | 4237 | 4238 | 4239 | 4240 | 4241 | 4242 | 4243 | 4244 |
4245 |
4246 | 4247 | 4248 | 4249 | 4250 | 4251 |
4252 |
4253 | 4254 | 4255 | 4256 | 4257 | 4258 |
4259 |
4260 |
4261 | 4262 | 4263 |
4264 |
4265 | 4266 |
4267 |
4268 | 4269 | 4270 |
4271 |
4272 |
4273 | 4279 |
4280 |
4281 |
4282 | 4283 | 4284 | 4285 | 4286 | 4287 | 4299 | 4300 | 4301 | 4302 | 4303 | 4304 | -------------------------------------------------------------------------------- /template.py: -------------------------------------------------------------------------------- 1 | import frida 2 | import sys 3 | def on_message(message, data): 4 | print message['payload'] 5 | 6 | jscode = """ 7 | """ 8 | session = frida.attach("") 9 | script = session.create_script(jscode) 10 | script.on('message', on_message) 11 | script.load() 12 | sys.stdin.read() 13 | 14 | 15 | --------------------------------------------------------------------------------