【课程笔记】南大软件分析课程12——Soundiness(课时16)

目录

  1. Soundness & Soundiness

  2. 复杂语言特性一:Java Reflection

  3. 复杂语言特性二:Native Code

重点

理解soundiness的含义,为什么要引入它?

理解为什么Java reflectionnative code分析这么复杂。

课程就这么结束了,抽象解释可能要在研究生课程再讲。


分析真实复杂程序时,产生的问题都与Soundiness有关,是最前沿的topic之一。

1.Soundness & Soundiness

Soundness:保守估计,分析结果能包含程序所有可能的执行。学术界和工业界都做不到。

复杂语言特性:导致分析结果不精确。

  • Java:Reflection, native code, dynamic class loading, etc.
  • JavaScript:eval(执行任意命令), document object model (DOM,和DOM加护), etc.
  • C/C++:Pointer arithmetic(指针地址+1或乘以), function pointers, etc.

现状:有些文章不提这类问题,或者随意一提(如eval)。极具误导性,导致相信该工具很sound,且影响专家的评判。

Soundiness:直观相信的"truth",但没有任何事实和证据。

词语对比

  • sound analysis:能捕捉所有动态运行行为,理想化。
  • soundy analysis:目标是捕捉所有动态行为,但对于某些复杂语言特性可以unsound。
  • unsound analysis:为了效率、精度,故意不处理某些行为。

2.复杂语言特性一:Java Reflection—反射

(1)介绍Java反射

Java Reflection:反射机制很重要的一点就是“运行时”,其使得我们可以在程序运行时加载、探索以及使用编译期间完全未知的 .class 文件。换句话说,Java 程序可以加载一个运行时才得知名称的 .class 文件,然后获悉其完整构造,并生成其对象实体、或对其 fields(变量)设值、或调用其 methods(方法)。

12-2-1-Java反射示例.png

说明:无反射代码在编译时就能确定对象;反射代码在运行时才确定对象,如c指向什么,"Person"也可能是的字符串指针,很难静态分析。分析该类代码很有必要,如弄清对象到底调用了哪个目标函数、对象域的指向关系等。

(2)分析方法

分析方法:String Contant analysis + Pointer Analysis(Reflection Analysis for Java——APLAS 2005)。

示例:目标是分析m调用的目标函数。

  • 找到m的定义点,即Method m = c.getMethod(mName, ...);
  • 通过String Contant analysis找到mName指向内容
  • 通过指针分析找到c指向内容
  • 通过String Contant analysis找到cName指向内容
  • 知道了是调用Person类的setName函数
12-2-2-Java反射分析.png

问题:若字符串的值无法通过静态分析得到,则反射目标不能求解。Eg,字符串来自配置文件、网络、命令行、复杂字符串处理、动态生成、加密。

(3)改进

解决方法:Type Inference + String analysis + Pointer Analysis(Self-Inferencing Reflection Resolution for Java——ECOOP 2014,李樾,谭添老师的成果)。在创造点不可推,但在使用点可推。

示例:类名依赖cmd参数,解不出来;但在调用点,通过Java的类型系统推导parameters,发现parameters是this指针。推出结论就是,175行的目标函数有1个参数,且声明类型要么是FrameworkCommandInterpreter要么是其子类。结果推断出50个反射目标函数,48个为true。

12-2-3-改进方法.png

最新工作Understanding and Analyzing Java Reflection (TOSEM 2019) Yue Li, Tian Tan, Jingling Xue。不仅求解反射对象更准确更多,而且能说出哪里解的不准。

常用方法Taming reflection: Aiding static analysis in the presence of reflection and custom class loaders (ICSE 2011)。利用动态分析来解,缺点是测试用例的覆盖路径有限,优点是只要解出来,结果都为真。


3.复杂语言特性二:Native Code

Native Code:一个Native Method就是一个java调用非java代码的接口。该方法的实现由非java语言实现,已被编译为特定于处理器的机器码的代码,这些代码可以直接被虚拟机执行,与字节码的区别:虚拟机是一个把通用字节码转换成用于特定处理器的本地代码的程序,比如C。这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern “C”告知C++编译器去调用一个C的函数。

Java Native Interface(JNI):是一种编程框架(函数模型,反映参数格式等),使得Java虚拟机中的Java程序可以调用本地应用/或库,也可以被其他程序调用。 本地程序一般是用其它语言(CC++汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序。

示例:先加载Native库,声明Native函数,*env变量可以在Native代码中用于创建对象、访问域、调用Java中的方法等,支持230个JNI函数。问题是跨语言之后,如何静态分析je.guessMe()这个调用?

12-3-1-Java Native Code.png

方法:对重要的native code手动建模。例如,对经常调用的arraycopy()函数进行建模,建模后就是一个拷贝循环,但从指针分析角度来讲,看到这个循环,我们就把数组指针进行传递。

12-3-2-Native Code建模示例.png

最新工作:Identifying Java Calls in Native Code via Binary Scanning (ISSTA 2020)。通过扫描二进制程序来识别native code中的Java调用。

扩展:想深入研究Soundiness,可参考网站http://soundiness.org

参考

Java 反射由浅入深 | 进阶必备

java native方法使用