Skip to content

Commit

Permalink
Split up DownloadLogger component into more generic CallLogger and St…
Browse files Browse the repository at this point in the history
…reamLogger components
  • Loading branch information
palant committed Mar 1, 2021
1 parent 55c9014 commit 7dc0d83
Show file tree
Hide file tree
Showing 12 changed files with 442 additions and 266 deletions.
45 changes: 33 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,48 @@ Each component has a `filter` option allowing to restrict its functionality. It
* `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)

## MethodLogger component
## Extended format strings

This component will add logging to the start of each method. In addition to the method signature, the parameter values will be logged.
Some components will allow specifying extended format strings for data to be logged. These use the usual [Java format specifiers](https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax) like `%s` or `%i` but require specifying the input as well, e.g. `{this:%s}` (format `this` value as a string) or `{arg2:%i}` (format second parameter as integer). The following input specifiers are possible:

* `method`: The signature of the calling method
* `result`: Call result if available
* `this`: Instance reference
* `argNN`: Argument value where NN is the argument’s zero-based position

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

## CallLogger component

This component will add logging code after calls to specified methods. See `config.properties.downloads` for a configuration example logging `URLConnection` interactions.

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.tag`: (optional) log tag to be used (default is `MethodLogger`)
* `CallLogger.enabled`: add to enable this component
* `CallLogger.filter`: (optional) restricts functionality to a set of classes or methods (see 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).

## DownloadLogger component
## StreamLogger component

This component will log `URLConnection` interactions.
This component will wrap `InputStream` and `OutputStream` instances returned by specified methods to log data being sent or received. See `config.properties.downloads` for a configuration example logging streams returned by `URLConnection.getInputStream()` and `URLConnection.getOutputStream()`.

Configuration options:

* `DownloadLogger.enabled`: add to enable this component
* `DownloadLogger.filter`: (optional) restricts functionality to a set of classes or methods (see Filters section above)
* `DownloadLogger.tag`: (optional) log tag to be used (default is `DownloadLogger`)
* `DownloadLogger.requestBodies`: (optional) if present, data sent via the connection will be logged
* `DownloadLogger.responses`: (optional) if present, data received via the connection will be logged
* `StreamLogger.enabled`: add to enable this component
* `StreamLogger.filter`: (optional) restricts functionality to a set of classes or methods (see 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).

## MethodLogger component

This component will add logging to the start of each method. In addition to the method signature, the parameter values will be logged.

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.tag`: (optional) log tag to be used (default is `MethodLogger`)

## AssignmentRemover component

Expand Down
21 changes: 21 additions & 0 deletions config.properties.downloads
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
sdk=/path/to/android/sdk
input=game.apk
output=game-instrumented.apk
keystore=debug.jks
keypass=123456

CallLogger.enabled = true
CallLogger.java.net.URL\:openConnection = URLConnection {result:%x}: opened for URL {this:%s} (method {method:%s})
CallLogger.java.net.URLConnection\:addRequestProperty(java.lang.String,java.lang.String) = URLConnection {this:%x}: added request header {arg0:%s}: {arg1:%s} (method {method:%s})
CallLogger.java.net.URLConnection\:connect() = URLConnection {this:%x}: connected (method {method:%s})
CallLogger.java.net.URLConnection\:getContentLength() = URLConnection {this:%x}: response content length is {result:%i} (method {method:%s})
CallLogger.java.net.URLConnection\:getContentType() = URLConnection {this:%x}: response content type is {result:%s} (method {method:%s})
CallLogger.java.net.URLConnection\:getHeaderField(java.lang.String) = URLConnection {this:%x}: header {arg0:%s} value is {result:%s} (method {method:%s})
CallLogger.java.net.URLConnection\:setRequestProperty(java.lang.String,java.lang.String) = URLConnection {this:%x}: set request header {arg0:%s}: {arg1:%s} (method {method:%s})
CallLogger.java.net.HttpURLConnection\:getResponseCode() = URLConnection {this:%x}: response code is {result:%i} (method {method:%s})
CallLogger.java.net.HttpURLConnection\:setRequestMethod(java.lang.String) = URLConnection {this:%x}: request method set to {arg0:%s} (method {method:%s})

StreamLogger.enabled = true
StreamLogger.java.net.URL\:openStream = URL {this:%s} response (requested by method {method:%s})
StreamLogger.java.net.URLConnection\:getInputStream = URLConnection {this:%x}: response (requested by method {method:%s})
StreamLogger.java.net.URLConnection\:getOutputStream = URLConnection {this:%x}: request body (requested by method {method:%s})
64 changes: 64 additions & 0 deletions src/info/palant/apkInstrumentation/CallLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* 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.Map;
import java.util.Properties;

import soot.Body;
import soot.SootMethod;
import soot.Unit;
import soot.BodyTransformer;

public class CallLogger extends BodyTransformer
{
private final Filter 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);
else
this.filter = null;

this.tag = config.getProperty("CallLogger.tag");
if (tag == null)
this.tag = "CallLogger";

this.methodConfig = new MethodConfig(config, "CallLogger.");
}

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

for (Unit unit: body.getUnits().toArray(new Unit[0]))
{
SootMethod method = UnitParser.getInvocationMethod(unit);
if (method == null)
continue;

String formatString = this.methodConfig.get(method);
if (formatString == null)
continue;

UnitSequence units = new UnitSequence(body);
units.log(this.tag, units.extendedFormat(
formatString,
UnitParser.getAssignmentTarget(unit),
UnitParser.getInvocationBase(unit),
UnitParser.getInvocationArgs(unit)
));
units.insertAfter(unit);
}
}
}
234 changes: 0 additions & 234 deletions src/info/palant/apkInstrumentation/DownloadLogger.java

This file was deleted.

Loading

0 comments on commit 7dc0d83

Please sign in to comment.