【FlowDroid】一、处理流程学习

FlowDroid 一、处理流程学习

  • 下载配置
  • 源码概况
  • 代码逻辑分析
    • analyzeAPKFile
    • runInfoflow
    • processEntryPoint
    • calculateCallbacks(sourcesAndSinks)
    • 再次回到processEntryPoint

自己做一些笔记

下载配置

参照我前面的文章可以使用FlowDroid安装初体验
为了看代码了解FlowDroid如何处理,clone其官方仓库FlowDroid GitHub

源码概况

下载下来的内容还是挺多的,主要分了以下几个文件夹

  • soot-infoflow: 核心功能代码
  • soot-infoflowandroid: 安卓数据流分析代码
  • soot-infoflow-summaries:字面意思函数摘要
  • soot-infoflow-cmd:使用cmd的解释运行流程
    测试用例
    下面对AliasingTest进行案例分析

代码逻辑分析

analyzeAPKFile

代码片段
这部分跟进去是一个自定义的测试代码片段,跟进去看具体实现,可以看到不同的接口

ICC model(GPT4的回答):
在FlowDroid中,ICC(Inter-Component Communication,组件间通信)模型用于表示和处理安卓应用中各个组件(例如活动、服务、广播接收器等)之间如何相互通信。在Android中,组件通常通过Intent机制来相互通信。ICC模型旨在建模这种Intent传递机制,以更准确地进行数据流分析。
具体来说,FlowDroid的ICC模型可能包括以下几方面的信息:

  • 哪个组件发送了Intent。
  • Intent中包含哪些数据。
  • Intent被发送到哪个组件。
  • 如何处理接收到的Intent。

通过精确地建模这些交互,FlowDroid可以更准确地追踪可能的数据流路径,从而更有效地检测潜在的安全问题。该模型对于理解应用如何处理敏感数据,以及这些数据可能如何泄露(通过组件间的不安全通信)等问题非常有用。
代码片段
再往下跟就是一些配置信息,读取环境变量等,跟进runInfoflow函数,是比较关键的

runInfoflow

代码片段

//这两行代码做了soot的初始化
if (config.getSootIntegrationMode() == SootIntegrationMode.CreateNewInstance) {G.reset();initializeSoot();
}
//soot初始化关键函数,比较常规
private void initializeSoot() {logger.info("Initializing Soot...");final String androidJar = config.getAnalysisFileConfig().getAndroidPlatformDir();final String apkFileLocation = config.getAnalysisFileConfig().getTargetAPKFile();// Clean up any old Soot instance we may haveG.reset();Options.v().set_no_bodies_for_excluded(true);Options.v().set_allow_phantom_refs(true);if (config.getWriteOutputFiles())Options.v().set_output_format(Options.output_format_jimple);elseOptions.v().set_output_format(Options.output_format_none);Options.v().set_whole_program(true);Options.v().set_process_dir(Collections.singletonList(apkFileLocation));if (forceAndroidJar)Options.v().set_force_android_jar(androidJar);elseOptions.v().set_android_jars(androidJar);Options.v().set_src_prec(Options.src_prec_apk_class_jimple);Options.v().set_keep_offset(false);Options.v().set_keep_line_number(config.getEnableLineNumbers());Options.v().set_throw_analysis(Options.throw_analysis_dalvik);Options.v().set_process_multiple_dex(config.getMergeDexFiles());Options.v().set_ignore_resolution_errors(true);// Set soot phase option if original names should be usedif (config.getEnableOriginalNames())Options.v().setPhaseOption("jb", "use-original-names:true");// Set the Soot configuration options. Note that this will needs to be// done before we compute the classpath.if (sootConfig != null)sootConfig.setSootOptions(Options.v(), config);Options.v().set_soot_classpath(getClasspath());Main.v().autoSetOptions();configureCallgraph();// Load whatever we needlogger.info("Loading dex files...");Scene.v().loadNecessaryClasses();// Make sure that we have valid Jimple bodiesPackManager.v().getPack("wjpp").apply();// Patch the callgraph to support additional edges. We do this now,// because during callback discovery, the context-insensitive callgraph// algorithm would flood us with invalid edges.LibraryClassPatcher patcher = getLibraryClassPatcher();patcher.patchLibraries();}

接下来对apk资源文件进行解析,分析入口点

try {parseAppResources();} catch (IOException | XmlPullParserException e) {logger.error("Parse app resource failed", e);throw new RuntimeException("Parse app resource failed", e);}
protected void parseAppResources() throws IOException, XmlPullParserException {final File targetAPK = new File(config.getAnalysisFileConfig().getTargetAPKFile());if (!targetAPK.exists())throw new RuntimeException(String.format("Target APK file %s does not exist", targetAPK.getCanonicalPath()));// Parse the resource filelong beforeARSC = System.nanoTime();this.resources = new ARSCFileParser();this.resources.parse(targetAPK.getAbsolutePath());logger.info("ARSC file parsing took " + (System.nanoTime() - beforeARSC) / 1E9 + " seconds");// To look for callbacks, we need to start somewhere. We use the Android// lifecycle methods for this purpose.this.manifest = createManifestParser(targetAPK);SystemClassHandler.v().setExcludeSystemComponents(config.getIgnoreFlowsInSystemPackages());Set<String> entryPoints = manifest.getEntryPointClasses();this.entrypoints = new HashSet<>(entryPoints.size());for (String className : entryPoints) {SootClass sc = Scene.v().getSootClassUnsafe(className);if (sc != null)this.entrypoints.add(sc);}}

processEntryPoint

Runs the data flow analysis on the given entry point class

if (config.getOneComponentAtATime()) {List<SootClass> entrypointWorklist = new ArrayList<>(entrypoints);while (!entrypointWorklist.isEmpty()) {SootClass entrypoint = entrypointWorklist.remove(0);processEntryPoint(sourcesAndSinks, resultAggregator, entrypointWorklist.size(), entrypoint);}} elseprocessEntryPoint(sourcesAndSinks, resultAggregator, -1, null);

resultAggregator 记录结果的地方

	protected void processEntryPoint(ISourceSinkDefinitionProvider sourcesAndSinks,MultiRunResultAggregator resultAggregator, int numEntryPoints, SootClass entrypoint) {long beforeEntryPoint = System.nanoTime();// Get rid of leftovers from the last entry pointresultAggregator.clearLastResults();// Perform basic app parsinglong callbackDuration = System.nanoTime();try {if (config.getOneComponentAtATime())calculateCallbacks(sourcesAndSinks, entrypoint);elsecalculateCallbacks(sourcesAndSinks);} catch (IOException | XmlPullParserException e) {logger.error("Callgraph construction failed: " + e.getMessage(), e);throw new RuntimeException("Callgraph construction failed", e);}callbackDuration = Math.round((System.nanoTime() - callbackDuration) / 1E9);logger.info(String.format("Collecting callbacks and building a callgraph took %d seconds", (int) callbackDuration));final Collection<? extends ISourceSinkDefinition> sources = getSources();final Collection<? extends ISourceSinkDefinition> sinks = getSinks();final String apkFileLocation = config.getAnalysisFileConfig().getTargetAPKFile();if (config.getOneComponentAtATime())logger.info("Running data flow analysis on {} (component {}/{}: {}) with {} sources and {} sinks...",apkFileLocation, (entrypoints.size() - numEntryPoints), entrypoints.size(), entrypoint,sources == null ? 0 : sources.size(), sinks == null ? 0 : sinks.size());elselogger.info("Running data flow analysis on {} with {} sources and {} sinks...", apkFileLocation,sources == null ? 0 : sources.size(), sinks == null ? 0 : sinks.size());// Create a new entry point and compute the flows in it. If we// analyze all components together, we do not need a new callgraph,// but can reuse the one from the callback collection phase.if (config.getOneComponentAtATime() && config.getSootIntegrationMode().needsToBuildCallgraph()) {createMainMethod(entrypoint);constructCallgraphInternal();}// Create and run the data flow trackerinfoflow = createInfoflow();infoflow.addResultsAvailableHandler(resultAggregator);infoflow.runAnalysis(sourceSinkManager, entryPointCreator.getGeneratedMainMethod());// Update the statisticsif (config.getLogSourcesAndSinks() && infoflow.getCollectedSources() != null)this.collectedSources.addAll(infoflow.getCollectedSources());if (config.getLogSourcesAndSinks() && infoflow.getCollectedSinks() != null)this.collectedSinks.addAll(infoflow.getCollectedSinks());// Print out the found results{int resCount = resultAggregator.getLastResults() == null ? 0 : resultAggregator.getLastResults().size();if (config.getOneComponentAtATime())logger.info("Found {} leaks for component {}", resCount, entrypoint);elselogger.info("Found {} leaks", resCount);}// Update the performance object with the real data{InfoflowResults lastResults = resultAggregator.getLastResults();if (lastResults != null) {InfoflowPerformanceData perfData = lastResults.getPerformanceData();if (perfData == null)lastResults.setPerformanceData(perfData = new InfoflowPerformanceData());perfData.setCallgraphConstructionSeconds((int) callbackDuration);perfData.setTotalRuntimeSeconds((int) Math.round((System.nanoTime() - beforeEntryPoint) / 1E9));}}// We don't need the computed callbacks anymorethis.callbackMethods.clear();this.fragmentClasses.clear();// Notify our result handlersfor (ResultsAvailableHandler handler : resultsAvailableHandlers)handler.onResultsAvailable(resultAggregator.getLastICFG(), resultAggregator.getLastResults());}

calculateCallbacks(sourcesAndSinks)

传进来的参数即为读取的sources和sinks
Calculates the sets of sources, sinks, entry points, and callbacks methods
for the entry point in the given APK file.
sources and sinks

private void calculateCallbacks(ISourceSinkDefinitionProvider sourcesAndSinks, SootClass entryPoint)throws IOException, XmlPullParserException {// Add the callback methodsLayoutFileParser lfp = null;final CallbackConfiguration callbackConfig = config.getCallbackConfig();if (callbackConfig.getEnableCallbacks()) {// If we have a callback file, we use itString callbackFile = callbackConfig.getCallbacksFile();if (callbackFile != null && !callbackFile.isEmpty()) {File cbFile = new File(callbackFile);if (cbFile.exists()) {CollectedCallbacks callbacks = CollectedCallbacksSerializer.deserialize(callbackConfig);if (callbacks != null) {// Get our callback data from the fileentrypoints = callbacks.getEntryPoints();fragmentClasses = callbacks.getFragmentClasses();callbackMethods = callbacks.getCallbackMethods();// Create the callgraphcreateMainMethod(entryPoint);constructCallgraphInternal();createSourceSinkProvider(entryPoint, lfp);return;}}}if (callbackClasses != null && callbackClasses.isEmpty()) {logger.warn("Callback definition file is empty, disabling callbacks");} else {lfp = createLayoutFileParser();switch (callbackConfig.getCallbackAnalyzer()) {case Fast:calculateCallbackMethodsFast(lfp, entryPoint);break;case Default:calculateCallbackMethods(lfp, entryPoint);break;default:throw new RuntimeException("Unknown callback analyzer");}}} else if (config.getSootIntegrationMode().needsToBuildCallgraph()) {// Create the new iteration of the main methodcreateMainMethod(entryPoint);constructCallgraphInternal();}logger.info("Entry point calculation done.");createSourceSinkProvider(entryPoint, lfp);}

在此过程中给对Layout进行了解析LayoutFileParser(this.manifest.getPackageName(), this.resources);

lfp = createLayoutFileParser();
calculateCallbackMethods(lfp, entryPoint);
下面这是真正的计算了

private void calculateCallbackMethods(LayoutFileParser lfp, SootClass component) throws IOException {final CallbackConfiguration callbackConfig = config.getCallbackConfig();// Load the APK fileif (config.getSootIntegrationMode().needsToBuildCallgraph())releaseCallgraph();// Make sure that we don't have any leftovers from previous runsPackManager.v().getPack("wjtp").remove("wjtp.lfp");PackManager.v().getPack("wjtp").remove("wjtp.ajc");// Get the classes for which to find callbacksSet<SootClass> entryPointClasses = getComponentsToAnalyze(component);// Collect the callback interfaces implemented in the app's// source code. Note that the filters should know all components to// filter out callbacks even if the respective component is only// analyzed later.AbstractCallbackAnalyzer jimpleClass = callbackClasses == null? new DefaultCallbackAnalyzer(config, entryPointClasses, callbackMethods, callbackFile): new DefaultCallbackAnalyzer(config, entryPointClasses, callbackMethods, callbackClasses);if (valueProvider != null)jimpleClass.setValueProvider(valueProvider);jimpleClass.addCallbackFilter(new AlienHostComponentFilter(entrypoints));jimpleClass.addCallbackFilter(new ApplicationCallbackFilter(entrypoints));jimpleClass.addCallbackFilter(new UnreachableConstructorFilter());jimpleClass.collectCallbackMethods();// Find the user-defined sources in the layout XML files. This// only needs to be done once, but is a Soot phase.lfp.parseLayoutFile(config.getAnalysisFileConfig().getTargetAPKFile());// Watch the callback collection algorithm's memory consumptionFlowDroidMemoryWatcher memoryWatcher = null;FlowDroidTimeoutWatcher timeoutWatcher = null;if (jimpleClass instanceof IMemoryBoundedSolver) {// Make sure that we don't spend too much time and memory in the callback// analysismemoryWatcher = createCallbackMemoryWatcher(jimpleClass);timeoutWatcher = createCallbackTimeoutWatcher(callbackConfig, jimpleClass);}try {int depthIdx = 0;boolean hasChanged = true;boolean isInitial = true;while (hasChanged) {hasChanged = false;// Check whether the solver has been aborted in the meantimeif (jimpleClass instanceof IMemoryBoundedSolver) {if (((IMemoryBoundedSolver) jimpleClass).isKilled())break;}// Create the new iteration of the main methodcreateMainMethod(component);int numPrevEdges = 0;if (Scene.v().hasCallGraph()) {numPrevEdges = Scene.v().getCallGraph().size();}// Since the generation of the main method can take some time,// we check again whether we need to stop.if (jimpleClass instanceof IMemoryBoundedSolver) {if (((IMemoryBoundedSolver) jimpleClass).isKilled()) {logger.warn("Callback calculation aborted due to timeout");break;}}if (!isInitial) {// Reset the callgraphreleaseCallgraph();// We only want to parse the layout files oncePackManager.v().getPack("wjtp").remove("wjtp.lfp");}isInitial = false;// Run the soot-based operationsconstructCallgraphInternal();if (!Scene.v().hasCallGraph())throw new RuntimeException("No callgraph in Scene even after creating one. That's very sad "+ "and should never happen.");lfp.parseLayoutFileDirect(config.getAnalysisFileConfig().getTargetAPKFile());PackManager.v().getPack("wjtp").apply();// Creating all callgraph takes time and memory. Check whether// the solver has been aborted in the meantimeif (jimpleClass instanceof IMemoryBoundedSolver) {if (((IMemoryBoundedSolver) jimpleClass).isKilled()) {logger.warn("Aborted callback collection because of low memory");break;}}if (numPrevEdges < Scene.v().getCallGraph().size())hasChanged = true;// Collect the results of the soot-based phasesif (this.callbackMethods.putAll(jimpleClass.getCallbackMethods()))hasChanged = true;if (entrypoints.addAll(jimpleClass.getDynamicManifestComponents()))hasChanged = true;// Collect the XML-based callback methodsif (collectXmlBasedCallbackMethods(lfp, jimpleClass))hasChanged = true;// Avoid callback overruns. If we are beyond the callback limit// for one entry point, we may not collect any further callbacks// for that entry point.if (callbackConfig.getMaxCallbacksPerComponent() > 0) {for (Iterator<SootClass> componentIt = this.callbackMethods.keySet().iterator(); componentIt.hasNext();) {SootClass callbackComponent = componentIt.next();if (this.callbackMethods.get(callbackComponent).size() > callbackConfig.getMaxCallbacksPerComponent()) {componentIt.remove();jimpleClass.excludeEntryPoint(callbackComponent);}}}// Check depth limitingdepthIdx++;if (callbackConfig.getMaxAnalysisCallbackDepth() > 0&& depthIdx >= callbackConfig.getMaxAnalysisCallbackDepth())break;// If we work with an existing callgraph, the callgraph never// changes and thus it doesn't make any sense to go multiple// roundsif (config.getSootIntegrationMode() == SootIntegrationMode.UseExistingCallgraph)break;}} catch (Exception ex) {logger.error("Could not calculate callback methods", ex);throw ex;} finally {// Shut down the watchersif (timeoutWatcher != null)timeoutWatcher.stop();if (memoryWatcher != null)memoryWatcher.close();}// Filter out callbacks that belong to fragments that are not used by// the host activityAlienFragmentFilter fragmentFilter = new AlienFragmentFilter(invertMap(fragmentClasses));fragmentFilter.reset();for (Iterator<Pair<SootClass, AndroidCallbackDefinition>> cbIt = this.callbackMethods.iterator(); cbIt.hasNext();) {Pair<SootClass, AndroidCallbackDefinition> pair = cbIt.next();// Check whether the filter accepts the given mappingif (!fragmentFilter.accepts(pair.getO1(), pair.getO2().getTargetMethod()))cbIt.remove();else if (!fragmentFilter.accepts(pair.getO1(), pair.getO2().getTargetMethod().getDeclaringClass())) {cbIt.remove();}}// Avoid callback overrunsif (callbackConfig.getMaxCallbacksPerComponent() > 0) {for (Iterator<SootClass> componentIt = this.callbackMethods.keySet().iterator(); componentIt.hasNext();) {SootClass callbackComponent = componentIt.next();if (this.callbackMethods.get(callbackComponent).size() > callbackConfig.getMaxCallbacksPerComponent())componentIt.remove();}}// Make sure that we don't retain any weird Soot phasesPackManager.v().getPack("wjtp").remove("wjtp.lfp");PackManager.v().getPack("wjtp").remove("wjtp.ajc");// Warn the user if we had to abort the callback analysis earlyboolean abortedEarly = false;if (jimpleClass instanceof IMemoryBoundedSolver) {if (((IMemoryBoundedSolver) jimpleClass).isKilled()) {logger.warn("Callback analysis aborted early due to time or memory exhaustion");abortedEarly = true;}}if (!abortedEarly)logger.info("Callback analysis terminated normally");// Serialize the callbacksif (callbackConfig.isSerializeCallbacks()) {CollectedCallbacks callbacks = new CollectedCallbacks(entryPointClasses, callbackMethods, fragmentClasses);CollectedCallbacksSerializer.serialize(callbacks, callbackConfig);}}

这段代码首先对调用图进行重置

	protected void releaseCallgraph() {// If we are configured to use an existing callgraph, we may not release// itif (config.getSootIntegrationMode() == SootIntegrationMode.UseExistingCallgraph)return;Scene.v().releaseCallGraph();Scene.v().releasePointsToAnalysis();Scene.v().releaseReachableMethods();G.v().resetSpark();}

接下来两行代码不懂问了GPT

		// Make sure that we don't have any leftovers from previous runsPackManager.v().getPack("wjtp").remove("wjtp.lfp");PackManager.v().getPack("wjtp").remove("wjtp.ajc");
PackManager.v().getPack("wjtp")

这部分获取名为 “wjtp” 的分析阶段组(pack)。Soot框架将各种分析和转换任务组织在不同的阶段组(如 “wjtp”, “jtp”, “cg” 等)中。

remove(“wjtp.lfp”) 和 remove(“wjtp.ajc”):这两行代码从 “wjtp” 阶段组中移除特定的分析或转换阶段。具体来说,它们移除名为 “wjtp.lfp” 和 “wjtp.ajc” 的阶段。

这两行代码确保在新一轮的Soot分析或转换开始之前,清除先前可能添加到 “wjtp” 阶段组的 “wjtp.lfp” 和 “wjtp.ajc” 分析阶段。这样做主要是为了避免先前运行的残留影响到当前的运行。这是一种清理机制,确保每次运行都是在干净、一致的环境中进行。

再次回到processEntryPoint

变量值
准备数据流

Instantiates and configures the data flow engine

	private IInPlaceInfoflow createInfoflow() {// Some sanity checksif (config.getSootIntegrationMode().needsToBuildCallgraph()) {if (entryPointCreator == null)throw new RuntimeException("No entry point available");if (entryPointCreator.getComponentToEntryPointInfo() == null)throw new RuntimeException("No information about component entry points available");}// Get the component lifecycle methodsCollection<SootMethod> lifecycleMethods = Collections.emptySet();if (entryPointCreator != null) {ComponentEntryPointCollection entryPoints = entryPointCreator.getComponentToEntryPointInfo();if (entryPoints != null)lifecycleMethods = entryPoints.getLifecycleMethods();}// Initialize and configure the data flow trackerIInPlaceInfoflow info = createInfoflowInternal(lifecycleMethods);if (ipcManager != null)info.setIPCManager(ipcManager);info.setConfig(config);info.setSootConfig(sootConfig);info.setTaintWrapper(taintWrapper);info.setTaintPropagationHandler(taintPropagationHandler);info.setAliasPropagationHandler(aliasPropagationHandler);// We use a specialized memory manager that knows about Androidinfo.setMemoryManagerFactory(new IMemoryManagerFactory() {@Overridepublic IMemoryManager<Abstraction, Unit> getMemoryManager(boolean tracingEnabled,PathDataErasureMode erasePathData) {return new AndroidMemoryManager(tracingEnabled, erasePathData, entrypoints);}});info.setMemoryManagerFactory(null);// Inject additional post-processorsinfo.setPostProcessors(Collections.singleton(new PostAnalysisHandler() {@Overridepublic InfoflowResults onResultsAvailable(InfoflowResults results, IInfoflowCFG cfg) {// Purify the ICC results if requestedfinal IccConfiguration iccConfig = config.getIccConfig();if (iccConfig.isIccResultsPurifyEnabled()) {// no-op at the moment. We used to have a purifier here, but it didn't make// any sense. Removed it for the better.}return results;}}));return info;}

接下来进入到runAnalysis函数内部,这个函数似乎比较关键
Conducts a taint analysis on an already initialized callgraph

	protected void runAnalysis(final ISourceSinkManager sourcesSinks, final Set<String> additionalSeeds) {final InfoflowPerformanceData performanceData = createPerformanceDataClass();try {// Clear the data from previous runsresults = createResultsObject();results.setPerformanceData(performanceData);// Print and check our configurationcheckAndFixConfiguration();config.printSummary();// Register a memory watcherif (memoryWatcher != null) {memoryWatcher.clearSolvers();memoryWatcher = null;}memoryWatcher = new FlowDroidMemoryWatcher(results, config.getMemoryThreshold());// Initialize the abstraction configurationAbstraction.initialize(config);// Build the callgraphlong beforeCallgraph = System.nanoTime();constructCallgraph();performanceData.setCallgraphConstructionSeconds((int) Math.round((System.nanoTime() - beforeCallgraph) / 1E9));logger.info(String.format(Locale.getDefault(), "Callgraph construction took %d seconds",performanceData.getCallgraphConstructionSeconds()));// Initialize the source sink managerif (sourcesSinks != null)sourcesSinks.initialize();// Perform constant propagation and remove dead codeif (config.getCodeEliminationMode() != CodeEliminationMode.NoCodeElimination) {long currentMillis = System.nanoTime();eliminateDeadCode(sourcesSinks);logger.info("Dead code elimination took " + (System.nanoTime() - currentMillis) / 1E9 + " seconds");}// After constant value propagation, we might find more call edges// for reflective method callsif (config.getEnableReflection()) {releaseCallgraph();constructCallgraph();}if (config.getCallgraphAlgorithm() != CallgraphAlgorithm.OnDemand)logger.info("Callgraph has {} edges", Scene.v().getCallGraph().size());IInfoflowCFG iCfg = icfgFactory.buildBiDirICFG(config.getCallgraphAlgorithm(),config.getEnableExceptionTracking());if (config.isTaintAnalysisEnabled())runTaintAnalysis(sourcesSinks, additionalSeeds, iCfg, performanceData);// Gather performance dataperformanceData.setTotalRuntimeSeconds((int) Math.round((System.nanoTime() - beforeCallgraph) / 1E9));performanceData.updateMaxMemoryConsumption(getUsedMemory());logger.info(String.format("Data flow solver took %d seconds. Maximum memory consumption: %d MB",performanceData.getTotalRuntimeSeconds(), performanceData.getMaxMemoryConsumption()));// Provide the handler with the final resultsfor (ResultsAvailableHandler handler : onResultsAvailable)handler.onResultsAvailable(iCfg, results);// Write the Jimple files to disk if requestedif (config.getWriteOutputFiles())PackManager.v().writeOutput();} catch (Exception ex) {StringWriter stacktrace = new StringWriter();PrintWriter pw = new PrintWriter(stacktrace);ex.printStackTrace(pw);if (results != null)results.addException(ex.getClass().getName() + ": " + ex.getMessage() + "\n" + stacktrace.toString());logger.error("Exception during data flow analysis", ex);if (throwExceptions)throw ex;}}

constructCallgraph();
构造调用图

	protected void constructCallgraph() {if (config.getSootIntegrationMode().needsToBuildCallgraph()) {// Allow the ICC manager to change the Soot Scene before we continueif (ipcManager != null)ipcManager.updateJimpleForICC();// Run the preprocessorsfor (PreAnalysisHandler tr : preProcessors)tr.onBeforeCallgraphConstruction();// Patch the system libraries we need for callgraph constructionLibraryClassPatcher patcher = getLibraryClassPatcher();patcher.patchLibraries();// To cope with broken APK files, we convert all classes that are still// dangling after resolution into phantomsfor (SootClass sc : Scene.v().getClasses())if (sc.resolvingLevel() == SootClass.DANGLING) {sc.setResolvingLevel(SootClass.BODIES);sc.setPhantomClass();}// We explicitly select the packs we want to run for performance// reasons. Do not re-run the callgraph algorithm if the host// application already provides us with a CG.if (config.getCallgraphAlgorithm() != CallgraphAlgorithm.OnDemand && !Scene.v().hasCallGraph()) {PackManager.v().getPack("wjpp").apply();PackManager.v().getPack("cg").apply();}}// If we don't have a FastHierarchy, we need to create it - even if we use an// existing callgraphhierarchy = Scene.v().getOrMakeFastHierarchy();if (config.getSootIntegrationMode().needsToBuildCallgraph()) {// Run the preprocessorsfor (PreAnalysisHandler tr : preProcessors)tr.onAfterCallgraphConstruction();}}

runAnalysis分析结束后回到了processEntryPoint

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/62318.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

homeassistant ubuntu自启动 网络设置

命令行安装virtualbox 或者安装包 hass官网下载 haos_ova-10.4.vdi virtualbox 装hass 最少2G内存 其他省略 自启动&#xff1a; gnome-session-properties 添加 VBoxManage startvm hass --type headless hass为自己的虚拟机名字 网络配置如下&#xff1a; 要全部打开

【云原生】Kubernetes容器编排工具

目录 1. K8S介绍 1.1 k8s的由来 下载地址 1.2 docker编排与k8s编排相比 1.3 传统后端部署与k8s 的对比 传统部署 k8s部署 ​2. k8s的集群架构与组件 &#xff08;1&#xff09; Kube-apiserver &#xff08;2&#xff09;Kube-controller-manager &#xff08;3&a…

Qt应用开发(基础篇)——对话框窗口 QDialog

一、前言 QDialog类继承于QWidget&#xff0c;是Qt基于对话框窗口(消息窗口QMessageBox、颜色选择窗口QColorDialog、文件选择窗口QFileDialog等)的基类。 QDialog窗口是顶级的窗口&#xff0c;一般情况下&#xff0c;用来当做用户短期任务(确认、输入、选择)或者和用户交流(提…

一、安装GoLang环境和开发工具

一、安装GoLang环境 GoLang中国镜像站 下载后对应的环境包以后&#xff0c;一路下一步就好了&#xff0c;安装路径的话&#xff0c;尽量就安装到默认的文件目录下。 二、配置Go的环境变量 右击此电脑–>属性–>高级系统设置–>环境变量&#xff0c;打开环境变量设置…

MySQL高阶语句之常用查询

目录 常用查询 按关键字排序 区间判断及查询不重复记录 对结果进行分组 限制结果条目 设置别名 通配符 子查询 常用查询 &#xff08;增、删、改、查&#xff09; 对 MySQL 数据库的查询&#xff0c;除了基本的查询外&#xff0c;有时候需要对查询的结果集进行处理。 …

设计模式之工厂模式(万字长文)

文章目录 概述工厂模式的优点包括工厂模式有几种主要的变体看一个具体需求使用传统的方式来完成传统的方式的优缺点 简单工厂模式基本介绍使用简单工厂模式简单工厂模式的优缺点优点&#xff1a;缺点&#xff1a; 工厂方法模式看一个新的需求思路 1思路 2工厂方法模式介绍工厂方…

nextTick原理

nextTick 是 Vue 提供的一个异步方法&#xff0c;用于在 DOM 更新之后执行回调函数。它的原理是利用 JavaScript 的事件循环机制来实现异步执行。 具体来说&#xff0c;当我们调用 nextTick 方法时&#xff0c;Vue 会将传入的回调函数添加到一个队列中。在下一个事件循环中&am…

Django(7)-项目实战-发布会签到管理系统

本文使用django实现一个简单的发布会签到管理系统 登录功能 模板页面 sign/templates/index.html <!DOCTYPE html> <html> <head><title>Login Page</title> </head> <body><h1>发布会管理</h1><form action=&qu…

springboot实战(一)之项目搭建

环境准备 ideajdk1.8springboot版本 2.7.15 项目开始 1.打开idea&#xff0c;点击new project 2.选择spring initillizr 核对&#xff1a;Server Url是否是&#xff1a;start.spring.io&#xff0c;然后根据自己依次设置项目名称、存储位置和包名&#xff0c;如下&#xff…

北京开发APP的费用明细

开发APP项目时&#xff0c;在功能确定后需要知道有哪些可能的费用&#xff0c;安排项目预算。北京开发APP的费用明细可能会包括以下几个部分&#xff0c;每个部分都会产生一些费用。今天和大家分享APP费用明细有哪些&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&…

vue2 自定义指令,插槽

一、学习目标 1.自定义指令 基本语法&#xff08;全局、局部注册&#xff09;指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 二、自定义指令 1.指令介绍 内置指令&#xff1a;v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令&#xff0c;…

大数据之Maven

一、Maven的作用 作用一&#xff1a;下载对应的jar包 避免jar包重复下载配置&#xff0c;保证多个工程共用一份jar包。Maven有一个本地仓库&#xff0c;可以通过pom.xml文件来记录jar所在的位置。Maven会自动从远程仓库下载jar包&#xff0c;并且会下载所依赖的其他jar包&…

《信息系统项目管理师教程(第4版)》第17章 采购管理、合同管理 知识点整理,xmind思维导图

已上传采购管理xmind思维导图&#xff0c;需要的同学可以直接下载哦。 一、规划采购管理 二、实施采购 三、控制采购 四、合同管理 4.1 合同类型 4.2 合同管理过程 签订履行变更档案&#xff0c;合同档案管理是整个合同管理的基础&#xff0c;要求采用电脑打印文本&#xff…

考研408 | 【操作系统】终章

I/O设备的基本概念和分类 I/O设备&#xff1a; I/O设备的分类 1.按使用特性&#xff1a; 2.按传输速率分类&#xff1a; 3.按信息交换的单位分类&#xff1a; 总结&#xff1a; I/O控制器 I/O设备的机械部件&#xff1a; I/O设备的电子部件&#xff08;I/O控制器&#…

国标视频融合云平台EasyCVR视频汇聚平台的应用场景及其功能说明

一、平台简介 EasyCVR国标视频融合云平台是一款基于端-边-云一体化架构的视频融合AI智能分析网关平台。EasyCVR平台支持视频汇聚、融合管理&#xff0c;兼容多类型设备、多协议接入。其提供的视频功能包括&#xff1a;视频监控、无插件直播录像、云存储、检索回放、智能告警、…

uniapp微信小程序使用stomp.js实现STOMP传输协议的实时聊天

简介&#xff1a; 原生微信小程序中使用 本来使用websocket&#xff0c;后端同事使用了stomp协议&#xff0c;导致前端也需要对应修改。 如何使用 1.yarn add stompjs 2.版本 “stompjs”: “^2.3.3” 3.在static/js中新建stomp.js和websocket.js&#xff0c;然后在需要使用…

E8267D 是德科技矢量信号发生器

描述 最先进的微波信号发生器 安捷伦E8267D PSG矢量信号发生器是业界首款集成式微波矢量信号发生器&#xff0c;I/Q调制最高可达44 GHz&#xff0c;典型输出功率为23 dBm&#xff0c;最高可达20 GHz&#xff0c;对于10 GHz信号&#xff0c;10 kHz偏移时的相位噪声为-120 dBc/…

【C51基础实验 LED流水灯】

51单片机项目基础篇 LED流水灯1、硬件电路设计和原理分析2、软件设计2.1、利用循环和移位操作符功能实现&#xff1a;LED流水灯2.2、利用利用封装好的库函数功能实现&#xff1a;LED流水灯 3、编译结果4、结束语 LED流水灯 前言&#xff1a; 前几篇学会了LED驱动原理&#xff…

爬虫逆向实战(二十六)--某某学堂登录

一、数据接口分析 主页地址&#xff1a;某某学堂 1、抓包 通过抓包可以发现数据接口是Account/LoginPost 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现pass是加密参数 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无co…

YOLOv5算法改进(7)— 添加SimAM注意力机制

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。SimAM&#xff08;Similarity-based Attention Mechanism&#xff09;是一种基于相似度的注意力机制&#xff0c;它的原理是通过计算查询向量与每个键向量之间的相似度&#xff0c;从而确定每个键向量对于查询向量的重要性…