├── LICENSE ├── README.md ├── frida_android_libbinder.js └── images └── preview.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hamza 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # frida-android-libbinder 2 | 3 | PoC Frida script to view Android libbinder traffic. The following links were a great source of inspiration and knowledge: 4 | - https://www.blackhat.com/docs/eu-14/materials/eu-14-Artenstein-Man-In-The-Binder-He-Who-Controls-IPC-Controls-The-Droid.pdf 5 | - https://sc1.checkpoint.com/downloads/Man-In-The-Binder-He-Who-Controls-IPC-Controls-The-Droid-wp.pdf 6 | - https://www.synacktiv.com/posts/systems/binder-transactions-in-the-bowels-of-the-linux-kernel.html 7 | - http://newandroidbook.com/files/Andevcon-Binder.pdf 8 | - http://androidxref.com 9 | - https://android.googlesource.com/platform/frameworks/native/+/jb-dev/libs/binder/ 10 | 11 | I wrote a blogpost which can be found here: [https://bhamza.me/blogpost/2019/04/24/Frida-Android-libbinder.html](https://bhamza.me/blogpost/2019/04/24/Frida-Android-libbinder.html) 12 | 13 | ## Usage 14 | 15 | - Spawn app: `frida -U -l frida_android_libbinder.js -f com.example.app.id --no-pause` 16 | - Attach to app: `frida -U -l frida_android_libbinder.js -n com.example.app.id --no-pause` 17 | 18 | ![preview][preview] 19 | 20 | [preview]: /images/preview.png 21 | -------------------------------------------------------------------------------- /frida_android_libbinder.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const PYMODE = false; 4 | var CACHE_LOG = ""; 5 | 6 | function log(type, message) { 7 | if(message.toString() == CACHE_LOG.toString()) return; // Let's hide duplicate logs... 8 | 9 | CACHE_LOG = message; 10 | if(PYMODE) { 11 | send({'type':type, 'message': message}); 12 | } else { 13 | console.log('[' + type + '] ' + message); 14 | } 15 | } 16 | 17 | // http://androidxref.com/kernel_3.18/xref/drivers/staging/android/uapi/binder.h#273 18 | var binder_driver_command_protocol = { // enum binder_driver_command_protocol 19 | "BC_TRANSACTION": 0, 20 | "BC_REPLY": 1, 21 | "BC_ACQUIRE_RESULT": 2, 22 | "BC_FREE_BUFFER": 3, 23 | "BC_INCREFS": 4, 24 | "BC_ACQUIRE": 5, 25 | "BC_RELEASE": 6, 26 | "BC_DECREFS": 7, 27 | "BC_INCREFS_DONE": 8, 28 | "BC_ACQUIRE_DONE": 9, 29 | "BC_ATTEMPT_ACQUIRE": 10, 30 | "BC_REGISTER_LOOPER": 11, 31 | "BC_ENTER_LOOPER": 12, 32 | "BC_EXIT_LOOPER": 13, 33 | "BC_REQUEST_DEATH_NOTIFICATION": 14, 34 | "BC_CLEAR_DEATH_NOTIFICATION": 15, 35 | "BC_DEAD_BINDER_DONE": 16, 36 | }; 37 | 38 | // http://androidxref.com/kernel_3.18/xref/drivers/staging/android/uapi/binder.h#77 39 | function parse_struct_binder_write_read(binder_write_read) { 40 | // arm64/include/uapi/linux/android/binder.h 41 | // struct binder_write_read { 42 | // binder_size_t write_size; /* bytes to write */ 43 | // binder_size_t write_consumed; /* bytes consumed by driver */ 44 | // binder_uintptr_t write_buffer; 45 | // binder_size_t read_size; /* bytes to read */ 46 | // binder_size_t read_consumed; /* bytes consumed by driver */ 47 | // binder_uintptr_t read_buffer; 48 | // }; 49 | var offset = 8; // 64b 50 | 51 | return { 52 | "write_size": binder_write_read.readU64(), 53 | "write_consumed": binder_write_read.add(offset).readU64(), 54 | "write_buffer": binder_write_read.add(offset * 2).readPointer(), 55 | "read_size": binder_write_read.add(offset * 3).readU64(), 56 | "read_consumed": binder_write_read.add(offset * 4).readU64(), 57 | "read_buffer": binder_write_read.add(offset * 5).readPointer() 58 | } 59 | } 60 | 61 | // http://androidxref.com/kernel_3.18/xref/drivers/staging/android/uapi/binder.h#129 62 | function parse_binder_transaction_data(binder_transaction_data) { 63 | // arm64/include/uapi/linux/android/binder.h 64 | // struct binder_transaction_data { 65 | // /* The first two are only used for bcTRANSACTION and brTRANSACTION, 66 | // * identifying the target and contents of the transaction. 67 | // */ 68 | // union { 69 | // /* target descriptor of command transaction */ 70 | // __u32 handle; 71 | // /* target descriptor of return transaction */ 72 | // binder_uintptr_t ptr; 73 | // } target; 74 | // binder_uintptr_t cookie; /* target object cookie */ 75 | // __u32 code; /* transaction command */ 76 | // 77 | // /* General information about the transaction. */ 78 | // __u32 flags; 79 | // pid_t sender_pid; 80 | // uid_t sender_euid; 81 | // binder_size_t data_size; /* number of bytes of data */ 82 | // binder_size_t offsets_size; /* number of bytes of offsets */ 83 | // 84 | // /* If this transaction is inline, the data immediately 85 | // * follows here; otherwise, it ends with a pointer to 86 | // * the data buffer. 87 | // */ 88 | // union { 89 | // struct { 90 | // /* transaction data */ 91 | // binder_uintptr_t buffer; 92 | // /* offsets from buffer to flat_binder_object structs */ 93 | // binder_uintptr_t offsets; 94 | // } ptr; 95 | // __u8 buf[8]; 96 | // } data; 97 | // }; 98 | return { 99 | "target": { // can either be u32 (handle) or 64b ptr 100 | "handle": binder_transaction_data.readU32(), 101 | "ptr": binder_transaction_data.readPointer() 102 | }, 103 | "cookie": binder_transaction_data.add(8).readPointer(), 104 | "code": binder_transaction_data.add(16).readU32(), 105 | "flags": binder_transaction_data.add(20).readU32(), 106 | "sender_pid": binder_transaction_data.add(24).readS32(), 107 | "sender_euid": binder_transaction_data.add(28).readU32(), 108 | "data_size": binder_transaction_data.add(32).readU64(), 109 | "offsets_size": binder_transaction_data.add(40).readU64(), 110 | "data": { 111 | "ptr": { 112 | "buffer": binder_transaction_data.add(48).readPointer(), 113 | "offsets": binder_transaction_data.add(56).readPointer() 114 | }, 115 | "buf": binder_transaction_data.add(48).readByteArray(8) 116 | } 117 | } 118 | } 119 | 120 | // http://androidxref.com/kernel_3.18/xref/drivers/staging/android/binder.c#1754 121 | function handle_write(write_buffer, write_size, write_consumed) { // binder_thread_write 122 | var cmd = write_buffer.readU32() & 0xff; 123 | var ptr = write_buffer.add(write_consumed + 4); // 4 = sizeof(uint32_t), the first 4 bytes contain "cmd" 124 | var end = write_buffer.add(write_size); 125 | 126 | switch (cmd) { 127 | // Implement cases from binder_driver_command_protocol, we're only interested in BC_TRANSACTION / BC_REPLY 128 | case binder_driver_command_protocol.BC_TRANSACTION: 129 | case binder_driver_command_protocol.BC_REPLY: 130 | // log('INFO', "TRANSACTION / BC_REPLY!"); 131 | var binder_transaction_data = parse_binder_transaction_data(ptr); 132 | 133 | // Show me the secrets 134 | log("INFO", "\n" + hexdump(binder_transaction_data.data.ptr.buffer, { 135 | length: binder_transaction_data.data_size, 136 | ansi: true, 137 | }) + "\n"); 138 | break; 139 | default: 140 | // log('ERR', 'NOOP handler') 141 | } 142 | } 143 | 144 | Java.perform(function(){ 145 | var ioctl = Module.findExportByName("libbinder.so", "ioctl"); 146 | Interceptor.attach(ioctl, { 147 | onEnter: function(args) { 148 | var fd = args[0]; // int 149 | var cmd = args[1]; // int 150 | 151 | // value calculated from #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) 152 | if(cmd != 0xc0306201) return; // if 0xc0306201 then enter BINDER_WRITE_READ flow 153 | var data = args[2]; // void * -> pointer to binder_write_read 154 | 155 | var binder_write_read = parse_struct_binder_write_read(data); 156 | 157 | if(binder_write_read.write_size > 0) { 158 | handle_write(binder_write_read.write_buffer, binder_write_read.write_size, binder_write_read.write_consumed); 159 | } 160 | } 161 | }) 162 | }); 163 | 164 | 165 | -------------------------------------------------------------------------------- /images/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamz-a/frida-android-libbinder/adb8124768c9f20d4c3b2de57418b5aef063431c/images/preview.png --------------------------------------------------------------------------------