正在使用什么方法来保护这个Android APK:反思?加密?如何进行逆向工程分析? [英] What methods are being used to protect this Android APK: Reflection? Encryption? How do I reverse engineer it and analyze it?

查看:532
本文介绍了正在使用什么方法来保护这个Android APK:反思?加密?如何进行逆向工程分析?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道Java编程的基础知识,但我是逆向工程APK的新手,所以解释很棒!






我有一个APK文件文件,但不是Java源码。在线上解压缩APK:



大部分应用程序隐藏在


资产> classes.dex.dat


我发现的唯一的java文件是


com> ...> util> ProtectedUtils.java


我有ProtectedUtils.java :如果有人感兴趣,请链接到完整的文件

  import android.app.Application; 
import android.app.Instrumentation;
import android.content.Context;
import android.os.Build.VERSION;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

public class ProtectedApplicationUtils extends Application {
private static Application f0d;
private static boolean f1d;
private static transient Object [] f2d;
private static Application dd;
private static boolean gfgf;

public ProtectedApplicationUtils(){
dd = this;
}

private static final int attachBaseContext(int i,int i2){
int i3 =(i2 + i)>> 24;
return(i>>> i2)| (i <(-i2));
}

public static Context attachBaseContext(Context context){
attachBaseContext();
return context == dd? f0d:上下文
}

private static void attachBaseContext(){
if(!f1d){
f1d = true;
类cls = Class.forName(m1d(\\\傳\\\졉\\\\\\퀐\\\�\\\䗥\\\欓\\\㛠\\\๻\\\쫧\\\睎\\\슰 \\\롊\\\�\\\遱\\\㿒\\\㷖\\\㙶\\\闊\\\̛\\\�\\\響\\\㯱\\\व\\\疯\\\폖\" ));
Class [] clsArr = new Class [0];
对象调用= cls.getMethod(m1d(\\\傱\\\졒\\\\\\퀐\\\�\\\䗢\\\欃\\\㚏\\\๹\ucc3-3\\\睗\\\싨 \ubuntu2 \\\�\\\遼\\\㿯\\\㷈\\\㙭\\\闛\\\̃\\\�),clsArr).invoke(null,new Object [0]);
Field declaredField = cls.getDeclaredField(m1d(\\\傿\\\졦\\\\\\퀎\\\�\\\䗼\\\欇\\\㚢\\\๳\\\쫴\\\睟\\\싪 \\\롢\\\�\\\遫\\\㿈\" ));
declaredField.setAccessible(true);
((List)declaredField.get(invoke))。add(0,f0d);
Field declaredField2 = cls.getDeclaredField(m1d(\\\傿\\\졮\\\\\\퀋\\\�\\\䗥\\\欖\\\㚢\\\๛\\\첧\\\睎\\\싲 \\\롢\\\�\\\遤\\\㿏\\\㷉\\\㙰\\\闐\" ));
declaredField2.setAccessible(true);
declaredField2.set(invoke,f0d);
Field declaredField3 = cls.getDeclaredField(m1d(\\\傿\\\졥\\\\\\퀗\\\�\\\䗨\\\欶\\\㚾\\\๪\\\쫻\\\睗\\\싽 \\\롪\\\�\\\遬\\\㿔\\\㷎));
declaredField3.setAccessible(true);
Object obj = declaredField3.get(invoke);
Field declaredField4 = obj.getClass()。getDeclaredField(m1d(\\\傻\\\졉\\\\\\퀍));
declaredField4.setAccessible(true);
Object obj2 = declaredField4.get(obj);
Field declaredField5 = obj2.getClass()。getDeclaredField(m1d(\\\傿\\\졦\\\\\\퀒\\\�\\\䗥\\\欔\\\㚯\\\๮\\\쫾\ u7751\\\싰\" ));
declaredField5.setAccessible(true);
declaredField5.set(obj2,f0d);
上下文baseContext = f0d.getBaseContext();
Field declaredField6 = baseContext.getClass()。getDeclaredField(m1d(\\\傿\\\졨\\\\\\퀖\\\�\\\䗾\\\欴\\\㚡\\\๴\\\쫣\ u775b\\\싦\\\롿));
declaredField6.setAccessible(true);
declaredField6.set(baseContext,f0d);
}
}

private static final int m0d(byte [] bArr,int i){
Object obj = null;
int i2 = bArr [14]<< 16;
Object obj2 = null;
while(obj2 == null){
obj2 = 3;
try {
return(bArr [(i>>> 24)& 255]<< 24)| ((bArr [i& 255]& 255)|((bArr [(i> 8)& 255]& 255)< 8))|((bArr [(i& ;> 16)& 255]& 255)<< 16));
} catch(Exception e){
}
}
while(obj == null){
obj = 2;
try {
return bArr [i& >> 8;
} catch(异常e2){
}
}
return i2;
}

static final String m1d(String str){
if(f2d == null){
mark();
}
Object [] objArr =(Object [])((Method)f2d [8])。invoke(((Method)f2d [7])。invoke(null,null),null) ;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(((Method)f2d [10])。invoke(objArr [((Integer)f2d [12])。intValue()],null));
int hashCode = stringBuilder.append(((Method)f2d [11])。invoke(objArr [((Integer)f2d [12])。intValue()],null))toString()。hashCode );
int [] iArr =(int [])f2d [6];
int i = hashCode ^ iArr [0];
int i2 = hashCode ^ iArr [1];
int i3 = hashCode ^ iArr [2];
int i4 = hashCode ^ iArr [3];
iArr =(int [])f2d [5];
int [] iArr2 =(int [])f2d [1];
int [] iArr3 =(int [])f2d [2];
int [] iArr4 =(int [])f2d [3];
int [] iArr5 =(int [])f2d [4];
byte [] bArr =(byte [])f2d [0];
char [] cArr =(char [])((Method)f2d [9])。invoke(str,null);
int i5 = i3;
i3 = i2;
i2 = i;
i = i4;
Object obj = null;
while(obj == null){
try {
int length = cArr.length; (int i6 = 0; i6 if(i6%8 == 0){
int i7;
int i8;
int i9;
int i10 = i2 ^ iArr [0];
int i11 = i3 ^ iArr [1];
int i12 = i5 ^ iArr [2];
i4 = iArr [3] ^ i;
int i13 = 4;
while(i13< 36){
i7 =((iArr2 [i10& 255] ^ iArr3 [(i11> 8)& 255])^ iArr4 [(i12& ;> 16)& 255])^ iArr5 [i4>> 24])^ iArr [i13];
i8 =(((iArr2 [i11& 255] ^ iArr3 [(i12> 8)& 255])^ iArr4 [(i4> 16)& 255])^ iArr5 [i10>> 24])^ iArr [i13 + 1];
i9 =(((iArr2 [i12& 255] ^ iArr3 [(i4> 8)& 255])^ iArr4 [(i10> 16)& 255])^ iArr5 [i11>> 24])^ iArr [i13 + 2];
i4 =(((iArr2 [i4& 255] ^ iArr3 [(i10> 8)& 255])^ iArr4 [(i11> 16)& 255])^ iArr5 [i12>> 24])^ iArr [i13 + 3];
i13 + = 4;
i10 =(((iArr2 [i7& 255] ^ iArr3 [(i8> 8)& 255])^ iArr4 [(i9> 16)& 255])^ iArr5 [i4>> 24])^ iArr [i13];
i11 = iArr [i13 + 1] ^(((iArr2 [i8& 255] ^ iArr3 [(i9> 8)& 255])^ iArr4 [(i4> 16) & 255])^ iArr5 [i7>> 24]);
i12 =(((iArr2 [i9& 255] ^ iArr3 [(i4> 8)& 255])^ iArr4 [(i7> 16)& 255])^ iArr5 [i8>> 24])^ iArr [i13 + 2];
i4 =(((iArr2 [i4& 255] ^ iArr3 [(i7> 8)& 255])^ iArr4 [(i8> 16)& 255])^ iArr5 [i9>> 24])^ iArr [i13 + 3];
i13 + = 4;
}
i7 =((iArr2 [i10& 255] ^ iArr3 [(i11> 8)& 255])^ iArr4 [(i12> 16)& 255])^ iArr5 [i4>> 24])^ iArr [i13];
i8 =(((iArr2 [i11& 255] ^ iArr3 [(i12> 8)& 255])^ iArr4 [(i4> 16)& 255])^ iArr5 [i10>> 24])^ iArr [i13 + 1];
i9 =(((iArr2 [i12& 255] ^ iArr3 [(i4> 8)& 255])^ iArr4 [(i10> 16)& 255])^ iArr5 [i11>> 24])^ iArr [i13 + 2];
i4 =(((iArr2 [i4& 255] ^ iArr3 [(i10> 8)& 255])^ iArr4 [(i11> 16)& 255])^ iArr5 [i12>> 24])^ iArr [i13 + 3];
i12 = i13 + 4; $(bArr [i7& 255]& 255)^( ;< 8))^((bArr [(i9> 16)& 255]& 255)<< 16))^(bArr [i4>> 24] ; 24)); $(bArr [i8& 255]& 255)^ ;< 8))^((bArr [(i4> 16)& 255]& 255)< 16))^(bArr [i7> 24] ; 24)); $(bArr [i9& 255]& 255)^( ;< 8))^((bArr [(i7> 16)& 255]& 255)< 16))^(bArr [18]> 24] ; 24));
i = iArr [i12 + 3] ^((((bArr [i4& 255]& 255)^((bArr [(i7> 8)& 255]& 255) < 8))^((bArr [(i8> 16)& 255]& 255)< 16))^(bArr [i>≥24] 24));
}
obj = null;
while(obj == null){
obj = 3;
try {
switch(i6%8){
case 0:
cArr [i6] =(char)((i2>> 16)^ cArr [i6] );
break;
案例1:
cArr [i6] =(char)(cArr [i6] ^ i2);
break;
case 2:
cArr [i6] =(char)((i3>>> 16)^ cArr [i6]);
break;
案例3:
cArr [i6] =(char)(cArr [i6] ^ i3);
break;
案例4:
cArr [i6] =(char)((i5>> 16)^ cArr [i6]);
break;
案例5:
cArr [i6] =(char)(cArr [i6] ^ i5);
break;
case 6:
cArr [i6] =(char)((i>>  16)^ cArr [i6]);
break;
case 7:
cArr [i6] =(char)(cArr [i6] ^ i);
break;
默认值:
break;
}
} catch(Throwable th){
}
}
}
return new String(cArr);
} catch(Throwable th2){
i4 = 1;
}
}
return new String(cArr);
}


private void eee(){
if(!gfgf){


...


byte [] bArr = new byte [length];
int i = 0; (int i2 = 1; i2< toCharArray.length; i2 ++){
char c = toCharArray [i2];

int i3 = i + 1;
bArr [i] =(byte)(c>> 8);
i = i3 + 1;
bArr [i3] =(byte)c;
}
length - = toCharArray [0];
类cls = Class.forName(m1d(\\\櫼\\\只\\\\\\矑\\\\\\겑\\\儹\\\벽\\\祵\\\왚\\\\\\暬 \\\삌\\\䣊\\\ី\\\꜁\" ));
类cls2 = Class.forName(m1d(\\\櫼\\\只\\\\\\矑\\\\\\겔\\\儷\\\볽\\\祔\\\옝\\\\\\暽 ));
构造函数构造函数= cls2.getConstructor(new Class [] {cls2,cls});
方法方法= Class.forName(m1d(\\\櫷\\\句\\\\\\矂\\\\\\겔\\\儼\\\볽\\\祱\\\옛\\\\\\暬 \\\삛\\\䣍\\\អ\\\Ꝉ\\\淼\\\豼\\\텾\\\賌\\\鍈\\\\\\歖 ))。getMethod(M1D( \\\櫱\\\叮\ ue9e5\\\矴\\\\\\겏),新的Class [] {cls,Integer.TYPE});
Object invoke = method.invoke(this,new Object [] {m​​1d(\\\櫲\\\叮\\\),Integer.valueOf(0)});
对象invoke2 = method.invoke(this,new Object [] {m​​1d(\\\櫹\\\叾\e9e5\\\矔\\\\\\겅),Integer.valueOf(0)}) ;
对象newInstance = constructor.newInstance(new Object [] {invoke,m1d(\\\櫸\\\叮\\\\\\瞞\\\\\\겍\\\儳)});
Object newInstance2 = constructor.newInstance(new Object [] {invoke2,m1d(\\\櫸\\\叮\\\\\\瞞\\\\\\겙\\\儽\\\벫)});
类cls3 = Class.forName(m1d(\\\櫼\\\只\\\\\\矑\\\\\\겔\\\儷\\\볽\\\祔\\\옝\\\\\\暽 \\\삱\\\䣖\\\អ\\\꜖\\\淊\\\豧\\\텃\\\賌\\\鍟\\\\\\歃\\\廟));
Object newInstance3 = cls3.getConstructor(new Class [] {cls2})。newInstance(new Object [] {newInstance});
尝试{
cls3.getMethod(m1d(\\\櫡\\\叹\\\\\\矄\\\),新的Class [] {byte []。class,Integer.TYPE, Integer.TYPE})。invoke(newInstance3,new Object [] {bArr,Integer.valueOf(0),Integer.valueOf(length)});
Class [] clsArr = new Class [0];
cls3.getMethod(m1d(\\\櫵\\\叧\\\\\\矃\\\),clsArr).invoke(newInstance3,new Object [0]);
clsArr = new Class [0];
方法method2 = cls2.getMethod(m1d(\\\櫱\\\叮\\\\\\石\\\\\\겓\\\儷\\\벽\\\祻\\\옗\\\\\\暴 \\\삮\\\䣂\\\អ\\\꜎),clsArr);
类cls4 = Class.forName(m1d(\\\櫲\\\只\\\\\\矆\\\\\\겖\\\其\ubc0\\\祫\\\옇\\\\\\暽 \\\삓\\\䢍\\\ធ\\\꜃\\\淇\\\豕\\\텹\\\賔\\\鍈\" ));
方法method3 = cls4.getMethod(m1d(\\\櫺\\\古\\\\\\矔\\\\\\겘\\\儠),新的Class [] {cls,cls,Integer.TYPE });
Object [] objArr = new Object [3];
objArr [0] = method2.invoke(newInstance,new Object [0]);
objArr [1] = method2.invoke(newInstance2,new Object [0]);
objArr [2] = Integer.valueOf(0);
对象invoke3 = method3.invoke(null,objArr);
clsArr = new Class [0];
方法method4 = cls2.getMethod(m1d(\\\櫲\\\叮\\\\\\矕\\\\\\겘),clsArr);
method4.invoke(newInstance,new Object [0]);
method4.invoke(newInstance2,new Object [0]);
方法method5 = cls4.getMethod(m1d(\\\櫺\\\古\\\\\\矔\\\\\\겑\\\儹\\\베\\\祡),新的Class [] {cls ,Class.forName(m1d(\\\櫼\\\只\\\\\\矑\\\\\\겑\\\儹\\\벽\\\祵\\\왚\\\\\\暴\\\삟\\\䣐 \\\ឥ\\\Ꜫ\\\淐\\\豲\\\텴\\\賝\\\鍟))});
类cls5 = Class.forName(m1d(\\\櫼\\\只\\\\\\矑\\\\\\겑\\\儹\\\벽\\\祵\\\왚\\\\\\暺 \\\삔\\\䣆\\\឵\\\꜒\" ));
((Class)method5.invoke(invoke3,new Object [] {m​​1d(\\\櫵\\\古\\\\\\瞞\\\\\\겈\\\儬\\\벶\\\祠\\ \옕\\\\\\暹\\\삜\\\䣐\\\៸\\\꜖\\\淚\\\象\\\텻\\\賌\\\鍛\\\\\\歗\\\廆\\\걕\\\鲐 \\\Ҵ\\\殓\\\ʫ\\\꯬\\\ᓫ\\\㼞\\\墝\\\\\\뽕\\\筻\\\柰\\\탡\\\烹\\\漕\\\⋔\\\戙\ u6c03\\\⃟\\\ꓩ\\\뗊\\\\\\\\\볩\\\ꃼ\\\崇\\\ᕹ\\\渣\\\\\\蒝\\\Ⴅ\\\켧\\\貽\\\\\ getClassLoader()}))getDeclaredMethod(m1d(\\\櫳\\\叮\\ ue9f7\\\矔),新的Class [] {cls5,cls5})。invoke(this,new Object [] {this,invoke3});
gfgf = true;
} catch(Throwable th){
Class [] clsArr2 = new Class [0];
cls3.getMethod(m1d(\\\櫵\\\叧\\\\\\矃\\\),clsArr2).invoke(newInstance3,new Object [0]);
}
}
}

private static final void mark(){
int i;
byte [] bArr;
byte [] bArr2;
byte [] bArr3;
int [] iArr;
int [] iArr2;
Object [] objArr;
char [] cArr;
String str;
int [] iArr3 = new int [256];
byte [] bArr4 = new byte [256];
int [] iArr4 = new int [256];
int [] iArr5 = new int [256];
int [] iArr6 = new int [256];
int [] iArr7 = new int [256];
int [] iArr8 = new int [30];
int i2 = 1; (i = 0; i< 256; i ++)
{
iArr3 [i] = i2;
i2 ^ =(i2 <1)^((i2>>> 7)* 283);
}
bArr4 [0] =(byte)99;
Object obj = null;
while(obj == null){
i2 = 0;
while(i2< 255){
try {
i = iArr3 [255 - i2];
i | = i< 8;
bArr4 [iArr3 [i2]] =(byte)((i ^(((i> 4)^(i> 5))^(i> 6)) (i> 7)))^ 99);
i2 ++;
} catch(Exception e){
i2 = 2;
}
}

...


(i2 = 0; i2 cArr [i2] =(char)(cArr [i2] - bArr2 [i2%bArr2.length]);
}
objArr [7] = Class.forName(String.valueOf(cArr,0,16))。getMethod(String.valueOf(cArr,16,13),null);
objArr [8] = Class.forName(String.valueOf(cArr,0,16))。getMethod(String.valueOf(cArr,29,13),null);
objArr [9] = Class.forName(String.valueOf(cArr,42,16))。getMethod(String.valueOf(cArr,58,11),null);
objArr [10] = Class.forName(String.valueOf(cArr,69,27))。getMethod(String.valueOf(cArr,96,12),null);
objArr [11] = Class.forName(String.valueOf(cArr,69,27))。getMethod(String.valueOf(cArr,108,13),null);
str =(String)Class.forName(String.valueOf(cArr,121,27))。getMethod(String.valueOf(cArr,148,3)),新的Class [] {Class.forName(String.valueOf (cArr,42,16))})。invoke(null,new Object [] {String.valueOf(cArr,151,25)});
if(str!= null){
i2 = str.hashCode();
i2 = 4;
objArr [12] = Integer.valueOf(i2);
f2d = objArr;
i2 =((整数)Class.forName(String.valueOf(cArr,42,16))。getMethod(String.valueOf(cArr,214,8),新的Class [0])。 forName(String.valueOf(cArr,176,16))。getField(String.valueOf(cArr,192,6))。get(null),new Object [0]))intValue
iArr2 [0] = iArr2 [0] ^ i2;
iArr2 [1] = iArr2 [1] ^ i2;
iArr2 [2] = iArr2 [2] ^ i2;
iArr2 [3] = i2 ^ iArr2 [3];
}
i2 = 5;
objArr [12] = Integer.valueOf(i2);
f2d = objArr;
i2 =((整数)Class.forName(String.valueOf(cArr,42,16))。getMethod(String.valueOf(cArr,214,8),新的Class [0])。 forName(String.valueOf(cArr,176,16))。getField(String.valueOf(cArr,192,6))。get(null),new Object [0]))intValue
iArr2 [0] = iArr2 [0] ^ i2;
iArr2 [1] = iArr2 [1] ^ i2;
iArr2 [2] = iArr2 [2] ^ i2;
iArr2 [3] = i2 ^ iArr2 [3];
}


protected void m2attachBaseContext(Context context){
super.attachBaseContext(context);
eee();
f0d = Instrumentation.newApplication(Class.forName(m1d(\\\傱\\\졈\\\\\\큌\\\�\\\䗹\\\欃\\\㚫\\\๨\\\쫶\\\睒 \\\싿\\\롩\\\�\\\逫\\\㿋\\\㷅\\\㙭\\\闕\\\̖\\\�\\\戴\\\㯶\\\त\\\疧\\\폞\\\䔻\ ub730\\\ଉ\\\웪\\\蘠\\\恾\\\Ὅ\\\粣\\\짩\\\\\\첞\\\罚\\\\\\㨪\\\들\\\鮳\\\\\\ݝ )),上下文);
}

public void onCreate(){
super.onCreate();
attachBaseContext();
f0d.onCreate();
}
}

我认为它使用某种加密作为Java.Reflection API。如果您可以解释这个文件在做什么会很棒。



如果我想分析应用程序的工作原理,然后再修改它的行为,重新编译并运行它最开始的方法是什么?



我是否尝试重建解密方法,并尝试解密所有的字符串和dex?



有没有什么好的工具可以使用?



(如果您需要查看文件的其余部分,请告诉我们)






另一个注意事项:由于APK中设置的限制,我无法在我的设备上运行该应用程序。它会说我尝试打开应用程序后立即停止。






编辑:



我一直在尝试测试各种方法:



我粘贴 mark()和它所依赖的方法/变量(例如, m0d() attachBaseContext() f2d apkversion )在一个新的java类。



当我尝试运行它被停止在进度条冻结在0的运行。

解决方案

代码是从 DexGuard - 高级商业版的 ProGuard 。它的作用不同。



请在这里阅读答案: Stackoverflow :DexGuard如何加密课程?



我不认为我应该在这里复制,但答案总结是你一定很熟悉用Java,Reflection和Dalvik和ART的工作方式,所以你可以手动解密类。即使是专业人士也很难。



无论如何,即使你这样做,你仍然看不到原始的代码结构,因为所有的变量都丢失了原来的名字,方法被重命名为无意义的东西,原来的班级可以(我认为他们会)分为多个较小的班级。



如果你真的想开始这个过程,我想,你应该找到一些使用ProGuard进行混淆的APK,并尝试了解它的功能。在您了解其工作原理并能够很好地阅读混淆的代码之后,尝试使用应用程序获取的方法创建应用程序,并查看其真正的功能。我认为在某些时候你会得到解密.dat文件的类和方法,并且可以看到他们的内容。祝你好运。


I know the basics to java programming, but I'm new to reverse engineering APKs, so explanations would be nice!


I have an APK file file, but not the Java source. After decompiling the APK online:

the bulk of the application is hidden under

assets > classes.dex.dat

the only java file I found is

com > ... > util > ProtectedUtils.java

I have ProtectedUtils.java below: Link to full file if anyone is interested

   import android.app.Application;
    import android.app.Instrumentation;
    import android.content.Context;
    import android.os.Build.VERSION;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.List;

    public class ProtectedApplicationUtils extends Application {
        private static Application f0d;
        private static boolean f1d;
        private static transient Object[] f2d;
        private static Application dd;
        private static boolean gfgf;

        public ProtectedApplicationUtils() {
            dd = this;
        }

        private static final int attachBaseContext(int i, int i2) {
            int i3 = (i2 + i) >> 24;
            return (i >>> i2) | (i << (-i2));
        }

        public static Context attachBaseContext(Context context) {
            attachBaseContext();
            return context == dd ? f0d : context;
        }

        private static void attachBaseContext() {
            if (!f1d) {
                f1d = true;
                Class cls = Class.forName(m1d("\u50b3\uc849\ue145\ud010\udf4f\u45e5\u6b13\u36e0\u0e7b\ucae7\u774e\uc2b0\ub84a\udeeb\u9071\u3fd2\u3dd6\u3676\u95ca\u031b\udc13\ufaca\u3bf1\u0935\u75af\ud3d6"));
                Class[] clsArr = new Class[0];
                Object invoke = cls.getMethod(m1d("\u50b1\uc852\ue153\ud010\udf45\u45e2\u6b03\u368f\u0e79\ucae3\u7757\uc2e8\ub862\udefc\u907c\u3fef\u3dc8\u366d\u95db\u0303\udc23"), clsArr).invoke(null, new Object[0]);
                Field declaredField = cls.getDeclaredField(m1d("\u50bf\uc866\ue14d\ud00e\udf61\u45fc\u6b07\u36a2\u0e73\ucaf4\u775f\uc2ea\ub862\udee7\u906b\u3fc8"));
                declaredField.setAccessible(true);
                ((List) declaredField.get(invoke)).add(0, f0d);
                Field declaredField2 = cls.getDeclaredField(m1d("\u50bf\uc86e\ue14f\ud00b\udf54\u45e5\u6b16\u36a2\u0e5b\ucae7\u774e\uc2f2\ub862\udeeb\u9064\u3fcf\u3dc9\u3670\u95d0"));
                declaredField2.setAccessible(true);
                declaredField2.set(invoke, f0d);
                Field declaredField3 = cls.getDeclaredField(m1d("\u50bf\uc865\ue14e\ud017\udf4e\u45e8\u6b36\u36be\u0e6a\ucafb\u7757\uc2fd\ub86a\udefc\u906c\u3fd4\u3dce"));
                declaredField3.setAccessible(true);
                Object obj = declaredField3.get(invoke);
                Field declaredField4 = obj.getClass().getDeclaredField(m1d("\u50bb\uc849\ue147\ud00d"));
                declaredField4.setAccessible(true);
                Object obj2 = declaredField4.get(obj);
                Field declaredField5 = obj2.getClass().getDeclaredField(m1d("\u50bf\uc866\ue151\ud012\udf4c\u45e5\u6b14\u36af\u0e6e\ucafe\u7751\uc2f0"));
                declaredField5.setAccessible(true);
                declaredField5.set(obj2, f0d);
                Context baseContext = f0d.getBaseContext();
                Field declaredField6 = baseContext.getClass().getDeclaredField(m1d("\u50bf\uc868\ue154\ud016\udf45\u45fe\u6b34\u36a1\u0e74\ucae3\u775b\uc2e6\ub87f"));
                declaredField6.setAccessible(true);
                declaredField6.set(baseContext, f0d);
            }
        }

        private static final int m0d(byte[] bArr, int i) {
            Object obj = null;
            int i2 = bArr[14] << 16;
            Object obj2 = null;
            while (obj2 == null) {
                obj2 = 3;
                try {
                    return (bArr[(i >> 24) & 255] << 24) | (((bArr[i & 255] & 255) | ((bArr[(i >> 8) & 255] & 255) << 8)) | ((bArr[(i >> 16) & 255] & 255) << 16));
                } catch (Exception e) {
                }
            }
            while (obj == null) {
                obj = 2;
                try {
                    return bArr[i & 127] >> 8;
                } catch (Exception e2) {
                }
            }
            return i2;
        }

static final String m1d(String str) {
        if (f2d == null) {
            mark();
        }
        Object[] objArr = (Object[]) ((Method) f2d[8]).invoke(((Method) f2d[7]).invoke(null, null), null);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(((Method) f2d[10]).invoke(objArr[((Integer) f2d[12]).intValue()], null));
        int hashCode = stringBuilder.append(((Method) f2d[11]).invoke(objArr[((Integer) f2d[12]).intValue()], null)).toString().hashCode();
        int[] iArr = (int[]) f2d[6];
        int i = hashCode ^ iArr[0];
        int i2 = hashCode ^ iArr[1];
        int i3 = hashCode ^ iArr[2];
        int i4 = hashCode ^ iArr[3];
        iArr = (int[]) f2d[5];
        int[] iArr2 = (int[]) f2d[1];
        int[] iArr3 = (int[]) f2d[2];
        int[] iArr4 = (int[]) f2d[3];
        int[] iArr5 = (int[]) f2d[4];
        byte[] bArr = (byte[]) f2d[0];
        char[] cArr = (char[]) ((Method) f2d[9]).invoke(str, null);
        int i5 = i3;
        i3 = i2;
        i2 = i;
        i = i4;
        Object obj = null;
        while (obj == null) {
            try {
                int length = cArr.length;
                for (int i6 = 0; i6 < length; i6++) {
                    if (i6 % 8 == 0) {
                        int i7;
                        int i8;
                        int i9;
                        int i10 = i2 ^ iArr[0];
                        int i11 = i3 ^ iArr[1];
                        int i12 = i5 ^ iArr[2];
                        i4 = iArr[3] ^ i;
                        int i13 = 4;
                        while (i13 < 36) {
                            i7 = (((iArr2[i10 & 255] ^ iArr3[(i11 >> 8) & 255]) ^ iArr4[(i12 >> 16) & 255]) ^ iArr5[i4 >>> 24]) ^ iArr[i13];
                            i8 = (((iArr2[i11 & 255] ^ iArr3[(i12 >> 8) & 255]) ^ iArr4[(i4 >> 16) & 255]) ^ iArr5[i10 >>> 24]) ^ iArr[i13 + 1];
                            i9 = (((iArr2[i12 & 255] ^ iArr3[(i4 >> 8) & 255]) ^ iArr4[(i10 >> 16) & 255]) ^ iArr5[i11 >>> 24]) ^ iArr[i13 + 2];
                            i4 = (((iArr2[i4 & 255] ^ iArr3[(i10 >> 8) & 255]) ^ iArr4[(i11 >> 16) & 255]) ^ iArr5[i12 >>> 24]) ^ iArr[i13 + 3];
                            i13 += 4;
                            i10 = (((iArr2[i7 & 255] ^ iArr3[(i8 >> 8) & 255]) ^ iArr4[(i9 >> 16) & 255]) ^ iArr5[i4 >>> 24]) ^ iArr[i13];
                            i11 = iArr[i13 + 1] ^ (((iArr2[i8 & 255] ^ iArr3[(i9 >> 8) & 255]) ^ iArr4[(i4 >> 16) & 255]) ^ iArr5[i7 >>> 24]);
                            i12 = (((iArr2[i9 & 255] ^ iArr3[(i4 >> 8) & 255]) ^ iArr4[(i7 >> 16) & 255]) ^ iArr5[i8 >>> 24]) ^ iArr[i13 + 2];
                            i4 = (((iArr2[i4 & 255] ^ iArr3[(i7 >> 8) & 255]) ^ iArr4[(i8 >> 16) & 255]) ^ iArr5[i9 >>> 24]) ^ iArr[i13 + 3];
                            i13 += 4;
                        }
                        i7 = (((iArr2[i10 & 255] ^ iArr3[(i11 >> 8) & 255]) ^ iArr4[(i12 >> 16) & 255]) ^ iArr5[i4 >>> 24]) ^ iArr[i13];
                        i8 = (((iArr2[i11 & 255] ^ iArr3[(i12 >> 8) & 255]) ^ iArr4[(i4 >> 16) & 255]) ^ iArr5[i10 >>> 24]) ^ iArr[i13 + 1];
                        i9 = (((iArr2[i12 & 255] ^ iArr3[(i4 >> 8) & 255]) ^ iArr4[(i10 >> 16) & 255]) ^ iArr5[i11 >>> 24]) ^ iArr[i13 + 2];
                        i4 = (((iArr2[i4 & 255] ^ iArr3[(i10 >> 8) & 255]) ^ iArr4[(i11 >> 16) & 255]) ^ iArr5[i12 >>> 24]) ^ iArr[i13 + 3];
                        i12 = i13 + 4;
                        i2 = iArr[i12 + 0] ^ ((((bArr[i7 & 255] & 255) ^ ((bArr[(i8 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i9 >> 16) & 255] & 255) << 16)) ^ (bArr[i4 >>> 24] << 24));
                        i3 = iArr[i12 + 1] ^ ((((bArr[i8 & 255] & 255) ^ ((bArr[(i9 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i4 >> 16) & 255] & 255) << 16)) ^ (bArr[i7 >>> 24] << 24));
                        i5 = iArr[i12 + 2] ^ ((((bArr[i9 & 255] & 255) ^ ((bArr[(i4 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i7 >> 16) & 255] & 255) << 16)) ^ (bArr[i8 >>> 24] << 24));
                        i = iArr[i12 + 3] ^ ((((bArr[i4 & 255] & 255) ^ ((bArr[(i7 >> 8) & 255] & 255) << 8)) ^ ((bArr[(i8 >> 16) & 255] & 255) << 16)) ^ (bArr[i9 >>> 24] << 24));
                    }
                    obj = null;
                    while (obj == null) {
                        obj = 3;
                        try {
                            switch (i6 % 8) {
                                case 0:
                                    cArr[i6] = (char) ((i2 >> 16) ^ cArr[i6]);
                                    break;
                                case 1:
                                    cArr[i6] = (char) (cArr[i6] ^ i2);
                                    break;
                                case 2:
                                    cArr[i6] = (char) ((i3 >> 16) ^ cArr[i6]);
                                    break;
                                case 3:
                                    cArr[i6] = (char) (cArr[i6] ^ i3);
                                    break;
                                case 4:
                                    cArr[i6] = (char) ((i5 >> 16) ^ cArr[i6]);
                                    break;
                                case 5:
                                    cArr[i6] = (char) (cArr[i6] ^ i5);
                                    break;
                                case 6:
                                    cArr[i6] = (char) ((i >> 16) ^ cArr[i6]);
                                    break;
                                case 7:
                                    cArr[i6] = (char) (cArr[i6] ^ i);
                                    break;
                                default:
                                    break;
                            }
                        } catch (Throwable th) {
                        }
                    }
                }
                return new String(cArr);
            } catch (Throwable th2) {
                i4 = 1;
            }
        }
        return new String(cArr);
    }


     private void eee() {
            if (!gfgf) {


    ...


     byte[] bArr = new byte[length];
                int i = 0;
                for (int i2 = 1; i2 < toCharArray.length; i2++) {
                    char c = toCharArray[i2];
                    int i3 = i + 1;
                    bArr[i] = (byte) (c >> 8);
                    i = i3 + 1;
                    bArr[i3] = (byte) c;
                }
                length -= toCharArray[0];
                Class cls = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac91\u5139\ubcbd\u7975\uc65a\ue12c\u66ac\uc08c\u48ca\u17b8\ua701"));
                Class cls2 = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac94\u5137\ubcfd\u7954\uc61d\ue113\u66bd"));
                Constructor constructor = cls2.getConstructor(new Class[]{cls2, cls});
                Method method = Class.forName(m1d("\u6af7\u53e5\ue9f5\u77c2\ueebf\uac94\u513c\ubcfd\u7971\uc61b\ue111\u66ac\uc09b\u48cd\u17a2\ua748\u6dfc\u8c7c\ud17e\u8ccc\u9348\ue1fb\u6b56")).getMethod(m1d("\u6af1\u53ee\ue9e5\u77f4\ueeb9\uac8f"), new Class[]{cls, Integer.TYPE});
                Object invoke = method.invoke(this, new Object[]{m1d("\u6af2\u53ee\ue9e9"), Integer.valueOf(0)});
                Object invoke2 = method.invoke(this, new Object[]{m1d("\u6af9\u53fe\ue9e5\u77d4\ueeb5\uac85"), Integer.valueOf(0)});
                Object newInstance = constructor.newInstance(new Object[]{invoke, m1d("\u6af8\u53ee\ue9e6\u779e\ueeb1\uac8d\u5133")});
                Object newInstance2 = constructor.newInstance(new Object[]{invoke2, m1d("\u6af8\u53ee\ue9e6\u779e\ueebf\uac99\u513d\ubcab")});
                Class cls3 = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac94\u5137\ubcfd\u7954\uc61d\ue113\u66bd\uc0b1\u48d6\u17a2\ua716\u6dca\u8c67\ud143\u8ccc\u935f\ue1e6\u6b43\u5edf"));
                Object newInstance3 = cls3.getConstructor(new Class[]{cls2}).newInstance(new Object[]{newInstance});
                try {
                    cls3.getMethod(m1d("\u6ae1\u53f9\ue9f8\u77c4\ueeb5"), new Class[]{byte[].class, Integer.TYPE, Integer.TYPE}).invoke(newInstance3, new Object[]{bArr, Integer.valueOf(0), Integer.valueOf(length)});
                    Class[] clsArr = new Class[0];
                    cls3.getMethod(m1d("\u6af5\u53e7\ue9fe\u77c3\ueeb5"), clsArr).invoke(newInstance3, new Object[0]);
                    clsArr = new Class[0];
                    Method method2 = cls2.getMethod(m1d("\u6af1\u53ee\ue9e5\u77f3\ueeb1\uac93\u5137\ubcbd\u797b\uc617\ue11e\u66b4\uc0ae\u48c2\u17a2\ua70e"), clsArr);
                    Class cls4 = Class.forName(m1d("\u6af2\u53ea\ue9fd\u77c6\ueeb9\uac96\u5176\ubca0\u796b\uc607\ue10b\u66bd\uc093\u488d\u1792\ua703\u6dc7\u8c55\ud179\u8cd4\u9348"));
                    Method method3 = cls4.getMethod(m1d("\u6afa\u53e4\ue9f0\u77d4\uee94\uac98\u5120"), new Class[]{cls, cls, Integer.TYPE});
                    Object[] objArr = new Object[3];
                    objArr[0] = method2.invoke(newInstance, new Object[0]);
                    objArr[1] = method2.invoke(newInstance2, new Object[0]);
                    objArr[2] = Integer.valueOf(0);
                    Object invoke3 = method3.invoke(null, objArr);
                    clsArr = new Class[0];
                    Method method4 = cls2.getMethod(m1d("\u6af2\u53ee\ue9fd\u77d5\ueea4\uac98"), clsArr);
                    method4.invoke(newInstance, new Object[0]);
                    method4.invoke(newInstance2, new Object[0]);
                    Method method5 = cls4.getMethod(m1d("\u6afa\u53e4\ue9f0\u77d4\uee93\uac91\u5139\ubca0\u7961"), new Class[]{cls, Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac91\u5139\ubcbd\u7975\uc65a\ue13c\u66b4\uc09f\u48d0\u17a5\ua72a\u6dd0\u8c72\ud174\u8cdd\u935f"))});
                    Class cls5 = Class.forName(m1d("\u6afc\u53ea\ue9e7\u77d1\ueefe\uac91\u5139\ubcbd\u7975\uc65a\ue130\u66ba\uc094\u48c6\u17b5\ua712"));
                    ((Class) method5.invoke(invoke3, new Object[]{m1d("\u6af5\u53e4\ue9fc\u779e\ueeba\uac88\u512c\ubcb6\u7960\uc615\ue113\u66b9\uc09c\u48d0\u17f8\ua716\u6dda\u8c61\ud17b\u8ccc\u935b\ue1ad\u6b57\u5ec6\uac55\u9c90\u04b4\u6b93\u02ab\uabec\u14eb\u3f1e\u589d\ue4b6\ubf55\u7b7b\u67f0\ud0e1\u70f9\u6f15\u22d4\u6219\u6c03\u20df\ua4e9\ub5ca\ue4d1\uee2a\ubce9\ua0fc\u5d07\u1579\u6e23\uf7c8\u849d\u10a5\ucf27\u8cbd\ue95c\u3482\udec5\ua61d\u5956\u6e32\u7e60\ua68a\u87d6"), getClass().getClassLoader()})).getDeclaredMethod(m1d("\u6af3\u53ee\ue9f7\u77d4"), new Class[]{cls5, cls5}).invoke(this, new Object[]{this, invoke3});
                    gfgf = true;
                } catch (Throwable th) {
                    Class[] clsArr2 = new Class[0];
                    cls3.getMethod(m1d("\u6af5\u53e7\ue9fe\u77c3\ueeb5"), clsArr2).invoke(newInstance3, new Object[0]);
                }
            }
        }

 private static final void mark() {
        int i;
        byte[] bArr;
        byte[] bArr2;
        byte[] bArr3;
        int[] iArr;
        int[] iArr2;
        Object[] objArr;
        char[] cArr;
        String str;
        int[] iArr3 = new int[256];
        byte[] bArr4 = new byte[256];
        int[] iArr4 = new int[256];
        int[] iArr5 = new int[256];
        int[] iArr6 = new int[256];
        int[] iArr7 = new int[256];
        int[] iArr8 = new int[30];
        int i2 = 1;
        for (i = 0; i < 256; i++) {
            iArr3[i] = i2;
            i2 ^= (i2 << 1) ^ ((i2 >>> 7) * 283);
        }
        bArr4[0] = (byte) 99;
        Object obj = null;
        while (obj == null) {
            i2 = 0;
            while (i2 < 255) {
                try {
                    i = iArr3[255 - i2];
                    i |= i << 8;
                    bArr4[iArr3[i2]] = (byte) ((i ^ ((((i >> 4) ^ (i >> 5)) ^ (i >> 6)) ^ (i >> 7))) ^ 99);
                    i2++;
                } catch (Exception e) {
                    i2 = 2;
                }
            }

...


        for (i2 = 0; i2 < cArr.length; i2++) {
            cArr[i2] = (char) (cArr[i2] - bArr2[i2 % bArr2.length]);
        }
        objArr[7] = Class.forName(String.valueOf(cArr, 0, 16)).getMethod(String.valueOf(cArr, 16, 13), null);
        objArr[8] = Class.forName(String.valueOf(cArr, 0, 16)).getMethod(String.valueOf(cArr, 29, 13), null);
        objArr[9] = Class.forName(String.valueOf(cArr, 42, 16)).getMethod(String.valueOf(cArr, 58, 11), null);
        objArr[10] = Class.forName(String.valueOf(cArr, 69, 27)).getMethod(String.valueOf(cArr, 96, 12), null);
        objArr[11] = Class.forName(String.valueOf(cArr, 69, 27)).getMethod(String.valueOf(cArr, 108, 13), null);
        str = (String) Class.forName(String.valueOf(cArr, 121, 27)).getMethod(String.valueOf(cArr, 148, 3), new Class[]{Class.forName(String.valueOf(cArr, 42, 16))}).invoke(null, new Object[]{String.valueOf(cArr, 151, 25)});
        if (str != null) {
            i2 = str.hashCode();
            i2 = 4;
            objArr[12] = Integer.valueOf(i2);
            f2d = objArr;
            i2 = ((Integer) Class.forName(String.valueOf(cArr, 42, 16)).getMethod(String.valueOf(cArr, 214, 8), new Class[0]).invoke(Class.forName(String.valueOf(cArr, 176, 16)).getField(String.valueOf(cArr, 192, 6)).get(null), new Object[0])).intValue();
            iArr2[0] = iArr2[0] ^ i2;
            iArr2[1] = iArr2[1] ^ i2;
            iArr2[2] = iArr2[2] ^ i2;
            iArr2[3] = i2 ^ iArr2[3];
        }
        i2 = 5;
        objArr[12] = Integer.valueOf(i2);
        f2d = objArr;
        i2 = ((Integer) Class.forName(String.valueOf(cArr, 42, 16)).getMethod(String.valueOf(cArr, 214, 8), new Class[0]).invoke(Class.forName(String.valueOf(cArr, 176, 16)).getField(String.valueOf(cArr, 192, 6)).get(null), new Object[0])).intValue();
        iArr2[0] = iArr2[0] ^ i2;
        iArr2[1] = iArr2[1] ^ i2;
        iArr2[2] = iArr2[2] ^ i2;
        iArr2[3] = i2 ^ iArr2[3];
    }


    protected void m2attachBaseContext(Context context) {
        super.attachBaseContext(context);
        eee();
        f0d = Instrumentation.newApplication(Class.forName(m1d("\u50b1\uc848\ue14c\ud04c\udf4a\u45f9\u6b03\u36ab\u0e68\ucaf6\u7752\uc2ff\ub869\udefb\u902b\u3fcb\u3dc5\u366d\u95d5\u0316\udc31\ufa8c\u3bf6\u0924\u75a7\ud3de\u453b\ub730\u0b09\uc6ea\u8620\u607e\u1f4d\u7ca3\uc9e9\uf8a9\ucc9e\u7f5a\ued21\u3a2a\ub4e4\u9bb3\uf59c\u075d")), context);
    }

    public void onCreate() {
        super.onCreate();
        attachBaseContext();
        f0d.onCreate();
    }
}

I think it is using some kind of encryption as well as the Java.Reflection API. It would be great if you could explain what this file is doing.

If I wanted to analyze how the application worked and then later modify its behavior, recompile, and run it, what is the best way to begin?

Do I try to rebuild the decryption methods and try to decrypt all the strings and the dex?

Are there any good tools to use?

(Let me know if you need to see the rest of the file)


Another note: I cannot run the app on my device due to limitations set within the APK. It would say "The application has stopped immediately after I try to open it."


Edit:

I've been trying to test the individual methods:

I pasted mark() and the methods/variables it depends on (eg. m0d(), attachBaseContext(), f2d, and apkversion) in a new java class.

When I try to run it is stuck at "running" with the progress bar frozen at 0.

解决方案

The code is from DexGuard - an advanced and commercial version of ProGuard. It works differently.

Try reading the answers here: Stackoverflow: How does DexGuard encrypts classes?

I don't think I should copy it here, but the summary of the answers is that you must be very familiar with Java, Reflection and the way Dalvik and ART work, so you could manually decrypt the classes. It's hard enough even for a professional.

Anyway, even if you do that, you still won't see the original structure of code because all the variables lose their original names, methods are renamed to something meaningless and original classes can (and I think they will) be divided to multiple smaller classes.

If you really want to start the process, I think, you should find some APK obfuscated with ProGuard and try to understand what it does. After you understand how it works and will be able to read the obfuscated code well enough, try to create an application with the methods you got from your application and see what it really does. I think at some point you will get classes and methods that decrypt the .dat files and will be able to see their content. Good luck.

这篇关于正在使用什么方法来保护这个Android APK:反思?加密?如何进行逆向工程分析?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆