在https://www.jianshu.com/p/feecde9a9aee这篇文章里,我讲到了如何成功dump出360的dex方法,但是没有dump出壳内真正apk的dex文件。网上有一种说法是从mmap函数入手,我尝试了一下,但是失败了,过程记录一下:
mmap.cpp文件
所在目录:bionic/libc/bionic/mmap.cpp
编译目录:bionic/libc/
ALOGE使用不了
在DvmDex.cpp里,可以直接调用ALOGE打印android日志,但是到了mmap.cpp却没法直接使用。网上百度了各种办法都不行,编译虽然通过,系统跑不起来,大概是https://blog.csdn.net/flydream0/article/details/7344730里的方案的综合,有的是教怎么在JNI的cpp里如何打印android日志,有的虽然是教源码里cpp如何打印android日志。可能是不同的模块修改Android.mk的方式不一样。
最终,我参照DvmDex.cpp所在模块的Android.mk,依葫芦画瓢找到了答案:
bionic/libc/Android.mk的 libc_common.a处增加libcutils和liblog依赖,在mmap.cpp里增加#include <cutils/log.h>即可。
image.png
- 依葫芦画瓢的过程:
首先看DvmDex.cpp的include的.h文件,
#include "Dalvik.h"
#include <sys/mman.h>
先去DvmDex.cpp的当前目录下找这两个文件,发现Dalvik.h有一个
#include "Common.h"
在Common.h里发现
#include "cutils/log.h"
然而,在当前目录发现找不到cutils/log.h这个文件,为何?(关于这个问题,我研究发现要单独成文,想要知道libxxx.so xxx.a这些共享库、静态库都是怎么生成的,请转至:)
看先去DvmDex.cpp编译模块的Android.mk文件:
![](https://img.haomeiwen.com/i18328858/18e9f1296302050e.png)
然后文章开头,我照样将libcutils、liblog两个静态库添加到bionic/libc/Android.mk中。
网上的很多的做法都是将libcutils添加到LOCAL_SHARED_LIBRARIES的后面,把静态库添加到共享库变量里,我不知道编译为啥还成功了,但是系统跑不起来(Nexus出现Google页面2次后卡在感叹号机器人页面)。
有了ALOG,就等于有了眼睛,等于我们离底层又更进了一步。
mmap函数研究
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset)
我的目的还是希望通过addr和size来dump出dex的内存,但是mmap会被频繁的调用到。
我在https://www.jianshu.com/p/feecde9a9aee这篇文章提到过,DvmDex.cpp文件中的dvmDexFileOpenPartial的调用时机问题我已经解决了。但是mmap函数,我如何确定是360壳内部的应用的dex加载时调用了呢?我想到了几种解决方案:
1)利用Dex文件结构
![](https://img.haomeiwen.com/i18328858/cc6dbad15e620812.png)
了解Dex文件结构的都知道Dex文件开头的7个字节始终是固定的:64 65 78 0A 30 33 35,对应的字符串是dex.035。那么是否可以通过addr和size来判断呢?
我操作星(result+x)判断字节,编译直接报错。void星指针不能直接拿来运算
我写了下面的这些的几行代码,发现系统起不来,出现2次Google页面后卡在感叹号机器人页面。
![](https://img.haomeiwen.com/i18328858/5d78c349c4f0458c.png)
原来mmap函数的参数void* addr,addr可能是任意的类型,直接强转成int星肯定会报错。但是我发现void*可以强转成unsiged char *,
看与mmap.cpp同级的目录的memcmp.c文件,google官方就是这么干的。
![](https://img.haomeiwen.com/i18328858/67ae2f8735ebf311.png)
所以对代码再一次做了优化:
![](https://img.haomeiwen.com/i18328858/e393401e77e26a64.png)
这次是卡在android字样页面。
将下面这行代码注释掉,系统起来了。
//ALOGE("CZLog mmap find dex035");
为什么限制了条件之后打Log反而打不出来呢?不光限制条件,就在条件里进行变量的运算,自增、自减运算,系统也会起不来。
memcmp函数研究
这篇https://www.52pojie.cn/thread-648311-1-1.html博客解释了360没有使用 系统的dvmDexFileOpenPartial函数,而是模仿了系统的解析dex的方法:DexFile.c中的dexFileParse方法,然后使用了memcmp函数(系统方法,我们找的就是系统方法。),所以mmap行不通,尝试修改这个函数。
关于博客里有2个常量:DEX_OPT_MAGIC和DEX_OPT_MAGIC_VERS,请看https://blog.csdn.net/yhtppp/article/details/44829449?locationNum=12,位于/dalvik/libdex/DexFile.h 文件中。
<u> memcmp.c一引入了cutil/log,然后bionic/libc/Android.mk增加libcutil、liblog,就会导致整个make都无法使用,报错如下:
没有规则可以创建“out/host/linux-x86/obj/SHARED_LIBRARIES/libdvm_intermediates/import_includes”需要的目标“out/host/linux-x86/obj/SHARED_LIBRARIES/libcutils_intermediates/export_includes”。 停止
在memcmp.c可以直接使用ALOGE,也不用引入cutil/log头文件,不知道是什么个原理。</u>
上面这段奇遇,可能是由于什么缓存,或者源码的某个文件不小心删除造成的。后来重新下载源码重新走流程就没有什么问题。但是,memcmp.c里的android日志没有输出。
首先我怀疑360可能根本没有调用这个方法,为了证明我的猜想,我写了一个JNI程序,调用了C的memcmp方法,memcmp.c里的android日志仍然没有输出。
重新研究bionic/libc/Android.mk发现端倪
在Android.mk里搜索memcmp.c,发现只有一处引用:
![](https://img.haomeiwen.com/i18328858/6687134b79656065.png)
Android.mk文件里的关键变量:
TARGET_ARCH: 目标 CPU平台的名字, 和android 开放源码中指定的那样。如果是
arm,表示要生成 ARM 兼容的指令,与 CPU架构的修订版无关。
memcmp.c编译mips架构的组件时才会被依赖。
使用
adb shell
cat /proc/cpuinfo
发现我的调试设备的架构是armv7,所以memcmp.c不会被我的设备调用,更别谈打印日志了。
-
看看arm架构的依赖:
有一个wmemcmp.c和memcmp.c长得很像。
image.png
定位到文件
image.png
加上日志
#include <cutils/log.h>
int
wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n)
{
size_t i;
ALOGE("CZLog3333333333");
for (i = 0; i < n; i++) {
if (*s1 != *s2) {
/* wchar might be unsigned */
return *s1 > *s2 ? 1 : -1;
}
s1++;
s2++;
}
return 0;
}
android日志TM还是没有输出,气死人了。
Android源码与NDK的关系
在上面,我写了个JNI,调用memcmp()方法,以为就是调用的源码里的bionic/libc/upstream-freebsd/lib/libc/string/wmemcmp.c的wmemcmp方法。
其实,这里我有个很大的误区:JNI调用的库<string.h>并非Android源码里的<string.h>,而且NDK里的库。而NDK是独立于Android系统的,是一个开发工具集,有着很多和Android源码里相似的库,但是它不属于Android系统本身的一部分。
网友评论