Soot:从头创建一个类
来源:互联网 发布:欧莱雅 曼秀雷敦 知乎 编辑:程序博客网 时间:2024/05/16 05:26
Soot:从头创建一个类
(Creating a class from scratch)
首先,我们需要创建一个类,以放入方法。接下来的步骤对于创建一个类文件是必要的。
加载Java.lang.Object和Library类
加载java.lang.Object,Java类层次结构的root节点。
该步骤对于那些扩展Soot框架的构建代码来说,是没必要的。在那种情况下,当用户代码被调用时,类文件就已经被加载了。
Scene.v().loadClassAndSupport("java.lang.Object");
该行代码使得Soot去加载java.lang.Object类,并创建其对应的SootClass对象,也包括与其成员对应的SootMethod(s)和SootField(s)。当然java.lang.Object有着对其它对象的引用。loadClassAndSupport方法的调用,将加载指定类的传递闭包(transitive closure),以便所有为了加载java.lang.Object所需的类型能被加载。
这一过程被称为resolution。
因为我们的HelloWorld程序将使用标准库中的类,我们也需要解析(resolve)它们:
Scene.v().loadClassAndSupport("java.lang.System");
该行引用了Scene.v()。Scene是指在程序中所有SootClass(es)的容器,并且提供了各种实用的方法。有一个单例的Scene对象,可以通过Scene.v()来调用获取。
注意事项:Soot从类文件或.jimple的输入文件中加载这些类。当使用的是前者的话,Soot将加载所有在每个类文件的常量池中获取到的类名。从Jimple中加载时,Soot将只加载要求的类型。
创建一个新的SootClass对象
创建一个"HelloWorld"类,并设置它的超类为"java.lang.Object"。
SootClass sClass = new SootClass("HelloWorld",Modifier.PUBLIC);
该行代码为一个名为HelloWorld的Public类创建SootClass对象。
sClass.setSuperClass(Scene.v().getSootClass("java.lang.Object"));
这将为这个新创建的类设置相应于java.lang.Object的SootClass对象,作为其超类。注意这里Scene的getSootClass功能方法的使用。
Scene.v().addClass(sClass);
这将添加新创建的HelloWorld类Scene中。所有的类,一旦它创建后,都应该归属到Scene中。
添加方法到SootClass中
为HelloWorld创建一个含有空方法体的main()方法。
现在,我们拥有一个SootClass,我们需要为其添加方法。
SootMethod method = new SootMethod("main",
Arrays.asList(new Type[]{ArrayType.v(RefType.v("java.lang.String"),1)}),
VoidType.v(), Modifier.Public | Modifier.STATIC);
我们创建了一个public static方法,main,声明了它携带了一个java.lang.String的对象,并且它返回void。
SootMethod的构造器要求一个list,所以我们使用Java实用方法Arrays.asList来从单元素数组(我们从newType[]中生成)中创建一个list。在该列表中,我们装入一个数组类型,对应于java.lang.String对象的一维数组类型。
Types: 每个SootClass表示一个Java对象。我们可以实例化该类,通过指定一个类的给定类型。两个概念:--type和class--密切相关,但带有区分。为了获取java.lang.Stirng类的type,通过名字,我们调用RefType.v("java.lang.String")。给定一个SootClass对象sc,我们也可以调用sc.getType()来获取对应的类型。
sClass.addMethod(method);
这一代码将方法添加到包含它的类中。
为方法添加代码
方法如果不包含代码则没有意义。我们为main方法添加一些代码。为了达到该目的,我们需要为该代码选择一种中间表示。
创建JimpleBody
在Soot中,我们将Body附着到一个SootMethod方法以关联该方法的一些代码。每个Body知道它对应的SootMethod,但一个SootMethod在一个时刻只有有一个active的Body(通过SootMethod.getActiveBody())。各种中间表示提供了不同的Body的类型,Soot有JimpleBody,ShimpleBody,BafBody和GrimpleBody。
更确切的讲,Body有3种重要的特征:Locals,Traps和Units的Chain。Chain是一种类似list结构的,提供O(1)的插入和删除元素访问。Locals指的是Body的本地变量。Traps指的是哪些语句捕获了哪些异常。而Units指的是这些语句本身。
注意,Unit是这么个术语,既表示Jimple中的Statement也表示Baf的instruction。
为main方法创建一个Jimple Body,添加locals和instruction到Body上。
JimpleBody body = JimpleBody.v().newBody(method);
Method.setActiveBody(body);
我们调用Jimple的单例对象以创建一个新的JimpleBody,并关联到我们的方法中,并且设置为方法的active body。
添加Local
Local arg = Jimple.v().newLocal("10",ArrayType.v(RefType.v("java.lang.String"),1));
body.getLocals().add(arg);
我们创建少数的新的Jimple Local并添加到Body中。
添加Unit
Units.add(Jimple.v().newIdentifyStmt(arg,
Jimple.v().newParameterRef(ArrayType.v
(RefType.v("java.lang.String"),1),0)));
Soot方法声明了它拥有参数,但没有将其与Body的Locals绑定。而IdentityStmt完成这一切。它将第一个参数,即字符串数组赋值给args。
//insert "tmpRef.println("Hello World1")"
{
SootMethod toCall = Scene.v().getMethod
("<java.io.PrintStream: void println(java.lang.String)>");
Units.add(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr
(tmpRef, toCall.makeRef(), StringConstant.v("Hello World!"));
))
}
我们获取方法签名:"<java.io.PrintStream: void println(java.lang.String)>"(它的名字叫println,术语PrintStream),返回void并且将一个String作为它的参数---这对于唯一确定一个方法足够了,并且携带一个StringConstant:"Hello World"。
写入类文件
为了将程序输出到class文件中,方法体必须从Jimple转换为Jasmine,并且二进制汇编到字节码。二进制汇编到字节码是过JasminOutputStream来执行的。
我们首先构建了输出流,它携带了Jasmine源,并且输出了.class文件。我们可手动指定文件名,或者可以让Soot决策合适的文件名。我们使用后者,如下:
String filename = SourceLocator.v().getFileNameFor(sClass,Options.output_format_class)
OutputStream streamOut = new JasminOutputStream(new FileOutpuStream(fileName));
PrintWriter writeOut = new PrintWriter(new OutputStreamWriter(streamOut));
我们现在将Jimple转换为Jasmin,并且打印Jasmine的结果类到输出流中。
JasminClass jasmineClass = new soot.jimple.JasminClass(sClass);
jasminClass.print(writerOut);
writerOut.flush();
streamOut.close();
如果我们希望输出是Jimple源而表示class文件,则如下:
String filename = SourceLocator.v().getFileNameFor(sClass,Options.output_fomart_jimple);
OutputStream streamOut = new FileOutputStream(filename);
PrintWriter writerOut = new PrintWriter(new OutputStreamWriter(streamOut));
Print.v().printTo(sClass,writerOut);
writerOut.flush();
streamOut.close();
我们忽略了JasminOutputStream,并且在Printer上调用了printTo方法。
Jimple格式的Hellow类如下:
public class HelloWorld extends java.lang.Object
{
public static void main(java.lang.String[])
{
java.lang.String[] r0;
java.io.PrintStream r1;
r0 := @parameter0: java.lang.String[];
r1 = <java.lang.System: java.io.PrintStream out>;
virtualinvoke r1.<java.io.PrintStream: void println(java.lang.String)>("Hello world!");
return;
}
}
完整代码如下:
/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-1999 Raja Vallee-Rai
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
//package ashes.examples.createclass;
import soot.*;
import soot.jimple.*;
import soot.options.Options;
import soot.util.*;
import java.io.*;
import java.util.*;
/** Example of using Soot to create a classfile from scratch.
* The 'createclass' example creates a HelloWorld class file using Soot.
* It proceeds as follows:
*
* - Create a SootClass <code>HelloWorld</code> extending java.lang.Object.
*
* - Create a 'main' method and add it to the class.
*
* - Create an empty JimpleBody and add it to the 'main' method.
*
* - Add locals and statements to JimpleBody.
*
* - Write the result out to a class file.
*/
public class Main
{
public static void main(String[] args) throws FileNotFoundException, IOException
{
SootClass sClass;
SootMethod method;
// Resolve dependencies
Scene.v().loadClassAndSupport("java.lang.Object");
Scene.v().loadClassAndSupport("java.lang.System");
// Declare 'public class HelloWorld'
sClass = new SootClass("HelloWorld", Modifier.PUBLIC);
// 'extends Object'
sClass.setSuperclass(Scene.v().getSootClass("java.lang.Object"));
Scene.v().addClass(sClass);
// Create the method, public static void main(String[])
method = new SootMethod("main",
Arrays.asList(new Type[] {ArrayType.v(RefType.v("java.lang.String"), 1)}),
VoidType.v(), Modifier.PUBLIC | Modifier.STATIC);
sClass.addMethod(method);
// Create the method body
{
// create empty body
JimpleBody body = Jimple.v().newBody(method);
method.setActiveBody(body);
Chain units = body.getUnits();
Local arg, tmpRef;
// Add some locals, java.lang.String l0
arg = Jimple.v().newLocal("l0", ArrayType.v(RefType.v("java.lang.String"), 1));
body.getLocals().add(arg);
// Add locals, java.io.printStream tmpRef
tmpRef = Jimple.v().newLocal("tmpRef", RefType.v("java.io.PrintStream"));
body.getLocals().add(tmpRef);
// add "l0 = @parameter0"
units.add(Jimple.v().newIdentityStmt(arg,
Jimple.v().newParameterRef(ArrayType.v(RefType.v("java.lang.String"), 1), 0)));
// add "tmpRef = java.lang.System.out"
units.add(Jimple.v().newAssignStmt(tmpRef, Jimple.v().newStaticFieldRef(
Scene.v().getField("<java.lang.System: java.io.PrintStream out>").makeRef())));
// insert "tmpRef.println("Hello world!")"
{
SootMethod toCall = Scene.v().getMethod("<java.io.PrintStream: void println(java.lang.String)>");
units.add(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(tmpRef, toCall.makeRef(), StringConstant.v("Hello world!"))));
}
// insert "return"
units.add(Jimple.v().newReturnVoidStmt());
}
String fileName = SourceLocator.v().getFileNameFor(sClass, Options.output_format_class);
OutputStream streamOut = new JasminOutputStream(
new FileOutputStream(fileName));
PrintWriter writerOut = new PrintWriter(
new OutputStreamWriter(streamOut));
JasminClass jasminClass = new soot.jimple.JasminClass(sClass);
jasminClass.print(writerOut);
writerOut.flush();
streamOut.close();
}
}
- Soot:从头创建一个类
- Soot:从头创建一个类
- soot基础 -- 从头开始创建一个类
- Soot 学习笔记 5:使用 Soot 创建 Java class
- soot
- Creating a class from scratch(从头开始创建一个类)
- 从头创建一个基于 React, webpack, babel 的模板项目
- 从头创建一个基于react,webpack,babel的项目
- 从头创建一个简单的RPC服务框架
- 从头创建一个基于 React, webpack, babel 的模板项目
- Soot 学习笔记 6:一些 Soot 重要的类
- 从头开始创建新图像
- 从头写一个rtsp服务器
- 从头开始绘制一个球体
- 从头开始绘制一个圆锥体
- 从头开始实现一个神经网络
- 从头开始构建一个应用
- 从头开始教你创建一个自定义可视化的Winows Form控件(Divider Panel)--For Begnners
- 连续整数的和
- Spring Boot : 自动JSON转换和热部署(二)
- bzoj 1704: [Usaco2007 Mar]Face The Right Way 自动转身机
- Android源码下载和编译
- Oracle删除当前用户下的所有表、视图、序列、函数、存储过程、包
- Soot:从头创建一个类
- 算法十七周解题报告
- MongoDB入门
- 集合中的Iterator抛出的ConcurrentModificationException源码分析
- 安卓游戏--浅塘之辅助开发(C/S模式)
- 字面常量 与 符号常量
- [续]Bean Validation和Hibernate Validator使用小记
- 关于BT5不能使用apt-get命令的解决方法
- 关于WeX5的carousel控件如何清除图片和增加图片