README.md
Rendering markdown...
#include "hwbinder.h"
#include<sys/wait.h>
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; i<off_count; i++){
binder_size_t offset = off[i];
struct binder_object* obj =
(struct binder_object*)
(tr->data.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; i<off_count; i++){
binder_size_t offset = off[i];
struct binder_object* obj =
(struct binder_object*)
(tr->data.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; i<off_count; i++){
binder_size_t offset = off[i];
struct binder_object* obj =
(struct binder_object*)
(tr->data.ptr.buffer + offset);
switch (obj->hdr.type)
{
case BINDER_TYPE_HANDLE:
{
handle = obj->fbo.handle;
binder_acquire(info, handle);
break;
}
default:
break;
}
}
return handle;
}