文章目录
WALA安装与基础使用
前段时间由于课程需要,用到了WALA框架。但苦于网上资料较少,学习过程比较曲折。故打算写一篇文章,希望能帮助大家入门~
Reference
特别感谢课程助教!
WALA简介
WALA是IBM公司于2006年开源的一个静态程序分析框架
WALA的核心功能:
- Java类型系统和类层次结构分析
- 支持Java和JavaScript的源语言框架
- 过程间数据流分析(RHS求解器)
- 基于上下文的基于列表的切片器
- 指针分析和调用图构造
- 基于SSA的寄存器传输语言IR
- 迭代数据流的通用框架
- 通用分析工具和数据结构
- 字节码检测库(Shrike)和Java的动态加载时检测库(Dila)
WALA导入
方法一 通过pom.xml文件导入
此处提供我的pom.xml作为样例~
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>automatedtesting2020</groupId>
<artifactId>test-selection</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.ibm.wala/com.ibm.wala.util -->
<dependency>
<groupId>com.ibm.wala</groupId>
<artifactId>com.ibm.wala.util</artifactId>
<version>1.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.ibm.wala/com.ibm.wala.shrike -->
<dependency>
<groupId>com.ibm.wala</groupId>
<artifactId>com.ibm.wala.shrike</artifactId>
<version>1.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.ibm.wala/com.ibm.wala.core -->
<dependency>
<groupId>com.ibm.wala</groupId>
<artifactId>com.ibm.wala.core</artifactId>
<version>1.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.ibm.wala/com.ibm.wala.cast -->
<dependency>
<groupId>com.ibm.wala</groupId>
<artifactId>com.ibm.wala.cast</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
方法二 从maven库中下载jar包
下载地址为maven库
如果不知道怎么下载jar包,参见如何从maven资源库下载jar包
然后将下载好的jar包导入到你的工程中。
WALA使用
配置文件
主要的配置文件有三个: wala.properties 、 scope.txt 、 exclusions.txt 。以maven项目结构为 例: wala.properties 必须放在 /src/main/resources 下, scope.txt 和 exclusion.txt 推荐放 在 /src/main/resources 下。
配件文件示例
exclusions.txt
- 排除配置文件,与静态分析的范围 AnalysisScope 有关。改文件记录了一些静态分析中不关心的 类。文件每行一条记录,支持正则表达式,表示在本次静态分析中排除在外的类
- ⚠ 注意:静态分析的计算复杂度较高,通过 exclusion.txt 可以有效地缩减分析域、提高分析效 率。但排除过多的类可能会丢失一些分析必须的类,导致抛出异常。
apple\/.*
com\/apple\/.*
com\/ibm\/.*
com\/oracle\/.*
com\/sun\/.*
dalvik\/.*
java\/beans\/.*
java\/io\/ObjectStreamClass*
java\/rmi\/.*
java\/text\/.*
java\/time\/.*
javafx\/.*
javafx\/beans\/.*
javafx\/collections\/.*
javafx\/scene\/.*
javax\/accessibility\/.*
javax\/activation\/.*
javax\/activity\/.*
javax\/annotation\/.*
javax\/crypto\/.*
javax\/imageio\/.*
javax\/jnlp\/.*
javax\/jws\/.*
javax\/management\/.*
javax\/net\/.*
javax\/print\/.*
javax\/rmi\/.*
javax\/script\/.*
javax\/smartcardio\/.*
javax\/sound\/.*
javax\/sql\/.*
javax\/tools\/.*
jdk\/.*
netscape\/.*
oracle\/jrockit\/.*
org\/apache\/xerces\/.*
org\/ietf\/.*
org\/jcp\/.*
org\/netbeans\/.*
org\/omg\/.*
org\/openide\/.*
sun\/.*
sun\/awt\/.*
sun\/swing\/.*
scope.txt
- 域配置文件,与静态分析的范围 AnalysisScope有关。WALA提供了读取配置文件和直接添加类文件进入分析域两种构建分析域的手段 scope.txt 就和第一种方式相关,详细教程见:http://wala.sourceforge.net/wiki/index.php/UserGuide:AnalysisScope
Primordial,Java,stdlib,none
wala.properties
- wala属性文件,记录了运行wala所需要的一些环境配置。其中最重要的属性是 java_runtime_dir 。请将该属性修改成自己的jdk文件夹路径
- ⚠ 注意:在IDEA开发环境中运行时,有可能会出现java_runtime_dir 配置错误、但是程序依然能够运行的情况。这个时候控制台一般会抛出WARNING,但是打成jar包后可能不能正常运行。
###############################################################################
# WALA property file
# This file defines the default settings for the core WALA Engine
###############################################################################
################# Mandatory settings without default value ####################
#####
# Identify the directory where Java Runtime libraries are located.
# For instance, on a windows OS it's typically C:/Progra~1/Java/j2reYourVersion/lib
# On MAC OS, typically /System/Library/Frameworks/JavaVM.framework/Classes
#
# N.B. On Windows or Linux, this directory must contain a valid core.jar (or rt.jar
# for older VMs). On Mac, it should contain the classes.jar file.
# On IBM 1.4.x SDKs, this means you need to specify Java14x/jre/lib and not
# Java14x/lib!
#
# Info: Location must be absolute.
#####
################### Mandatory settings with default value ######################
##### Default output dir
# Identify directory where all generated files without absolute path will be located.
# Note that this directory must be created manually; WALA may fail if it does not exist.
# Default value: results [Non absolute path are relative to WALA home location]
# Info: Can be absolute or relative.
#####
#output_dir = Your location
################### Mandatory settings for Android (Dalvik) ####################
# location of runtime jar
#android_rt_jar = .../android-sdk-macosx/platforms/android-20/android.jar
# location of jar-to-dex tool
#android_dx_tool = .../android-sdk-macosx/build-tools/20.0.0/dx
############################ Optional settings ################################
#####
# Identify the directory where J2EE standard libraries are located.
# Required only if you ask to analyze J2EE code.
# No default value.
# Info: Location must be absolute.
#####
#j2ee_runtime_dir = Your location
#####
# Identify the directory where Eclipse plugins are installed
# Required only if you ask to analyze Eclipse plugins.
# No default value.
# Info: Location must be absolute.
#####
#eclipse_plugins_dir = Your location
##### Report file
# Identify file name where to output WALA trace file.
# Default value: wala_report.txt [Non absolute path are relative to 'output.dir' variable value]
# Info: Can be absolute or relative.
#####
#WALA_report = Your file name
#
# the location of DroidBench for Android oldTests
#
#droidbench.root = Your location
java_runtime_dir =.
WALA基础使用
生成分析域
推荐同时使用两种方式综合构建 AnalysisScope 对象,涉及到两个方法两个步骤:
- AnalysisScopeReader.readJavaScope(scopePath, new File(exPath), classLoader); 保持配置样例中 scope.txt 的内容不变,该方法能够返回一个只包含Java原生类的分析域,并排除一些不常用的原生类(如: sun.awt.* )
- scope.addClassFileToScope(ClassLoaderReference.Application, clazz); scope 是一个 AnalysisScope 对象, clazz 是一个我们想要加入分析域的类文件对象。这行代码 能够将我们想要分析的类动态地加入到分析域中。
具体实例
AnalysisScope scope = AnalysisScopeReader.readJavaScope("scope.txt",
new FileProvider().getFile("exclusion.txt"),
classLoader);//classLoader为类加载器
scope.addClassFileToScope(ClassLoaderReference.Application, file);//file为一个.class文件
生成类层次
类层次生成方法由工厂类 ClassHierarchyFactory 提供,以分析域对象为构建原料,这里推荐使用 makeWithRoot 方法构建类层次对象:
ClassHierarchy cha = ClassHierarchyFactory.makeWithRoot(scope);
在缺失了某些分析所需的类时, makeWithRoot 方法会尽可能地为依赖这些缺失类的方法添加“Root”, 即认为 java.lang.Object 为这些类的父类。
确定进入点
进入点和我们分析的兴趣的有关,以分析域和类层次对象为构建原料。WALA内置了若干种进入点集合,如:
- 针对主程序生成进入点: Util.makeMainEntryPoints
- 针对所有Application类(非原生类)生成进入点: new AllApplicationEntrypoints(scope, cha)
- 此外,还支持自定义进入点,可以通过实现自己的进入点子类实现。
- 为了降低实现难度,这里推荐大家 使用 AllApplicationEntrypoints构建进入点。
构建调用图
依赖分析通常 和构建调用图有关,这里推荐两种构建调用图的方法:
- . CHACallGraph :使用类层次分析(Class Hierarchy Analysis)算法构建调用图。该方法构建的调 用图精度较低,但是速度较快,构建例子如下:
CHACallGraph cg = new CHACallGraph(cha);
cg.init(new AllApplicationEntrypoints(scope, cha);
- 使用0-CFA算法,通过上下文无关的方式构建调用图。相比于第一种方法构建的调用图,该方法构 建的调用图精度更高,但同时速度更慢。构建例子如下:
ClassHierarchy cha = ClassHierarchyFactory.makeWithRoot(scope);
AllApplicationEntrypoints entrypoints = new AllApplicationEntrypoints(scope,
cha);
AnalysisOptions option = new AnalysisOptions(scope, entrypoints);
SSAPropagationCallGraphBuilder builder = Util.makeZeroCFABuilder(
Language.JAVA, option, new AnalysisCacheImpl(), cha, scope
);
WALA使用实例
AnalysisScope scope = AnalysisScopeReader.readJavaScope("scope.txt",
new FileProvider().getFile("exclusion.txt"),
classLoader);//classLoader为类加载器
scope.addClassFileToScope(ClassLoaderReference.Application, file);//file自己找一个.class文件!
// 1.生成类层次关系对象
ClassHierarchy cha = ClassHierarchyFactory.makeWithRoot(scope);
// 2.生成进入点
Iterable<Entrypoint> eps = new AllApplicationEntrypoints(scope, cha);
// 3.利用CHA算法构建调用图
// CallGraph cg = new CHACallGraph(cha); // 这句出错了,请注意。正确用法见下一行
CHACallGraph cg = new CHACallGraph(cha);
cg.init(eps);
// 4.遍历cg中所有的节点
for(CGNode node: cg) {
// node中包含了很多信息,包括类加载器、方法信息等,这里只筛选出需要的信息
if(node.getMethod() instanceof ShrikeBTMethod) {
// node.getMethod()返回一个比较泛化的IMethod实例,不能获取到我们想要的信息
// 一般地,本项目中所有和业务逻辑相关的方法都是ShrikeBTMethod对象
ShrikeBTMethod method = (ShrikeBTMethod) node.getMethod();
// 使用Primordial类加载器加载的类都属于Java原生类,我们一般不关心。
if("Application".equals(method.getDeclaringClass().getClassLoader().toString())) {
// 获取声明该方法的类的内部表示
String classInnerName = method.getDeclaringClass().getName().toString;
// 获取方法签名
String signature = method.getSignature();
System.out.println(classInnerName + " " + signature);
}
} else {
System.out.println(String.format("'%s'不是一个ShrikeBTMethod:%s",
node.getMethod(), node.getMethod().getClass());
}
}