Skip to content

Commit

Permalink
Added a way to replace classes by Jimple code
Browse files Browse the repository at this point in the history
  • Loading branch information
palant committed Jun 9, 2022
1 parent e26b172 commit 07d2a46
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 2 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# APK Instrumentation

**Warning**: This is a repository with quick-and-dirty code rewriting tools based on [Soot](https://soot-oss.github.io/soot/) which I use for my own research. The documentation is limited and support cannot be provided. Use at your own risk!
**Warning**: This is a repository with quick-and-dirty code rewriting tools based on [Soot](https://soot-oss.github.io/soot/) which I use for my own research. It has only been tested with Soot 4.2.1. The documentation is limited and support cannot be provided. Use at your own risk!

## Getting started

Expand Down Expand Up @@ -48,6 +48,17 @@ Some components will allow specifying extended format strings for data to be log

In addition, the format specifier `%x` is treated specially: `System.identityHashCode()` will be called on the corresponding input and the result hex-formatted.

## ClassReplacer component

This component will load classes from `.jimple` files and replace existing files with them. You can take the `.jimple` file for a class from the decompilation output, modify it as needed and give the result to this component to replace the original with it.

*Note*: This will do nothing for classes that don’t exist in the original archive.

Configuration options:

* `ClassReplacer.enabled`: add to enable this component
* `ClassReplacer.classes`: list of paths to `.jimple` files

## CallLogger component

This component will add logging code after calls to specified methods. See `config.properties.downloads` for a configuration example logging `URLConnection` interactions.
Expand Down
2 changes: 1 addition & 1 deletion build
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import zipfile
if len(sys.argv) < 2:
print('Please provide path to soot-jar-with-dependencies.jar on the command line', file=sys.stderr)
sys.exit(1)
soot = sys.argv[1]
basedir = os.path.dirname(sys.argv[0]) or os.getcwd()
soot = os.path.abspath(sys.argv[1])

if 'JAVA_HOME' in os.environ:
javac = os.path.join(os.environ['JAVA_HOME'], 'bin', 'javac')
Expand Down
51 changes: 51 additions & 0 deletions src/info/palant/apkInstrumentation/ClassInjector.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,23 @@

package info.palant.apkInstrumentation;

import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import soot.Body;
import soot.Local;
import soot.SootModuleResolver;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.Unit;
import soot.jimple.AssignStmt;
import soot.jimple.CastExpr;
import soot.jimple.InvokeStmt;
import soot.jimple.SpecialInvokeExpr;
import soot.jimple.parser.JimpleAST;

public abstract class ClassInjector
{
Expand Down Expand Up @@ -73,4 +80,48 @@ else if (unit instanceof InvokeStmt)
}
}
}

public static void injectJimple(String path)
{
try
{
JimpleAST ast = new JimpleAST(new FileInputStream(path));
try
{
ast.getSkeleton(new SootClass("Temp"));
return;
}
catch (RuntimeException e)
{
// Ugly hack: get the class name from the error message
Matcher matcher = Pattern.compile("expected:\\s*([^\\s,]+)").matcher(e.getMessage());
if (matcher.find())
{
SootClass cls = ast.getResolver().resolveClass(matcher.group(1), SootClass.BODIES);
if (cls.isPhantom())
return;

ArrayList<SootClass> interfaceList = new ArrayList<SootClass>(cls.getInterfaces());
for (SootClass iface: interfaceList)
cls.removeInterface(iface);
ArrayList<SootField> fieldList = new ArrayList<SootField>(cls.getFields());
for (SootField field: fieldList)
cls.removeField(field);
ArrayList<SootMethod> methodList = new ArrayList<SootMethod>(cls.getMethods());
for (SootMethod method: methodList)
cls.removeMethod(method);

ast.getSkeleton(cls);
for (SootMethod method: cls.getMethods())
method.setActiveBody(ast.getBody(method));
}
else
throw e;
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
40 changes: 40 additions & 0 deletions src/info/palant/apkInstrumentation/ClassReplacer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* This Source Code is subject to the terms of the Mozilla Public License
* version 2.0 (the "License"). You can obtain a copy of the License at
* http://mozilla.org/MPL/2.0/.
*/

package info.palant.apkInstrumentation;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import soot.SceneTransformer;

public class ClassReplacer extends SceneTransformer
{
private List<String> paths = new ArrayList<String>();

public ClassReplacer(Properties config)
{
StringTokenizer tokenizer = new StringTokenizer(config.getProperty("ClassReplacer.classes"));
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (token.equals(""))
continue;

paths.add(token);
}
}

@Override
protected void internalTransform(String phaseName, Map<String, String> options)
{
for (String path: this.paths)
ClassInjector.injectJimple(path);
}
}
6 changes: 6 additions & 0 deletions src/info/palant/apkInstrumentation/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ private static void setupSoot(String platformsPath, String platformVersion, Stri
Options.v().set_include_all(true);
Options.v().set_ignore_resolving_levels(true);
Options.v().set_process_multiple_dex(true);
Options.v().set_whole_program(true);

// Write (APK Generation) Options
Options.v().set_output_format(Options.output_format_dex);
Expand Down Expand Up @@ -229,6 +230,11 @@ private static void addTransformers(Properties config)
PackManager.v().getPack("jtp").add(new Transform("jtp.StreamLogger", new StreamLogger(config)));
hasTransformers = true;
}
if (config.getProperty("ClassReplacer.enabled") != null)
{
PackManager.v().getPack("wjtp").add(new Transform("wjtp.ClassReplacer", new ClassReplacer(config)));
hasTransformers = true;
}

if (!hasTransformers)
{
Expand Down

0 comments on commit 07d2a46

Please sign in to comment.