http://blog.itpub.net/31562043/viewspace-2284074/
https://blog.csdn.net/tabactivity/article/details/50435140
https://blog.csdn.net/chenya866/article/details/79355156 (分析了各大加密产品的共性)
https://blog.csdn.net/androidsecurity/article/details/8678399
https://blog.csdn.net/zzx410527/article/details/51673908 (不落地式加载dex)
最新各大apk加固特征库
https://blog.csdn.net/g5703129/article/details/85054405
目录
通过给ClassLoader加日志分析APK加固原理
1.给各个ClassLoader加上日志
在android4.4源码里我在DexClassLoader、BaseDexClassLoader、ClassLoader均加了日志,所有的地方都要将dexPath判断一下再输出日志,否则系统无法正常启动。
加日志的目的:如果360使用了自定义的ClassLoader,就能知道。
- ClassLoader
源码目录1:libcore/libdvm/src/main/java/java/lang
源码目录2:libcore/libart/src/main/java/java/lang
编译目录:libcore
重载了一个dexPath的构造方法,给BaseDexClassLoader调用,两个目录的ClassLoader都要修改。
/**
* CZ define
* @param parentLoader
* @param dexPath
*/
protected ClassLoader(ClassLoader parentLoader,String dexPath) {
this(parentLoader, false);
if(dexPath.startsWith("/data/app/")){
Logger logger = Logger.getLogger("CZLogQiHu4444444");
logger.warning("ClassLoader: " + ",dexPath = " + dexPath + ",name = " + getClass().getName());
}
}
- BaseDexClassLoader
源码目录:libcore/dalvik/src/main/java/dalvik/system
编译目录:libcore
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent,dexPath);
//super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
if(dexPath.startsWith("/data/app/")){
Logger logger = Logger.getLogger("CZLogQiHu111");
logger.warning("BaseDexClassLoader: " + ",dexPath = " + dexPath + "\npathList = " + pathList + ",name = " + getClass().getName());
}
}
- DexClassLoader
源码目录:libcore/dalvik/src/main/java/dalvik/system
编译目录:libcore
public DexClassLoader(String dexPath, String optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
if(dexPath.startsWith("/data/app/")){
Logger logger = Logger.getLogger("CZLogQiHu2222");
logger.warning("DexClassLoader: " + ",dexPath = " + dexPath + ",optimizedDirectory = " + optimizedDirectory +
",libraryPath = " + libraryPath + ",name = " + getClass().getName()
);
}
}
2.给DexFile相关类加上日志
- DexFile.java
源码目录:libcore/dalvik/src/main/java/dalvik/system
编译目录:libcore
static public DexFile loadDex(String sourcePathName, String outputPathName,
int flags) throws IOException {
/*
* TODO: we may want to cache previously-opened DexFile objects.
* The cache would be synchronized with close(). This would help
* us avoid mapping the same DEX more than once when an app
* decided to open it multiple times. In practice this may not
* be a real issue.
*/
log("DexFile loadDex:sourcePathName = " + sourcePathName + ",outputPathName = " + outputPathName);
return new DexFile(sourcePathName, outputPathName, flags);
}
private DexFile(String sourceName, String outputName, int flags) throws IOException {
if (outputName != null) {
try {
String parent = new File(outputName).getParent();
if (Libcore.os.getuid() != Libcore.os.stat(parent).st_uid) {
throw new IllegalArgumentException("Optimized data directory " + parent
+ " is not owned by the current user. Shared storage cannot protect"
+ " your application from code injection attacks.");
}
} catch (ErrnoException ignored) {
// assume we'll fail with a more contextual error later
}
}
if(outputName == null ){
log("DexFile created here");
}
mCookie = openDexFile(sourceName, outputName, flags);
mFileName = sourceName;
guard.open("close");
//System.out.println("DEX FILE cookie is " + mCookie);
}
private static int openDexFile(String sourceName, String outputName,
int flags) throws IOException {
log("DexFile openDexFile,sourceName = " + sourceName + ",outputName = " + outputName);
return openDexFileNative(new File(sourceName).getCanonicalPath(),
(outputName == null) ? null : new File(outputName).getCanonicalPath(),
flags);
}
- dalvik_system_DexFile.cpp
源码目录:dalvik/vm/native
编译目录:dalvik/vm
static void Dalvik_dalvik_system_DexFile_openDexFileNative(const u4* args,
JValue* pResult)
{
ALOGE("CZLog Dalvik_dalvik_system_DexFile_openDexFileNative");
StringObject* sourceNameObj = (StringObject*) args[0];
StringObject* outputNameObj = (StringObject*) args[1];
DexOrJar* pDexOrJar = NULL;
JarFile* pJarFile;
RawDexFile* pRawDexFile;
char* sourceName;
char* outputName;
if (sourceNameObj == NULL) {
dvmThrowNullPointerException("sourceName == null");
RETURN_VOID();
}
sourceName = dvmCreateCstrFromString(sourceNameObj);
ALOGE("CZLog from dvmCreateCstrFromString sourceName%s",sourceName);
if (outputNameObj != NULL)
outputName = dvmCreateCstrFromString(outputNameObj);
else
outputName = NULL;
static void addToDexFileTable(DexOrJar* pDexOrJar) {
ALOGE("CZLog addToDexFileTable");
3.安装一个普通的没有加固的app(直接从as上run)
开机首次安装应用,会先启动系统的两个系统应用pm和am(as上run才有这个日志)。
pm
E/dalvikvm( 2201): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative
E/dalvikvm( 2201): CZLog from dvmCreateCstrFromString sourceName/system/framework/pm.jar
E/dalvikvm( 2201): Couldn't open /system/framework/pm.odex: No such file or directory
E/dalvikvm( 2201): dvmJarFileOpen: Checking cache for /system/framework/pm.jar (/data/dalvik-cache/system@framework@pm.jar@classes.dex)
E/dalvikvm( 2201): Successfully opened 'classes.dex' in '/system/framework/pm.jar'
E/dalvikvm( 2201): Opening DEX file '/system/framework/pm.jar' (Jar)
E/dalvikvm( 2201): CZLog addToDexFileTable
am
E/dalvikvm( 2259): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative
E/dalvikvm( 2259): CZLog from dvmCreateCstrFromString sourceName/system/framework/am.jar
E/dalvikvm( 2259): Couldn't open /system/framework/am.odex: No such file or directory
E/dalvikvm( 2259): dvmJarFileOpen: Checking cache for /system/framework/am.jar (/data/dalvik-cache/system@framework@am.jar@classes.dex)
E/dalvikvm( 2259): Successfully opened 'classes.dex' in '/system/framework/am.jar'
E/dalvikvm( 2259): Opening DEX file '/system/framework/am.jar' (Jar)
E/dalvikvm( 2259): CZLog addToDexFileTable
然后就是我安装的应用的日志:
W/CZLogQiHu4444444( 2275): ClassLoader: ,dexPath = /data/app/com.example.jni02-1.apk,name = dalvik.system.PathClassLoader
W/CZLogXXX( 2275): DexFile openDexFile,sourceName = /data/app/com.example.jni02-1.apk,outputName = null
E/dalvikvm( 2275): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative
E/dalvikvm( 2275): CZLog from dvmCreateCstrFromString sourceName/data/app/com.example.jni02-1.apk
E/dalvikvm( 2275): Couldn't open /data/app/com.example.jni02-1.odex: No such file or directory
E/dalvikvm( 2275): dvmJarFileOpen: Checking cache for /data/app/com.example.jni02-1.apk (/data/dalvik-cache/data@app@com.example.jni02-1.apk@classes.dex)
E/dalvikvm( 2275): Successfully opened 'classes.dex' in '/data/app/com.example.jni02-1.apk'
E/dalvikvm( 2275): Opening DEX file '/data/app/com.example.jni02-1.apk' (Jar)
E/dalvikvm( 2275): CZLog addToDexFileTable
W/CZLogQiHu111( 2275): BaseDexClassLoader: ,dexPath = /data/app/com.example.jni02-1.apk
W/CZLogQiHu111( 2275): pathList = DexPathList[[zip file "/data/app/com.example.jni02-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.jni02-1, /vendor/lib, /system/lib]],name = dalvik.system.PathClassLoader
https://blog.csdn.net/black_dreamer/article/details/81665728
所以,apk 安装时,系统会使用 PathClassLoader 来加载apk文件中的dex
4.安装加固的app
第一部分:加载壳dex
壳apk执行普通apk的加载流程
I/ActivityManager( 753): Start proc com.chinalwb.are.demo for activity com.chinalwb.are.demo/.IndexActivity: pid=2485 uid=10073 gids={50073, 1028, 1015, 3003}
W/CZLogQiHu4444444( 2485): ClassLoader: ,dexPath = /data/app/com.chinalwb.are.demo-1.apk,name = dalvik.system.PathClassLoader
W/CZLogXXX( 2485): DexFile openDexFile,sourceName = /data/app/com.chinalwb.are.demo-1.apk,outputName = null
E/dalvikvm( 2485): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative
E/dalvikvm( 2485): CZLog from dvmCreateCstrFromString sourceName/data/app/com.chinalwb.are.demo-1.apk
E/dalvikvm( 2485): Couldn't open /data/app/com.chinalwb.are.demo-1.odex: No such file or directory
E/dalvikvm( 2485): dvmJarFileOpen: Checking cache for /data/app/com.chinalwb.are.demo-1.apk (/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex)
E/dalvikvm( 2485): Successfully opened 'classes.dex' in '/data/app/com.chinalwb.are.demo-1.apk'
E/dalvikvm( 2485): Opening DEX file '/data/app/com.chinalwb.are.demo-1.apk' (Jar)
E/dalvikvm( 2485): CZLog addToDexFileTable
W/CZLogQiHu111( 2485): BaseDexClassLoader: ,dexPath = /data/app/com.chinalwb.are.demo-1.apk
W/CZLogQiHu111( 2485): pathList = DexPathList[[zip file "/data/app/com.chinalwb.are.demo-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.chinalwb.are.demo-1, /vendor/lib, /system/lib]],name = dalvik.system.PathClassLoader
D/dalvikvm( 2485): DexOpt: couldn't find static field Landroid/os/Build;.SUPPORTED_32_BIT_ABIS
W/dalvikvm( 2485): VFY: unable to resolve static field 4 (SUPPORTED_32_BIT_ABIS) in Landroid/os/Build;
D/dalvikvm( 2485): VFY: replacing opcode 0x62 at 0x0004
D/dalvikvm( 2485): Trying to load lib /data/data/com.chinalwb.are.demo/.jiagu/libjiagu837801602.so 0x42628f50
D/dalvikvm( 2485): Added shared lib /data/data/com.chinalwb.are.demo/.jiagu/libjiagu837801602.so 0x42628f50
E/dalvikvm( 2485): ERROR: couldn't find native method
E/dalvikvm( 2485): Requested: Lcom/stub/StubApp;.interface7:(Landroid/app/Application;Landroid/content/Context;)Z
第二部分:再次加载了一次dex
上面的日志里最后一行
```Requested: Lcom/stub/StubApp;.interface7:(Landroid/app/Application;Landroid/content/Context;)Z```应该就是360解密壳内部真正的地方
然后它没有自定义任何的ClassLoader,而是直接使用DexFile.java的loadDex方法加载dex。
W/CZLogXXX( 2485): DexFile loadDex:sourcePathName = /data/app/com.chinalwb.are.demo-1.apk,outputPathName = null
W/CZLogXXX( 2485): DexFile created here
W/CZLogXXX( 2485): DexFile openDexFile,sourceName = /data/app/com.chinalwb.are.demo-1.apk,outputName = null
E/dalvikvm( 2485): CZLog Dalvik_dalvik_system_DexFile_openDexFileNative
E/dalvikvm( 2485): CZLog from dvmCreateCstrFromString sourceName/data/app/com.chinalwb.are.demo-1.apk
E/dalvikvm( 2485): Couldn't open /data/app/com.chinalwb.are.demo-1.odex: No such file or directory
E/dalvikvm( 2485): dvmJarFileOpen: Checking cache for /data/app/com.chinalwb.are.demo-1.apk (/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex)
E/dalvikvm( 2485): Successfully opened 'classes.dex' in '/data/app/com.chinalwb.are.demo-1.apk'
E/dalvikvm( 2485): Opening DEX file '/data/app/com.chinalwb.are.demo-1.apk' (Jar)
E/dalvikvm( 2485): CZLog addToDexFileTable
注意
```E/dalvikvm( 2094): Opening DEX file '/data/app/com.chinalwb.are.demo-1.apk' (Jar)```这行日志,这是系统自己打的日志。

调用了```dvmJarFileOpen```方法来打开dex
这个方法的实现不在dalvik_system_DexFile.cpp文件,通过```grep 'dvmJarFileOpen' -Inrw --include=*.cpp```找到方法的实现位置
- JarFile.cpp
源码目录:dalvik/vm
编译目录:dalvik/vm
关于dvmJarFileOpen这个方法的资料:
这个方法真的十分重要!!!!!!
https://bbs.pediy.com/thread-209631.htm
https://blog.csdn.net/mengkevin/article/details/74177927
JarFile.cpp的日志都是用ALOGV来打印的,logcat捕捉不到,改用ALOGE。 -
/data/dalvik-cache目录下的dex
看
```dvmJarFileOpen: Checking cache for /data/app/com.chinalwb.are.demo-1.apk (/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex)```这行日志,这里的```/data/dalvik-cache/data@app@com.chinalwb.are.demo-1.apk@classes.dex```dex是不是呢?
pull出来,无法反编译出smali,下面博客说明了这个dex不是源程序的dex。
[https://blog.csdn.net/u010144805/article/details/78894321](https://blog.csdn.net/u010144805/article/details/78894321)
##5.360解密后的dex
通过上面详细的日志分析可知,360加固后的app进行了2次dex加载,那么真正的源程序的dex是否能拿到呢?
看JarFile.cpp的dvmDexFileOpenFromFd这个方法
/*
* Map the cached version. This immediately rewinds the fd, so it
* doesn't have to be seeked anywhere in particular.
*/
if (dvmDexFileOpenFromFd(fd, &pDvmDex) != 0) {
ALOGI("Unable to map %s in %s", kDexInJarName, fileName);
goto bail;
}
通过
```grep 'dvmDexFileOpenFromFd' -Inrw --include=*.cpp```搜索这个方法的实际定义位置,发现位于DvmDex.cpp。
- DvmDex.cpp
源码目录:dalvik/vm
编译目录:dalvik/vm

通过
```grep 'dexFileParse' -Inrw --include=*.cpp```搜索出dexFileParse所在的文件位置,为DexFile.cpp。
- DexFile.cpp。
源码目录:dalvik/libdex
编译目录:dalvik/libdex
关于dexFileParse方法我就不再细讲了,因为有了pDexFile就能搞到dex。
0 条评论