如何从Android用户态获取Binder的binder_node有效句柄
Android 原生Binder服务注册与句柄获取(基于ioctl实现)
1. 打开Binder设备驱动
首先需要打开/dev/binder设备文件,建立与内核Binder驱动的通信通道:
int binder_fd = open("/dev/binder", O_RDWR); if (binder_fd < 0) { perror("Failed to open /dev/binder"); return -1; }
2. 注册服务(创建binder_proc与binder_node)
通过发送BC_REGISTER_LOOPER和BC_ADD_SERVICE命令,完成进程的Binder looper注册与服务节点创建:
// 注册当前进程为Binder Looper,触发binder_proc创建 uint32_t register_cmd = BC_REGISTER_LOOPER; struct binder_write_read bwr = {0}; bwr.write_size = sizeof(register_cmd); bwr.write_buffer = (uintptr_t)®ister_cmd; bwr.read_size = 0; if (ioctl(binder_fd, BINDER_WRITE_READ, &bwr) < 0) { perror("ioctl BC_REGISTER_LOOPER failed"); close(binder_fd); return -1; } // 注册服务名称,触发binder_node创建 const char* service_name = "com.example.custombinder"; size_t name_len = strlen(service_name) + 1; // 包含字符串终止符 struct { uint32_t cmd; uint32_t handle; // 注册服务时填0 uintptr_t name; uint32_t name_len; uint32_t flags; // 通常设为0 } __attribute__((packed)) add_service_data; add_service_data.cmd = BC_ADD_SERVICE; add_service_data.handle = 0; add_service_data.name = (uintptr_t)service_name; add_service_data.name_len = name_len; add_service_data.flags = 0; bwr.write_size = sizeof(add_service_data); bwr.write_buffer = (uintptr_t)&add_service_data; bwr.read_size = 0; if (ioctl(binder_fd, BINDER_WRITE_READ, &bwr) < 0) { perror("ioctl BC_ADD_SERVICE failed"); close(binder_fd); return -1; }
3. 获取目标binder_node的有效句柄
场景1:获取其他进程已注册服务的句柄
通过BC_GET_SERVICE命令查询服务名称,内核会返回对应binder_node的句柄:
struct { uint32_t cmd; uintptr_t name; uint32_t name_len; } __attribute__((packed)) get_service_data; get_service_data.cmd = BC_GET_SERVICE; get_service_data.name = (uintptr_t)service_name; get_service_data.name_len = name_len; bwr.write_size = sizeof(get_service_data); bwr.write_buffer = (uintptr_t)&get_service_data; bwr.read_size = sizeof(uint32_t); // 接收返回的句柄 uint32_t target_handle = 0; bwr.read_buffer = (uintptr_t)&target_handle; if (ioctl(binder_fd, BINDER_WRITE_READ, &bwr) < 0) { perror("ioctl BC_GET_SERVICE failed"); close(binder_fd); return -1; } if (target_handle == 0) { fprintf(stderr, "Target service not found\n"); close(binder_fd); return -1; }
场景2:获取自身服务的句柄
若要向自身注册的服务发送事务,可直接使用0作为句柄(代表当前进程的Binder实体),或通过后续消息循环中接收的BR_TRANSACTION消息确认。
4. 完善事务发送代码(含Binder内存分配)
原生Binder事务数据需存放在驱动管理的共享内存中,需先通过BC_ALLOC_BUFFER分配内存,再执行你提供的BC_TRANSACTION逻辑:
// 分配Binder共享内存 uint32_t alloc_cmd = BC_ALLOC_BUFFER; struct { uint32_t cmd; uint32_t size; } __attribute__((packed)) alloc_data; alloc_data.cmd = BC_ALLOC_BUFFER; alloc_data.size = buffer_size + offsets_size; // 数据+偏移量总大小 bwr.write_size = sizeof(alloc_data); bwr.write_buffer = (uintptr_t)&alloc_data; bwr.read_size = sizeof(uintptr_t); uintptr_t binder_shared_buf = 0; bwr.read_buffer = (uintptr_t)&binder_shared_buf; if (ioctl(binder_fd, BINDER_WRITE_READ, &bwr) < 0) { perror("ioctl BC_ALLOC_BUFFER failed"); close(binder_fd); return -1; } // 将用户空间数据拷贝到共享内存 memcpy((void*)binder_shared_buf, data_buffer, buffer_size); memcpy((void*)(binder_shared_buf + buffer_size), off_buffer, offsets_size); // 构造事务数据 struct binder_transaction_data tr = {0}; tr.target.handle = target_handle; // 替换为获取到的有效句柄 tr.code = 0; tr.data_size = buffer_size; tr.offsets_size = offsets_size; tr.data.ptr.buffer = binder_shared_buf; tr.data.ptr.offsets = binder_shared_buf + buffer_size; // 发送BC_TRANSACTION struct { uint32_t cmd; struct binder_transaction_data tr; } __attribute__((packed)) write_data; write_data.cmd = BC_TRANSACTION; write_data.tr = tr; bwr.write_size = sizeof(write_data); bwr.write_consumed = 0; bwr.write_buffer = (uintptr_t)&write_data; bwr.read_size = 0; if (ioctl(binder_fd, BINDER_WRITE_READ, &bwr) < 0) { perror("[-] ioctl BINDER_WRITE_READ failed"); } // 释放共享内存(可选,若后续不再使用) uint32_t free_cmd = BC_FREE_BUFFER; struct { uint32_t cmd; uintptr_t buffer; } __attribute__((packed)) free_data; free_data.cmd = BC_FREE_BUFFER; free_data.buffer = binder_shared_buf; bwr.write_size = sizeof(free_data); bwr.write_buffer = (uintptr_t)&free_data; bwr.read_size = 0; ioctl(binder_fd, BINDER_WRITE_READ, &bwr);
关键注意事项
- 消息循环:注册服务后需持续调用
ioctl读取驱动返回的BR_XXX命令(如BR_TRANSACTION、BR_REPLY),否则驱动会判定进程无响应 - 权限:访问
/dev/binder需要系统权限或特定应用权限,普通第三方应用无法直接操作 - 内存安全:必须通过
BC_ALLOC_BUFFER/BC_FREE_BUFFER管理Binder共享内存,避免内存泄漏
内容的提问来源于stack exchange,提问作者Cyb3rCr0wCC
相关产品推荐
相关产品推荐

