1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "hidden_api_finder.h" 18 19 #include "dex/code_item_accessors-inl.h" 20 #include "dex/dex_instruction-inl.h" 21 #include "dex/dex_file.h" 22 #include "dex/method_reference.h" 23 #include "hidden_api.h" 24 #include "resolver.h" 25 #include "veridex.h" 26 27 #include <iostream> 28 29 namespace art { 30 31 void HiddenApiFinder::CheckMethod(uint32_t method_id, 32 VeridexResolver* resolver, 33 MethodReference ref) { 34 // Note: we always query whether a method is in a list, as the app 35 // might define blacklisted APIs (which won't be used at runtime). 36 std::string name = HiddenApi::GetApiMethodName(resolver->GetDexFile(), method_id); 37 if (hidden_api_.IsInRestrictionList(name)) { 38 method_locations_[name].push_back(ref); 39 } 40 } 41 42 void HiddenApiFinder::CheckField(uint32_t field_id, 43 VeridexResolver* resolver, 44 MethodReference ref) { 45 // Note: we always query whether a field is in a list, as the app 46 // might define blacklisted APIs (which won't be used at runtime). 47 std::string name = HiddenApi::GetApiFieldName(resolver->GetDexFile(), field_id); 48 if (hidden_api_.IsInRestrictionList(name)) { 49 field_locations_[name].push_back(ref); 50 } 51 } 52 53 void HiddenApiFinder::CollectAccesses(VeridexResolver* resolver) { 54 const DexFile& dex_file = resolver->GetDexFile(); 55 // Look at all types referenced in this dex file. Any of these 56 // types can lead to being used through reflection. 57 for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) { 58 std::string name(dex_file.StringByTypeIdx(dex::TypeIndex(i))); 59 if (hidden_api_.IsInRestrictionList(name)) { 60 classes_.insert(name); 61 } 62 } 63 // Note: we collect strings constants only referenced in code items as the string table 64 // contains other kind of strings (eg types). 65 size_t class_def_count = dex_file.NumClassDefs(); 66 for (size_t class_def_index = 0; class_def_index < class_def_count; ++class_def_index) { 67 const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); 68 const uint8_t* class_data = dex_file.GetClassData(class_def); 69 if (class_data == nullptr) { 70 // Empty class. 71 continue; 72 } 73 ClassDataItemIterator it(dex_file, class_data); 74 it.SkipAllFields(); 75 for (; it.HasNextMethod(); it.Next()) { 76 const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); 77 if (code_item == nullptr) { 78 continue; 79 } 80 CodeItemDataAccessor code_item_accessor(dex_file, code_item); 81 for (const DexInstructionPcPair& inst : code_item_accessor) { 82 switch (inst->Opcode()) { 83 case Instruction::CONST_STRING: { 84 dex::StringIndex string_index(inst->VRegB_21c()); 85 std::string name = std::string(dex_file.StringDataByIdx(string_index)); 86 // Cheap filtering on the string literal. We know it cannot be a field/method/class 87 // if it contains a space. 88 if (name.find(' ') == std::string::npos) { 89 // Class names at the Java level are of the form x.y.z, but the list encodes 90 // them of the form Lx/y/z;. Inner classes have '$' for both Java level class 91 // names in strings, and hidden API lists. 92 std::string str = HiddenApi::ToInternalName(name); 93 // Note: we can query the lists directly, as HiddenApi added classes that own 94 // private methods and fields in them. 95 // We don't add class names to the `strings_` set as we know method/field names 96 // don't have '.' or '/'. All hidden API class names have a '/'. 97 if (hidden_api_.IsInRestrictionList(str)) { 98 classes_.insert(str); 99 } else if (hidden_api_.IsInRestrictionList(name)) { 100 // Could be something passed to JNI. 101 classes_.insert(name); 102 } else { 103 // We only keep track of the location for strings, as these will be the 104 // field/method names the user is interested in. 105 strings_.insert(name); 106 reflection_locations_[name].push_back( 107 MethodReference(&dex_file, it.GetMemberIndex())); 108 } 109 } 110 break; 111 } 112 case Instruction::INVOKE_DIRECT: 113 case Instruction::INVOKE_INTERFACE: 114 case Instruction::INVOKE_STATIC: 115 case Instruction::INVOKE_SUPER: 116 case Instruction::INVOKE_VIRTUAL: { 117 CheckMethod( 118 inst->VRegB_35c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); 119 break; 120 } 121 122 case Instruction::INVOKE_DIRECT_RANGE: 123 case Instruction::INVOKE_INTERFACE_RANGE: 124 case Instruction::INVOKE_STATIC_RANGE: 125 case Instruction::INVOKE_SUPER_RANGE: 126 case Instruction::INVOKE_VIRTUAL_RANGE: { 127 CheckMethod( 128 inst->VRegB_3rc(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); 129 break; 130 } 131 132 case Instruction::IGET: 133 case Instruction::IGET_WIDE: 134 case Instruction::IGET_OBJECT: 135 case Instruction::IGET_BOOLEAN: 136 case Instruction::IGET_BYTE: 137 case Instruction::IGET_CHAR: 138 case Instruction::IGET_SHORT: { 139 CheckField( 140 inst->VRegC_22c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); 141 break; 142 } 143 144 case Instruction::IPUT: 145 case Instruction::IPUT_WIDE: 146 case Instruction::IPUT_OBJECT: 147 case Instruction::IPUT_BOOLEAN: 148 case Instruction::IPUT_BYTE: 149 case Instruction::IPUT_CHAR: 150 case Instruction::IPUT_SHORT: { 151 CheckField( 152 inst->VRegC_22c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); 153 break; 154 } 155 156 case Instruction::SGET: 157 case Instruction::SGET_WIDE: 158 case Instruction::SGET_OBJECT: 159 case Instruction::SGET_BOOLEAN: 160 case Instruction::SGET_BYTE: 161 case Instruction::SGET_CHAR: 162 case Instruction::SGET_SHORT: { 163 CheckField( 164 inst->VRegB_21c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); 165 break; 166 } 167 168 case Instruction::SPUT: 169 case Instruction::SPUT_WIDE: 170 case Instruction::SPUT_OBJECT: 171 case Instruction::SPUT_BOOLEAN: 172 case Instruction::SPUT_BYTE: 173 case Instruction::SPUT_CHAR: 174 case Instruction::SPUT_SHORT: { 175 CheckField( 176 inst->VRegB_21c(), resolver, MethodReference(&dex_file, it.GetMemberIndex())); 177 break; 178 } 179 180 default: 181 break; 182 } 183 } 184 } 185 } 186 } 187 188 void HiddenApiFinder::Run(const std::vector<std::unique_ptr<VeridexResolver>>& resolvers) { 189 for (const std::unique_ptr<VeridexResolver>& resolver : resolvers) { 190 CollectAccesses(resolver.get()); 191 } 192 } 193 194 void HiddenApiFinder::Dump(std::ostream& os, 195 HiddenApiStats* stats, 196 bool dump_reflection) { 197 static const char* kPrefix = " "; 198 stats->linking_count = method_locations_.size() + field_locations_.size(); 199 200 // Dump methods from hidden APIs linked against. 201 for (const std::pair<std::string, std::vector<MethodReference>>& pair : method_locations_) { 202 HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first); 203 stats->api_counts[api_list]++; 204 os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):"; 205 os << std::endl; 206 for (const MethodReference& ref : pair.second) { 207 os << kPrefix << HiddenApi::GetApiMethodName(ref) << std::endl; 208 } 209 os << std::endl; 210 } 211 212 // Dump fields from hidden APIs linked against. 213 for (const std::pair<std::string, std::vector<MethodReference>>& pair : field_locations_) { 214 HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(pair.first); 215 stats->api_counts[api_list]++; 216 os << "#" << ++stats->count << ": Linking " << api_list << " " << pair.first << " use(s):"; 217 os << std::endl; 218 for (const MethodReference& ref : pair.second) { 219 os << kPrefix << HiddenApi::GetApiMethodName(ref) << std::endl; 220 } 221 os << std::endl; 222 } 223 224 if (dump_reflection) { 225 // Dump potential reflection uses. 226 for (const std::string& cls : classes_) { 227 for (const std::string& name : strings_) { 228 std::string full_name = cls + "->" + name; 229 HiddenApiAccessFlags::ApiList api_list = hidden_api_.GetApiList(full_name); 230 stats->api_counts[api_list]++; 231 if (api_list != HiddenApiAccessFlags::kWhitelist) { 232 stats->reflection_count++; 233 os << "#" << ++stats->count << ": Reflection " << api_list << " " << full_name 234 << " potential use(s):"; 235 os << std::endl; 236 for (const MethodReference& ref : reflection_locations_[name]) { 237 os << kPrefix << HiddenApi::GetApiMethodName(ref) << std::endl; 238 } 239 os << std::endl; 240 } 241 } 242 } 243 } 244 } 245 246 } // namespace art 247