我知道java编程的基础知识,但我是逆向工程APK的新手,所以解释一下会很好!
我有一个APK文件,但不是Java源文件。在线反编译APK后:
大部分应用程序隐藏在下
assets>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 : context;
}
private static void attachBaseContext() {
if (!f1d) {
f1d = true;
Class cls = Class.forName(m1d("u50b3uc849ue145ud010udf4fu45e5u6b13u36e0u0e7bucae7u774euc2b0ub84audeebu9071u3fd2u3dd6u3676u95cau031budc13ufacau3bf1u0935u75afud3d6"));
Class[] clsArr = new Class[0];
Object invoke = cls.getMethod(m1d("u50b1uc852ue153ud010udf45u45e2u6b03u368fu0e79ucae3u7757uc2e8ub862udefcu907cu3fefu3dc8u366du95dbu0303udc23"), clsArr).invoke(null, new Object[0]);
Field declaredField = cls.getDeclaredField(m1d("u50bfuc866ue14dud00eudf61u45fcu6b07u36a2u0e73ucaf4u775fuc2eaub862udee7u906bu3fc8"));
declaredField.setAccessible(true);
((List) declaredField.get(invoke)).add(0, f0d);
Field declaredField2 = cls.getDeclaredField(m1d("u50bfuc86eue14fud00budf54u45e5u6b16u36a2u0e5bucae7u774euc2f2ub862udeebu9064u3fcfu3dc9u3670u95d0"));
declaredField2.setAccessible(true);
declaredField2.set(invoke, f0d);
Field declaredField3 = cls.getDeclaredField(m1d("u50bfuc865ue14eud017udf4eu45e8u6b36u36beu0e6aucafbu7757uc2fdub86audefcu906cu3fd4u3dce"));
declaredField3.setAccessible(true);
Object obj = declaredField3.get(invoke);
Field declaredField4 = obj.getClass().getDeclaredField(m1d("u50bbuc849ue147ud00d"));
declaredField4.setAccessible(true);
Object obj2 = declaredField4.get(obj);
Field declaredField5 = obj2.getClass().getDeclaredField(m1d("u50bfuc866ue151ud012udf4cu45e5u6b14u36afu0e6eucafeu7751uc2f0"));
declaredField5.setAccessible(true);
declaredField5.set(obj2, f0d);
Context baseContext = f0d.getBaseContext();
Field declaredField6 = baseContext.getClass().getDeclaredField(m1d("u50bfuc868ue154ud016udf45u45feu6b34u36a1u0e74ucae3u775buc2e6ub87f"));
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("u6afcu53eaue9e7u77d1ueefeuac91u5139ubcbdu7975uc65aue12cu66acuc08cu48cau17b8ua701"));
Class cls2 = Class.forName(m1d("u6afcu53eaue9e7u77d1ueefeuac94u5137ubcfdu7954uc61due113u66bd"));
Constructor constructor = cls2.getConstructor(new Class[]{cls2, cls});
Method method = Class.forName(m1d("u6af7u53e5ue9f5u77c2ueebfuac94u513cubcfdu7971uc61bue111u66acuc09bu48cdu17a2ua748u6dfcu8c7cud17eu8cccu9348ue1fbu6b56")).getMethod(m1d("u6af1u53eeue9e5u77f4ueeb9uac8f"), new Class[]{cls, Integer.TYPE});
Object invoke = method.invoke(this, new Object[]{m1d("u6af2u53eeue9e9"), Integer.valueOf(0)});
Object invoke2 = method.invoke(this, new Object[]{m1d("u6af9u53feue9e5u77d4ueeb5uac85"), Integer.valueOf(0)});
Object newInstance = constructor.newInstance(new Object[]{invoke, m1d("u6af8u53eeue9e6u779eueeb1uac8du5133")});
Object newInstance2 = constructor.newInstance(new Object[]{invoke2, m1d("u6af8u53eeue9e6u779eueebfuac99u513dubcab")});
Class cls3 = Class.forName(m1d("u6afcu53eaue9e7u77d1ueefeuac94u5137ubcfdu7954uc61due113u66bduc0b1u48d6u17a2ua716u6dcau8c67ud143u8cccu935fue1e6u6b43u5edf"));
Object newInstance3 = cls3.getConstructor(new Class[]{cls2}).newInstance(new Object[]{newInstance});
try {
cls3.getMethod(m1d("u6ae1u53f9ue9f8u77c4ueeb5"), 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("u6af5u53e7ue9feu77c3ueeb5"), clsArr).invoke(newInstance3, new Object[0]);
clsArr = new Class[0];
Method method2 = cls2.getMethod(m1d("u6af1u53eeue9e5u77f3ueeb1uac93u5137ubcbdu797buc617ue11eu66b4uc0aeu48c2u17a2ua70e"), clsArr);
Class cls4 = Class.forName(m1d("u6af2u53eaue9fdu77c6ueeb9uac96u5176ubca0u796buc607ue10bu66bduc093u488du1792ua703u6dc7u8c55ud179u8cd4u9348"));
Method method3 = cls4.getMethod(m1d("u6afau53e4ue9f0u77d4uee94uac98u5120"), 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("u6af2u53eeue9fdu77d5ueea4uac98"), clsArr);
method4.invoke(newInstance, new Object[0]);
method4.invoke(newInstance2, new Object[0]);
Method method5 = cls4.getMethod(m1d("u6afau53e4ue9f0u77d4uee93uac91u5139ubca0u7961"), new Class[]{cls, Class.forName(m1d("u6afcu53eaue9e7u77d1ueefeuac91u5139ubcbdu7975uc65aue13cu66b4uc09fu48d0u17a5ua72au6dd0u8c72ud174u8cddu935f"))});
Class cls5 = Class.forName(m1d("u6afcu53eaue9e7u77d1ueefeuac91u5139ubcbdu7975uc65aue130u66bauc094u48c6u17b5ua712"));
((Class) method5.invoke(invoke3, new Object[]{m1d("u6af5u53e4ue9fcu779eueebauac88u512cubcb6u7960uc615ue113u66b9uc09cu48d0u17f8ua716u6ddau8c61ud17bu8cccu935bue1adu6b57u5ec6uac55u9c90u04b4u6b93u02abuabecu14ebu3f1eu589due4b6ubf55u7b7bu67f0ud0e1u70f9u6f15u22d4u6219u6c03u20dfua4e9ub5caue4d1uee2aubce9ua0fcu5d07u1579u6e23uf7c8u849du10a5ucf27u8cbdue95cu3482udec5ua61du5956u6e32u7e60ua68au87d6"), getClass().getClassLoader()})).getDeclaredMethod(m1d("u6af3u53eeue9f7u77d4"), new Class[]{cls5, cls5}).invoke(this, new Object[]{this, invoke3});
gfgf = true;
} catch (Throwable th) {
Class[] clsArr2 = new Class[0];
cls3.getMethod(m1d("u6af5u53e7ue9feu77c3ueeb5"), 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("u50b1uc848ue14cud04cudf4au45f9u6b03u36abu0e68ucaf6u7752uc2ffub869udefbu902bu3fcbu3dc5u366du95d5u0316udc31ufa8cu3bf6u0924u75a7ud3deu453bub730u0b09uc6eau8620u607eu1f4du7ca3uc9e9uf8a9ucc9eu7f5aued21u3a2aub4e4u9bb3uf59cu075d")), context);
}
public void onCreate() {
super.onCreate();
attachBaseContext();
f0d.onCreate();
}
}
我认为它使用了某种加密以及Java.Reflection API。如果你能解释一下这个文件的作用,那就太好了。
如果我想分析应用程序是如何工作的,然后修改它的行为、重新编译和运行它,那么最好的开始方式是什么?
我是否尝试重新构建解密方法并尝试解密所有字符串和dex?
有什么好工具可以用吗?
(如果你需要查看文件的其余部分,请告诉我)
另一个注意事项:由于APK中设置的限制,我无法在设备上运行该应用程序。它会说"应用程序在我尝试打开后立即停止。"
编辑:
我一直在尝试测试单独的方法:
我将mark()
和它所依赖的方法/变量(例如m0d()
、attachBaseContext()
、f2d
和apkversion
)粘贴到一个新的java类中。
当我尝试运行时,它被困在"正在运行",进度条冻结在0。
代码来自DexGuard
——ProGuard
的高级商业版本。它的工作方式不同。
试着在这里阅读答案:堆栈溢出:DexGuard如何加密类?
我不认为我应该在这里复制它,但答案的总结是,你必须非常熟悉Java、Reflection以及Dalvik和ART的工作方式,所以你可以手动解密类。这对一个专业人士来说已经够难的了。
无论如何,即使你这样做,你仍然看不到代码的原始结构,因为所有变量都失去了它们的原始名称,方法被重命名为没有意义的东西,原始类可以(我认为它们会)被划分为多个更小的类。
我认为,如果你真的想开始这个过程,你应该找到一些被ProGuard混淆的APK,并试着了解它的作用。在你了解了它的工作原理并能够很好地阅读混淆的代码之后,试着用你从应用程序中得到的方法创建一个应用程序,看看它到底做了什么。我认为在某个时刻,您将获得解密.dat文件的类和方法,并能够看到它们的内容。祝你好运
ProGuard工具通过删除未使用的代码并用语义模糊的名称重命名类、字段和方法来缩小、优化和模糊代码。结果是一个更小的.apk文件,更难进行反向工程。
您可以在此处阅读更多信息:http://developer.android.com/intl/es/tools/help/proguard.html