【FlowDroid】一、处理流程学习

news2024/10/4 19:28:50

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 have
		G.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);
		else
			Options.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);
		else
			Options.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 used
		if (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 need
		logger.info("Loading dex files...");
		Scene.v().loadNecessaryClasses();

		// Make sure that we have valid Jimple bodies
		PackManager.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 file
		long 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);
			}
	} else
		processEntryPoint(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 point
		resultAggregator.clearLastResults();

		// Perform basic app parsing
		long callbackDuration = System.nanoTime();
		try {
			if (config.getOneComponentAtATime())
				calculateCallbacks(sourcesAndSinks, entrypoint);
			else
				calculateCallbacks(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());
		else
			logger.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 tracker
		infoflow = createInfoflow();
		infoflow.addResultsAvailableHandler(resultAggregator);
		infoflow.runAnalysis(sourceSinkManager, entryPointCreator.getGeneratedMainMethod());

		// Update the statistics
		if (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);
			else
				logger.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 anymore
		this.callbackMethods.clear();
		this.fragmentClasses.clear();

		// Notify our result handlers
		for (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 methods
		LayoutFileParser lfp = null;
		final CallbackConfiguration callbackConfig = config.getCallbackConfig();
		if (callbackConfig.getEnableCallbacks()) {
			// If we have a callback file, we use it
			String 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 file
						entrypoints = callbacks.getEntryPoints();
						fragmentClasses = callbacks.getFragmentClasses();
						callbackMethods = callbacks.getCallbackMethods();

						// Create the callgraph
						createMainMethod(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 method
			createMainMethod(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 file
		if (config.getSootIntegrationMode().needsToBuildCallgraph())
			releaseCallgraph();

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

		// Get the classes for which to find callbacks
		Set<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 consumption
		FlowDroidMemoryWatcher memoryWatcher = null;
		FlowDroidTimeoutWatcher timeoutWatcher = null;
		if (jimpleClass instanceof IMemoryBoundedSolver) {
			// Make sure that we don't spend too much time and memory in the callback
			// analysis
			memoryWatcher = 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 meantime
				if (jimpleClass instanceof IMemoryBoundedSolver) {
					if (((IMemoryBoundedSolver) jimpleClass).isKilled())
						break;
				}

				// Create the new iteration of the main method
				createMainMethod(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 callgraph
					releaseCallgraph();

					// We only want to parse the layout files once
					PackManager.v().getPack("wjtp").remove("wjtp.lfp");
				}
				isInitial = false;

				// Run the soot-based operations
				constructCallgraphInternal();
				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 meantime
				if (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 phases
				if (this.callbackMethods.putAll(jimpleClass.getCallbackMethods()))
					hasChanged = true;

				if (entrypoints.addAll(jimpleClass.getDynamicManifestComponents()))
					hasChanged = true;

				// Collect the XML-based callback methods
				if (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 limiting
				depthIdx++;
				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
				// rounds
				if (config.getSootIntegrationMode() == SootIntegrationMode.UseExistingCallgraph)
					break;
			}
		} catch (Exception ex) {
			logger.error("Could not calculate callback methods", ex);
			throw ex;
		} finally {
			// Shut down the watchers
			if (timeoutWatcher != null)
				timeoutWatcher.stop();
			if (memoryWatcher != null)
				memoryWatcher.close();
		}

		// Filter out callbacks that belong to fragments that are not used by
		// the host activity
		AlienFragmentFilter 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 mapping
			if (!fragmentFilter.accepts(pair.getO1(), pair.getO2().getTargetMethod()))
				cbIt.remove();
			else if (!fragmentFilter.accepts(pair.getO1(), pair.getO2().getTargetMethod().getDeclaringClass())) {
				cbIt.remove();
			}
		}

		// Avoid callback overruns
		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();
			}
		}

		// Make sure that we don't retain any weird Soot phases
		PackManager.v().getPack("wjtp").remove("wjtp.lfp");
		PackManager.v().getPack("wjtp").remove("wjtp.ajc");

		// Warn the user if we had to abort the callback analysis early
		boolean 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 callbacks
		if (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
		// it
		if (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 runs
		PackManager.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 checks
		if (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 methods
		Collection<SootMethod> lifecycleMethods = Collections.emptySet();
		if (entryPointCreator != null) {
			ComponentEntryPointCollection entryPoints = entryPointCreator.getComponentToEntryPointInfo();
			if (entryPoints != null)
				lifecycleMethods = entryPoints.getLifecycleMethods();
		}

		// Initialize and configure the data flow tracker
		IInPlaceInfoflow 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 Android
		info.setMemoryManagerFactory(new IMemoryManagerFactory() {

			@Override
			public IMemoryManager<Abstraction, Unit> getMemoryManager(boolean tracingEnabled,
					PathDataErasureMode erasePathData) {
				return new AndroidMemoryManager(tracingEnabled, erasePathData, entrypoints);
			}

		});
		info.setMemoryManagerFactory(null);

		// Inject additional post-processors
		info.setPostProcessors(Collections.singleton(new PostAnalysisHandler() {

			@Override
			public InfoflowResults onResultsAvailable(InfoflowResults results, IInfoflowCFG cfg) {
				// Purify the ICC results if requested
				final 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 runs
			results = createResultsObject();
			results.setPerformanceData(performanceData);

			// Print and check our configuration
			checkAndFixConfiguration();
			config.printSummary();

			// Register a memory watcher
			if (memoryWatcher != null) {
				memoryWatcher.clearSolvers();
				memoryWatcher = null;
			}
			memoryWatcher = new FlowDroidMemoryWatcher(results, config.getMemoryThreshold());

			// Initialize the abstraction configuration
			Abstraction.initialize(config);

			// Build the callgraph
			long 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 manager
			if (sourcesSinks != null)
				sourcesSinks.initialize();

			// Perform constant propagation and remove dead code
			if (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 calls
			if (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 data
			performanceData.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 results
			for (ResultsAvailableHandler handler : onResultsAvailable)
				handler.onResultsAvailable(iCfg, results);

			// Write the Jimple files to disk if requested
			if (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 continue
			if (ipcManager != null)
				ipcManager.updateJimpleForICC();

			// Run the preprocessors
			for (PreAnalysisHandler tr : preProcessors)
				tr.onBeforeCallgraphConstruction();

			// Patch the system libraries we need for callgraph construction
			LibraryClassPatcher patcher = getLibraryClassPatcher();
			patcher.patchLibraries();

			// To cope with broken APK files, we convert all classes that are still
			// dangling after resolution into phantoms
			for (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 callgraph
		hierarchy = Scene.v().getOrMakeFastHierarchy();

		if (config.getSootIntegrationMode().needsToBuildCallgraph()) {
			// Run the preprocessors
			for (PreAnalysisHandler tr : preProcessors)
				tr.onAfterCallgraphConstruction();
		}
	}

runAnalysis分析结束后回到了processEntryPoint

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

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

相关文章

关于CICD流水线的前端项目运行错误,npm项目环境配置时出现报错:Not Found - GET https://registry.npm...

关于CICD流水线的前端项目运行错误&#xff0c;npm项目环境配置时出现报错&#xff1a;Not Found - GET https://registry.npm… 原因应该是某些jar包缓存中没有需要改变镜像将包拉下来 npm config set registry http://registry.npm.taobao.org npm install npm run build

java实现多文件压缩zip

1&#xff0c;需求 需求要求实现多个文件压缩为zip文件 2&#xff0c;代码 package com.example.demo;import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import…

【宝藏系列】一文带你了解STM32内置的硬件功能安全属性

【宝藏系列】一文带你了解STM32内置的硬件功能安全属性 文章目录 【宝藏系列】一文带你了解STM32内置的硬件功能安全属性&#x1f468;‍&#x1f3eb;概览1️⃣双看门狗&#xff1a;独立看门狗和窗口看门狗2️⃣电源监测3️⃣时钟安全系统CSS4️⃣SRAM奇偶校验位5️⃣硬件ECC6…

【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之数码管动态显示(五)

本原创教程由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处 适用于板卡型号&#xff1a; 紫光同创PGL22G开发平台&#xff08;盘古22K&#xff09; 一&#xff1a;盘古22K开发板&#xff08;紫光同创PGL22G开发…

口碑最好的洗拖一体机 大面积洗地机十大排名

口碑最好的洗拖一体机 大面积洗地机十大排名 口碑最好的洗拖一体机&#xff0c;是现代家庭清洁的必备神器。它不仅能快速高效地清洁地面&#xff0c;还能省时省力&#xff0c;完成一些繁琐的家务活。那么&#xff0c;当我们面对市面上琳琅满目的洗地机品牌时&#xff0c;该如何…

Qt/C++编写视频监控系统81-Onvif报警抓图和录像并回放

一、前言 视频监控系统中的图文警情模块&#xff0c;是通过Onvif协议的事件订阅拿到的&#xff0c;通过事件订阅后&#xff0c;设备的各种报警事件比如入侵报警/遮挡报警/越界报警/开关量报警等&#xff0c;触发后都会主动往订阅者发送&#xff0c;而且一般都是会发送两次&…

idea创建同名模块问题:模块变为灰色不可用,模块已经存在

1. 问题1&#xff1a;同名模块变为灰色 idea创建一个模块&#xff0c;由于创建过程哪一步错误了&#xff0c;此时再次创建同名的模块&#xff0c;发现模块变为灰色&#xff1a;原因是创建同名的模块会被忽略掉&#xff0c;不可用。 删除模块 再次创建同名模块&#xff1a;变…

如何在 iPhone 上检索已删除的短信

我厌倦了垃圾短信。当我例行公事地删除 iPhone 上的这些不需要的消息时&#xff0c;当我分散注意力时&#xff0c;我通过点击错误的按钮清除了所有消息。这些被删除的消息中包含两条团购验证信息。有什么办法可以从 iPhone 检索我的消息吗&#xff1f; 有时我们可能会不小心删…

TypeScript_算法复杂度-哈希表

算法复杂度 对于同一个问题&#xff0c;我们往往其实有很多种解决它的思路和方法&#xff0c;也就是可以采用不同的算法 但是不同的算法&#xff0c;其实效率是不一样的 举个例子&#xff08;现实的例子&#xff09;:在一个庞大的图书馆中&#xff0c;我们需要找一本书。在图…

axis tstrb tkeep

AXI 协议支持地址非对齐的传输&#xff0c;允许突发传输的首字节地址&#xff0c;即起始地址与突发传输位宽不对齐。举个例子&#xff0c;总线位宽为 32bit 时&#xff0c;如果起始地址为 0x1002 &#xff0c;则产生了非对齐现象。与 32bit 位宽总线对齐的地址需要能被 4 整除&…

springboot3.1.3和mybatis-plus3.5和最新代码生成器实践

spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/数据库名?useUnicodetrue&characterEncodingutf-8&autoReconnecttrue&useSSLfalse&serverTimezoneUTCusername: rootpassword: 123456mybatis-plus:# xml地址ma…

c++搜索剪枝常见方法与技巧

目录 搜索剪枝常见方法与技巧 关键字 搜索方法,剪枝 摘要 正文 小结 程序 参考书目 搜索剪枝常见方法与技巧 关键字 搜索方法,剪枝 摘要 搜索是计算机解题中常用的方法&#xff0c;它实质上是枚举法的应用。由于它相当于枚举法&#xff0c;所以其效率是相当地的。因此…

冠达管理 :主升浪前最后一次洗盘?

随着科技的不断发展&#xff0c;人们关于金融商场的了解也越来越深入。在股市中&#xff0c;洗盘是一个非常重要的概念。洗盘是指许多的股票被清洗出某个价位上的持有者&#xff0c;从而拉低该价位上的股票价格&#xff0c;为后续上涨做出铺垫。而在股市中&#xff0c;主升浪前…

DolphinDB 携手白鲸开源 WhaleStudio 打造高效敏捷的 DataOps 解决方案

浙江智臾科技有限公司&#xff08;简称&#xff1a;DolphinDB&#xff09;和北京白鲸开源科技有限公司&#xff08;简称&#xff1a;白鲸开源&#xff09;是在大数据技术领域活跃的两支专业团队。 DolphinDB 专注于为用户提供集高性能存储、复杂分析能力和流处理于一体的实时计…

SUB-1G无线收发芯片DP4306低功耗的单片集成收发机

概述 DP4306是一款高性能低功耗的单片集成收发机&#xff0c;工作频率可覆盖200MHz~ 1000MHz, 芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK 解调器等功能模块。通过SPI接口可以对输出功率、频道选择以及数据包格式进行灵活配置&#xff0c;并且内置CRC、…

如何为新产品做好全网口碑推广?

互联网时代下&#xff0c;产品上市后的口碑营销直接关系到产品的销售量。不管是网购还是线下购物&#xff0c;消费者喜欢通过互联网去查询产品的网络口碑&#xff0c;如果产品评价不好可能不断丢失客户。新产品推出之后做好全网口碑推广&#xff0c;为新品的销售做好铺垫已经成…

MySQL 8 数据清洗总结

MySQL 8 数据清洗三要素&#xff1a; 库表拷贝和数据备份数据清洗SQL数据清洗必杀技-存储过程 前提&#xff1a;数据库关联库表初始化和基础数据初始化&#xff1a; -- usc.t_project definitionCREATE TABLE t_project (id varchar(64) NOT NULL COMMENT 主键,tid varchar(…

Scrum Master 面试问题- ChatGPT 版

之前&#xff0c;我测试了 ChatGPT 如何回答《Scrum Master 面试指南》中的问题&#xff1b;见下文。早在2023 年 1 月&#xff0c;我就不会在 Scrum Master 面试过程中采取下一步&#xff0c;邀请ChatGPT与几名Scrum团队成员进行全方位的面试。 那么&#xff0c;如果 GPT 3.5…

JavaScript(函数,作用域和闭包)

目录 一&#xff0c;什么是函数1.1&#xff0c;常用系统函数1.2&#xff0c;函数声明 1.3&#xff0c;函数表达式二&#xff0c;预解析2.1&#xff0c;函数自调用 2.2&#xff0c;回调函数三&#xff0c;变量的作用域3.1&#xff0c;隐式全局变量 四&#xff0c;作用域与块级作…

如何从0跑起Vue3项目(Node和npm环境配置)

文章目录 vue项目运行Node安装打开vue项目 vue项目 拥有了一个vue3项目后怎么将它跑起来&#xff1f; 期末在学长敲代码那儿做的vue课设&#xff0c;怎么将他从0跑起来&#xff1f; char[] str "如果需要做课设的小伙伴&#xff0c;也可以百度:学长敲代码" strin…