Skip to content

Commit

Permalink
core: option for control escaping of unicode characters (skylot#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
skylot committed Mar 7, 2016
1 parent e915f4f commit 218c39b
Show file tree
Hide file tree
Showing 22 changed files with 237 additions and 76 deletions.
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,22 @@ Run **jadx** on itself:
```
jadx[-gui] [options] <input file> (.dex, .apk, .jar or .class)
options:
-d, --output-dir - output directory
-j, --threads-count - processing threads count
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-r, --no-res - do not decode resources
-s, --no-src - do not decompile source code
--show-bad-code - show inconsistent code (incorrectly decompiled)
--cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions)
-v, --verbose - verbose output
--deobf - activate deobfuscation
--deobf-min - min length of name
--deobf-max - max length of name
--deobf-rewrite-cfg - force to save deobfuscation map
-h, --help - print this help
-d, --output-dir - output directory
-j, --threads-count - processing threads count
-f, --fallback - make simple dump (using goto instead of 'if', 'for', etc)
-r, --no-res - do not decode resources
-s, --no-src - do not decompile source code
--show-bad-code - show inconsistent code (incorrectly decompiled)
--cfg - save methods control flow graph to dot file
--raw-cfg - save methods control flow graph (use raw instructions)
-v, --verbose - verbose output
--deobf - activate deobfuscation
--deobf-min - min length of name
--deobf-max - max length of name
--deobf-rewrite-cfg - force to save deobfuscation map
--deobf-use-sourcename - use source file name as class name alias
--escape-unicode - escape non latin characters in strings (with \u)
-h, --help - print this help
Example:
jadx -d out classes.dex
```
Expand Down
15 changes: 14 additions & 1 deletion jadx-cli/src/main/java/jadx/cli/JadxCLIArgs.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package jadx.cli;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import jadx.api.IJadxArgs;
import jadx.api.JadxDecompiler;
import jadx.core.utils.exceptions.JadxException;
Expand Down Expand Up @@ -67,6 +69,9 @@ public class JadxCLIArgs implements IJadxArgs {
@Parameter(names = {"--deobf-use-sourcename"}, description = "use source file name as class name alias")
protected boolean deobfuscationUseSourceNameAsAlias = false;

@Parameter(names = {"--escape-unicode"}, description = "escape non latin characters in strings (with \\u)")
protected boolean escapeUnicode = false;

@Parameter(names = {"-h", "--help"}, description = "print this help", help = true)
protected boolean printHelp = false;

Expand Down Expand Up @@ -117,7 +122,10 @@ private boolean process() {
ch.qos.logback.classic.Logger rootLogger =
(ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
// remove INFO ThresholdFilter
rootLogger.getAppender("STDOUT").clearAllFilters();
Appender<ILoggingEvent> appender = rootLogger.getAppender("STDOUT");
if (appender != null) {
appender.clearAllFilters();
}
}
} catch (JadxException e) {
System.err.println("ERROR: " + e.getMessage());
Expand Down Expand Up @@ -251,4 +259,9 @@ public boolean isDeobfuscationForceSave() {
public boolean useSourceNameAsClassAlias() {
return deobfuscationUseSourceNameAsAlias;
}

@Override
public boolean escapeUnicode() {
return escapeUnicode;
}
}
2 changes: 2 additions & 0 deletions jadx-core/src/main/java/jadx/api/IJadxArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ public interface IJadxArgs {
boolean isDeobfuscationForceSave();

boolean useSourceNameAsClassAlias();

boolean escapeUnicode();
}
11 changes: 11 additions & 0 deletions jadx-core/src/main/java/jadx/api/JadxArgs.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class JadxArgs implements IJadxArgs {
private int deobfuscationMinLength = 0;
private int deobfuscationMaxLength = Integer.MAX_VALUE;

private boolean escapeUnicode = false;

@Override
public File getOutDir() {
return outDir;
Expand Down Expand Up @@ -149,4 +151,13 @@ public int getDeobfuscationMaxLength() {
public void setDeobfuscationMaxLength(int deobfuscationMaxLength) {
this.deobfuscationMaxLength = deobfuscationMaxLength;
}

@Override
public boolean escapeUnicode() {
return escapeUnicode;
}

public void setEscapeUnicode(boolean escapeUnicode) {
this.escapeUnicode = escapeUnicode;
}
}
8 changes: 6 additions & 2 deletions jadx-core/src/main/java/jadx/core/codegen/AnnotationGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ public void encodeValue(CodeWriter code, Object val) {
return;
}
if (val instanceof String) {
code.add(StringUtils.unescapeString((String) val));
code.add(getStringUtils().unescapeString((String) val));
} else if (val instanceof Integer) {
code.add(TypeGen.formatInteger((Integer) val));
} else if (val instanceof Character) {
code.add(StringUtils.unescapeChar((Character) val));
code.add(getStringUtils().unescapeChar((Character) val));
} else if (val instanceof Boolean) {
code.add(Boolean.TRUE.equals(val) ? "true" : "false");
} else if (val instanceof Float) {
Expand Down Expand Up @@ -172,4 +172,8 @@ public void encodeValue(CodeWriter code, Object val) {
throw new JadxRuntimeException("Can't decode value: " + val + " (" + val.getClass() + ")");
}
}

private StringUtils getStringUtils() {
return cls.dex().root().getStringUtils();
}
}
2 changes: 1 addition & 1 deletion jadx-core/src/main/java/jadx/core/codegen/ClassGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ private void addFields(CodeWriter code) throws CodegenException {
if (fv != null) {
code.add(" = ");
if (fv.getValue() == null) {
code.add(TypeGen.literalToString(0, f.getType()));
code.add(TypeGen.literalToString(0, f.getType(), cls));
} else {
if (fv.getValueType() == InitType.CONST) {
annotationGen.encodeValue(code, fv.getValue());
Expand Down
7 changes: 3 additions & 4 deletions jadx-core/src/main/java/jadx/core/codegen/InsnGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import jadx.core.dex.nodes.RootNode;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.RegionUtils;
import jadx.core.utils.StringUtils;
import jadx.core.utils.exceptions.CodegenException;
import jadx.core.utils.exceptions.JadxRuntimeException;

Expand Down Expand Up @@ -130,8 +129,8 @@ public void declareVar(CodeWriter code, RegisterArg arg) {
code.add(mgen.getNameGen().assignArg(arg));
}

private static String lit(LiteralArg arg) {
return TypeGen.literalToString(arg.getLiteral(), arg.getType());
private String lit(LiteralArg arg) {
return TypeGen.literalToString(arg.getLiteral(), arg.getType(), mth);
}

private void instanceField(CodeWriter code, FieldInfo field, InsnArg arg) throws CodegenException {
Expand Down Expand Up @@ -236,7 +235,7 @@ private void makeInsnBody(CodeWriter code, InsnNode insn, Set<Flags> state) thro
switch (insn.getType()) {
case CONST_STR:
String str = ((ConstStringNode) insn).getString();
code.add(StringUtils.unescapeString(str));
code.add(mth.dex().root().getStringUtils().unescapeString(str));
break;

case CONST_CLASS:
Expand Down
2 changes: 1 addition & 1 deletion jadx-core/src/main/java/jadx/core/codegen/RegionGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ private CodeWriter makeSwitch(SwitchRegion sw, CodeWriter code) throws CodegenEx
}
}
} else if (k instanceof Integer) {
code.add(TypeGen.literalToString((Integer) k, arg.getType()));
code.add(TypeGen.literalToString((Integer) k, arg.getType(), mth));
} else {
throw new JadxRuntimeException("Unexpected key in switch: " + (k != null ? k.getClass() : null));
}
Expand Down
13 changes: 12 additions & 1 deletion jadx-core/src/main/java/jadx/core/codegen/TypeGen.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package jadx.core.codegen;

import jadx.api.JadxArgs;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.PrimitiveType;
import jadx.core.dex.nodes.IDexNode;
import jadx.core.utils.StringUtils;
import jadx.core.utils.Utils;
import jadx.core.utils.exceptions.JadxRuntimeException;
Expand Down Expand Up @@ -31,7 +33,16 @@ public static String signature(ArgType type) {
*
* @throws JadxRuntimeException for incorrect type or literal value
*/
public static String literalToString(long lit, ArgType type, IDexNode dexNode) {
return literalToString(lit, type, dexNode.root().getStringUtils());
}

@Deprecated
public static String literalToString(long lit, ArgType type) {
return literalToString(lit, type, new StringUtils(new JadxArgs()));
}

private static String literalToString(long lit, ArgType type, StringUtils stringUtils) {
if (type == null || !type.isTypeKnown()) {
String n = Long.toString(lit);
if (Math.abs(lit) > 100) {
Expand All @@ -46,7 +57,7 @@ public static String literalToString(long lit, ArgType type) {
case BOOLEAN:
return lit == 0 ? "false" : "true";
case CHAR:
return StringUtils.unescapeChar((char) lit);
return stringUtils.unescapeChar((char) lit);
case BYTE:
return formatByte((byte) lit);
case SHORT:
Expand Down
8 changes: 7 additions & 1 deletion jadx-core/src/main/java/jadx/core/dex/nodes/ClassNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
import com.android.dex.ClassDef;
import com.android.dx.rop.code.AccessFlags;

public class ClassNode extends LineAttrNode implements ILoadable {
public class ClassNode extends LineAttrNode implements ILoadable, IDexNode {
private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class);

private final DexNode dex;
Expand Down Expand Up @@ -472,10 +472,16 @@ public AccessInfo getAccessFlags() {
return accessFlags;
}

@Override
public DexNode dex() {
return dex;
}

@Override
public RootNode root() {
return dex.root();
}

public String getRawName() {
return clsInfo.getRawName();
}
Expand Down
8 changes: 7 additions & 1 deletion jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import com.android.dex.ProtoId;
import com.android.dex.TypeList;

public class DexNode {
public class DexNode implements IDexNode {

public static final int NO_INDEX = -1;

Expand Down Expand Up @@ -210,10 +210,16 @@ public Section openSection(int offset) {
return dexBuf.open(offset);
}

@Override
public RootNode root() {
return root;
}

@Override
public DexNode dex() {
return this;
}

@Override
public String toString() {
return "DEX";
Expand Down
9 changes: 9 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/nodes/IDexNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package jadx.core.dex.nodes;

public interface IDexNode {

DexNode dex();

RootNode root();
}

8 changes: 7 additions & 1 deletion jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import com.android.dex.Code.CatchHandler;
import com.android.dex.Code.Try;

public class MethodNode extends LineAttrNode implements ILoadable {
public class MethodNode extends LineAttrNode implements ILoadable, IDexNode {
private static final Logger LOG = LoggerFactory.getLogger(MethodNode.class);

private final MethodInfo mthInfo;
Expand Down Expand Up @@ -594,10 +594,16 @@ public void setRegion(Region region) {
this.region = region;
}

@Override
public DexNode dex() {
return parentClass.dex();
}

@Override
public RootNode root() {
return dex().root();
}

public MethodInfo getMethodInfo() {
return mthInfo;
}
Expand Down
7 changes: 7 additions & 0 deletions jadx-core/src/main/java/jadx/core/dex/nodes/RootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import jadx.core.clsp.ClspGraph;
import jadx.core.dex.info.ClassInfo;
import jadx.core.utils.ErrorsCounter;
import jadx.core.utils.StringUtils;
import jadx.core.utils.exceptions.DecodeException;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.DexFile;
Expand All @@ -31,6 +32,7 @@ public class RootNode {

private final ErrorsCounter errorsCounter = new ErrorsCounter();
private final IJadxArgs args;
private final StringUtils stringUtils;

private List<DexNode> dexNodes;
private Map<Integer, String> resourcesNames = new HashMap<Integer, String>();
Expand All @@ -41,6 +43,7 @@ public class RootNode {

public RootNode(IJadxArgs args) {
this.args = args;
this.stringUtils = new StringUtils(args);
}

public void load(List<InputFile> inputFiles) throws DecodeException {
Expand Down Expand Up @@ -194,4 +197,8 @@ public ClassNode getAppResClass() {
public IJadxArgs getArgs() {
return args;
}

public StringUtils getStringUtils() {
return stringUtils;
}
}
23 changes: 15 additions & 8 deletions jadx-core/src/main/java/jadx/core/utils/StringUtils.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
package jadx.core.utils;

import jadx.api.IJadxArgs;

public class StringUtils {

private StringUtils() {
private final boolean escapeUnicode;

public StringUtils(IJadxArgs args) {
this.escapeUnicode = args.escapeUnicode();
}

public static String unescapeString(String str) {
public String unescapeString(String str) {
int len = str.length();
if (len == 0) {
return "\"\"";
}
StringBuilder res = new StringBuilder();

for (int i = 0; i < len; i++) {
int c = str.charAt(i) & 0xFFFF;
processChar(c, res);
}
return '"' + res.toString() + '"';
}

public static String unescapeChar(char ch) {
public String unescapeChar(char ch) {
if (ch == '\'') {
return "'\\\''";
}
Expand All @@ -25,7 +32,7 @@ public static String unescapeChar(char ch) {
return '\'' + res.toString() + '\'';
}

private static void processChar(int c, StringBuilder res) {
private void processChar(int c, StringBuilder res) {
switch (c) {
case '\n': res.append("\\n"); break;
case '\r': res.append("\\r"); break;
Expand All @@ -37,10 +44,10 @@ private static void processChar(int c, StringBuilder res) {
case '\\': res.append("\\\\"); break;

default:
if (32 <= c && c <= 126) {
res.append((char) c);
} else {
if (c < 32 || c >= 127 && escapeUnicode) {
res.append("\\u").append(String.format("%04x", c));
} else {
res.append((char) c);
}
break;
}
Expand Down
Loading

0 comments on commit 218c39b

Please sign in to comment.