Skip to content

Instantly share code, notes, and snippets.

@AKosterin
Last active July 3, 2019 13:23
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save AKosterin/af8c2dd2aa372c99b507 to your computer and use it in GitHub Desktop.
Save AKosterin/af8c2dd2aa372c99b507 to your computer and use it in GitHub Desktop.
New Dexguard String decoder for JEB 1.5. Tested on GFE 3.1.3. This release auto parse decoder function.
import jeb.api.IScript;
import jeb.api.JebInstance;
import jeb.api.ast.*;
import jeb.api.ast.Class;
import jeb.api.dex.*;
import jeb.api.ui.JavaView;
import jeb.api.ui.View;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
/**
* Created by AKosterin on 31/01/16.
*/
public class DexGuardDecoder implements IScript {
private static JebInstance mJebInstance;
private static HashMap<String,byte[]> staticByteArrays;
private static HashMap<String,Integer> staticIntegers;
private static String decoderMethodSignature;
private static boolean debug = false;
@Override
public void run(JebInstance jebInstance) {
mJebInstance = jebInstance;
mJebInstance.print("DexGuardDecoder_Start");
if (!mJebInstance.isFileLoaded()) {
mJebInstance.print("Please load a dex file");
return;
}
Dex mDex = mJebInstance.getDex();
JavaView view = (JavaView) jebInstance.getUI().getView(View.Type.JAVA);
String signature = view.getCodePosition().getSignature();
if (debug) mJebInstance.print(getClassFromSignature(signature));
Class mClass = mJebInstance.getDecompiledClassTree(getClassFromSignature(signature));
defineDecoderMethodSignature(mClass);
if(!decoderMethodSignature.isEmpty()){
normalizeDecoderMethod();
initDecoderValues(mClass);
for (Method mMethod : (List<Method>) mClass.getMethods()) {
decodeMethod(mMethod);
}
}
jebInstance.getUI().getView(View.Type.JAVA).refresh();
jebInstance.print("DexGuardStringDecoder_End");
}
private static void defineDecoderMethodSignature(Class mClass){
for (Method mMethod : (List<Method>) mClass.getMethods()) {
String mMethodSignature = mMethod.getSignature();
if(mMethod.isStatic() && Pattern.matches("^.*[(][IBS]{3}[)]Ljava[/]lang[/]String[;]$",mMethodSignature.split(">")[1])){
decoderMethodSignature = mMethodSignature;
if (debug) mJebInstance.print("decoderMethodSignature = " + decoderMethodSignature);
return;
}
}
}
private static void normalizeDecoderMethod(){
Method mMethod = mJebInstance.getDecompiledMethodTree(decoderMethodSignature);
Block mMethodBodyBlock = mMethod.getBody();
int ifStmLine = 0;
while(!(mMethodBodyBlock.get(ifStmLine) instanceof IfStm)){
ifStmLine++;
if(ifStmLine == mMethodBodyBlock.size()){
return;
}
}
Block mElseBlock = ((IfStm)mMethodBodyBlock.get(ifStmLine)).getDefaultBlock();
Block mWhileBlock = Block.build();
int labelLine = 0;
while(!(mElseBlock.get(0) instanceof Label)){
mMethodBodyBlock.insert(ifStmLine + labelLine, mElseBlock.get(0));
mElseBlock.remove(0);
labelLine++;
}
for (int i = 0; i < mElseBlock.size() - 1; i++) {
if(mElseBlock.get(i+1) instanceof IfStm){
IfStm mIfStm = (IfStm) mElseBlock.get(i+1);
Predicate mIfPredicate = mIfStm.getBranchPredicate(0);
Block mIfIfBlock = mIfStm.getBranchBody(0);
Block mIfElseBlock = mIfStm.getDefaultBlock();
mWhileBlock.insert(mWhileBlock.size(), IfStm.build(mIfPredicate,mIfIfBlock));
for (int k = 0; k < mIfElseBlock.size(); k++) {
mWhileBlock.insert(mWhileBlock.size(), mIfElseBlock.get(k));
}
} else {
mWhileBlock.insert(mWhileBlock.size(), mElseBlock.get(i + 1));
}
}
int size = mMethodBodyBlock.size() - ifStmLine - labelLine - 2;
for (int i = 0; i < size; i++) {
mWhileBlock.insert(mWhileBlock.size(), mMethodBodyBlock.get(ifStmLine + labelLine + 1));
mMethodBodyBlock.remove(ifStmLine+labelLine + 1);
}
mMethodBodyBlock.remove(ifStmLine + labelLine + 1);
IExpression mIExpression = new Constant.Builder(mJebInstance).buildInt(1);
Predicate mTruePredicate = Predicate.build(mIExpression, Operator.EQ, mIExpression);
WhileStm mWhileStm = WhileStm.build(mTruePredicate,mWhileBlock);
mMethodBodyBlock.replaceSubElement(mMethodBodyBlock.get(ifStmLine+labelLine), mWhileStm);
}
private static void initDecoderValues(Class mClass) {
staticByteArrays = new HashMap<String,byte[]>();
staticIntegers = new HashMap<String, Integer>();
for (Method mMethod : (List<Method>) mClass.getMethods()) {
if (mMethod.getName().equals("<clinit>")) {
Block clinitMethodBlock = mMethod.getBody();
for (int i = 0; i < clinitMethodBlock.size(); i++) {
if(clinitMethodBlock.get(i) instanceof Assignment){
Assignment mAssignment = (Assignment) clinitMethodBlock.get(i);
IExpression mLeftExpression = mAssignment.getLeft();
IExpression mRightExpression = mAssignment.getRight();
if(mLeftExpression instanceof StaticField) {
StaticField mStaticField = (StaticField) mLeftExpression;
if (mStaticField.getField().getType().equals("[B")) {
byte[] b = getByteArrayValue(mRightExpression, staticIntegers, staticByteArrays);
if (b == null){
mJebInstance.print("Incorrect static byte[] " + mStaticField.getField().getName() + " define - initDecoderValues");
return;
}
staticByteArrays.put(mStaticField.getField().getName(), b);
if (debug) mJebInstance.print("static byte[] " + mStaticField.getField().getName());
} else if (mStaticField.getField().getType().equals("I") || mStaticField.getField().getType().equals("S") || mStaticField.getField().getType().equals("B")) {
int a = getIntValueOfExpression(mRightExpression, staticIntegers, staticByteArrays);
if(a == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect int " + mStaticField.getField().getName());
return;
}
staticIntegers.put(mStaticField.getField().getName(), a);
if (debug) mJebInstance.print("static int " + mStaticField.getField().getName() + " = " + a);
}
}
}
}
}
}
}
private static void decodeMethod(Method mMethod){
if (debug) mJebInstance.print("Start decode " + mMethod.getSignature());
HashMap<String, Integer> intValues = new HashMap<String,Integer>();
intValues.putAll(staticIntegers);
HashMap<String, byte[]> byteArrayValues = new HashMap<String, byte[]>();
byteArrayValues.putAll(staticByteArrays);
for (int i = 0; i < mMethod.getBody().size(); i++){
if(!mMethod.getSignature().equals(decoderMethodSignature)) decodeIElement(mMethod.getBody().get(i), mMethod.getBody(), intValues, byteArrayValues, 1);
}
}
public static String repeat(String str, int times){
return new String(new char[times]).replace("\0", str);
}
private static void decodeIElement(IElement mIElement, IElement mParentIElement, HashMap<String, Integer> intValues, HashMap<String, byte[]> byteArrayValues, int level){
if (debug) mJebInstance.print(repeat("\t", level) + "decodeIElement(" + mIElement.getClass().getName() + ", " + mParentIElement.getClass().getName() + ", ... )");
if (mIElement instanceof Definition && !(mParentIElement instanceof Assignment)) {
Definition mDefinition = (Definition) mIElement;
String type = mDefinition.getType();
if (type.equals("I") || type.equals("B") || type.equals("S")){
intValues.put(mDefinition.getIdentifier().getName(), Integer.MIN_VALUE);
if (debug) mJebInstance.print("\t\tint " + mDefinition.getIdentifier().getName());
}
} else if (mIElement instanceof Assignment){
Assignment mAssignment = (Assignment) mIElement;
IExpression mLeftExpression = mAssignment.getLeft();
IExpression mRightExpression = mAssignment.getRight();
if (mAssignment.isSimpleAssignment()) {
if (mLeftExpression instanceof Definition) {
Definition mDefinition = (Definition) mLeftExpression;
String type = mDefinition.getType();
if (type.equals("I") || type.equals("B") || type.equals("S")) {
int val = getIntValueOfExpression(mRightExpression, intValues, byteArrayValues);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression int " + mDefinition.getIdentifier().getName() + " == " + val + " for SimpleAssignment - decodeIElement");
return;
}
intValues.put(mDefinition.getIdentifier().getName(), val);
if (debug)
mJebInstance.print("\t\tint " + mDefinition.getIdentifier().getName() + " = " + val);
} /*else if (type.equals("[B")) {
byte[] val = getByteArrayValue(mRightExpression, intValues, byteArrayValues);
if (val == null) {
mJebInstance.print("Incorrect mRightExpression byte[] " + mDefinition.getIdentifier().getName() + " == " + val + " for SimpleAssignment - decodeIElement");
return;
}
byteArrayValues.put(mDefinition.getIdentifier().getName(), val);
if (debug)
mJebInstance.print("\t\tbyte[] " + mDefinition.getIdentifier().getName() + " = " + Arrays.toString(val));
}*/
} else if (mLeftExpression instanceof Identifier) {
Identifier mIdentifier = (Identifier) mLeftExpression;
if (intValues.containsKey(mIdentifier.getName())) {
int val = getIntValueOfExpression(mRightExpression, intValues, byteArrayValues);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression " + mIdentifier.getName() + " == " + val + " for SimpleAssignment - decodeIElement");
return;
}
intValues.put(mIdentifier.getName(), val);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " = " + val);
} /*else if (byteArrayValues.containsKey(mIdentifier.getName())) {
byte[] val = getByteArrayValue(mRightExpression, intValues, byteArrayValues);
if (val == null) {
mJebInstance.print("Incorrect mRightExpression " + mIdentifier.getName() + " == " + val + " for SimpleAssignment - decodeIElement");
return;
}
byteArrayValues.put(mIdentifier.getName(), val);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " = " + val);
}*/
} /*else if (mLeftExpression instanceof ArrayElt) {
ArrayElt mArrayElt = (ArrayElt) mLeftExpression;
if (mArrayElt.getArray() instanceof Identifier) {
String arrayName = ((Identifier) mArrayElt.getArray()).getName();
if (!byteArrayValues.containsKey(arrayName)) {
mJebInstance.print("Unavailable byte[] " + arrayName + " for SimpleAssignment - decodeIElement");
return;
}
int position = getIntValueOfExpression(mArrayElt.getIndex(), intValues, byteArrayValues);
if (position < 0 || position >= byteArrayValues.get(arrayName).length) {
mJebInstance.print("Incorrect position " + position + " for SimpleAssignment - decodeIElement");
return;
}
byte[] result = byteArrayValues.get(arrayName);
int val = getIntValueOfExpression(mRightExpression, intValues, byteArrayValues);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression " + arrayName + "[" + position + "] == " + val + " for SimpleAssignment - decodeIElement");
return;
}
result[position] = (byte) val;
if (debug) mJebInstance.print("\t\t" + arrayName + "[" + position + "] = " + val);
byteArrayValues.put(arrayName, result);
}
}*/
} else if (mAssignment.isCombinedOperatorAssignment()) {
if (!(mLeftExpression instanceof Identifier)) {
mJebInstance.print("Incorrect left IExpression type " + mLeftExpression.getClass().getName() + " for CombinedOperatorAssignment - decodeIElement");
return;
}
if (mRightExpression == null) {
mJebInstance.print("Incorrect right IExpression " + mRightExpression.getClass().getName() + " == null for CombinedOperatorAssignment - decodeIElement");
return;
}
Identifier mIdentifier = (Identifier) mLeftExpression;
if (intValues.containsKey(mIdentifier.getName())) {
int val = getIntValueOfExpression(mRightExpression, intValues, byteArrayValues);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression int value " + val + " for CombinedOperatorAssignment - decodeIElement");
return;
}
Operator mOperator = mAssignment.getCombinedOperator();
if(mOperator.equals(Operator.ADD)){
int val2 = intValues.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " += " + val);
intValues.put(mIdentifier.getName(), val2 + val);
} else if (mOperator.equals(Operator.SUB)){
int val2 = intValues.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " -= " + val);
intValues.put(mIdentifier.getName(), val2 - val);
} else if (mOperator.equals(Operator.MUL)){
int val2 = intValues.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " *= " + val);
intValues.put(mIdentifier.getName(), val * val2);
}
}
} else if (mAssignment.isUnaryOperatorAssignment()) {
if (!(mLeftExpression instanceof Identifier)) {
mJebInstance.print("Incorrect left IExpretion type " + mLeftExpression.getClass().getName() + " for UnaryOperatorAssignment - decodeIElement");
return;
}
if (mRightExpression != null) {
mJebInstance.print("Incorrect right IExpretion " + mRightExpression.getClass().getName() + " != null for UnaryOperatorAssignment - decodeIElement");
return;
}
Identifier mIdentifier = (Identifier) mLeftExpression;
if (intValues.containsKey(mIdentifier.getName())) {
boolean[] unaryFlags = new boolean[2];
mAssignment.getUnaryOperator(unaryFlags);
if (unaryFlags[0]) {
intValues.put(mIdentifier.getName(), intValues.get(mIdentifier.getName()) + 1);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + "++");
} else {
intValues.put(mIdentifier.getName(), intValues.get(mIdentifier.getName()) - 1);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + "--");
}
}
}
} else if (mIElement instanceof Call) {
Call mCall = (Call) mIElement;
String methodSignature = mCall.getMethod().getSignature();
if(methodSignature.equals(decoderMethodSignature) && !(mParentIElement instanceof Block)){
List<IExpression> params = mCall.getArguments();
int param1 = getIntValueOfExpression(params.get(0),intValues,byteArrayValues);
int param2 = getIntValueOfExpression(params.get(1),intValues,byteArrayValues);
int param3 = getIntValueOfExpression(params.get(2),intValues,byteArrayValues);
String result = decodeDexGuardString(param1,param2,param3);
mJebInstance.print("decodeDexGuardString(" + param1 + ", " + param2 + ", " + param3 + ") = " + result);
if(result != null) mParentIElement.replaceSubElement(mIElement, (new Constant.Builder(mJebInstance)).buildString(result));
else if (debug) return;
} else {
for(int i = 0; i < mIElement.getSubElements().size(); i++){
decodeIElement((IElement)mIElement.getSubElements().get(i), mIElement, intValues, byteArrayValues, level+1);
}
}
}
for (IElement element : (List<IElement>) mIElement.getSubElements()) {
if (!((element instanceof Class) || (element instanceof Field) || (element instanceof Method))) {
decodeIElement(element, mIElement, intValues, byteArrayValues, level + 1);
}
}
}
private static String decodeDexGuardString(int param1, int param2, int param3) {
if (debug) mJebInstance.print("decodeDexGuardString(" + param1 + ", " + param2 + ", " + param3 + ")");
Method mMethod = mJebInstance.getDecompiledMethodTree(decoderMethodSignature);
List<Definition> params = mMethod.getParameters();
Block mMethodBlock = mMethod.getBody();
HashMap<String, Integer> intValuesMap = new HashMap<String, Integer>();
intValuesMap.put(params.get(0).getIdentifier().getName(), param1);
intValuesMap.put(params.get(1).getIdentifier().getName(), param2);
intValuesMap.put(params.get(2).getIdentifier().getName(), param3);
intValuesMap.putAll(staticIntegers);
HashMap<String, byte[]> byteArrayValuesMap = new HashMap<String, byte[]>();
byteArrayValuesMap.putAll(staticByteArrays);
for (int i = 0; i < mMethodBlock.size(); i++) {
if (debug) mJebInstance.print(mMethodBlock.get(i).getClass().getName());
if(mMethodBlock.get(i) instanceof Definition){
Definition mDefinition = (Definition) mMethodBlock.get(i);
String type = mDefinition.getType();
if (type.equals("I") || type.equals("B") || type.equals("S")){
intValuesMap.put(mDefinition.getIdentifier().getName(), Integer.MIN_VALUE);
if (debug) mJebInstance.print("\t\tint " + mDefinition.getIdentifier().getName());
} else if (type.equals("[B")){
byteArrayValuesMap.put(mDefinition.getIdentifier().getName(), null);
if (debug) mJebInstance.print("\t\tbyte[] " + mDefinition.getIdentifier().getName());
} else {
mJebInstance.print("Unsupported Definition variable " + mDefinition.getIdentifier().getName() + " type \"" + type + "\" - decodeDexGuardString / Definition");
return null;
}
} else if (mMethodBlock.get(i) instanceof Assignment){
Assignment mAssignment = (Assignment) mMethodBlock.get(i);
IExpression mLeftExpression = mAssignment.getLeft();
IExpression mRightExpression = mAssignment.getRight();
if (mAssignment.isSimpleAssignment()) {
if (mLeftExpression instanceof Definition) {
Definition mDefinition = (Definition) mLeftExpression;
String type = mDefinition.getType();
if (type.equals("I") || type.equals("B") || type.equals("S")) {
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression int " + mDefinition.getIdentifier().getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
intValuesMap.put(mDefinition.getIdentifier().getName(), val);
if (debug)
mJebInstance.print("\t\tint " + mDefinition.getIdentifier().getName() + " = " + val);
} else if (type.equals("[B")) {
byte[] val = getByteArrayValue(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == null) {
mJebInstance.print("Incorrect mRightExpression byte[] " + mDefinition.getIdentifier().getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
byteArrayValuesMap.put(mDefinition.getIdentifier().getName(), val);
if (debug)
mJebInstance.print("\t\tbyte[] " + mDefinition.getIdentifier().getName() + " = " + Arrays.toString(val));
} else {
mJebInstance.print("Unsupported Definition variable " + mDefinition.getIdentifier().getName() + " type \"" + type + "\" - decodeDexGuardString / Definition");
return null;
}
} else if (mLeftExpression instanceof Identifier) {
Identifier mIdentifier = (Identifier) mLeftExpression;
if (intValuesMap.containsKey(mIdentifier.getName())) {
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression " + mIdentifier.getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
intValuesMap.put(mIdentifier.getName(), val);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " = " + val);
} else if (byteArrayValuesMap.containsKey(mIdentifier.getName())) {
byte[] val = getByteArrayValue(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == null) {
mJebInstance.print("Incorrect mRightExpression " + mIdentifier.getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
byteArrayValuesMap.put(mIdentifier.getName(), val);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " = " + val);
} else {
mJebInstance.print("Unknown variable " + mIdentifier.getName() + " type - decodeDexGuardString / Definition");
return null;
}
} else if (mLeftExpression instanceof ArrayElt) {
ArrayElt mArrayElt = (ArrayElt) mLeftExpression;
if(mArrayElt.getArray() instanceof Identifier) {
String arrayName = ((Identifier)mArrayElt.getArray()).getName();
if(!byteArrayValuesMap.containsKey(arrayName)){
mJebInstance.print("Unavailable byte[] " + arrayName + " for SimpleAssignment - decodeDexGuardString / Assignment / ArrayElt");
return null;
}
int position = getIntValueOfExpression(mArrayElt.getIndex(), intValuesMap, byteArrayValuesMap);
if(position < 0 || position >= byteArrayValuesMap.get(arrayName).length){
mJebInstance.print("Incorrect position " + position + " for SimpleAssignment - decodeDexGuardString / Assignment / ArrayElt");
return null;
}
byte[] result = byteArrayValuesMap.get(arrayName);
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression " + arrayName + "[" + position + "] == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
result[position] = (byte) val;
if (debug) mJebInstance.print("\t\t" + arrayName + "[" + position + "] = " + val);
byteArrayValuesMap.put(arrayName, result);
} else {
mJebInstance.print("Incorrect Array IExpression type " + mArrayElt.getArray().getClass().getName() + " for SimpleAssignment - decodeDexGuardString / Assignment / ArrayElt");
return null;
}
} else {
mJebInstance.print("Incorrect left IExpression type " + mLeftExpression.getClass().getName() + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
} else if (mAssignment.isCombinedOperatorAssignment()){
if(!(mLeftExpression instanceof Identifier)){
mJebInstance.print("Incorrect left IExpression type " + mLeftExpression.getClass().getName() + " for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
if(mRightExpression == null){
mJebInstance.print("Incorrect right IExpression " + mRightExpression.getClass().getName() + " == null for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
Identifier mIdentifier = (Identifier) mLeftExpression;
if(!intValuesMap.containsKey(mIdentifier.getName())){
mJebInstance.print("Unavailable int " + mIdentifier.getName() + " for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if(val == Integer.MIN_VALUE){
mJebInstance.print("Incorrect mRightExpression int value " + val + " for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
Operator mOperator = mAssignment.getCombinedOperator();
if(mOperator.equals(Operator.ADD)){
int val2 = intValuesMap.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " += " + val);
intValuesMap.put(mIdentifier.getName(), val2 + val);
} else if (mOperator.equals(Operator.SUB)){
int val2 = intValuesMap.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " -= " + val);
intValuesMap.put(mIdentifier.getName(), val2 - val);
} else if (mOperator.equals(Operator.MUL)){
int val2 = intValuesMap.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " *= " + val);
intValuesMap.put(mIdentifier.getName(), val * val2);
} else {
mJebInstance.print("Unsopported combinedOperator type \"" + mOperator.toString() + "=\" for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
} else if (mAssignment.isUnaryOperatorAssignment()){
if(!(mLeftExpression instanceof Identifier)){
mJebInstance.print("Incorrect left IExpretion type " + mLeftExpression.getClass().getName() + " for UnaryOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
if(mRightExpression != null){
mJebInstance.print("Incorrect right IExpretion " + mRightExpression.getClass().getName() + " != null for UnaryOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
Identifier mIdentifier = (Identifier) mLeftExpression;
if(!intValuesMap.containsKey(mIdentifier.getName())){
mJebInstance.print("Unavailable int " + mIdentifier.getName() + " - decodeDexGuardString / Assignment");
return null;
}
boolean[] unaryFlags = new boolean[2];
mAssignment.getUnaryOperator(unaryFlags);
if(unaryFlags[0]){
intValuesMap.put(mIdentifier.getName(), intValuesMap.get(mIdentifier.getName()) + 1);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + "++");
} else {
intValuesMap.put(mIdentifier.getName(), intValuesMap.get(mIdentifier.getName()) - 1);
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + "--");
}
} else {
mJebInstance.print("Incorrect type Assignment - decodeDexGuardString");
}
} else if (mMethodBlock.get(i) instanceof WhileStm){
WhileStm mWhileStm = (WhileStm)mMethodBlock.get(i);
Block mWhileBlock = mWhileStm.getBody();
int controller = 0;
while (controller < 70) {
controller++;
for (int j = 0; j < mWhileBlock.size(); j++) {
if (debug) mJebInstance.print("\t\t\t\t"+ mWhileBlock.get(j).getClass().getName());
if(mWhileBlock.get(j) instanceof Definition){
Definition mDefinition = (Definition) mWhileBlock.get(j);
String type = mDefinition.getType();
if (type.equals("I") || type.equals("B") || type.equals("S")){
intValuesMap.put(mDefinition.getIdentifier().getName(), Integer.MIN_VALUE);
if (debug) mJebInstance.print("\t\t\t\t\t\tint " + mDefinition.getIdentifier().getName());
} else if (type.equals("[B")){
byteArrayValuesMap.put(mDefinition.getIdentifier().getName(), null);
if (debug) mJebInstance.print("\t\t\t\t\t\tbyte[] " + mDefinition.getIdentifier().getName());
} else {
mJebInstance.print("Unsupported Definition variable " + mDefinition.getIdentifier().getName() + " type \"" + type + "\" - decodeDexGuardString / Definition");
return null;
}
} else if (mWhileBlock.get(j) instanceof Assignment){
Assignment mAssignment = (Assignment) mWhileBlock.get(j);
IExpression mLeftExpression = mAssignment.getLeft();
IExpression mRightExpression = mAssignment.getRight();
if (mAssignment.isSimpleAssignment()){
if(mLeftExpression instanceof Definition){
Definition mDefinition = (Definition) mLeftExpression;
String type = mDefinition.getType();
if (type.equals("I") || type.equals("B") || type.equals("S")){
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression int " + mDefinition.getIdentifier().getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
intValuesMap.put(mDefinition.getIdentifier().getName(), val);
if (debug) mJebInstance.print("\t\t\t\t\t\tint " + mDefinition.getIdentifier().getName() + " = " + val);
} else if (type.equals("[B")){
byte[] val = getByteArrayValue(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == null) {
mJebInstance.print("Incorrect mRightExpression byte[] " + mDefinition.getIdentifier().getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
byteArrayValuesMap.put(mDefinition.getIdentifier().getName(), val);
if (debug) mJebInstance.print("\t\t\t\t\t\tbyte[] " + mDefinition.getIdentifier().getName() + " = " + Arrays.toString(val));
} else {
mJebInstance.print("Unsupported Definition variable " + mDefinition.getIdentifier().getName() + " type \"" + type + "\" - decodeDexGuardString / Definition");
return null;
}
} else if (mLeftExpression instanceof Identifier) {
Identifier mIdentifier = (Identifier) mLeftExpression;
if (intValuesMap.containsKey(mIdentifier.getName())){
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression " + mIdentifier.getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
intValuesMap.put(mIdentifier.getName(), val);
if (debug) mJebInstance.print("\t\t\t\t\t\t" + mIdentifier.getName() + " = " + val);
} else if (byteArrayValuesMap.containsKey(mIdentifier.getName())){
byte[] val = getByteArrayValue(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == null) {
mJebInstance.print("Incorrect mRightExpression " + mIdentifier.getName() + " == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
byteArrayValuesMap.put(mIdentifier.getName(), val);
if (debug) mJebInstance.print("\t\t\t\t\t\t" + mIdentifier.getName() + " = " + val);
} else {
mJebInstance.print("Unknown variable " + mIdentifier.getName() + " type - decodeDexGuardString / Definition");
return null;
}
} else if (mLeftExpression instanceof ArrayElt) {
ArrayElt mArrayElt = (ArrayElt) mLeftExpression;
if(mArrayElt.getArray() instanceof Identifier) {
String arrayName = ((Identifier)mArrayElt.getArray()).getName();
if(!byteArrayValuesMap.containsKey(arrayName)){
mJebInstance.print("Unavailable byte[] " + arrayName + " for SimpleAssignment - decodeDexGuardString / Assignment / ArrayElt");
return null;
}
int position = getIntValueOfExpression(mArrayElt.getIndex(), intValuesMap, byteArrayValuesMap);
if(position < 0 || position >= byteArrayValuesMap.get(arrayName).length){
mJebInstance.print("Incorrect position " + position + " for SimpleAssignment - decodeDexGuardString / Assignment / ArrayElt");
return null;
}
byte[] result = byteArrayValuesMap.get(arrayName);
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if (val == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect mRightExpression " + arrayName + "[" + position + "] == " + val + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
result[position] = (byte) val;
if (debug) mJebInstance.print("\t\t" + arrayName + "[" + position + "] = " + val);
byteArrayValuesMap.put(arrayName, result);
} else {
mJebInstance.print("Incorrect Array IExpression type " + mArrayElt.getArray().getClass().getName() + " for SimpleAssignment - decodeDexGuardString / Assignment / ArrayElt");
return null;
}
} else {
mJebInstance.print("Incorrect left IExpression type " + mLeftExpression.getClass().getName() + " for SimpleAssignment - decodeDexGuardString / Assignment");
return null;
}
} else if (mAssignment.isCombinedOperatorAssignment()){
if(!(mLeftExpression instanceof Identifier)){
mJebInstance.print("Incorrect left IExpression type " + mLeftExpression.getClass().getName() + " for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
if(mRightExpression == null){
mJebInstance.print("Incorrect right IExpression " + mRightExpression.getClass().getName() + " == null for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
Identifier mIdentifier = (Identifier) mLeftExpression;
if(!intValuesMap.containsKey(mIdentifier.getName())){
mJebInstance.print("Unavailable int " + mIdentifier.getName() + " for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
int val = getIntValueOfExpression(mRightExpression, intValuesMap, byteArrayValuesMap);
if(val == Integer.MIN_VALUE){
mJebInstance.print("Incorrect mRightExpression int value " + val + " for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
Operator mOperator = mAssignment.getCombinedOperator();
if(mOperator.equals(Operator.ADD)){
int val2 = intValuesMap.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " += " + val);
intValuesMap.put(mIdentifier.getName(), val2 + val);
} else if (mOperator.equals(Operator.SUB)){
int val2 = intValuesMap.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " -= " + val);
intValuesMap.put(mIdentifier.getName(), val2 - val);
} else if (mOperator.equals(Operator.MUL)){
int val2 = intValuesMap.get(mIdentifier.getName());
if (debug) mJebInstance.print("\t\t" + mIdentifier.getName() + " *= " + val);
intValuesMap.put(mIdentifier.getName(), val * val2);
} else {
mJebInstance.print("Unsopported combinedOperator type \"" + mOperator.toString() + "=\" for CombinedOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
} else if (mAssignment.isUnaryOperatorAssignment()){
if(!(mLeftExpression instanceof Identifier)){
mJebInstance.print("Incorrect left IExpretion type " + mLeftExpression.getClass().getName() + " for UnaryOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
if(mRightExpression != null){
mJebInstance.print("Incorrect right IExpretion " + mRightExpression.getClass().getName() + " != null for UnaryOperatorAssignment - decodeDexGuardString / Assignment");
return null;
}
Identifier mIdentifier = (Identifier) mLeftExpression;
if(!intValuesMap.containsKey(mIdentifier.getName())){
mJebInstance.print("Unavailable int " + mIdentifier.getName() + " - decodeDexGuardString / Assignment");
return null;
}
boolean[] unaryFlags = new boolean[2];
mAssignment.getUnaryOperator(unaryFlags);
if(unaryFlags[0]){
intValuesMap.put(mIdentifier.getName(), intValuesMap.get(mIdentifier.getName()) + 1);
if (debug) mJebInstance.print("\t\t\t\t\t\t" + mIdentifier.getName() + "++");
} else {
intValuesMap.put(mIdentifier.getName(), intValuesMap.get(mIdentifier.getName()) - 1);
if (debug) mJebInstance.print("\t\t\t\t\t\t" + mIdentifier.getName() + "--");
}
} else {
mJebInstance.print("Incorrect type Assignment - decodeDexGuardString");
}
} else if (mWhileBlock.get(j) instanceof IfStm){
IfStm mIfStm = (IfStm) mWhileBlock.get(j);
Predicate mPredicate = mIfStm.getBranchPredicate(0);
String lVarName = ((Identifier) mPredicate.getLeft()).getName();
String rVarName = ((Identifier) mPredicate.getRight()).getName();
Block ifBlock = mIfStm.getBranchBody(0);
if(intValuesMap.get(lVarName).equals(intValuesMap.get(rVarName))){
String resultByteArray = "";
for (int k = 0; k < ifBlock.size(); k++) {
if(ifBlock.get(k) instanceof Return){
Return mReturn = (Return) ifBlock.get(k);
if(mReturn.getExpression() instanceof New){
New mNew = (New) mReturn.getExpression();
List args = mNew.getArguments();
if (args.size() > 0 && args.get(0) instanceof Identifier) {
Identifier mIdentifier = (Identifier) args.get(0);
resultByteArray = mIdentifier.getName();
} else {
mJebInstance.print("String init params incorrect");
return null;
}
} else if (mReturn.getExpression() instanceof Call) {
Call mCall = (Call) mReturn.getExpression();
List<IExpression> par = mCall.getArguments();
if(par.size() <= 0) {
mJebInstance.print("Unavailable String Creater");
return null;
}
if (par.get(0) instanceof New) {
New mNew = (New) par.get(0);
List args = mNew.getArguments();
if (args.size() > 0 && args.get(0) instanceof Identifier) {
Identifier mIdentifier = (Identifier) args.get(0);
resultByteArray = mIdentifier.getName();
} else {
mJebInstance.print("String init params incorrect");
return null;
}
} else {
mJebInstance.print("Unavailable String Creater in Call");
return null;
}
} else {
mJebInstance.print("Incorrect Return Expression " + mReturn.getExpression().getClass().getName());
return null;
}
} else {
mJebInstance.print("Statement is not Return (" + ifBlock.get(k).getClass().getName() + ")");
return null;
}
}
//mJebInstance.print("t4 - " + resultByteArray + " = " + Arrays.toString(byteArrayValuesMap.get(resultByteArray)) + " " + new String(byteArrayValuesMap.get(resultByteArray)));
return new String(byteArrayValuesMap.get(resultByteArray));
}
} else {
mJebInstance.print("Unsupported Statement type " + mWhileBlock.get(j).getClass().getName() + " - decodeDexGuardString / Assignment");
return null;
}
}
}
} else {
mJebInstance.print("Unsupported Statement type " + mMethodBlock.get(i).getClass().getName() + " - decodeDexGuardString / Assignment");
return null;
}
}
return "";
}
private static byte[] getByteArrayValue(IExpression mIExpression, HashMap<String,Integer> intValues, HashMap<String, byte[]> byteArrayValues){
if (debug) mJebInstance.print("\t\t\t\t\t\t\t\tgetByteArrayValue for " + mIExpression.getClass().getName());
if (mIExpression instanceof Call) {
//TODO
mJebInstance.print("Unsupported IExpression parametr type - getByteArrayValue of Call");
return null;
} else if (mIExpression instanceof Identifier) {
Identifier mIdentifier = (Identifier) mIExpression;
if(!byteArrayValues.containsKey(mIdentifier.getName())) {
mJebInstance.print("Unavailable byte[] " + mIdentifier.getName() + " - getByteArrayValue of Identifier");
return null;
}
return byteArrayValues.get(mIdentifier.getName());
} else if (mIExpression instanceof InstanceField) {
//TODO
mJebInstance.print("Unsupported IExpression parametr type - getByteArrayValue of InstanceField");
return null;
} else if (mIExpression instanceof NewArray) {
NewArray mNewArray = (NewArray) mIExpression;
if(!mNewArray.getType().equals("[B")){
mJebInstance.print("Unsupported NewArray type " + mNewArray.getType() + " - getByteArrayValue of NewArray");
return null;
}
if(mNewArray.getInitialValues() != null){
List<Constant> initialValues = mNewArray.getInitialValues();
if(initialValues.isEmpty()){
return null;
}
byte[] rezult = new byte[initialValues.size()];
for (int i = 0; i < initialValues.size(); i++) {
rezult[i] = initialValues.get(i).getByte();
}
return rezult;
} else if (mNewArray.getSizes() != null) {
if (mNewArray.getSizes().size() > 1) {
mJebInstance.print("Unsupported NewArray multiSizes array " + mNewArray.getSizes().size() + " - getByteArrayValue of NewArray");
return null;
}
IExpression mSizeIExpression = (IExpression) mNewArray.getSizes().get(0);
int sizeArray = getIntValueOfExpression(mSizeIExpression, intValues, byteArrayValues);
if (sizeArray < 0) {
mJebInstance.print("Incorrect array size " + sizeArray + " - getByteArrayValue of NewArray");
return null;
}
return new byte[sizeArray];
} else {
mJebInstance.print("Error - getByteArrayValue of NewArray");
return null;
}
} else if (mIExpression instanceof StaticField) {
StaticField mStaticField = (StaticField) mIExpression;
String fType = mStaticField.getField().getType();
if(!fType.equals("[B")){
mJebInstance.print("Incorrect StaticField type " + fType + " - getByteArrayValue of StaticField");
return null;
}
if(!byteArrayValues.containsKey(mStaticField.getField().getName())){
mJebInstance.print("Unavailable byte[] " + mStaticField.getField().getName() + " - getByteArrayValue of StaticField");
return null;
}
return byteArrayValues.get(mStaticField.getField().getName());
} else {
mJebInstance.print("Unsupported IExpression parametr type - getByteArrayValue of " + mIExpression.getClass().getName());
return null;
}
}
private static int getIntValueOfExpression(IExpression mIExpression, HashMap<String, Integer> intValues, HashMap<String,byte[]> byteArrayValues) {
if (debug) mJebInstance.print("\t\t\t\t\t\t\t\tgetIntValueOfExpression for " + mIExpression.getClass().getName());
if(mIExpression instanceof ArrayElt){
ArrayElt mArrayElt = (ArrayElt) mIExpression;
if(!(mArrayElt.getArray() instanceof Identifier || mArrayElt.getArray() instanceof StaticField)){
mJebInstance.print("Unsupported type of Array " + mArrayElt.getArray().getClass().getName() + " - getIntValueOfExpression of ArrayElt");
return Integer.MIN_VALUE;
}
String byteArrayName = (mArrayElt.getArray() instanceof Identifier) ? ((Identifier)mArrayElt.getArray()).getName() : ((StaticField)mArrayElt.getArray()).getField().getName();
if(!byteArrayValues.containsKey(byteArrayName)){
mJebInstance.print("Unavailable byteArray " + byteArrayName + " - getIntValueOfExpression of ArrayElt");
return Integer.MIN_VALUE;
}
byte[] mBytes = byteArrayValues.get(byteArrayName);
int position = getIntValueOfExpression(mArrayElt.getIndex(), intValues, byteArrayValues);
if(mBytes.length <= position){
mJebInstance.print("Incorrect position (byte[].length " + mBytes.length + " <= position " + position + ") - getIntValueOfExpression of ArrayElt");
return Integer.MIN_VALUE;
} else if (position < 0){
mJebInstance.print("Incorrect position (position " + position + " < 0) - getIntValueOfExpression of ArrayElt");
return Integer.MIN_VALUE;
}
return mBytes[position];
} else if (mIExpression instanceof Call) {
//TODO
mJebInstance.print("Unsupported IExpression parametr type - getIntValueOfExpression of Call");
return Integer.MIN_VALUE;
} else if (mIExpression instanceof Constant) {
Constant mConstant = (Constant) mIExpression;
if(mConstant.isFalse() || mConstant.isNull() || mConstant.isTrue() || mConstant.isString()){
mJebInstance.print("Unsupported type of Constant - getIntValueOfExpression of Constant");
return Integer.MIN_VALUE;
}
String type = ((Constant) mIExpression).getType();
if(type.equals("B")){
return (int) ((Constant) mIExpression).getByte();
} else if (type.equals("S")){
return (int) ((Constant) mIExpression).getShort();
} else {
return ((Constant) mIExpression).getInt();
}
} else if (mIExpression instanceof Expression) {
Expression mExpression = (Expression) mIExpression;
int lValue = Integer.MIN_VALUE;
if(mExpression.getLeft() != null) {
lValue = getIntValueOfExpression(mExpression.getLeft(), intValues, byteArrayValues);
if (lValue == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect lValue " + lValue + " - getIntValueOfExpression of Expression");
return Integer.MIN_VALUE;
}
}
int rValue = getIntValueOfExpression(mExpression.getRight(), intValues, byteArrayValues);
if (rValue == Integer.MIN_VALUE) {
mJebInstance.print("Incorrect rValue " + rValue + " - getIntValueOfExpression of Expression");
return Integer.MIN_VALUE;
}
Operator mOperator = mExpression.getOperator();
if(mOperator.equals(Operator.ADD)){
return lValue + rValue;
} else if (mOperator.equals(Operator.SUB)){
return lValue - rValue;
} else if (mOperator.equals(Operator.MUL)){
return lValue * rValue;
} else if (mOperator.equals(Operator.DIV)){
return lValue / rValue;
} else if (mOperator.equals(Operator.REM)){
return lValue % rValue;
} else if (mOperator.equals(Operator.OR)){
return lValue | rValue;
} else if (mOperator.equals(Operator.AND)){
return lValue & rValue;
} else if (mOperator.equals(Operator.XOR)){
return lValue ^ rValue;
} else if (mOperator.equals(Operator.SHL)){
return lValue << rValue;
} else if (mOperator.equals(Operator.SHR)){
return lValue >> rValue;
} else if (mOperator.equals(Operator.USHR)){
return lValue >>> rValue;
} else if (mOperator.equals(Operator.NEG)) {
return -rValue;
} else if (mOperator.equals(Operator.CAST_TO_BYTE)) {
return rValue;
} else if (mOperator.equals(Operator.CAST_TO_SHORT)) {
return rValue;
} else if (mOperator.equals(Operator.CAST_TO_INT)) {
return rValue;
} else {
mJebInstance.print("Unsupported operation type \"" + mOperator.toString() + "\" - getIntValueOfExpression of Expression");
return Integer.MIN_VALUE;
}
} else if (mIExpression instanceof Identifier) {
Identifier mIdentifier = (Identifier) mIExpression;
if(!intValues.containsKey(mIdentifier.getName())){
mJebInstance.print("intValues.keys = " + Arrays.toString(intValues.keySet().toArray()));
mJebInstance.print("Unavailable int " + mIdentifier.getName() + " - getIntValueOfExpression of Identifier");
return Integer.MIN_VALUE;
}
return intValues.get(mIdentifier.getName());
} else if (mIExpression instanceof InstanceField) {
//TODO
mJebInstance.print("Unsupported IExpression parametr type - getIntValueOfExpression of InstanceField");
return Integer.MIN_VALUE;
} else if (mIExpression instanceof StaticField) {
StaticField mStaticField = (StaticField) mIExpression;
String fType = mStaticField.getField().getType();
if(!(fType.equals("I") || fType.equals("B") || fType.equals("S") )){
mJebInstance.print("Incorrect StaticField type " + fType + " - getIntValueOfExpression of StaticField");
return Integer.MIN_VALUE;
}
if(!intValues.containsKey(mStaticField.getField().getName())){
mJebInstance.print("Unavailable int " + mStaticField.getField().getName() + " - getIntValueOfExpression of StaticField");
return Integer.MIN_VALUE;
}
return intValues.get(mStaticField.getField().getName());
} else {
mJebInstance.print("Unsupported IExpression parametr type - getIntValueOfExpression of " + mIExpression.getClass().getName());
return Integer.MIN_VALUE;
}
}
private static String getClassFromSignature(String signature){
String pattern = "^(L[a-zA-Z/$]*[;])(.*)$";
return signature.replaceAll(pattern, "$1");
}
}
@bactis
Copy link

bactis commented Feb 9, 2016

thank you :)

@AKosterin
Copy link
Author

I continue to plug testing found a number of serious errors. In the near future I will update it

@virqdroid
Copy link

Thanks AKosterin 👍

@idanr1986
Copy link

first thank you very much!
any idea how to fix this ?

DexGuardDecoder_Start
Error executing java script:
java.lang.NullPointerException
DexGuardDecoder.run(DexGuardDecoder.java:47)

@AKosterin
Copy link
Author

idanr1986, it means that the script did not find the decryption method. Сan You send me the apk, that are you trying to decipher?

@idanr1986
Copy link

ahh ok can you write an md5 for example?

@jumbofreak
Copy link

one more
DexGuardDecoder_Start
Error executing script:
java.lang.NullPointerException
DexGuardDecoder.run(DexGuardDecoder.java:47)

This is the file https://www.virustotal.com/en/file/c655e01b40b7bc5e9c88429360828c046549ac07d7ba6d591b7bdda92597bafd/analysis/

@virqdroid
Copy link

@AKosterin
Copy link
Author

Can you send me apk?

@alxchk
Copy link

alxchk commented Apr 7, 2016

DexGuardDecoder.java:304: error: cannot find symbol
} else if (mAssignment.isCombinedOperatorAssignment()) {

:(

@mbazaliy
Copy link

Is it compatible with JEB 2.xx plugins API ?

@enovella
Copy link

enovella commented Jul 6, 2016

@jumbofreak && @virqdroid:

Can we download these APKs? Or could you upload them somewhere?

The script does work with some versions of DexGuard.

@parind
Copy link

parind commented Nov 24, 2018

Do they work with DexProtector ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment