struct user_data_t {
const char* target_name;
uintptr_t base_addr;
bool found;
};
// 回调函数:遍历每个模块时被调用
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
user_data_t* user_data = (user_data_t*)data;
const char* path = info->dlpi_name;
const char* basename = strrchr(path, '/');
if (basename) {
basename++;
} else {
basename = path;
}
if (strstr(basename, user_data->target_name) != nullptr) {
user_data->target_name = info->dlpi_name;
user_data->base_addr = info->dlpi_addr;
user_data->found = true;
return 1;
}
return 0;
}
// 获取内存中动态库的基地址
user_data_t npth_dlopen_(const char* module_name) {
user_data_t user_data;
user_data.target_name = module_name;
user_data.base_addr = 0;
user_data.found = false;
int result = dl_iterate_phdr(callback, &user_data);
return user_data;
}
// 手动解析 ELF 符号 (简化版)
void* npth_dlsym_symtab_(const char* library_path, const char* symbol_name) {
user_data_t user_data = npth_dlopen_(library_path);
if (!user_data.found) return nullptr;
int fd = open(user_data.target_name, O_RDONLY);
if (fd < 0) return nullptr;
off_t size = lseek(fd, 0, SEEK_END);
void* elf_data = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
Elf64_Ehdr* ehdr = (Elf64_Ehdr*)elf_data;
Elf64_Shdr* shdr = (Elf64_Shdr*)((uintptr_t)elf_data + ehdr->e_shoff);
Elf64_Sym* symtab = nullptr;
char* strtab = nullptr;
int sym_count = 0;
for (int i = 0; i < ehdr->e_shnum; i++) {
if (shdr[i].sh_type == SHT_DYNSYM) {
symtab = (Elf64_Sym*)((uintptr_t)elf_data + shdr[i].sh_offset);
sym_count = shdr[i].sh_size / sizeof(Elf64_Sym);
} else if (shdr[i].sh_type == SHT_STRTAB && i != ehdr->e_shstrndx) {
strtab = (char*)((uintptr_t)elf_data + shdr[i].sh_offset);
}
}
void* target_addr = nullptr;
for (int i = 0; i < sym_count; i++) {
char *name = strtab + symtab[i].st_name;
int addr = symtab[i].st_value;
if (strcmp(strtab + symtab[i].st_name, symbol_name) == 0) {
target_addr = (void*)(user_data.base_addr + symtab[i].st_value);
break;
}
}
munmap(elf_data, size);
return target_addr;
}
uint32_t bytedance_get_hidden_api_policy_(){
uint64_t counter = -49LL;
uint32_t* current_addr;
uint32_t target_instruction;
uint32_t offset = 0;
bool found = false;
void *get_hidden_api_enforcement_policy_addr = npth_dlsym_symtab_("libopenjdkjvmti.so","_ZN12openjdkjvmti9ClassUtil29GetHiddenApiEnforcementPolicyEP9_jvmtiEnvPi");
if (!get_hidden_api_enforcement_policy_addr) {
return 0;
}
current_addr = (uint32_t*)get_hidden_api_enforcement_policy_addr;
while (1) {
if (*current_addr == 706675680 || *current_addr == -113245944) {
uint32_t next_check = current_addr[2];
if (next_check == 706675680 || next_check == -1191182296) {
target_instruction = current_addr[1];
found = true;
break;
}
}
current_addr++;
counter++;
if (counter == 0) {
break;
}
}
if (found) {
__android_log_print(
4,
"OptimizeHiddenApi",
" Found the Ldr instruction in GetHiddenApiEnforcementPolicy, target_instruction is %p, i = %d",
(void*)target_instruction,
(int)(counter + 50));
if ((~target_instruction & 0xB8400000) != 0) {
offset = 0;
} else {
int scale;
int raw_offset;
if ((target_instruction & 0x40000000) != 0) {
scale = 8;
} else {
scale = 4;
}
if ((target_instruction & 0x1000000) != 0) {
raw_offset = (target_instruction >> 10) & 0xFFF;
} else {
raw_offset = (target_instruction >> 12) & 0x1FF;
}
offset = raw_offset * scale;
__android_log_print(
4,
"OptimizeHiddenApi",
"Get the offset of enforcement_policy: %x",
offset
);
}
}
return offset;
}
uint32_t bytedance_set_hidden_api_policy_() {
// 1. 查找HiddenApiPolicy字段的偏移地址
uint32_t hidden_api_policy_offset = bytedance_get_hidden_api_policy_();
if (!hidden_api_policy_offset) {
return 0;
}
// 2. 查找_ZN3art7Runtime9instance_E函数的符号
uint64_t** art_Runtime_instance_ptr_ptr = (uint64_t**)npth_dlsym_symtab_("libart.so","_ZN3art7Runtime9instance_E");;
if (!art_Runtime_instance_ptr_ptr) {
return 0;
}
uint64_t* runtime_instance = *art_Runtime_instance_ptr_ptr;
// 3. 计算隐藏API策略的地址
uint32_t* policy_ptr = (uint32_t*)((uint64_t)runtime_instance + hidden_api_policy_offset);
if (*policy_ptr < 1 || *policy_ptr > 2) {
return 0;
}
*policy_ptr = 0;
return 1;
}
extern "C" JNIEXPORT void JNICALL
Java_com_android_hiddenapi_MainActivity_bytedance(JNIEnv *env, jobject thiz) {
bytedance_set_hidden_api_policy_();
}