• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "veridex.h"
18 
19 #include <android-base/file.h>
20 #include <android-base/strings.h>
21 
22 #include "dex/dex_file.h"
23 #include "dex/dex_file_loader.h"
24 #include "hidden_api.h"
25 #include "hidden_api_finder.h"
26 #include "precise_hidden_api_finder.h"
27 #include "resolver.h"
28 
29 #include <cstdlib>
30 #include <sstream>
31 
32 namespace art {
33 
34 static VeriClass z_(Primitive::Type::kPrimBoolean, 0, nullptr);
35 static VeriClass b_(Primitive::Type::kPrimByte, 0, nullptr);
36 static VeriClass c_(Primitive::Type::kPrimChar, 0, nullptr);
37 static VeriClass s_(Primitive::Type::kPrimShort, 0, nullptr);
38 static VeriClass i_(Primitive::Type::kPrimInt, 0, nullptr);
39 static VeriClass f_(Primitive::Type::kPrimFloat, 0, nullptr);
40 static VeriClass d_(Primitive::Type::kPrimDouble, 0, nullptr);
41 static VeriClass j_(Primitive::Type::kPrimLong, 0, nullptr);
42 static VeriClass v_(Primitive::Type::kPrimVoid, 0, nullptr);
43 
44 VeriClass* VeriClass::boolean_ = &z_;
45 VeriClass* VeriClass::byte_ = &b_;
46 VeriClass* VeriClass::char_ = &c_;
47 VeriClass* VeriClass::short_ = &s_;
48 VeriClass* VeriClass::integer_ = &i_;
49 VeriClass* VeriClass::float_ = &f_;
50 VeriClass* VeriClass::double_ = &d_;
51 VeriClass* VeriClass::long_ = &j_;
52 VeriClass* VeriClass::void_ = &v_;
53 
54 // Will be set after boot classpath has been resolved.
55 VeriClass* VeriClass::object_ = nullptr;
56 VeriClass* VeriClass::class_ = nullptr;
57 VeriClass* VeriClass::class_loader_ = nullptr;
58 VeriClass* VeriClass::string_ = nullptr;
59 VeriClass* VeriClass::throwable_ = nullptr;
60 VeriMethod VeriClass::forName_ = nullptr;
61 VeriMethod VeriClass::getField_ = nullptr;
62 VeriMethod VeriClass::getDeclaredField_ = nullptr;
63 VeriMethod VeriClass::getMethod_ = nullptr;
64 VeriMethod VeriClass::getDeclaredMethod_ = nullptr;
65 VeriMethod VeriClass::getClass_ = nullptr;
66 VeriMethod VeriClass::loadClass_ = nullptr;
67 VeriField VeriClass::sdkInt_ = nullptr;
68 
69 static const char* kDexFileOption = "--dex-file=";
70 static const char* kStubsOption = "--core-stubs=";
71 static const char* kFlagsOption = "--api-flags=";
72 static const char* kImprecise = "--imprecise";
73 static const char* kTargetSdkVersion = "--target-sdk-version=";
74 static const char* kAppClassFilter = "--app-class-filter=";
75 static const char* kExcludeApiListsOption = "--exclude-api-lists=";
76 
77 struct VeridexOptions {
78   const char* dex_file = nullptr;
79   const char* core_stubs = nullptr;
80   const char* flags_file = nullptr;
81   bool precise = true;
82   int target_sdk_version = 29; /* Q */
83   std::vector<std::string> app_class_name_filter;
84   std::vector<std::string> exclude_api_lists;
85 };
86 
Substr(const char * str,int index)87 static const char* Substr(const char* str, int index) {
88   return str + index;
89 }
90 
StartsWith(const char * str,const char * val)91 static bool StartsWith(const char* str, const char* val) {
92   return strlen(str) >= strlen(val) && memcmp(str, val, strlen(val)) == 0;
93 }
94 
ParseArgs(VeridexOptions * options,int argc,char ** argv)95 static void ParseArgs(VeridexOptions* options, int argc, char** argv) {
96   // Skip over the command name.
97   argv++;
98   argc--;
99 
100   for (int i = 0; i < argc; ++i) {
101     if (StartsWith(argv[i], kDexFileOption)) {
102       options->dex_file = Substr(argv[i], strlen(kDexFileOption));
103     } else if (StartsWith(argv[i], kStubsOption)) {
104       options->core_stubs = Substr(argv[i], strlen(kStubsOption));
105     } else if (StartsWith(argv[i], kFlagsOption)) {
106       options->flags_file = Substr(argv[i], strlen(kFlagsOption));
107     } else if (strcmp(argv[i], kImprecise) == 0) {
108       options->precise = false;
109     } else if (StartsWith(argv[i], kTargetSdkVersion)) {
110       options->target_sdk_version = atoi(Substr(argv[i], strlen(kTargetSdkVersion)));
111     } else if (StartsWith(argv[i], kAppClassFilter)) {
112       options->app_class_name_filter = android::base::Split(
113           Substr(argv[i], strlen(kAppClassFilter)), ",");
114     } else if (StartsWith(argv[i], kExcludeApiListsOption)) {
115       options->exclude_api_lists = android::base::Split(
116           Substr(argv[i], strlen(kExcludeApiListsOption)), ",");
117     } else {
118       LOG(ERROR) << "Unknown command line argument: " << argv[i];
119     }
120   }
121 }
122 
Split(const std::string & str,char sep)123 static std::vector<std::string> Split(const std::string& str, char sep) {
124   std::vector<std::string> tokens;
125   std::string tmp;
126   std::istringstream iss(str);
127   while (std::getline(iss, tmp, sep)) {
128     tokens.push_back(tmp);
129   }
130   return tokens;
131 }
132 
133 class Veridex {
134  public:
Run(int argc,char ** argv)135   static int Run(int argc, char** argv) {
136     VeridexOptions options;
137     ParseArgs(&options, argc, argv);
138     android::base::InitLogging(argv);
139 
140     if (!options.dex_file) {
141       LOG(ERROR) << "Required argument '" << kDexFileOption << "' not provided.";
142       return 1;
143     }
144 
145     gTargetSdkVersion = options.target_sdk_version;
146 
147     std::vector<std::string> boot_content;
148     std::vector<std::string> app_content;
149     std::vector<std::unique_ptr<const DexFile>> boot_dex_files;
150     std::vector<std::unique_ptr<const DexFile>> app_dex_files;
151     std::string error_msg;
152 
153     // Read the boot classpath.
154     std::vector<std::string> boot_classpath = Split(options.core_stubs, ':');
155     boot_content.resize(boot_classpath.size());
156     uint32_t i = 0;
157     for (const std::string& str : boot_classpath) {
158       if (!Load(str, boot_content[i++], &boot_dex_files, &error_msg)) {
159         LOG(ERROR) << error_msg;
160         return 1;
161       }
162     }
163 
164     // Read the apps dex files.
165     std::vector<std::string> app_files = Split(options.dex_file, ':');
166     app_content.resize(app_files.size());
167     i = 0;
168     for (const std::string& str : app_files) {
169       if (!Load(str, app_content[i++], &app_dex_files, &error_msg)) {
170         LOG(ERROR) << error_msg;
171         return 1;
172       }
173     }
174 
175     // Resolve classes/methods/fields defined in each dex file.
176 
177     ApiListFilter api_list_filter(options.exclude_api_lists);
178     HiddenApi hidden_api(options.flags_file, api_list_filter);
179 
180     // Cache of types we've seen, for quick class name lookups.
181     TypeMap type_map;
182     // Add internally defined primitives.
183     type_map["Z"] = VeriClass::boolean_;
184     type_map["B"] = VeriClass::byte_;
185     type_map["S"] = VeriClass::short_;
186     type_map["C"] = VeriClass::char_;
187     type_map["I"] = VeriClass::integer_;
188     type_map["F"] = VeriClass::float_;
189     type_map["D"] = VeriClass::double_;
190     type_map["J"] = VeriClass::long_;
191     type_map["V"] = VeriClass::void_;
192 
193     // Cache of resolvers, to easily query address in memory to VeridexResolver.
194     DexResolverMap resolver_map;
195 
196     std::vector<std::unique_ptr<VeridexResolver>> boot_resolvers;
197     Resolve(boot_dex_files, resolver_map, type_map, &boot_resolvers);
198     for (const auto &it : type_map) {
199         hidden_api.AddSignatureSource(it.first, SignatureSource::BOOT);
200     }
201 
202     if (options.precise) {
203       // For precise mode we expect core-stubs to contain java.lang classes.
204       VeriClass::object_ = type_map["Ljava/lang/Object;"];
205       VeriClass::class_ = type_map["Ljava/lang/Class;"];
206       VeriClass::class_loader_ = type_map["Ljava/lang/ClassLoader;"];
207       VeriClass::string_ = type_map["Ljava/lang/String;"];
208       VeriClass::throwable_ = type_map["Ljava/lang/Throwable;"];
209       VeriClass::forName_ = boot_resolvers[0]->LookupDeclaredMethodIn(
210           *VeriClass::class_, "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
211       VeriClass::getField_ = boot_resolvers[0]->LookupDeclaredMethodIn(
212           *VeriClass::class_, "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
213       VeriClass::getDeclaredField_ = boot_resolvers[0]->LookupDeclaredMethodIn(
214           *VeriClass::class_, "getDeclaredField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
215       VeriClass::getMethod_ = boot_resolvers[0]->LookupDeclaredMethodIn(
216           *VeriClass::class_,
217           "getMethod",
218           "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
219       VeriClass::getDeclaredMethod_ = boot_resolvers[0]->LookupDeclaredMethodIn(
220           *VeriClass::class_,
221           "getDeclaredMethod",
222           "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
223       VeriClass::getClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
224           *VeriClass::object_, "getClass", "()Ljava/lang/Class;");
225       VeriClass::loadClass_ = boot_resolvers[0]->LookupDeclaredMethodIn(
226           *VeriClass::class_loader_, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
227 
228       VeriClass* version = type_map["Landroid/os/Build$VERSION;"];
229       if (version != nullptr) {
230         VeriClass::sdkInt_ = boot_resolvers[0]->LookupFieldIn(*version, "SDK_INT", "I");
231       }
232     }
233 
234     std::vector<std::unique_ptr<VeridexResolver>> app_resolvers;
235     Resolve(app_dex_files, resolver_map, type_map, &app_resolvers);
236     for (const auto &it : type_map) {
237       if (!hidden_api.IsInBoot(it.first)) {
238         hidden_api.AddSignatureSource(it.first, SignatureSource::APP);
239       }
240     }
241 
242     ClassFilter app_class_filter(options.app_class_name_filter);
243 
244     // Find and log uses of hidden APIs.
245     HiddenApiStats stats;
246 
247     HiddenApiFinder api_finder(hidden_api);
248     api_finder.Run(app_resolvers, app_class_filter);
249     api_finder.Dump(std::cout, &stats, !options.precise);
250 
251     if (options.precise) {
252       PreciseHiddenApiFinder precise_api_finder(hidden_api);
253       precise_api_finder.Run(app_resolvers, app_class_filter);
254       precise_api_finder.Dump(std::cout, &stats);
255     }
256 
257     DumpSummaryStats(std::cout, stats, api_list_filter);
258 
259     if (options.precise) {
260       std::cout << "To run an analysis that can give more reflection accesses, " << std::endl
261                 << "but could include false positives, pass the --imprecise flag. " << std::endl;
262     }
263 
264     return 0;
265   }
266 
267  private:
DumpSummaryStats(std::ostream & os,const HiddenApiStats & stats,const ApiListFilter & api_list_filter)268   static void DumpSummaryStats(std::ostream& os,
269                                const HiddenApiStats& stats,
270                                const ApiListFilter& api_list_filter) {
271     os << stats.count << " hidden API(s) used: "
272        << stats.linking_count << " linked against, "
273        << stats.reflection_count << " through reflection" << std::endl;
274     DumpApiListStats(os, stats, hiddenapi::ApiList(), api_list_filter);
275     for (size_t i = 0; i < hiddenapi::ApiList::kValueCount; ++i) {
276       DumpApiListStats(os, stats, hiddenapi::ApiList(i), api_list_filter);
277     }
278   }
279 
DumpApiListStats(std::ostream & os,const HiddenApiStats & stats,const hiddenapi::ApiList & api_list,const ApiListFilter & api_list_filter)280   static void DumpApiListStats(std::ostream& os,
281                                const HiddenApiStats& stats,
282                                const hiddenapi::ApiList& api_list,
283                                const ApiListFilter& api_list_filter) {
284     if (api_list_filter.Matches(api_list)) {
285       os << "\t" << stats.api_counts[api_list.GetIntValue()] << " in " << api_list << std::endl;
286     }
287   }
288 
Load(const std::string & filename,std::string & content,std::vector<std::unique_ptr<const DexFile>> * dex_files,std::string * error_msg)289   static bool Load(const std::string& filename,
290                    std::string& content,
291                    std::vector<std::unique_ptr<const DexFile>>* dex_files,
292                    std::string* error_msg) {
293     if (filename.empty()) {
294       *error_msg = "Missing file name";
295       return false;
296     }
297 
298     // TODO: once added, use an api to android::base to read a std::vector<uint8_t>.
299     if (!android::base::ReadFileToString(filename.c_str(), &content)) {
300       *error_msg = "ReadFileToString failed for " + filename;
301       return false;
302     }
303 
304     const DexFileLoader dex_file_loader;
305     DexFileLoaderErrorCode error_code;
306     static constexpr bool kVerifyChecksum = true;
307     static constexpr bool kRunDexFileVerifier = true;
308     if (!dex_file_loader.OpenAll(reinterpret_cast<const uint8_t*>(content.data()),
309                                  content.size(),
310                                  filename.c_str(),
311                                  kRunDexFileVerifier,
312                                  kVerifyChecksum,
313                                  &error_code,
314                                  error_msg,
315                                  dex_files)) {
316       if (error_code == DexFileLoaderErrorCode::kEntryNotFound) {
317         LOG(INFO) << "No .dex found, skipping analysis.";
318         return true;
319       }
320       return false;
321     }
322 
323     return true;
324   }
325 
Resolve(const std::vector<std::unique_ptr<const DexFile>> & dex_files,DexResolverMap & resolver_map,TypeMap & type_map,std::vector<std::unique_ptr<VeridexResolver>> * resolvers)326   static void Resolve(const std::vector<std::unique_ptr<const DexFile>>& dex_files,
327                       DexResolverMap& resolver_map,
328                       TypeMap& type_map,
329                       std::vector<std::unique_ptr<VeridexResolver>>* resolvers) {
330     for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
331       VeridexResolver* resolver =
332           new VeridexResolver(*dex_file.get(), resolver_map, type_map);
333       resolvers->emplace_back(resolver);
334       resolver_map[reinterpret_cast<uintptr_t>(dex_file->Begin())] = resolver;
335     }
336 
337     for (const std::unique_ptr<VeridexResolver>& resolver : *resolvers) {
338       resolver->Run();
339     }
340   }
341 };
342 
343 }  // namespace art
344 
main(int argc,char ** argv)345 int main(int argc, char** argv) {
346   return art::Veridex::Run(argc, argv);
347 }
348