libcore\dalvik\src\main\java\dalvik\system\DexFile.java
//增加dumpMethodCode纺铭,對(duì)應(yīng) art\runtime\native\dalvik_system_DexFile.cc DexFile_dumpMethodCode
private static native void dumpMethodCode(Object m);
frameworks\base\core\java\android\app\ActivityThread.java
- 主要是增加了在Activity OnCreate時(shí)虽画,遍歷所有dex并且遍歷所有類,遍歷所有方法朽砰,然后dump method
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//在Activity ONCREATE 后 增加了調(diào)用
fartthread();
//add
}
public static void fartthread() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Log.e("ActivityThread", "start sleep,wait for fartthread start......");
Thread.sleep(1 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("ActivityThread", "sleep over and start fartthread");
fart();
Log.e("ActivityThread", "fart run over");
}
}).start();
}
public static void fart() {
ClassLoader appClassloader = getClassloader();
List<Object> dexFilesArray = new ArrayList<Object>();
Field pathList_Field = (Field) getClassField(appClassloader, "dalvik.system.BaseDexClassLoader", "pathList");
Object pathList_object = getFieldOjbect("dalvik.system.BaseDexClassLoader", appClassloader, "pathList");
Object[] ElementsArray = (Object[]) getFieldOjbect("dalvik.system.DexPathList", pathList_object, "dexElements");
Field dexFile_fileField = null;
try {
dexFile_fileField = (Field) getClassField(appClassloader, "dalvik.system.DexPathList$Element", "dexFile");
} catch (Exception e) {
e.printStackTrace();
}
Class DexFileClazz = null;
try {
DexFileClazz = appClassloader.loadClass("dalvik.system.DexFile");
} catch (Exception e) {
e.printStackTrace();
}
Method getClassNameList_method = null;
Method defineClass_method = null;
Method dumpDexFile_method = null;
Method dumpMethodCode_method = null;
for (Method field : DexFileClazz.getDeclaredMethods()) {
if (field.getName().equals("getClassNameList")) {
getClassNameList_method = field;
getClassNameList_method.setAccessible(true);
}
if (field.getName().equals("defineClassNative")) {
defineClass_method = field;
defineClass_method.setAccessible(true);
}
if (field.getName().equals("dumpMethodCode")) {
dumpMethodCode_method = field;
dumpMethodCode_method.setAccessible(true);
}
}
Field mCookiefield = getClassField(appClassloader, "dalvik.system.DexFile", "mCookie");
for (int j = 0; j < ElementsArray.length; j++) {
Object element = ElementsArray[j];
Object dexfile = null;
try {
dexfile = (Object) dexFile_fileField.get(element);
} catch (Exception e) {
e.printStackTrace();
}
if (dexfile == null) {
continue;
}
if (dexfile != null) {
dexFilesArray.add(dexfile);
Object mcookie = getClassFieldObject(appClassloader, "dalvik.system.DexFile", dexfile, "mCookie");
if (mcookie == null) {
continue;
}
String[] classnames = null;
try {
//獲取dex中所有的類名
classnames = (String[]) getClassNameList_method.invoke(dexfile, mcookie);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
if (classnames != null) {
for (String eachclassname : classnames) {
//遍歷所有的類扔傅,并且調(diào)用新增的dumpMethodCode_method
loadClassAndInvoke(appClassloader, eachclassname, dumpMethodCode_method);
}
}
}
}
return;
}
//遍歷類,并且調(diào)用方法的dumpMethodCode_method
public static void loadClassAndInvoke(ClassLoader appClassloader, String eachclassname, Method dumpMethodCode_method) {
Log.i("ActivityThread", "go into loadClassAndInvoke->" + "classname:" + eachclassname);
Class resultclass = null;
try {
resultclass = appClassloader.loadClass(eachclassname);
} catch (Exception e) {
e.printStackTrace();
return;
} catch (Error e) {
e.printStackTrace();
return;
}
if (resultclass != null) {
try {
Constructor<?> cons[] = resultclass.getDeclaredConstructors();
for (Constructor<?> constructor : cons) {
if (dumpMethodCode_method != null) {
try {
dumpMethodCode_method.invoke(null, constructor);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
} else {
Log.e("ActivityThread", "dumpMethodCode_method is null ");
}
}
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
try {
Method[] methods = resultclass.getDeclaredMethods();
if (methods != null) {
for (Method m : methods) {
if (dumpMethodCode_method != null) {
try {
dumpMethodCode_method.invoke(null, m);
} catch (Exception e) {
e.printStackTrace();
continue;
} catch (Error e) {
e.printStackTrace();
continue;
}
} else {
Log.e("ActivityThread", "dumpMethodCode_method is null ");
}
}
}
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
}
}
art\runtime\interpreter\interpreter.cc
- 解釋執(zhí)行時(shí)dump 整體的dex
static inline JValue Execute(Thread* self, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
//ADD END 這里是解釋執(zhí)行模式苗傅,art虛擬機(jī)的clinit方法一定會(huì)走這里捺球,但是其他的oat優(yōu)化的方法 不一定會(huì)走這里缸浦。
if(strstr(PrettyMethod(shadow_frame.GetMethod()).c_str(),"<clinit>")!=nullptr)
{
//在執(zhí)行類初始化方法的時(shí)候 整體dump , 由于類加載的多氮兵,所以這里應(yīng)該會(huì)dump多次
dumpDexFileByExecute(shadow_frame.GetMethod());
}
//ADD END
*******
}
art\runtime\native\dalvik_system_DexFile.cc
- 增加DexFile_dumpMethodCode 裂逐,在ACtivity oncreate時(shí),主動(dòng)遍歷所有方法泣栈,調(diào)用此方法dump
- dumpDexFileByExecute 實(shí)現(xiàn)卜高,在解釋執(zhí)行時(shí)整體的dump
//addfunction
static void DexFile_dumpMethodCode(JNIEnv* env, jclass,jobject method) {
ScopedFastNativeObjectAccess soa(env);
if(method!=nullptr)
{
ArtMethod* artmethod = ArtMethod::FromReflectedMethod(soa, method);
myfartInvoke(artmethod);
}
return;
}
//addfunction
art\runtime\art_method.cc 主要邏輯
- ArtMethod::Invoke 時(shí),根據(jù)標(biāo)示Thread=null南片, dumpArtMethod
- 主動(dòng)調(diào)用 myfartInvoke 實(shí)現(xiàn)掺涛,主要進(jìn)行ArtMethod的Invoke調(diào)用,但是在invoke的時(shí)候根據(jù)標(biāo)示Thread *self = nullptr; 進(jìn)行dump
- 在dumpArtMethod時(shí)疼进,再次整體dump了dex薪缆,雖然dump了整體的dex,但是抽取殼伞广,可能函數(shù)體還是空的拣帽,所以會(huì)進(jìn)行codeitem的dump
- dumpArtMethod生成bin文件
void ArtMethod::Invoke(Thread * self, uint32_t * args,
1. uint32_t args_size, JValue * result,
const char *shorty) {
//ADD self等于null的時(shí)候 是自己調(diào)用的,dump方法
if (self == nullptr) {
dumpArtMethod(this);
return;
}
//ADD END
*******
}
//導(dǎo)出 myfartInvoke 在DexFile_dumpMethodCode 調(diào)用
extern "C" void myfartInvoke(ArtMethod * artmethod)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
JValue *result = nullptr;
Thread *self = nullptr;//nullptr 標(biāo)示 主動(dòng)調(diào)用 不執(zhí)行代碼邏輯嚼锄,只進(jìn)行方法的dump
uint32_t temp = 6;
uint32_t *args = &temp;
uint32_t args_size = 6;
artmethod->Invoke(self, args, args_size, result, "fart");
}
//計(jì)算有異常的codeitem長(zhǎng)度
uint8_t *codeitem_end(const uint8_t ** pData) {
uint32_t num_of_list = DecodeUnsignedLeb128(pData);
for (; num_of_list > 0; num_of_list--) {
int32_t num_of_handlers =
DecodeSignedLeb128(pData);
int num = num_of_handlers;
if (num_of_handlers <= 0) {
num = -num_of_handlers;
}
for (; num > 0; num--) {
DecodeUnsignedLeb128(pData);
DecodeUnsignedLeb128(pData);
}
if (num_of_handlers <= 0) {
DecodeUnsignedLeb128(pData);
}
}
return (uint8_t *) (*pData);
}
//將code item 進(jìn)行base64的輸出减拭,方便閱讀
extern "C" char *base64_encode(char *str, long str_len,
long *outlen) {
long len;
char *res;
int i, j;
const char *base64_table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
if (str_len % 3 == 0)
len = str_len / 3 * 4;
else
len = (str_len / 3 + 1) * 4;
res = (char *) malloc(sizeof(char) * (len + 1));
res[len] = '\0';
*outlen = len;
for (i = 0, j = 0; i < len - 2; j += 3, i += 4) {
res[i] = base64_table[str[j] >> 2];
res[i + 1] =
base64_table[(str[j] & 0x3) << 4 |
(str[j + 1] >> 4)];
res[i + 2] =
base64_table[(str[j + 1] & 0xf) << 2 |
(str[j + 2] >> 6)];
res[i + 3] = base64_table[str[j + 2] & 0x3f];
}
switch (str_len % 3) {
case 1:
res[i - 2] = '=';
res[i - 1] = '=';
break;
case 2:
res[i - 1] = '=';
break;
}
return res;
}
//整體dump d_dexfile_execute.dex 調(diào)用時(shí)機(jī)在解釋器解釋執(zhí)行類cliniT的時(shí)候
extern "C" void dumpDexFileByExecute(ArtMethod * artmethod)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
char *dexfilepath = (char *) malloc(sizeof(char) * 2000);
if (dexfilepath == nullptr) {
LOG(INFO) <<
"ArtMethod::dumpDexFileByExecute,methodname:"
<< PrettyMethod(artmethod).
c_str() << "malloc 2000 byte failed";
return;
}
int fcmdline = -1;
char szCmdline[64] = { 0 };
char szProcName[256] = { 0 };
int procid = getpid();
sprintf(szCmdline, "/proc/%d/cmdline", procid);
fcmdline = open(szCmdline, O_RDONLY, 0644);
if (fcmdline > 0) {
read(fcmdline, szProcName, 256);
close(fcmdline);
}
if (szProcName[0]) {
const DexFile *dex_file = artmethod->GetDexFile();
const uint8_t *begin_ = dex_file->Begin(); // Start of data.
size_t size_ = dex_file->Size(); // Length of data.
memset(dexfilepath, 0, 2000);
int size_int_ = (int) size_;
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath, "%s", "/sdcard/fart");
mkdir(dexfilepath, 0777);
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath, "/sdcard/fart/%s",
szProcName);
mkdir(dexfilepath, 0777);
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath,
"/sdcard/fart/%s/%d_dexfile_execute.dex",
szProcName, size_int_);
int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
if (dexfilefp > 0) {
close(dexfilefp);
dexfilefp = 0;
} else {
dexfilefp =
open(dexfilepath, O_CREAT | O_RDWR,
0666);
if (dexfilefp > 0) {
write(dexfilefp, (void *) begin_,
size_);
fsync(dexfilefp);
close(dexfilefp);
}
}
}
if (dexfilepath != nullptr) {
free(dexfilepath);
dexfilepath = nullptr;
}
}
//主動(dòng)調(diào)用了invoke,如果殼在這個(gè)時(shí)機(jī)区丑,將代碼還原拧粪,那么將可以dumP出method
//方法的code-item dump
//在這里進(jìn)行了_dexfile.dex的dump
extern "C" void dumpArtMethod(ArtMethod * artmethod)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
char *dexfilepath = (char *) malloc(sizeof(char) * 2000);
if (dexfilepath == nullptr) {
LOG(INFO) <<
"ArtMethod::dumpArtMethodinvoked,methodname:"
<< PrettyMethod(artmethod).
c_str() << "malloc 2000 byte failed";
return;
}
int fcmdline = -1;
char szCmdline[64] = { 0 };
char szProcName[256] = { 0 };
int procid = getpid();
sprintf(szCmdline, "/proc/%d/cmdline", procid);
fcmdline = open(szCmdline, O_RDONLY, 0644);
if (fcmdline > 0) {
read(fcmdline, szProcName, 256);
close(fcmdline);
}
if (szProcName[0]) {
const DexFile *dex_file = artmethod->GetDexFile();
const char *methodname =
PrettyMethod(artmethod).c_str();
const uint8_t *begin_ = dex_file->Begin();
size_t size_ = dex_file->Size();
memset(dexfilepath, 0, 2000);
int size_int_ = (int) size_;
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath, "%s", "/sdcard/fart");
mkdir(dexfilepath, 0777);
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath, "/sdcard/fart/%s",
szProcName);
mkdir(dexfilepath, 0777);
memset(dexfilepath, 0, 2000);
sprintf(dexfilepath,
"/sdcard/fart/%s/%d_dexfile.dex",//dump整體的dex
szProcName, size_int_);
int dexfilefp = open(dexfilepath, O_RDONLY, 0666);
if (dexfilefp > 0) {
close(dexfilefp);
dexfilefp = 0;
} else {
dexfilefp =
open(dexfilepath, O_CREAT | O_RDWR,
0666);
if (dexfilefp > 0) {
write(dexfilefp, (void *) begin_,
size_);
fsync(dexfilefp);
close(dexfilefp);
}
}
const DexFile::CodeItem * code_item =
artmethod->GetCodeItem();
if (LIKELY(code_item != nullptr)) {
int code_item_len = 0;//這里計(jì)算code item的長(zhǎng)度
uint8_t *item = (uint8_t *) code_item;
if (code_item->tries_size_ > 0) {//有異常的計(jì)算方式要加上try catch的長(zhǎng)度
const uint8_t *handler_data =
(const uint8_t *) (DexFile::
GetTryItems
(*code_item,
code_item->
tries_size_));
uint8_t *tail =
codeitem_end(&handler_data);
code_item_len =
(int) (tail - item);
} else {//沒(méi)有try catch
code_item_len =
16 +
code_item->
insns_size_in_code_units_ * 2;
}
memset(dexfilepath, 0, 2000);
int size_int = (int) dex_file->Size(); // Length of data
uint32_t method_idx =
artmethod->get_method_idx();
sprintf(dexfilepath,
"/sdcard/fart/%s/%d_%ld.bin",//生成BIN文件。
szProcName, size_int, gettidv1());
int fp2 =
open(dexfilepath,
O_CREAT | O_APPEND | O_RDWR,
0666);
if (fp2 > 0) {
lseek(fp2, 0, SEEK_END);
memset(dexfilepath, 0, 2000);
int offset = (int) (item - begin_);
sprintf(dexfilepath,
"{name:%s,method_idx:%d,offset:%d,code_item_len:%d,ins:",
methodname, method_idx,
offset, code_item_len);
int contentlength = 0;
while (dexfilepath[contentlength]
!= 0)
contentlength++;
write(fp2, (void *) dexfilepath,
contentlength);
long outlen = 0;
char *base64result =
base64_encode((char *) item,
(long)
code_item_len,
&outlen);
write(fp2, base64result, outlen);
write(fp2, "};", 2);
fsync(fp2);
close(fp2);
if (base64result != nullptr) {
free(base64result);
base64result = nullptr;
}
}
}
}
if (dexfilepath != nullptr) {
free(dexfilepath);
dexfilepath = nullptr;
}
}