extern
"C"
void dumpArtMethod(ArtMethod
*
artmethod) REQUIRES_SHARED(Locks::mutator_lock_) {
char
*
dexfilepath
=
(char
*
)malloc(sizeof(char)
*
1000
);
if
(dexfilepath
=
=
nullptr)
{
LOG(ERROR) <<
"ArtMethod::dumpArtMethodinvoked,methodname:"
<<artmethod
-
>PrettyMethod().c_str()<<
"malloc 1000 byte failed"
;
return
;
}
int
result
=
0
;
int
fcmdline
=
-
1
;
char szCmdline[
64
]
=
{
0
};
char szProcName[
256
]
=
{
0
};
int
procid
=
getpid();
/
/
我查了下,
/
proc
/
pid
/
cmdline 是可以读取到进程的启动参数。启动参数的默认第一个一般都是进程的完整路径
sprintf(szCmdline,
"/proc/%d/cmdline"
, procid);
fcmdline
=
open
(szCmdline, O_RDONLY,
0644
);
if
(fcmdline >
0
)
{
result
=
read(fcmdline, szProcName,
256
);
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,open cmdline file file error"
;
}
close(fcmdline);
}
if
(szProcName[
0
])
{
const DexFile
*
dex_file
=
artmethod
-
>GetDexFile();
/
/
要保存dexfile的起始位置
const uint8_t
*
begin_
=
dex_file
-
>Begin();
/
/
Start of data.
/
/
要保存dexfile的大小
size_t size_
=
dex_file
-
>Size();
/
/
Length of data.
memset(dexfilepath,
0
,
1000
);
int
size_int_
=
(
int
)size_;
/
/
先初始化目录
/
sdcard
/
fart 创建目录并给
0777
的权限
memset(dexfilepath,
0
,
1000
);
sprintf(dexfilepath,
"%s"
,
"/sdcard/fart"
);
mkdir(dexfilepath,
0777
);
/
/
然后把cmdline中读取到的路径在fart中同样创建目录,这样就可以区分不同的apk的结果写在不同目录
memset(dexfilepath,
0
,
1000
);
sprintf(dexfilepath,
"/sdcard/fart/%s"
,szProcName);
mkdir(dexfilepath,
0777
);
/
/
最后创建要写入保存的文件
memset(dexfilepath,
0
,
1000
);
sprintf(dexfilepath,
"/sdcard/fart/%s/%d_dexfile.dex"
,szProcName,size_int_);
int
dexfilefp
=
open
(dexfilepath,O_RDONLY,
0666
);
/
/
这里相当于是查一下这个文件是否存在。如果fp大于
0
表示存在,则不用再dump了。
if
(dexfilefp>
0
){
close(dexfilefp);
dexfilefp
=
0
;
}
else
{
int
fp
=
open
(dexfilepath,O_CREAT|O_APPEND|O_RDWR,
0666
);
if
(fp>
0
)
{
/
/
将要保存的数据写入文件,这种应该是属于整体dump
result
=
write(fp,(void
*
)begin_,size_);
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,open dexfilepath file error"
;
}
fsync(fp);
close(fp);
/
/
下面是把所有类名写入文件保存。方便搜索。可能修复的时候也会用到这个文件
memset(dexfilepath,
0
,
1000
);
sprintf(dexfilepath,
"/sdcard/fart/%s/%d_classlist.txt"
,szProcName,size_int_);
int
classlistfile
=
open
(dexfilepath,O_CREAT|O_APPEND|O_RDWR,
0666
);
if
(classlistfile>
0
)
{
/
/
这里我瞅着眼熟,然后翻了下。其实就是参考GetClassNames的处理。获取了所有的类名列表,然后写入文件
for
(size_t ii
=
0
; ii< dex_file
-
>NumClassDefs();
+
+
ii)
{
const DexFile::ClassDef& class_def
=
dex_file
-
>GetClassDef(ii);
const char
*
descriptor
=
dex_file
-
>GetClassDescriptor(class_def);
result
=
write(classlistfile,(void
*
)descriptor,strlen(descriptor));
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error"
;
}
const char
*
temp
=
"\n"
;
result
=
write(classlistfile,(void
*
)temp,
1
);
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,write classlistfile file error"
;
}
}
fsync(classlistfile);
close(classlistfile);
}
}
}
/
/
下面是要对函数进行dump
const DexFile::CodeItem
*
code_item
=
artmethod
-
>GetCodeItem();
if
(LIKELY(code_item !
=
nullptr))
{
int
code_item_len
=
0
;
uint8_t
*
item
=
(uint8_t
*
) code_item;
/
/
这里表示是否有
try
,因为
try
的数量会影响函数的大小,我们dump需要函数的位置和计算出函数大小。
if
(code_item
-
>tries_size_>
0
) {
/
/
有
try
的情况计算比较复杂,这个codeitem_end里面封装了一系列的计算,我感觉好像是获取了
try
的数量,然后再一系列的计算,最终得到的函数大小
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
{
/
/
如果没有
try
的情况。就简单的可以计算出来。
code_item_len
=
16
+
code_item
-
>insns_size_in_code_units_
*
2
;
}
/
/
有了函数的大小和位置后,这里又获取了函数的index
memset(dexfilepath,
0
,
1000
);
int
size_int
=
(
int
)dex_file
-
>Size();
uint32_t method_idx
=
artmethod
-
>GetDexMethodIndexUnchecked();
/
/
最后把获取到的相关数据按照特定的格式写入.
bin
的文件中。这个文件后面就可以拿来做修复dex。因为已经有了对每个函数的详细描述了。
sprintf(dexfilepath,
"/sdcard/fart/%s/%d_ins_%d.bin"
,szProcName,size_int,(
int
)gettidv1());
int
fp2
=
open
(dexfilepath,O_CREAT|O_APPEND|O_RDWR,
0666
);
if
(fp2>
0
){
lseek(fp2,
0
,SEEK_END);
memset(dexfilepath,
0
,
1000
);
int
offset
=
(
int
)(item
-
begin_);
sprintf(dexfilepath,
"{name:%s,method_idx:%d,offset:%d,code_item_len:%d,ins:"
,artmethod
-
>PrettyMethod().c_str(),method_idx,offset,code_item_len);
int
contentlength
=
0
;
while
(dexfilepath[contentlength]!
=
0
) contentlength
+
+
;
result
=
write(fp2,(void
*
)dexfilepath,contentlength);
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,write ins file error"
;
}
long
outlen
=
0
;
char
*
base64result
=
base64_encode((char
*
)item,(
long
)code_item_len,&outlen);
result
=
write(fp2,base64result,outlen);
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,write ins file error"
;
}
result
=
write(fp2,
"};"
,
2
);
if
(result<
0
)
{
LOG(ERROR) <<
"ArtMethod::dumpdexfilebyArtMethod,write ins file error"
;
}
fsync(fp2);
close(fp2);
if
(base64result!
=
nullptr){
free(base64result);
base64result
=
nullptr;
}
}
}
}
if
(dexfilepath!
=
nullptr)
{
free(dexfilepath);
dexfilepath
=
nullptr;
}
}