#include "hwbinder.h" #include int hwbinder_open(PBINDER_INFO info, size_t mapsize){ struct binder_version ver; size_t max_threads = DEFAULT_MAX_BINDER_THREADS; info->fd_ = open(HWBINDER_DEVICE, O_RDWR | O_CLOEXEC); CHECK_LOG("binder device open failed!", info->fd_ >= 0); if(ioctl(info->fd_, BINDER_VERSION, &ver) < 0) return BINDER_VERSION_ERROR; if(ioctl(info->fd_, BINDER_SET_MAX_THREADS, &max_threads) < 0) return BINDER_SET_MAX_THREADS_ERROR; info->mapsize_ = mapsize; info->mapped_ = mmap( NULL, mapsize, PROT_READ, MAP_PRIVATE, info->fd_, 0); if(info->mapped_ == MAP_FAILED) return BINDER_MAPPED_ERROR; return BINDER_SUCCESS; } /* Create wrapper for hidl_strings. */ hidl_string *hidl_string_new(const char *str) { size_t len; hidl_string *hstr = calloc(1, sizeof(*hstr)); if (!hstr) return NULL; len = strlen(str); hstr->buffer_ = (hidl_pointer)malloc(len + 1); if (!hstr->buffer_) { free(hstr); return NULL; } strcpy(hstr->buffer_, str); hstr->size_ = len; hstr->owns_buffer_ = 1; return hstr; } hidl_vec hidl_vec_new( BYTE* token, size_t size ){ hidl_vec bundle; bundle.buffer = token; bundle.owns_buffer = 0; bundle.size = size; return bundle; } uint32_t find_hwservice( PBINDER_INFO info, hidl_string* name, hidl_string* instance ){ uint32_t handle = 0; hidl_string* hstr = NULL; binder_size_t buffer_size = 0; struct binder_buffer_object* objs = NULL; BYTE buffer[0x1000]; BYTE rbuffer[0x400]; binder_size_t offsets[0x10]; BYTE* ptr = buffer; const BYTE* ptr_start = ptr; size_t ptr_len = 0x1000; size_t rsize = 0x400; struct { uint32_t cmd_; struct binder_transaction_data_sg tr_; } __packed data; memset(offsets, 0, 0x10); memset(rbuffer, 0, rsize); memset(&data, 0, sizeof(data)); memset(ptr, 0, ptr_len); memcpy(ptr, HWSERVICE_MANAGER, sizeof(HWSERVICE_MANAGER)); MOV_PTR(ptr, sizeof(HWSERVICE_MANAGER) + 1); ALIGN_32(ptr); /** * embedded binder object * |--------bbo1(service name, parent data point to bbo2)------------| * |---------------bbo2(service name data, child data)---------------| * |--------bbo3(instance name, parent data point to bbo3)-----------| * |---------------bbo3(instance name data, child data)--------------| */ // parent service name objs = (struct binder_buffer_object*)ptr; objs[0].hdr.type = BINDER_TYPE_PTR; objs[0].buffer = (binder_uintptr_t)name; objs[0].length = sizeof(hidl_string); objs[0].flags = 0; objs[0].parent = 0; objs[0].parent_offset = 0; buffer_size += objs[0].length; offsets[0] = (binder_size_t)(ptr - ptr_start); // child service name data ptr = (BYTE*)(&(objs[1])); objs[1].hdr.type = BINDER_TYPE_PTR; objs[1].buffer = (binder_uintptr_t)name->buffer_; objs[1].length = name->size_ + 1; objs[1].flags = 1; objs[1].parent = 0; objs[1].parent_offset = 0; buffer_size += objs[1].length; offsets[1] = (binder_size_t)(ptr - ptr_start); // parent instance name ptr = (BYTE*)(&(objs[2])); objs[2].hdr.type = BINDER_TYPE_PTR; objs[2].buffer = (binder_uintptr_t)instance; objs[2].length = sizeof(hidl_string); objs[2].flags = 0; objs[2].parent = 0; objs[2].parent_offset = 0; buffer_size += objs[2].length; offsets[2] = (binder_size_t)(ptr - ptr_start); // child instance name data ptr = (BYTE*)(&(objs[3])); objs[3].hdr.type = BINDER_TYPE_PTR; objs[3].buffer = (binder_uintptr_t)instance->buffer_; objs[3].length = instance->size_ + 1; objs[3].flags = 1; objs[3].parent = 2; objs[3].parent_offset = 0; buffer_size += objs[3].length; offsets[3] = (binder_size_t)(ptr - ptr_start); ptr = (BYTE*)(&(objs[4])); data.cmd_ = BC_TRANSACTION_SG; data.tr_.transaction_data.code = 1; data.tr_.transaction_data.target.handle = 0; data.tr_.transaction_data.flags = 0x10; data.tr_.transaction_data.data_size = (binder_size_t)(ptr - ptr_start); data.tr_.transaction_data.offsets_size = (binder_size_t)(4 * sizeof(binder_uintptr_t)); data.tr_.transaction_data.data.ptr.buffer = (binder_uintptr_t)ptr_start; data.tr_.transaction_data.data.ptr.offsets = (binder_uintptr_t)offsets; ALIGN_64(buffer_size); data.tr_.buffers_size = buffer_size; binder_write(info, (BYTE*)&data, sizeof(data)); size_t d = binder_read(info, rbuffer, rsize); if(d <= 0){ perror("reply is null!"); return 0; } BYTE* res = parse_binder_message(rbuffer, d); struct binder_transaction_data* tr = (struct binder_transaction_data*)res; size_t off_count = (size_t)(tr->offsets_size / sizeof(binder_uintptr_t)); binder_size_t* off = (binder_size_t*)tr->data.ptr.offsets; // Parse binder object for(size_t i=0; idata.ptr.buffer + offset); switch (obj->hdr.type) { case BINDER_TYPE_HANDLE: handle = obj->fbo.handle; binder_acquire(info, handle); break; default: perror("Invalid binder object type"); break; } } binder_free_buffer(info, tr->data.ptr.buffer); return handle; } uint32_t get_token_manager(PBINDER_INFO info){ const char service[] = TOKEN_MANAGER; const char instance[] = "default"; hidl_string* svc = hidl_string_new(service); hidl_string* ins = hidl_string_new(instance); uint32_t handle = find_hwservice(info, svc, ins); FREE(svc); FREE(ins); return handle; } BOOL create_token( PBINDER_INFO info, uint32_t tm, uint32_t svc, hidl_vec* tk ){ BYTE reply[0x400]; BYTE buffer[0x400]; size_t rsize = 0x400; size_t size = 0x400; BYTE* ptr = buffer; BOOL ret = FALSE; const BYTE* ptr_start = ptr; binder_size_t buffer_size = 0; binder_size_t offsets[0x10]; struct binder_buffer_object* objs = NULL; struct flat_binder_object* fbo = NULL; struct { uint32_t cmd_; struct binder_transaction_data_sg tr_; }__packed data; memset(offsets, 0, 0x10); memset(reply, 0, rsize); memset(buffer, 0, size); memset(&data, 0, sizeof(data)); memcpy(ptr, TOKEN_MANAGER, sizeof(TOKEN_MANAGER)); MOV_PTR(ptr, sizeof(TOKEN_MANAGER) + 1); ALIGN_32(ptr); fbo = (struct flat_binder_object*)ptr; fbo->hdr.type = BINDER_TYPE_BINDER; fbo->binder = svc; offsets[0] = (binder_size_t)(ptr - ptr_start); ptr = (BYTE*)(&fbo[1]); data.cmd_ = BC_TRANSACTION_SG; data.tr_.transaction_data.target.handle = tm; data.tr_.transaction_data.code = 1; // create data.tr_.transaction_data.flags = 0; data.tr_.transaction_data.offsets_size = (binder_size_t)( 1 * sizeof(binder_size_t)); data.tr_.transaction_data.data_size = (binder_size_t)(ptr - ptr_start); data.tr_.transaction_data.data.ptr.buffer = (binder_uintptr_t)ptr_start; data.tr_.transaction_data.data.ptr.offsets = (binder_uintptr_t)offsets; ALIGN_64(buffer_size); data.tr_.buffers_size = buffer_size; binder_write(info, (BYTE*)&data, sizeof(data)); size_t d = binder_read(info, (BYTE*)reply, rsize); if(d <= 0){ perror("reply is null!"); return FALSE; } BYTE* res = parse_binder_message(reply, d); struct binder_transaction_data* tr = (struct binder_transaction_data*)res; size_t off_count = (tr->offsets_size / sizeof(binder_size_t)); binder_size_t* off = (binder_size_t*)tr->data.ptr.offsets; // Parse binder object for(size_t i=0; idata.ptr.buffer + offset); switch (obj->hdr.type) { case BINDER_TYPE_PTR: { struct binder_buffer_object* bbo = (struct binder_buffer_object*)obj; /** * Parse embedded binder object * bbo1.buffer(parent object): * |-----------------------------parent data---------------------------| * |---child data(point to bbo2.buffer)----|-----size-----|-----1------| * * bbo2.buffer(child object): * |-------------------child data-------------------| * |-------------------token data-------------------| */ if(bbo->length == sizeof(hidl_vec)){ // Parse first bbo hidl_vec* tp_tk = (hidl_vec*)bbo->buffer; tk->owns_buffer = tp_tk->owns_buffer; if(tk->size < tp_tk->size){ perror("hidl_vec token buffer too small!"); binder_free_buffer(info, tr->data.ptr.buffer); return FALSE; } tk->size = tp_tk->size; continue; }else{ // Parse second bbo if(bbo->length == tk->size){ memcpy(tk->buffer, (const void*)bbo->buffer, bbo->length); ret = TRUE; } else ret = FALSE; } break; } default: perror("Invalid binder object type"); break; } } binder_free_buffer(info, tr->data.ptr.buffer); return ret; } BOOL unregister_token( PBINDER_INFO info, uint32_t tm, const hidl_vec* tk ){ uint32_t handle = 0; BYTE buffer[0x400]; BYTE reply[0x400]; BYTE* ptr = buffer; const BYTE* ptr_start = ptr; binder_size_t offsets[0x10]; binder_size_t buffer_size = 0; struct binder_buffer_object* objs = NULL; size_t size = 0x400; size_t rsize = 0x400; struct { uint32_t cmd_; struct binder_transaction_data_sg tr_; }__packed data; memset(offsets, 0, 0x10); memset(buffer, 0, size); memset(reply, 0, rsize); memset(&data, 0, sizeof(data)); memcpy(ptr, TOKEN_MANAGER, sizeof(TOKEN_MANAGER)); MOV_PTR(ptr, sizeof(TOKEN_MANAGER) + 1); ALIGN_32(ptr); objs = (struct binder_buffer_object*)ptr; objs[0].hdr.type = BINDER_TYPE_PTR; objs[0].flags = 0; objs[0].parent = 0; objs[0].parent_offset = 0; objs[0].buffer = (binder_uintptr_t)tk; objs[0].length = sizeof(*tk); buffer_size += objs[0].length; offsets[0] = (binder_size_t)(ptr - ptr_start); ptr = (BYTE*)(&objs[1]); objs[1].hdr.type = BINDER_TYPE_PTR; objs[1].flags = 1; objs[1].parent = 0; objs[1].parent_offset = 0; objs[1].buffer = (binder_uintptr_t)tk->buffer; objs[1].length = (binder_size_t)tk->size; buffer_size += objs[1].length; offsets[1] = (binder_size_t)(ptr - ptr_start); ptr = (BYTE*)(&objs[2]); data.cmd_ = BC_TRANSACTION_SG; data.tr_.transaction_data.code = 3; // get data.tr_.transaction_data.target.handle = tm; data.tr_.transaction_data.data_size = (binder_size_t)(ptr - ptr_start); data.tr_.transaction_data.offsets_size = (binder_size_t)(2 * sizeof(binder_size_t)); data.tr_.transaction_data.data.ptr.buffer = (binder_uintptr_t)ptr_start; data.tr_.transaction_data.data.ptr.offsets = (binder_uintptr_t)offsets; ALIGN_64(buffer_size); data.tr_.buffers_size = buffer_size; binder_write(info, (BYTE*)&data, sizeof(data)); size_t d = binder_read(info, reply, rsize); if(d <= 0){ perror("reply is null!"); return FALSE; } // TODO print_hex(reply, d); BYTE* res = parse_binder_message(reply, d); return TRUE; } uint32_t get_handle_by_token( PBINDER_INFO info, uint32_t tm, hidl_vec* tk ){ uint32_t handle = 0; BYTE buffer[0x400]; BYTE reply[0x400]; BYTE* ptr = buffer; const BYTE* ptr_start = ptr; binder_size_t offsets[0x10]; binder_size_t buffer_size = 0; struct binder_buffer_object* objs = NULL; size_t size = 0x400; size_t rsize = 0x400; struct { uint32_t cmd_; struct binder_transaction_data_sg tr_; }__packed data; memset(offsets, 0, 0x10); memset(buffer, 0, size); memset(reply, 0, rsize); memset(&data, 0, sizeof(data)); memcpy(ptr, TOKEN_MANAGER, sizeof(TOKEN_MANAGER)); MOV_PTR(ptr, sizeof(TOKEN_MANAGER) + 1); ALIGN_32(ptr); objs = (struct binder_buffer_object*)ptr; objs[0].hdr.type = BINDER_TYPE_PTR; objs[0].flags = 0; objs[0].parent = 0; objs[0].parent_offset = 0; objs[0].buffer = (binder_uintptr_t)tk; objs[0].length = sizeof(*tk); buffer_size += objs[0].length; offsets[0] = (binder_size_t)(ptr - ptr_start); ptr = (BYTE*)(&objs[1]); objs[1].hdr.type = BINDER_TYPE_PTR; objs[1].flags = 1; objs[1].parent = 0; objs[1].parent_offset = 0; objs[1].buffer = (binder_uintptr_t)tk->buffer; objs[1].length = (binder_size_t)tk->size; buffer_size += objs[1].length; offsets[1] = (binder_size_t)(ptr - ptr_start); ptr = (BYTE*)(&objs[2]); data.cmd_ = BC_TRANSACTION_SG; data.tr_.transaction_data.code = 3; // get data.tr_.transaction_data.target.handle = tm; data.tr_.transaction_data.data_size = (binder_size_t)(ptr - ptr_start); data.tr_.transaction_data.offsets_size = (binder_size_t)(2 * sizeof(binder_size_t)); data.tr_.transaction_data.data.ptr.buffer = (binder_uintptr_t)ptr_start; data.tr_.transaction_data.data.ptr.offsets = (binder_uintptr_t)offsets; ALIGN_64(buffer_size); data.tr_.buffers_size = buffer_size; binder_write(info, (BYTE*)&data, sizeof(data)); size_t d = binder_read(info, reply, rsize); if(d <= 0){ perror("reply is null!"); return 0; } BYTE* res = parse_binder_message(reply, d); struct binder_transaction_data* tr = (struct binder_transaction_data*)res; size_t off_count = (tr->offsets_size / sizeof(binder_size_t)); binder_size_t* off = (binder_size_t*)tr->data.ptr.offsets; for(size_t i=0; idata.ptr.buffer + offset); switch (obj->hdr.type) { case BINDER_TYPE_HANDLE: { handle = obj->fbo.handle; binder_acquire(info, handle); break; } default: break; } } return handle; }