首页
社区
课程
招聘
[原创] ANDROID 黑科技 : HIDE API 调用
发表于: 2026-2-2 16:01 5424

[原创] ANDROID 黑科技 : HIDE API 调用

2026-2-2 16:01
5424

X音版本 : 370401

ANDROID 版本 : API 36

主动调用

X音绕过 HIDE API 的模块是 libjato.so, 导出函数是 Java_com_bytedance_common_jato_boost_HiddenApiOpt_nOptimize,将以下的 SO 模块打包进 ANDROID 的项目:

libart_sym.so  libbytehook.so  libc++_shared.so  libjato.so  libnpth_dl.so  libshadowhook.so

HiddenApiOpt 的类代码如下:

package com.bytedance.common.jato.boost;

public class HiddenApiOpt {
    
    public static native boolean nOptimize();

    static {
        System.loadLibrary("jato");
    }

}

测试使用 @hide 注解的函数是 setTargetSdkVersion 源码如下:

/**
    * Sets the target SDK version. Should only be called before the
    * app starts to run, because it may change the VM's behavior in
    * dangerous ways. Defaults to {@link #SDK_VERSION_CUR_DEVELOPMENT}.
    *
    * @param targetSdkVersion the SDK version the app wants to run with.
    *
    * @hide
    */
@UnsupportedAppUsage(maxTargetSdk=0, publicAlternatives="Use the {@code targetSdkVersion}"
    +" attribute in the {@code uses-sdk} manifest tag instead.")
@SystemApi(client = MODULE_LIBRARIES)
public synchronized void setTargetSdkVersion(int targetSdkVersion) {
    this.targetSdkVersion = targetSdkVersion;
    setTargetSdkVersionNative(this.targetSdkVersion);
}

调用代码如下:

public void VMRuntimeSetTargetSdkVersion(){
    try {
        Class runtimeClass = Class.forName("dalvik.system.VMRuntime");
        Method nativeLoadMethod = runtimeClass.getDeclaredMethod("setTargetSdkVersion",
                new Class[] {int.class});

        Log.d("hiddenapi", "setTargetSdkVersion success!");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

执行 VMRuntimeSetTargetSdkVersion 后的报错信息如下:

hiddenapi: Accessing hidden method Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V (runtime_flags=CorePlatformApi, domain=core-platform, api=blocked,core-platform-api) from Lcom/android/hiddenapi/MainActivity; (domain=app) using reflection: denied
java.lang.NoSuchMethodException: dalvik.system.VMRuntime.setTargetSdkVersion [int]
    at java.lang.Class.getMethod(Class.java:2940)
    at java.lang.Class.getDeclaredMethod(Class.java:2919)
    at com.android.hiddenapi.MainActivity.VMRuntimeSetTargetSdkVersion(MainActivity.java:138)
    at com.android.hiddenapi.MainActivity$1.onClick(MainActivity.java:43)
    at android.view.View.performClick(View.java:8083)
    at android.view.View.performClickInternal(View.java:8060)
    at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
    at android.view.View$PerformClick.run(View.java:31549)
    at android.os.Handler.handleCallback(Handler.java:995)
    at android.os.Handler.dispatchMessage(Handler.java:103)
    at android.os.Looper.loopOnce(Looper.java:248)
    at android.os.Looper.loop(Looper.java:338)
    at android.app.ActivityThread.main(ActivityThread.java:9067)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)

反射调用被拒绝 : (domain=app) using reflection: denied

使用字节的绕过模块,然后再调用 VMRuntimeSetTargetSdkVersion 显示反射调用成功。

HiddenApiOpt mHiddenApiOpt = new HiddenApiOpt();
mHiddenApiOpt.nOptimize();

显示日志如下:

Init libart.so handle: 0xb4000077c46762c0
Load /data/app/~~VGNwNanmQ4UBtavm8SqM-w==/com.android.hiddenapi-VIzkuLnqpv5NAhGt5WmmUw==/base.apk!/lib/arm64-v8a/libjato.so using class loader ns clns-9 (caller=/data/data/com.android.hiddenapi/code_cache/.overlay/base.apk/classes6.dex): ok
 Found the Ldr instruction in GetHiddenApiEnforcementPolicy, target_instruction is 0xb9443d08,  i = 14
Get the offset of enforcement_policy: 43c 
setTargetSdkVersion success!

绕过分析

分析 libjato.so 的 Java_com_bytedance_common_jato_boost_HiddenApiOpt_nOptimize 是如何绕过 HIDE API 限制的, 主要代码如下:

v2 = sub_876C4();                           // hook libart GetReflectionCallerAccessContext
v3 = atomic_load((unsigned __int8 *)&qword_15BD30);// 原子读取
if ( (v3 & 1) == 0 && __cxa_guard_acquire(&qword_15BD30) )// 构造加锁
{
    dword_15BD2C = sub_87784();               // GetHiddenApiEnforcementPolicy
    __cxa_guard_release(&qword_15BD30);       // 构造解锁
}
v4 = dword_15BD2C;
if ( dword_15BD2C )
{
    v5 = npth_dlopen("libart.so");
    v6 = (_QWORD *)npth_dlsym(v5, "_ZN3art7Runtime9instance_E");
    if ( v5 )
    npth_dlclose(v5);
    if ( !v6 || (unsigned int)(*(_DWORD *)(*v6 + (unsigned int)dword_15BD2C) - 1) > 1 )
    {
    v0 = v2;
    return v0 & 1;
    }
    *(_DWORD *)((unsigned int)dword_15BD2C + *v6) = 0;// GetHiddenApiEnforcementPolicy + _ZN3art7Runtime9instance_E = 0
    v4 = 1;
}
v0 = v2 | v4;

HOOK

首先分析 sub_876C4 函数:

__int64 sub_876C4()
{
  __int64 v0; // x20
  __int64 v1; // x19
  __int64 result; // x0
  __int64 v3; // x0
  const char *v4; // x0

  v0 = npth_dlopen("libart.so");
  v1 = npth_dlsym(v0, "_ZN3art9hiddenapi32GetReflectionCallerAccessContextEPNS_6ThreadE");
  if ( v0 )
    npth_dlclose(v0);
  result = 0LL;
  if ( v1 )
  {
    shadowhook_init(0LL, 0LL);
    v3 = shadowhook_hook_sym_addr(v1, sub_874D8, &unk_15BD20);
    if ( (unsigned int)shadowhook_get_errno(v3) )
    {
      v4 = (const char *)shadowhook_to_errmsg();
      __android_log_print(6, "OptimizeHiddenApi", "hook libart GetReflectionCallerAccessContext error, msg: %s", v4);
      return 0LL;
    }
    else
    {
      if ( (sub_73888() & 1) != 0 )
        __android_log_print(3, "OptimizeHiddenApi", " hook libart GetReflectionCallerAccessContext success");
      return 1LL;
    }
  }
  return result;
}

因为 ANDROID 的版本限制, dlopen 是无法直接打开 libart.so 模块的。

在 ibnpth_dl.so 模块中有导出函数 npth_dlopen 和 npth_dlsym。

npth_dlopen

在 npth_dlopen 的函数中,根据 ANDROID 的 API 版本来获取 libart.so 加载模块的基址:

int (**sub_39A8())(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data)
{
  n0x14 = npth_dlapilevel_0();
  if ( &dl_iterate_phdr )
  {
    if ( n0x14 - 21 >= 2 )                      // API >= 23
      return &dl_iterate_phdr;
    else
      return (int (**)(int (*)(struct dl_phdr_info *, size_t, void *), void *))sub_3E8C;
  }
  if ( n0x14 > 0x14 )                           // API > 20
    return 0LL;
  d_tag = &sub_3F04;
  if ( n2 == 1 )
    return (int (**)(int (*)(struct dl_phdr_info *, size_t, void *), void *))d_tag;
  if ( n2 == 2 )
    return 0LL;
}

如果 ANDROID API 大于等于 23 ,则调用 dl_iterate_phdr 来遍历所有加载的模块,然后在回调函数中根据模块的名称来获取对应的加载基址,dl_iterate_phdr 的函数原型如下:

/**
 * [dl_iterate_phdr(3)](4f2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0j5h3^5%4i4K6u0W2L8%4u0Y4i4K6u0r3L8r3W2F1N6i4S2Q4x3V1k6E0j5h3&6Q4x3X3c8H3j5h3N6W2M7#2)9J5c8X3#2S2L8U0y4Q4x3V1k6V1L8q4)9#2k6X3W2@1k6i4u0S2N6r3g2Q4y4h3k6H3K9r3c8J5i4K6u0W2x3#2)9J5k6h3S2@1L8h3I4Q4x3U0V1`.
 * calls the given callback once for every loaded shared object. The size
 * argument to the callback lets you determine whether you have a smaller
 * `dl_phdr_info` from before API level 30, or the newer full one.
 * The data argument to the callback is whatever you pass as the data argument
 * to dl_iterate_phdr().
 *
 * Returns the value returned by the final call to the callback.
 */
int dl_iterate_phdr(int (* _Nonnull __callback)(struct dl_phdr_info* _Nonnull __info, size_t __size, void* _Nullable __data), void* _Nullable __data);

如果 ANDROID API 小于 23 , 则读取 /proc/self/maps 的内容,然后解析获取到 libart.so 的基址,解析 /proc/self/maps 内容格式的代码如下:

char *__fastcall sub_57A0(unsigned __int64 ptr)
{
  FILE *stream; // x0
  FILE *stream_1; // x19
  const char *s_1; // x0
  char *s_2; // x20
  char *v6; // x0
  unsigned __int64 ptr_2; // [xsp+0h] [xbp-410h] BYREF
  unsigned __int64 ptr_1; // [xsp+8h] [xbp-408h] BYREF
  char s[1024]; // [xsp+10h] [xbp-400h] BYREF

  stream = fopen("/proc/self/maps", "r");
  if ( !stream )
    return 0LL;
  stream_1 = stream;
  if ( !fgets(s, 1024, stream) )
    goto LABEL_12;
  while ( 1 )
  {
    if ( sscanf(s, "%lx-%lx r", &ptr_1, &ptr_2) == 2 )
    {
      if ( ptr_1 > ptr )
        goto LABEL_12;
      if ( ptr_2 > ptr )
        break;
    }
    if ( !fgets(s, 1024, stream_1) )
      goto LABEL_12;
  }
  s_1 = (const char *)__strchr_chk(s, 47LL, 1024LL);
  s_2 = (char *)s_1;
  if ( !s_1 )
    goto LABEL_13;
  v6 = strchr(s_1, 32);
  if ( v6 || (v6 = strchr(s_2, 10)) != 0LL )
  {
    *v6 = 0;
    s_2 = strdup(s_2);
  }
  else
  {
LABEL_12:
    s_2 = 0LL;
  }
LABEL_13:
  fclose(stream_1);
  return s_2;
}

npth_dlsym

npth_dlsym 的关键代码如下:

_QWORD *__fastcall npth_dlsym_size(_QWORD *ptr, char *s2, _QWORD *a3)
{
  _QWORD *ptr_1; // x19
  __int64 *v6; // x0
  __int64 v7; // x0
  __int64 v8; // x8
  int n6; // w9

  if ( !ptr )
    return ptr;
  ptr_1 = ptr;
  v6 = (__int64 *)ptr[6];
  if ( !v6 )
  {
    v6 = (__int64 *)sub_4520(ptr_1[5], ptr_1[4], ptr_1[1]);
    ptr_1[6] = v6;
    if ( !v6 )
    {
      if ( (unsigned int)sub_5BC0() )
        __android_log_print(4LL, "NPTH_DL", "cannot load dynamic sections!");
      return 0LL;
    }
  }
  v7 = sub_4384(v6, s2);
  if ( !v7 )
  {
    if ( (unsigned int)sub_5BC0() )
      __android_log_print(4LL, "NPTH_DL", "cannot found symbol!");
    return 0LL;
  }
  v8 = v7;
  ptr = 0LL;
  n6 = *(_BYTE *)(v8 + 4) & 0xF;
  if ( n6 != 6 && n6 != 10 )
  {
    if ( a3 )
      *a3 = *(_QWORD *)(v8 + 16);
    return (_QWORD *)(*(_QWORD *)(v8 + 8) + ptr_1[1]);
  }
  return ptr;
}

核心的函数有两个 v6 = (__int64 *)sub_4520(ptr_1[5], ptr_1[4], ptr_1[1]); 和 v7 = sub_4384(v6, s2);

其中 sub_4520 函数是动态节 (Dynamic Section) 解析器。

sub_4384 函数是符号查找器。它使用解析出的动态节信息,在符号表中查找指定的符号名。

npth_dlsym 模拟了系统 dlsym 的功能,手动解析 ELF 的格式信息,最终返回函数的指针。

GetReflectionCallerAccessContext

GetReflectionCallerAccessContext 函数的源码如下:

hiddenapi::AccessContext GetReflectionCallerAccessContext(Thread* self)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  // Walk the stack and find the first frame not from java.lang.Class,
  // java.lang.invoke or java.lang.reflect. This is very expensive.
  // Save this till the last.
  ...
  FirstExternalCallerVisitor visitor(self);
  visitor.WalkStack();
  // Construct AccessContext from the calling class found on the stack.
  // If the calling class cannot be determined, e.g. unattached threads,
  // we conservatively assume the caller is trusted.
  ObjPtr<mirror::Class> caller =
      (visitor.caller == nullptr) ? nullptr : visitor.caller->GetDeclaringClass();
  return caller.IsNull() ? AccessContext(/* is_trusted= */ true) : AccessContext(caller);
}

HOOK _ZN3art9hiddenapi32GetReflectionCallerAccessContextEPNS_6ThreadE 代码如下:

v3 = shadowhook_hook_sym_addr(v1, sub_874D8, &unk_15BD20);
__int64 __usercall sub_874D8@<X0>(_QWORD *a1@<X8>)
{
  __int64 v1; // x30
  __int64 mode; // x0

  *a1 = 0LL;
  a1[1] = 0LL;
  a1[2] = 0LL;
  mode = shadowhook_get_mode();
  if ( !(_DWORD)mode )
    return shadowhook_pop_stack(v1);
  return mode;
}

GetReflectionCallerAccessContext 的参数是 Thread 变量, HOOK 函数将 Thread 变量的前 24 个字节数据清零。

当 caller.IsNull() 时 返回了 AccessContext(/* is_trusted= */ true); 从而绕过了 HIDE API 的调用限制。

HiddenApiPolicy

获取 hidden_api_policy_ 字段偏移的代码在 sub_87784() :

__int64 sub_87784()
{
  __int64 v0; // x0
  __int64 v1; // x19
  _DWORD *v2; // x0
  __int64 v3; // x21
  bool v4; // cf
  int n706675680; // w11
  unsigned int v6; // w20
  int n8; // w8
  int v8; // w9
  unsigned int v9; // w20

  v0 = npth_dlopen_force("libopenjdkjvmti.so");
  if ( v0 )
  {
    v1 = v0;
    v2 = (_DWORD *)npth_dlsym_force(v0, "_ZN12openjdkjvmti9ClassUtil29GetHiddenApiEnforcementPolicyEP9_jvmtiEnvPi");
    if ( !v2 )
      goto LABEL_19;
    v3 = -49LL;
    while ( 1 )
    {
      if ( *v2 == 706675680 || *v2 == -113245944 )
      {
        n706675680 = v2[2];
        if ( n706675680 == 706675680 || n706675680 == -1191182296 )
          break;
      }
      v4 = __CFADD__(v3++, 1LL);
      ++v2;
      if ( v4 )
        goto LABEL_19;
    }
    v6 = v2[1];
    if ( (sub_73888() & 1) != 0 )
      __android_log_print(
        3,
        "OptimizeHiddenApi",
        " Found the Ldr instruction in GetHiddenApiEnforcementPolicy, target_instruction is %p,  i = %d",
        (const void *)v6,
        v3 + 50);
    if ( (~v6 & 0xB8400000) != 0 )
    {
LABEL_19:
      v9 = 0;
    }
    else
    {
      if ( (v6 & 0x40000000) != 0 )
        n8 = 8;
      else
        n8 = 4;
      if ( (v6 & 0x1000000) != 0 )
        v8 = (v6 >> 10) & 0xFFF;
      else
        v8 = (v6 >> 12) & 0x1FF;
      v9 = v8 * n8;
      __android_log_print(4, "OptimizeHiddenApi", "Get the offset of enforcement_policy: %x ", v8 * n8);
    }
    npth_dlclose_force(v1);
  }
  else
  {
    return 0;
  }
  return v9;
}

首先获取 libopenjdkjvmti.so 的 openjdkjvmti::ClassUtil::GetHiddenApiEnforcementPolicy 的符号地址:

...
v0 = npth_dlopen_force("libopenjdkjvmti.so");
...
v2 = (_DWORD *)npth_dlsym_force(v0, "_ZN12openjdkjvmti9ClassUtil29GetHiddenApiEnforcementPolicyEP9_jvmtiEnvPi");
...

然后从函数的开始地址进行二机制搜索:

while ( 1 )
{
    if ( *v2 == 706675680 || *v2 == -113245944 )
    {
    n706675680 = v2[2];
    if ( n706675680 == 706675680 || n706675680 == -1191182296 )
        break;
    }
    v4 = __CFADD__(v3++, 1LL);
    ++v2;
    if ( v4 )
    goto LABEL_19;
}

ZN12openjdkjvmti9ClassUtil29GetHiddenApiEnforcementPolicyEP9_jvmtiEnvPi 返回 hidden_api_policy 的汇编代码如下:

48 04 00 D0             ADRP            X8, #_ZN3art7Runtime9instance_E_ptr@PAGE
08 D9 45 F9             LDR             X8, [X8,#_ZN3art7Runtime9instance_E_ptr@PAGEOFF]
E0 03 1F 2A             MOV             W0, WZR
08 01 40 F9             LDR             X8, [X8] ; art::Runtime::instance_
08 3D 44 B9             LDR             W8, [X8,#0x43C]
28 00 00 B9             STR             W8, [X1]
C0 03 5F D6             RET

-113245944 = 0xFFFFFFFFF9400108 -> LDR X8, [X8] ; art::Runtime::instance_

-1191182296 = 0xFFFFFFFFB9000028 -> STR W8, [X1]

根据上下文定位到 LDR W8, [X8,#0x43C];

最后解析获取到 hidden_api_policy_ 的偏移是 0x43C

获取到偏移后再获取 _ZN3art7Runtime9instance_E 的地址:

v3 = atomic_load((unsigned __int8 *)&qword_15BD30);// 原子读取
if ( (v3 & 1) == 0 && __cxa_guard_acquire(&qword_15BD30) )// 构造加锁
{
    dword_15BD2C = sub_87784();               // GetHiddenApiEnforcementPolicy
    __cxa_guard_release(&qword_15BD30);       // 构造解锁
}
v4 = dword_15BD2C;
if ( dword_15BD2C )
{
    v5 = npth_dlopen("libart.so");
    v6 = (_QWORD *)npth_dlsym(v5, "_ZN3art7Runtime9instance_E");
    if ( v5 )
    npth_dlclose(v5);
    if ( !v6 || (unsigned int)(*(_DWORD *)(*v6 + (unsigned int)dword_15BD2C) - 1) > 1 )
    {
    v0 = v2;
    return v0 & 1;
    }
    *(_DWORD *)((unsigned int)dword_15BD2C + *v6) = 0;// GetHiddenApiEnforcementPolicy + _ZN3art7Runtime9instance_E = 0
    v4 = 1;
}

根据 Runtime 实例加上 hidden_api_policy_ 偏移来定位到 hidden_api_policy_ 变量的地址

hidden_api_policy_ 是一个枚举的类型:

enum class EnforcementPolicy {
  kDisabled             = 0,
  kJustWarn             = 1,  // keep checks enabled, but allow everything (enables logging)
  kEnabled              = 2,  // ban conditionally blocked & blocklist
  kMax = kEnabled,
};

将 hidden_api_policy_ 设置为 0 来关闭 HIDE API 的执行策略

绕过代码

#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <elf.h>
#include <android/log.h>
#include <link.h>
#include <jni.h>
#include <cstring>

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_();
}

关闭策略运行前后的日志如下:

hiddenapi: Accessing hidden method Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V (runtime_flags=CorePlatformApi, domain=core-platform, api=blocked,core-platform-api) from Lcom/android/hiddenapi/MainActivity; (domain=app) using reflection: denied
java.lang.NoSuchMethodException: dalvik.system.VMRuntime.setTargetSdkVersion [int]
    at java.lang.Class.getMethod(Class.java:2940)
    at java.lang.Class.getDeclaredMethod(Class.java:2919)
    at com.android.hiddenapi.MainActivity.VMRuntimeSetTargetSdkVersion(MainActivity.java:142)
    at com.android.hiddenapi.MainActivity$1.onClick(MainActivity.java:43)
    at android.view.View.performClick(View.java:8083)
    at android.view.View.performClickInternal(View.java:8060)
    at android.view.View.-$$Nest$mperformClickInternal(Unknown Source:0)
    at android.view.View$PerformClick.run(View.java:31549)
    at android.os.Handler.handleCallback(Handler.java:995)
    at android.os.Handler.dispatchMessage(Handler.java:103)
    at android.os.Looper.loopOnce(Looper.java:248)
    at android.os.Looper.loop(Looper.java:338)
    at android.app.ActivityThread.main(ActivityThread.java:9067)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:593)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:932)
 Found the Ldr instruction in GetHiddenApiEnforcementPolicy, target_instruction is 0xb9443d08,  i = 14
Get the offset of enforcement_policy: 43c
setTargetSdkVersion success!

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 2026-4-1 00:43 被易之生生编辑 ,原因:
收藏
免费 21
支持
分享
最新回复 (7)
雪    币: 1550
活跃值: (4463)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
2
666
2026-2-3 13:48
0
雪    币: 7534
活跃值: (24371)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
3
有点东西
2026-2-3 14:41
0
雪    币: 1806
活跃值: (4763)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
好东西
2026-2-4 08:36
0
雪    币: 2930
活跃值: (3283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
已易学习
2026-2-4 16:05
0
雪    币: 94
活跃值: (4722)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
66666
2026-2-4 16:10
0
雪    币: 104
活跃值: (8162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
tql
2026-2-8 18:33
0
雪    币: 6
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
apk链接方便发一下吗
2026-2-20 13:20
0
游客
登录 | 注册 方可回帖
返回