正在使用什么方法来保护此 Android APK:Reflection?加密?我如何对其进行逆向工程和分析?
What methods are being used to protect this Android APK: Reflection? Encryption? How do I reverse engineer it and analyze it?
我知道 java 编程的基础知识,但我是逆向工程 APK 的新手,所以解释会很好!
我有一个 APK 文件,但没有 Java 源。在线反编译APK后:
大部分应用程序隐藏在
下
assets > classes.dex.dat
我找到的唯一 java 文件是
com > ... > util > ProtectedUtils.java
我下面有ProtectedUtils.java: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();
}
}
我认为它使用了某种加密方式以及 Java.Reflection API。如果你能解释一下这个文件的作用就太好了。
如果我想分析应用程序的工作方式,然后修改其行为、重新编译并运行,最好的开始方式是什么?
我是否尝试重建解密方法并尝试解密所有字符串和 dex?
有没有什么好用的工具?
(如果您需要查看文件的其余部分,请告诉我)
另请注意:由于 APK 中设置的限制,我无法 运行 我的设备上的应用程序。它会说 "The application has stopped immediately after I try to open it."
编辑:
我一直在尝试测试各个方法:
我粘贴了 mark()
和它所依赖的 methods/variables(例如 m0d()
、attachBaseContext()
、f2d
和 apkversion
)在一个新的 java class.
当我尝试 运行 时,它卡在 "running",进度条冻结在 0。
ProGuard 工具通过删除未使用的代码并使用语义模糊的名称重命名 类、字段和方法来缩小、优化和混淆您的代码。结果是一个更小的 .apk 文件更难逆向工程。
您可以在这里阅读更多内容:http://developer.android.com/intl/es/tools/help/proguard.html
代码来自 DexGuard
- ProGuard
的高级商业版本。它的工作方式不同。
尝试阅读此处的答案:Whosebug: How does DexGuard encrypts classes?
我认为我不应该在这里复制它,但答案的总结是你必须非常熟悉Java,反射和Dalvik和ART的工作方式,所以你可以手动解密类。即使是专业人士也很难。
无论如何,即使你这样做了,你仍然看不到原来的代码结构,因为所有的变量都失去了原来的名字,方法被重命名为无意义的东西,原来 类 可以(而且我认为他们会)被分成多个更小的类。
如果你真的想开始这个过程,我认为你应该找到一些混淆了 ProGuard 的 APK 并尝试了解它的作用。在您了解它的工作原理并且能够很好地阅读混淆代码后,尝试使用您从应用程序中获得的方法创建一个应用程序,看看它到底做了什么。我认为在某些时候您将获得 类 和解密 .dat 文件的方法,并且能够看到它们的内容。祝你好运。
我知道 java 编程的基础知识,但我是逆向工程 APK 的新手,所以解释会很好!
我有一个 APK 文件,但没有 Java 源。在线反编译APK后:
大部分应用程序隐藏在
下assets > classes.dex.dat
我找到的唯一 java 文件是
com > ... > util > ProtectedUtils.java
我下面有ProtectedUtils.java: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();
}
}
我认为它使用了某种加密方式以及 Java.Reflection API。如果你能解释一下这个文件的作用就太好了。
如果我想分析应用程序的工作方式,然后修改其行为、重新编译并运行,最好的开始方式是什么?
我是否尝试重建解密方法并尝试解密所有字符串和 dex?
有没有什么好用的工具?
(如果您需要查看文件的其余部分,请告诉我)
另请注意:由于 APK 中设置的限制,我无法 运行 我的设备上的应用程序。它会说 "The application has stopped immediately after I try to open it."
编辑:
我一直在尝试测试各个方法:
我粘贴了 mark()
和它所依赖的 methods/variables(例如 m0d()
、attachBaseContext()
、f2d
和 apkversion
)在一个新的 java class.
当我尝试 运行 时,它卡在 "running",进度条冻结在 0。
ProGuard 工具通过删除未使用的代码并使用语义模糊的名称重命名 类、字段和方法来缩小、优化和混淆您的代码。结果是一个更小的 .apk 文件更难逆向工程。
您可以在这里阅读更多内容:http://developer.android.com/intl/es/tools/help/proguard.html
代码来自 DexGuard
- ProGuard
的高级商业版本。它的工作方式不同。
尝试阅读此处的答案:Whosebug: How does DexGuard encrypts classes?
我认为我不应该在这里复制它,但答案的总结是你必须非常熟悉Java,反射和Dalvik和ART的工作方式,所以你可以手动解密类。即使是专业人士也很难。
无论如何,即使你这样做了,你仍然看不到原来的代码结构,因为所有的变量都失去了原来的名字,方法被重命名为无意义的东西,原来 类 可以(而且我认为他们会)被分成多个更小的类。
如果你真的想开始这个过程,我认为你应该找到一些混淆了 ProGuard 的 APK 并尝试了解它的作用。在您了解它的工作原理并且能够很好地阅读混淆代码后,尝试使用您从应用程序中获得的方法创建一个应用程序,看看它到底做了什么。我认为在某些时候您将获得 类 和解密 .dat 文件的方法,并且能够看到它们的内容。祝你好运。