Skip to content

Commit

Permalink
Merged MethodConfig and Filter classes, using same syntax everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
palant committed Mar 1, 2021
1 parent 7dc0d83 commit cc30bd3
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 100 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ The following configuration options are independent of the components enabled:
* `keystore`: (optional) path to the key store containing the signing key
* `keypass`: (optional) password protecting the key store

## Filters
## Method filters

Each component has a `filter` option allowing to restrict its functionality. It’s a space-separated list, entries can have the following format:
Some configuration options use method filters determining which methods are included. These are space-separated lists, entries can have the following format:

* `com.example.test.*`: includes all classes with names matching a particular prefix
* `com.example.test.Main`: includes all methods of a specific class
* `com.example.test.Main.dump()`: includes all methods with a particular name inside a class (empty parentheses at the end are mandatory)
* `com.example.test.Main:*`: includes all methods of a specific class
* `com.example.test.Main:dump(java.lang.String,int)`: includes only the method with the specified signature

## Extended format strings

Expand All @@ -50,7 +50,7 @@ This component will add logging code after calls to specified methods. See `conf
Configuration options:

* `CallLogger.enabled`: add to enable this component
* `CallLogger.filter`: (optional) restricts functionality to a set of classes or methods (see Filters section above)
* `CallLogger.filter`: (optional) restricts functionality to a set of methods, for value format see Method filters section above
* `CallLogger.tag`: (optional) log tag to be used (default is `CallLogger`)
* `CallLogger.<class>:<method>`: specifies a call to be logged. `<class>` has to be a full class name like `java.net.URL`. `<method>` can be either a method name like `openConnection` or a more specific method name along with parameter types like `getHeaderField(java.lang.String)`. The value is a format string (see Extended format strings section above).

Expand All @@ -61,9 +61,9 @@ This component will wrap `InputStream` and `OutputStream` instances returned by
Configuration options:

* `StreamLogger.enabled`: add to enable this component
* `StreamLogger.filter`: (optional) restricts functionality to a set of classes or methods (see Filters section above)
* `StreamLogger.filter`: (optional) restricts functionality to a set of methods, for value format see Method filters section above
* `StreamLogger.tag`: (optional) log tag to be used (default is `StreamLogger`)
* `StreamLogger.<class>:<method>`: specifies a call returning a stream that should be wrapped. `<class>` has to be a full class name like `java.net.URLConnection`. `<method>` can be either a method name like `getInputStream` or a more specific method name along with parameter types like `getOutputStream(java.net.URL)`. The value is a format string that will be used as a prefix for logged data (see Extended format strings section above).
* `StreamLogger.<method filter>`: specifies a call returning a stream that should be wrapped. `<method filter>` is a method specification as outlined in the Method filters section above. Note that `.properties` format requires colons to be prefixed with a backslash: `\:`. The value is a format string that will be used as a prefix for logged data (see Extended format strings section above).

## MethodLogger component

Expand All @@ -72,7 +72,7 @@ This component will add logging to the start of each method. In addition to the
Configuration options:

* `MethodLogger.enabled`: add to enable this component
* `MethodLogger.filter`: (optional) restricts functionality to a set of classes or methods (see Filters section above)
* `MethodLogger.filter`: (optional) restricts functionality to a set of methods, for value format see Method filters section above
* `MethodLogger.tag`: (optional) log tag to be used (default is `MethodLogger`)

## AssignmentRemover component
Expand All @@ -82,5 +82,5 @@ This component will remove any assignments with the specified result type. Note
Configuration options:

* `AssignmentRemover.enabled`: add to enable this component
* `AssignmentRemover.filter`: (optional) restricts functionality to a set of classes or methods (see Filters section above)
* `AssignmentRemover.filter`: (optional) restricts functionality to a set of methods, for value format see Method filters section above
* `AssignmentRemover.type`: the result type identifying the assignment to be removed
16 changes: 8 additions & 8 deletions config.properties.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ output=game-instrumented.apk
keystore=debug.jks
keypass=123456

MethodLogger.enabled=true
MethodLogger.filter=com.example.funnygame.* \
com.example.util.Util \
com.example.util.Downloader.download()
MethodLogger.tag=MethodEntered
MethodLogger.enabled = true
MethodLogger.filter = com.example.funnygame.* \
com.example.util.Util:* \
com.example.util.Downloader:download()
MethodLogger.tag = MethodEntered

AssignmentRemover.enabled=true
AssignmentRemover.filter=com.example.funnygame.SomeClass.<clinit>()
AssignmentRemover.type=com.example.funnygame.SomeInterface
AssignmentRemover.enabled = true
AssignmentRemover.filter = com.example.funnygame.SomeClass:<clinit>()
AssignmentRemover.type = com.example.funnygame.SomeInterface
6 changes: 3 additions & 3 deletions src/info/palant/apkInstrumentation/AssignmentRemover.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

public class AssignmentRemover extends BodyTransformer
{
private Filter filter;
private MethodConfig filter;
private String type;

public AssignmentRemover(Properties config)
Expand All @@ -26,15 +26,15 @@ public AssignmentRemover(Properties config)

String filterSpec = config.getProperty("AssignmentRemover.filter");
if (filterSpec != null)
this.filter = new Filter(filterSpec);
this.filter = new MethodConfig(filterSpec, "");
else
this.filter = null;
}

@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options)
{
if (this.filter != null && !this.filter.matches(body))
if (this.filter != null && this.filter.get(body.getMethod()) == null)
return;

body.getUnits().removeIf(unit -> {
Expand Down
6 changes: 3 additions & 3 deletions src/info/palant/apkInstrumentation/CallLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

public class CallLogger extends BodyTransformer
{
private final Filter filter;
private final MethodConfig filter;
private String tag;
private MethodConfig methodConfig;

public CallLogger(Properties config)
{
String filterSpec = config.getProperty("CallLogger.filter");
if (filterSpec != null)
this.filter = new Filter(filterSpec);
this.filter = new MethodConfig(filterSpec, "");
else
this.filter = null;

Expand All @@ -38,7 +38,7 @@ public CallLogger(Properties config)
@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options)
{
if (this.filter != null && !this.filter.matches(body))
if (this.filter != null && this.filter.get(body.getMethod()) == null)
return;

for (Unit unit: body.getUnits().toArray(new Unit[0]))
Expand Down
59 changes: 0 additions & 59 deletions src/info/palant/apkInstrumentation/Filter.java

This file was deleted.

61 changes: 49 additions & 12 deletions src/info/palant/apkInstrumentation/MethodConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,81 @@

package info.palant.apkInstrumentation;

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

import soot.SootClass;
import soot.SootMethod;
import soot.Type;

public class MethodConfig
{
private Map<String,Map<String,String>> methods;
private Map<String,Map<String,String>> methods = new HashMap<String,Map<String,String>>();
private List<String[]> classPrefixes = new ArrayList<String[]>();

public MethodConfig(Properties config, String configPrefix)
{
this.methods = new HashMap<String,Map<String,String>>();

for (String property: config.stringPropertyNames())
{
if (!property.startsWith(configPrefix))
continue;

String signature = property.substring(configPrefix.length());
int index = signature.indexOf(":");
if (index < 0)
this.add(property.substring(configPrefix.length()), config.getProperty(property));
}
}

public MethodConfig(String key, String value)
{
this.add(key, value);
}

private void add(String key, String value)
{
StringTokenizer tokenizer = new StringTokenizer(key);
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
if (token.equals(""))
continue;

String className = signature.substring(0, index).trim();
String methodName = signature.substring(index + 1).trim();
if (!this.methods.containsKey(className))
this.methods.put(className, new HashMap<String,String>());
this.methods.get(className).put(methodName, config.getProperty(property));
int index = token.indexOf(":");
if (index < 0)
{
if (token.endsWith("*"))
this.classPrefixes.add(new String[] {
token.substring(0, token.length() - 1),
value
});
}
else
{
String className = token.substring(0, index).trim();
String methodName = token.substring(index + 1).trim();
if (!this.methods.containsKey(className))
this.methods.put(className, new HashMap<String,String>());
this.methods.get(className).put(methodName, value);
}
}

}

public String get(SootMethod method)
{
SootClass cls = method.getDeclaringClass();
while (true)
{
Map<String,String> classConfig = this.methods.get(cls.getName());
String className = cls.getName();
for (String[] prefixConfig: this.classPrefixes)
{
if (className.startsWith(prefixConfig[0]))
return prefixConfig[1];
}

Map<String,String> classConfig = this.methods.get(className);
if (classConfig != null)
{
String methodConfig = classConfig.get(method.getName());
Expand All @@ -64,6 +99,8 @@ public String get(SootMethod method)
signature += ")";
methodConfig = classConfig.get(signature);
}
if (methodConfig == null)
methodConfig = classConfig.get("*");

if (methodConfig != null)
return methodConfig;
Expand Down
6 changes: 3 additions & 3 deletions src/info/palant/apkInstrumentation/MethodLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@

public class MethodLogger extends BodyTransformer
{
private final Filter filter;
private final MethodConfig filter;
private String tag;

public MethodLogger(Properties config)
{
String filterSpec = config.getProperty("MethodLogger.filter");
if (filterSpec != null)
this.filter = new Filter(filterSpec);
this.filter = new MethodConfig(filterSpec, "");
else
this.filter = null;

Expand All @@ -36,7 +36,7 @@ public MethodLogger(Properties config)
@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options)
{
if (this.filter != null && !this.filter.matches(body))
if (this.filter != null && this.filter.get(body.getMethod()) == null)
return;

UnitSequence units = new UnitSequence(body);
Expand Down
6 changes: 3 additions & 3 deletions src/info/palant/apkInstrumentation/StreamLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public class StreamLogger extends BodyTransformer
{
final static String OUTPUT_STREAM_CLASS = "info.palant.apkInstrumentation.LoggingOutputStream";
final static String INPUT_STREAM_CLASS = "info.palant.apkInstrumentation.LoggingInputStream";
private final Filter filter;
private final MethodConfig filter;
private String tag;
private MethodConfig methodConfig;

public StreamLogger(Properties config)
{
String filterSpec = config.getProperty("StreamLogger.filter");
if (filterSpec != null)
this.filter = new Filter(filterSpec);
this.filter = new MethodConfig(filterSpec, "");
else
this.filter = null;

Expand All @@ -45,7 +45,7 @@ public StreamLogger(Properties config)
@Override
protected void internalTransform(Body body, String phaseName, Map<String, String> options)
{
if (this.filter != null && !this.filter.matches(body))
if (this.filter != null && this.filter.get(body.getMethod()) == null)
return;

for (Unit unit: body.getUnits().toArray(new Unit[0]))
Expand Down

0 comments on commit cc30bd3

Please sign in to comment.