学习笔记,自用,整理中
摘要:
面试:
apk打包流程:as电脑里面有给appdata/local/android/sdk/build-tools/aapt aidl
一系列工具完成的;gradle处理了。
运行时解密;
attachbasecontext 开始解密;
tinker:腾讯热修复
hook 勾子 :反射技术去反射 android源码的过程
大部分手机是23以上的
------------------------------------------------------------------------------------
内容:
--------------------------------------------------------------------------------------------------------------------
加密:
public class MyMain {
public static void main(String[] args)throws Exception {
byte[] mainDexData; //�洢Դapk�е�Դdex�ļ�
byte[] aarData; // �洢���еĿ�dex�ļ�
byte[] mergeDex; // �洢��dex ��Դdex �ĺϲ�����dex�ļ�
File tempFileApk =new File("source/apk/temp");
if (tempFileApk.exists()) {
File[]files = tempFileApk.listFiles();
for(File file: files){
if (file.isFile()) {
file.delete();
}
}
}
File tempFileAar =new File("source/aar/temp");
if (tempFileAar.exists()) {
File[]files = tempFileAar.listFiles();
for(File file: files){
if (file.isFile()) {
file.delete();
}
}
}
/**
* ��һ�� ����ԭʼapk ����dex
*
*/
AES.init(AES.DEFAULT_PWD);
//��ѹapk
File apkFile =new File("source/apk/app-debug.apk");
File newApkFile =new File(apkFile.getParent() + File.separator +"temp");
if(!newApkFile.exists()) {
newApkFile.mkdirs();
}
File mainDexFile = AES.encryptAPKFile(apkFile,newApkFile);
if (newApkFile.isDirectory()) {
File[] listFiles = newApkFile.listFiles();
for (File file : listFiles) {
if (file.isFile()) {
if (file.getName().endsWith(".dex")) {
String name = file.getName();
System.out.println("rename step1:"+name);
int cursor = name.indexOf(".dex");
String newName = file.getParent()+ File.separator + name.substring(0, cursor) +"_" +".dex";
System.out.println("rename step2:"+newName);
file.renameTo(new File(newName));
}
}
}
}
/**
* �ڶ��� ����aar ��ÿ�dex
*/
File aarFile =new File("source/aar/mylibrary-debug.aar");
File aarDex = Dx.jar2Dex(aarFile);
// aarData = Utils.getBytes(aarDex); //��dex�ļ�����byte ����
File tempMainDex =new File(newApkFile.getPath() + File.separator +"classes.dex");
if (!tempMainDex.exists()) {
tempMainDex.createNewFile();
}
// System.out.println("MyMain" + tempMainDex.getAbsolutePath());
FileOutputStream fos =new FileOutputStream(tempMainDex);
byte[] fbytes = Utils.getBytes(aarDex);
fos.write(fbytes);
fos.flush();
fos.close();
/**
* ��3�� ���ǩ��
*/
File unsignedApk =new File("result/apk-unsigned.apk");
unsignedApk.getParentFile().mkdirs();
// File disFile = new File(apkFile.getAbsolutePath() + File.separator+ "temp");
Zip.zip(newApkFile, unsignedApk);
//���ò���Ͳ����Զ�ʹ��ԭapk��ǩ��...
File signedApk =new File("result/apk-signed.apk");
Signature.signature(unsignedApk, signedApk);
}
private static FilegetMainDexFile(File apkFile) {
// TODO Auto-generated method stub
File disFile =new File(apkFile.getAbsolutePath() +"unzip");
Zip.unZip(apkFile, disFile);
File[] files = disFile.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
if (name.endsWith(".dex")) {
return true;
}
return false;
}
});
for (File file: files) {
if (file.getName().endsWith("classes.dex")) {
return file;
}
}
return null;
}
}
----------------------------------------------------------------------------------------------------------------------------
解密:
public class ShellApplicationextends Application {
private static final StringTAG ="ShellApplication";
public static StringgetPassword(){
return "abcdefghijklmnop";
}
// static {
// System.loadLibrary("native-lib");
// }
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
AES.init(getPassword());
File apkFile =new File(getApplicationInfo().sourceDir);
//data/data/包名/files/fake_apk/
File unZipFile = getDir("fake_apk", MODE_PRIVATE);
File app =new File(unZipFile, "app");
if (!app.exists()) {
Zip.unZip(apkFile, app);
File[] files = app.listFiles();
for (File file : files) {
String name = file.getName();
if (name.equals("classes.dex")) {
}else if (name.endsWith(".dex")) {
try {
byte[] bytes = getBytes(file);
FileOutputStream fos =new FileOutputStream(file);
byte[] decrypt = AES.decrypt(bytes);
// fos.write(bytes);
fos.write(decrypt);
fos.flush();
fos.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
}
List list =new ArrayList<>();
Log.d("FAKE", Arrays.toString(app.listFiles()));
for (File file : app.listFiles()) {
if (file.getName().endsWith(".dex")) {
list.add(file);
}
}
Log.d("FAKE", list.toString());
try {
V19.install(getClassLoader(), list, unZipFile);
}catch (IllegalAccessException e) {
e.printStackTrace();
}catch (NoSuchFieldException e) {
e.printStackTrace();
}catch (InvocationTargetException e) {
e.printStackTrace();
}catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private static FieldfindField(Object instance, String name)throws NoSuchFieldException {
Class clazz = instance.getClass();
while (clazz !=null) {
try {
Field e = clazz.getDeclaredField(name);
if (!e.isAccessible()) {
e.setAccessible(true);
}
return e;
}catch (NoSuchFieldException var4) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchFieldException("Field " + name +" not found in " + instance.getClass());
}
private static MethodfindMethod(Object instance, String name, Class... parameterTypes)
throws NoSuchMethodException {
Class clazz = instance.getClass();
// Method[] declaredMethods = clazz.getDeclaredMethods();
// System.out.println(" findMethod ");
// for (Method m : declaredMethods) {
// System.out.print(m.getName() + " : ");
// Class[] parameterTypes1 = m.getParameterTypes();
// for (Class clazz1 : parameterTypes1) {
// System.out.print(clazz1.getName() + " ");
// }
// System.out.println("");
// }
while (clazz !=null) {
try {
Method e = clazz.getDeclaredMethod(name, parameterTypes);
if (!e.isAccessible()) {
e.setAccessible(true);
}
return e;
}catch (NoSuchMethodException var5) {
clazz = clazz.getSuperclass();
}
}
throw new NoSuchMethodException("Method " + name +" with parameters " + Arrays.asList
(parameterTypes) +" not found in " + instance.getClass());
}
private static void expandFieldArray(Object instance, String fieldName, Object[]
extraElements)throws NoSuchFieldException, IllegalArgumentException,
IllegalAccessException {
Field jlrField =findField(instance, fieldName);
Object[] original = (Object[]) ((Object[]) jlrField.get(instance));
Object[] combined = (Object[]) ((Object[]) Array.newInstance(original.getClass()
.getComponentType(), original.length + extraElements.length));
System.arraycopy(original, 0, combined, 0, original.length);
System.arraycopy(extraElements, 0, combined, original.length, extraElements.length);
jlrField.set(instance, combined);
}
private static final class V19 {
private V19() {
}
private static void install(ClassLoader loader, List additionalClassPathEntries,
File optimizedDirectory)throws IllegalArgumentException,
IllegalAccessException, NoSuchFieldException, InvocationTargetException,
NoSuchMethodException {
Field pathListField =findField(loader, "pathList");
Object dexPathList = pathListField.get(loader);
ArrayList suppressedExceptions =new ArrayList();
Log.d(TAG, "Build.VERSION.SDK_INT " + Build.VERSION.SDK_INT);
if (Build.VERSION.SDK_INT >=23) {
expandFieldArray(dexPathList, "dexElements", makePathElements(dexPathList, new
ArrayList(additionalClassPathEntries), optimizedDirectory,
suppressedExceptions));
}else {
expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new
ArrayList(additionalClassPathEntries), optimizedDirectory,
suppressedExceptions));
}
if (suppressedExceptions.size() >0) {
Iterator suppressedExceptionsField = suppressedExceptions.iterator();
while (suppressedExceptionsField.hasNext()) {
IOException dexElementsSuppressedExceptions = (IOException)
suppressedExceptionsField.next();
Log.w("MultiDex", "Exception in makeDexElement",
dexElementsSuppressedExceptions);
}
Field suppressedExceptionsField1 =findField(loader,
"dexElementsSuppressedExceptions");
IOException[] dexElementsSuppressedExceptions1 = (IOException[]) ((IOException[])
suppressedExceptionsField1.get(loader));
if (dexElementsSuppressedExceptions1 ==null) {
dexElementsSuppressedExceptions1 = (IOException[]) suppressedExceptions
.toArray(new IOException[suppressedExceptions.size()]);
}else {
IOException[] combined =new IOException[suppressedExceptions.size() +
dexElementsSuppressedExceptions1.length];
suppressedExceptions.toArray(combined);
System.arraycopy(dexElementsSuppressedExceptions1, 0, combined,
suppressedExceptions.size(), dexElementsSuppressedExceptions1.length);
dexElementsSuppressedExceptions1 = combined;
}
suppressedExceptionsField1.set(loader, dexElementsSuppressedExceptions1);
}
}
private static Object[]makeDexElements(Object dexPathList,
ArrayList files, File
optimizedDirectory,
ArrayList suppressedExceptions)throws
IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Method makeDexElements =findMethod(dexPathList, "makeDexElements", new
Class[]{ArrayList.class, File.class, ArrayList.class});
return ((Object[]) makeDexElements.invoke(dexPathList, new Object[]{files,
optimizedDirectory, suppressedExceptions}));
}
}
/**
* A wrapper around
* {@code private static final dalvik.system.DexPathList#makePathElements}.
*/
private static Object[]makePathElements(
Object dexPathList, ArrayList files, File optimizedDirectory,
ArrayList suppressedExceptions)
throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Method makePathElements;
try {
makePathElements =findMethod(dexPathList, "makePathElements", List.class, File.class,
List.class);
}catch (NoSuchMethodException e) {
Log.e(TAG, "NoSuchMethodException: makePathElements(List,File,List) failure");
try {
makePathElements =findMethod(dexPathList, "makePathElements", ArrayList.class, File.class, ArrayList.class);
}catch (NoSuchMethodException e1) {
Log.e(TAG, "NoSuchMethodException: makeDexElements(ArrayList,File,ArrayList) failure");
try {
Log.e(TAG, "NoSuchMethodException: try use v19 instead");
return V19.makeDexElements(dexPathList, files, optimizedDirectory, suppressedExceptions);
}catch (NoSuchMethodException e2) {
Log.e(TAG, "NoSuchMethodException: makeDexElements(List,File,List) failure");
throw e2;
}
}
}
return (Object[]) makePathElements.invoke(dexPathList, files, optimizedDirectory, suppressedExceptions);
}
private byte[]getBytes(File file)throws Exception {
RandomAccessFile r =new RandomAccessFile(file, "r");
byte[] buffer =new byte[(int) r.length()];
r.readFully(buffer);
r.close();
return buffer;
}
}