ART学习系列:Android 9 的隐藏Api的突破-元反射原理解释

545 阅读4分钟

上一篇章中我们了解ART 虚拟机中Native Get Method的调用过程。并尝试用元反射的形式去突破隐藏Api的调用。但是我们并不深入了解元反射怎么个原理。本文继续翻阅源码,做一些推测,如果说的不对的地方请多指正。

思路

1.Android 9 IsCallerTrusted 方法解析

2.hiddenapi::IsCallerTrusted的作用

3.VisitFrame 的调用逻辑

art/runtime/native/java_lang_Class.cc

55 
 static bool IsCallerTrusted(Thread* selfREQUIRES_SHARED(Locks::mutator_lock_) {
56    // Walk the stack and find the first frame not from java.lang.Class and not from java.lang.invoke.
57    // This is very expensive. Save this till the last.
58    struct FirstExternalCallerVisitor : public StackVisitor {
59      explicit FirstExternalCallerVisitor(Thread* thread)
60         : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
61            caller(nullptr) {
62     }
63  
64      bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
65        ArtMethod *m = GetMethod();
66        if (m == nullptr) {
67          // Attached native thread. Assume this is *not* boot class path.
68          caller = nullptr;
69          return false;
70       } else if (m->IsRuntimeMethod()) {
71          // Internal runtime method, continue walking the stack.
72          return true;
73       }
74  
75        ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
76        if (declaring_class->IsBootStrapClassLoaded()) {
77          if (declaring_class->IsClassClass()) {
78            return true;
79         }
80          // Check classes in the java.lang.invoke package. At the time of writing, the
81          // classes of interest are MethodHandles and MethodHandles.Lookup, but this
82          // is subject to change so conservatively cover the entire package.
83          // NB Static initializers within java.lang.invoke are permitted and do not
84          // need further stack inspection.
85          ObjPtr<mirror::Class> lookup_class = mirror::MethodHandlesLookup::StaticClass();
86          if ((declaring_class == lookup_class || declaring_class->IsInSamePackage(lookup_class))
87              && !m->IsClassInitializer()) {
88            return true;
89         }
90       }
91  
92        caller = m;
93        return false;
94     }
95  
96      ArtMethod* caller;
97   };
98  
99    FirstExternalCallerVisitor visitor(self);
100    visitor.WalkStack();
101    return visitor.caller != nullptr &&
102           hiddenapi::IsCallerTrusted(visitor.caller->GetDeclaringClass());
103  }

分解来看

static bool IsCallerTrusted(Thread* self) 
   // 创建 vsitor 对象
   FirstExternalCallerVisitor visitor(self);
   // vsitor 对象通过walk stack 方法遍历堆栈
   visitor.WalkStack();
   // 如果 visitor.caller 不为空 则通过hiddenapi::IsCallerTrusted 再次判断
   return visitor.caller != nullptr &&
          hiddenapi::IsCallerTrusted(visitor.caller->GetDeclaringClass());
}

art/runtime/hidden_api.h
hiddenapi::IsCallerTrusted

inline bool IsCallerTrusted(ObjPtr<mirror::Class> caller) REQUIRES_SHARED(Locks::mutator_lock_) {
231    return !caller.IsNull() &&
232        detail::IsCallerTrusted(caller, caller->GetClassLoader(), caller->GetDexCache());
233 }
161  ALWAYS_INLINE
162  inline bool IsCallerTrusted(ObjPtr<mirror::Class> caller,
163                              ObjPtr<mirror::ClassLoader> caller_class_loader,
164                              ObjPtr<mirror::DexCache> caller_dex_cache)
165      REQUIRES_SHARED(Locks::mutator_lock_) {
166    if (caller_class_loader.IsNull()) {
167      // Boot class loader.
168      return true;
169   }
170  
171    if (!caller_dex_cache.IsNull()) {
172      const DexFile* caller_dex_file = caller_dex_cache->GetDexFile();
173      if (caller_dex_file != nullptr && caller_dex_file->IsPlatformDexFile()) {
174        // Caller is in a platform dex file.
175        return true;
176     }
177   }
178  
179    if (!caller.IsNull() &&
180        caller->ShouldSkipHiddenApiChecks() &&
181        Runtime::Current()->IsJavaDebuggable()) {
182      // We are in debuggable mode and this caller has been marked trusted.
183      return true;
184   }
185  
186    return false;
187 }

visitor.WalkStack(); 看看你walkstack 如何遍历堆栈的

// /art/runtime/stack.cc
766  void StackVisitor::WalkStack(bool include_transitions) {
767 
771    bool exit_stubs_installed = Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled();
772    uint32_t instrumentation_stack_depth = 0;
773    size_t inlined_frames_count = 0;
774  
775    for (const ManagedStack* current_fragment = thread_->GetManagedStack();
776         current_fragment != nullptr; current_fragment = current_fragment->GetLink()) {
777      cur_shadow_frame_ = current_fragment->GetTopShadowFrame();
778      cur_quick_frame_ = current_fragment->GetTopQuickFrame();
779      cur_quick_frame_pc_ = 0;
780      cur_oat_quick_method_header_ = nullptr;
781  
782      if (cur_quick_frame_ != nullptr) {  // Handle quick stack frames.
783        // Can't be both a shadow and a quick fragment.
784        DCHECK(current_fragment->GetTopShadowFrame() == nullptr);
785        ArtMethod* method = *cur_quick_frame_;
786        DCHECK(method != nullptr);
787        bool header_retrieved = false;
788        if (method->IsNative()) {
789          //省略 native
822       }
823        while (method != nullptr) {
824         
829           //省略
​
830          if ((walk_kind_ == StackWalkKind::kIncludeInlinedFrames)
831              && (cur_oat_quick_method_header_ != nullptr)
832              && cur_oat_quick_method_header_->IsOptimized()) {
833            CodeInfo code_info = cur_oat_quick_method_header_->GetOptimizedCodeInfo();
834            CodeInfoEncoding encoding = code_info.ExtractEncoding();
835            uint32_t native_pc_offset =
836                cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_);
837            StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
838            if (stack_map.IsValid() && stack_map.HasInlineInfo(encoding.stack_map.encoding)) {
839              InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding);
840              DCHECK_EQ(current_inlining_depth_, 0u);
841              for (current_inlining_depth_ = inline_info.GetDepth(encoding.inline_info.encoding);
842                   current_inlining_depth_ != 0;
843                   --current_inlining_depth_) {
844                bool should_continue = VisitFrame();
845                if (UNLIKELY(!should_continue)) {
846                  return;
847               }
848                cur_depth_++;
849                inlined_frames_count++;
850             }
851           }
852         }
853          
            //这块发现 我们在之前看到的在java_lang_class.cc isCallerTrust方法里调用的内容
854          bool should_continue = VisitFrame();
855          if (UNLIKELY(!should_continue)) {
856            return;
857         }
858  
859         // 省略 大概猜是在遍历吧
​
926          method = *cur_quick_frame_;
927       }
928     } else if (cur_shadow_frame_ != nullptr) {
929        do {
930          SanityCheckFrame();
931          bool should_continue = VisitFrame();
932          if (UNLIKELY(!should_continue)) {
933            return;
934         }
935          cur_depth_++;
936          cur_shadow_frame_ = cur_shadow_frame_->GetLink();
937       } while (cur_shadow_frame_ != nullptr);
938     }
939      if (include_transitions) {
940        bool should_continue = VisitFrame();
941        if (!should_continue) {
942          return;
943       }
944     }
945      if (kCount == CountTransitions::kYes) {
946        cur_depth_++;
947     }
948   }
949    if (num_frames_ != 0) {
950      CHECK_EQ(cur_depth_, num_frames_);
951   }
952 }

经过上面的WalkStack,如果VisitFrame 返回false,也就是找到了当前的方法的调用者。

由此可以看出, visitor通过遍历找到了调用的caller。对caller 进行check。

99    FirstExternalCallerVisitor visitor(self);
100    visitor.WalkStack();
101    return visitor.caller != nullptr &&
102           hiddenapi::IsCallerTrusted(visitor.caller->GetDeclaringClass());

那我们看现在的调用关系

ART学习-HiddenApi方式区别.png

由此可见,通过反射Method本身的方法 getDeclareMethod 使调用关系发生了变化。获得ART检查方法的调用着的信任。

以上是我阅读源码后对此的理解。

遗留的内容

1.Android 9,10,11 的该方法差距

2.Android 11 不OK的原因猜测

3.Android 11上的其他绕过方式