通过了解ELF文件格式,了解got表hook原理。
本文用到的简单demo以及编译后的so库名称为libtestLib.so
Executable and Linkable Format 可执行可链接文件,主要用在linux相关操作系统上,文件中存储了程序运行的信息
很多文件格式都是有固定的魔数信息,代表了文件属于哪一种格式。比如zip格式,tar.gz,exe等
elf文件也有固定魔数,我们通过hexdump看一下头部的信息
前四个字节就代表了elf文件的魔数,为什么是前四个字节?因为源码中就定义了魔数信息。
SELFMAG就是长度的意思,4个字节。"\177"是8进制,16进制就是7f。与hexdump呈现的16进制视图完全一致。
文件头包含魔数,还包含其他关键信息。
文件头的size是多少呢?其实armv8文件头是固定的长度,armv7文件头也是固定的长度。长度只与当前so库对应的平台相关。
比如apk中libs/armeabi-v7a/下面的所有so库都拥有一样长度的文件头。
使用ida工具打开一个arm64的so库,我们看看工具所解析的elf文件头包含的信息:
结合该图,再来看看linker的源码,增加大家对ELF文件头的印象
源码位置aosp7.1 bionic/linker/linker_phdr.cpp
这两个表大家要牢记,elf文件头包含了这两个表的信息。
先啰嗦一下表这个关键字:elf文件中,一个区域存储了很多个一摸一样的结构体,这个区域就可以视作表。比如got表,符号表,字符串表等等。这些表后边也会提到。
程序头表上面已经从ELF文件头信息中拿到了。通过循环遍历这个表,可以找到一个PT_DYNAMIC类型的程序头,这个程序头中存储了动态表的偏移大小等信息。我把demo中的so库用010editor这个工具解析出来贴了个图
大家可能有疑问,程序头表中有很多个程序头,为什么仅仅要拿到PT_DYNAMIC这个程序头,拿到动态表呢?
其实程序头表中的信息都很重要,比如图中的前两个程序头(loadable segment),这两个程序头包含了一些装载信息。
linker会用到装载信息。比如so库装载到内存中需要多大空间,内存中的属性(可读可写可执行等)。
既然提到了装载,那就简单说一下装载和链接吧。
so库包含了程序运行需要用的数据以及指令,这些数据以及指令需要加载到内存中,加载到内存的过程就可以简单理解为装载。
so库一般会使用到外部的一些符号,比如open,close,mmap,strlen等导入符号,这些符号的真实地址不在本so库,可能在系统的libc库等等。那么本so库要调用open这些函数的话,肯定需要一些特殊的方式拿到其真实地址。这些真实地址其实保存在so库的got表中。linker将so库装载后, 会将这些符号进行重新定位,重新定位简称为重定位。其实重定位不仅仅包含外部的一些符号,还包含本so库的一些符号。重定位修复的整个过程可以理解为链接。
上边提到了前两个程序头(loadable_segment)与装载有关系。那么链接过程需要用的重定位信息在哪里呢?寻找这个答案,就需要PT_DYNAMIC这个程序头, 程序头有一个字端为p_vaddr,值为0x2D28,这个地址就是动态节区,因为这个区域又是数组,后边就把这个节区称为动态表。
动态表中的DT_JMPREL这个结构体,包含了重定位表的信息,继续用ida工具查看0x9f8->重定位表
重定位表包含了需要重定位的函数信息,包括__open_2函数。
前边提到了linker对so库链接的过程会进行符号重定位,重定位的信息就在重定位表中。
继续以__open_2这个重定位信息为例
Elf64_Rela<0x2F90, 0xc00000402, 0>, IDA已经解析出来了,这个结构体中0x2f90是个偏移,指向的地址就是got表, 0xc00000402这个数据其实是一个info,会解析出符号索引,通过这个索引拿到符号名(__open_2),也可以拿到这个重定位信息类型。
ELFE(R_TYPE)与ELFW(R_SYM)宏定义在libc/kernel/uapi/linux/elf.h中
刚才提到的0x2f90这个偏移也贴个图吧
linker重定位修复的数据就包括got表,比如0x2f90这个地方,使用8个字节存放了__open_2函数的真实地址(64位系统需要8个字节存放一个地址,这个地址的数据类型简单理解为void*)。
关键的地方就在这里,既然linker通过重定位,将0x2f90这个地方的数据改了。那我们也仿照linker搞一个重定位的修复,将这个地方的数据改为我们的函数地址,是不是就可以实现hook了。答案是yes。
上述文件格式的分析,都是基于so库的静态分析。所有的偏移地址,都是一个相对地址,我们只要拿到so库在内存中加载的基址加上这个偏移,就可以了。
具体的代码百度一大堆,大家自行实现。这里简单的贴个图,看看maps文件
比如要hook的libtestLib.so库
base地址为77b61f6000,open_2在got表的偏移地址为0x2F90,我们通过将base + offset这个内存块的数据改为我们的函数地址就可以实现__open_2的hook了。
为什么是targetsdk<= 23,继续查看linker的源码
bionic/linker/linker.cpp
bionic/linker/linker.cpp
dlopen函数最终会调用到linker中的do_dlopen,do_dlopen的返回值为soinfo->to_handle()
void* soinfo::to_handle()这个函数中明确了targetsdk <= 23返回this(即so info),否则会通过get_handle返回一个随机值。
来看看soinfo结构体:
省略了很多,可以查看源码(bionic/linker/linker.h)
soinfo中可以拿到phdr*(程序头表), phnum(程序头个数), base(装载基址), size(装载所需空间)等等。
linker源码文件结构图,便于大家理解关键文件
目前只简单实现了arch64的got表重定位hook。下面是一部分demo源码
__open_2_hook函数中特别的加上了一行log,打印了文件路径
__open_2_hook函数中打印的文件路径,其实是libtestLib.so访问的。运行程序后发现确实打印了相关日志:
static void testOpen(JNIEnv
*
env, jclass clazz, jstring jPath) {
const char
*
cPath
=
env
-
>GetStringUTFChars(jPath, JNI_FALSE);
int
fd
=
open
(cPath, O_RDONLY);
LOGD(
"open %s fd: %d"
, cPath, fd);
if
(fd >
0
) close(fd);
env
-
>ReleaseStringUTFChars(jPath, cPath);
}
static void testOpen(JNIEnv
*
env, jclass clazz, jstring jPath) {
const char
*
cPath
=
env
-
>GetStringUTFChars(jPath, JNI_FALSE);
int
fd
=
open
(cPath, O_RDONLY);
LOGD(
"open %s fd: %d"
, cPath, fd);
if
(fd >
0
) close(fd);
env
-
>ReleaseStringUTFChars(jPath, cPath);
}
admin@C02D7132MD6R ~
%
hexdump
-
C
-
n
20
~
/
Downloads
/
libart.so
00000000
7f
45
4c
46
02
01
01
00
00
00
00
00
00
00
00
00
|.ELF............|
00000010
03
00
b7
00
|....|
00000014
admin@C02D7132MD6R ~
%
admin@C02D7132MD6R ~
%
hexdump
-
C
-
n
20
~
/
Downloads
/
libart.so
00000000
7f
45
4c
46
02
01
01
00
00
00
00
00
00
00
00
00
|.ELF............|
00000010
03
00
b7
00
|....|
00000014
admin@C02D7132MD6R ~
%
admin@C02D7132MD6R bionic
%
vim libc
/
kernel
/
uapi
/
linux
/
elf.h
admin@C02D7132MD6R bionic
%
admin@C02D7132MD6R bionic
%
admin@C02D7132MD6R bionic
%
vim libc
/
kernel
/
uapi
/
linux
/
elf.h
admin@C02D7132MD6R bionic
%
admin@C02D7132MD6R bionic
%
/
/
通过pread64将文件头的内容读到内存header_中
bool
ElfReader::ReadElfHeader() {
ssize_t rc
=
TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
if
(rc <
0
) {
DL_ERR(
"can't read file \"%s\": %s"
, name_.c_str(), strerror(errno));
return
false;
}
if
(rc !
=
sizeof(header_)) {
DL_ERR(
"\"%s\" is too small to be an ELF executable: only found %zd bytes"
, name_.c_str(),
static_cast<size_t>(rc));
return
false;
}
return
true;
}
/
/
校验elf文件头
bool
ElfReader::VerifyElfHeader() {
/
/
1.
校验魔数信息
if
(memcmp(header_.e_ident, ELFMAG, SELFMAG) !
=
0
) {
DL_ERR(
"\"%s\" has bad ELF magic"
, name_.c_str());
return
false;
}
/
/
2.
校验文件类别,
64
位运行时只能加载
64
位so库,
32
位运行时只能加载
32
位so库
/
/
Try to give a clear diagnostic
for
ELF
class
mismatches, since they're
/
/
an easy mistake to make during the
32
-
bit
/
64
-
bit transition period.
int
elf_class
=
header_.e_ident[EI_CLASS];
if
(elf_class !
=
ELFCLASS64) {
if
(elf_class
=
=
ELFCLASS32) {
DL_ERR(
"\"%s\" is 32-bit instead of 64-bit"
, name_.c_str());
}
else
{
DL_ERR(
"\"%s\" has unknown ELF class: %d"
, name_.c_str(), elf_class);
}
return
false;
}
if
(elf_class !
=
ELFCLASS32) {
if
(elf_class
=
=
ELFCLASS64) {
DL_ERR(
"\"%s\" is 64-bit instead of 32-bit"
, name_.c_str());
}
else
{
DL_ERR(
"\"%s\" has unknown ELF class: %d"
, name_.c_str(), elf_class);
}
return
false;
}
/
/
3.
检验大小端对齐方式,目前安卓上为小端对齐
if
(header_.e_ident[EI_DATA] !
=
ELFDATA2LSB) {
DL_ERR(
"\"%s\" not little-endian: %d"
, name_.c_str(), header_.e_ident[EI_DATA]);
return
false;
}
/
/
4.
校验文件类型是否为动态库
if
(header_.e_type !
=
ET_DYN) {
DL_ERR(
"\"%s\" has unexpected e_type: %d"
, name_.c_str(), header_.e_type);
return
false;
}
/
/
5.
校验版本号,安卓上目前只能是EV_CURRENT
if
(header_.e_version !
=
EV_CURRENT) {
DL_ERR(
"\"%s\" has unexpected e_version: %d"
, name_.c_str(), header_.e_version);
return
false;
}
/
/
6.
校验machine
if
(header_.e_machine !
=
GetTargetElfMachine()) {
DL_ERR(
"\"%s\" has unexpected e_machine: %d"
, name_.c_str(), header_.e_machine);
return
false;
}
return
true;
}
/
/
通过pread64将文件头的内容读到内存header_中
bool
ElfReader::ReadElfHeader() {
ssize_t rc
=
TEMP_FAILURE_RETRY(pread64(fd_, &header_, sizeof(header_), file_offset_));
if
(rc <
0
) {
DL_ERR(
"can't read file \"%s\": %s"
, name_.c_str(), strerror(errno));
return
false;
}
if
(rc !
=
sizeof(header_)) {
DL_ERR(
"\"%s\" is too small to be an ELF executable: only found %zd bytes"
, name_.c_str(),
static_cast<size_t>(rc));
return
false;
}
return
true;
}
/
/
校验elf文件头
bool
ElfReader::VerifyElfHeader() {
/
/
1.
校验魔数信息
if
(memcmp(header_.e_ident, ELFMAG, SELFMAG) !
=
0
) {
DL_ERR(
"\"%s\" has bad ELF magic"
, name_.c_str());
return
false;
}
/
/
2.
校验文件类别,
64
位运行时只能加载
64
位so库,
32
位运行时只能加载
32
位so库
/
/
Try to give a clear diagnostic
for
ELF
class
mismatches, since they're
/
/
an easy mistake to make during the
32
-
bit
/
64
-
bit transition period.
int
elf_class
=
header_.e_ident[EI_CLASS];
if
(elf_class !
=
ELFCLASS64) {
if
(elf_class
=
=
ELFCLASS32) {
DL_ERR(
"\"%s\" is 32-bit instead of 64-bit"
, name_.c_str());
}
else
{
DL_ERR(
"\"%s\" has unknown ELF class: %d"
, name_.c_str(), elf_class);
}
return
false;
}
if
(elf_class !
=
ELFCLASS32) {
if
(elf_class
=
=
ELFCLASS64) {
DL_ERR(
"\"%s\" is 64-bit instead of 32-bit"
, name_.c_str());
}
else
{
DL_ERR(
"\"%s\" has unknown ELF class: %d"
, name_.c_str(), elf_class);
}
return
false;
}
/
/
3.
检验大小端对齐方式,目前安卓上为小端对齐
if
(header_.e_ident[EI_DATA] !
=
ELFDATA2LSB) {
DL_ERR(
"\"%s\" not little-endian: %d"
, name_.c_str(), header_.e_ident[EI_DATA]);
return
false;
}
/
/
4.
校验文件类型是否为动态库
if
(header_.e_type !
=
ET_DYN) {
DL_ERR(
"\"%s\" has unexpected e_type: %d"
, name_.c_str(), header_.e_type);
return
false;
}
/
/
5.
校验版本号,安卓上目前只能是EV_CURRENT
if
(header_.e_version !
=
EV_CURRENT) {
DL_ERR(
"\"%s\" has unexpected e_version: %d"
, name_.c_str(), header_.e_version);
return
false;
}
/
/
6.
校验machine
if
(header_.e_machine !
=
GetTargetElfMachine()) {
DL_ERR(
"\"%s\" has unexpected e_machine: %d"
, name_.c_str(), header_.e_machine);
return
false;
}
return
true;
}
bool
ElfReader::ReadProgramHeaders() {
phdr_num_
=
header_.e_phnum;
/
/
Like the kernel, we only accept program header tables that
/
/
are smaller than
64KiB
.
if
(phdr_num_ <
1
|| phdr_num_ >
65536
/
sizeof(ElfW(Phdr))) {
DL_ERR(
"\"%s\" has invalid e_phnum: %zd"
, name_.c_str(), phdr_num_);
return
false;
}
/
/
Boundary checks
size_t size
=
phdr_num_
*
sizeof(ElfW(Phdr));
if
(!CheckFileRange(header_.e_phoff, size, alignof(ElfW(Phdr)))) {
DL_ERR_AND_LOG(
"\"%s\" has invalid phdr offset/size: %zu/%zu"
,
name_.c_str(),
static_cast<size_t>(header_.e_phoff),
size);
return
false;
}
/
/
将elf文件的程序头表内容映射到内存中,程序头表的文件偏移为header_.e_phoff
if
(!phdr_fragment_.
Map
(fd_, file_offset_, header_.e_phoff, size)) {
DL_ERR(
"\"%s\" phdr mmap failed: %s"
, name_.c_str(), strerror(errno));
return
false;
}
phdr_table_
=
static_cast<ElfW(Phdr)
*
>(phdr_fragment_.data());
return
true;
}
bool
ElfReader::ReadProgramHeaders() {
phdr_num_
=
header_.e_phnum;
/
/
Like the kernel, we only accept program header tables that
/
/
are smaller than
64KiB
.
if
(phdr_num_ <
1
|| phdr_num_ >
65536
/
sizeof(ElfW(Phdr))) {
DL_ERR(
"\"%s\" has invalid e_phnum: %zd"
, name_.c_str(), phdr_num_);
return
false;
}
/
/
Boundary checks
size_t size
=
phdr_num_
*
sizeof(ElfW(Phdr));
if
(!CheckFileRange(header_.e_phoff, size, alignof(ElfW(Phdr)))) {
DL_ERR_AND_LOG(
"\"%s\" has invalid phdr offset/size: %zu/%zu"
,
name_.c_str(),
static_cast<size_t>(header_.e_phoff),
size);
return
false;
}
/
/
将elf文件的程序头表内容映射到内存中,程序头表的文件偏移为header_.e_phoff
if
(!phdr_fragment_.
Map
(fd_, file_offset_, header_.e_phoff, size)) {
DL_ERR(
"\"%s\" phdr mmap failed: %s"
, name_.c_str(), strerror(errno));
return
false;
}
phdr_table_
=
static_cast<ElfW(Phdr)
*
>(phdr_fragment_.data());
return
true;
}
bool
ElfReader::ReadSectionHeaders() {
shdr_num_
=
header_.e_shnum;
if
(shdr_num_
=
=
0
) {
DL_ERR_AND_LOG(
"\"%s\" has no section headers"
, name_.c_str());
return
false;
}
size_t size
=
shdr_num_
*
sizeof(ElfW(Shdr));
if
(!CheckFileRange(header_.e_shoff, size, alignof(const ElfW(Shdr)))) {
DL_ERR_AND_LOG(
"\"%s\" has invalid shdr offset/size: %zu/%zu"
,
name_.c_str(),
static_cast<size_t>(header_.e_shoff),
size);
return
false;
}
/
/
将elf文件的节头表内容映射到内存中,节头表的文件偏移为header_.e_shoff
if
(!shdr_fragment_.
Map
(fd_, file_offset_, header_.e_shoff, size)) {
DL_ERR(
"\"%s\" shdr mmap failed: %s"
, name_.c_str(), strerror(errno));
return
false;
}
shdr_table_
=
static_cast<const ElfW(Shdr)
*
>(shdr_fragment_.data());
return
true;
}
bool
ElfReader::ReadSectionHeaders() {
shdr_num_
=
header_.e_shnum;
if
(shdr_num_
=
=
0
) {
DL_ERR_AND_LOG(
"\"%s\" has no section headers"
, name_.c_str());
return
false;
}
size_t size
=
shdr_num_
*
sizeof(ElfW(Shdr));
if
(!CheckFileRange(header_.e_shoff, size, alignof(const ElfW(Shdr)))) {
DL_ERR_AND_LOG(
"\"%s\" has invalid shdr offset/size: %zu/%zu"
,
name_.c_str(),
static_cast<size_t>(header_.e_shoff),
size);
return
false;
}
/
/
将elf文件的节头表内容映射到内存中,节头表的文件偏移为header_.e_shoff
if
(!shdr_fragment_.
Map
(fd_, file_offset_, header_.e_shoff, size)) {
DL_ERR(
"\"%s\" shdr mmap failed: %s"
, name_.c_str(), strerror(errno));
return
false;
}
shdr_table_
=
static_cast<const ElfW(Shdr)
*
>(shdr_fragment_.data());
return
true;
}
ElfW(Word)
type
=
ELFW(R_TYPE)(rel
-
>r_info);
/
/
符号的类型
ElfW(Word) sym
=
ELFW(R_SYM)(rel
-
>r_info);
/
/
符号的索引
ElfW(Word)
type
=
ELFW(R_TYPE)(rel
-
>r_info);
/
/
符号的类型
ElfW(Word) sym
=
ELFW(R_SYM)(rel
-
>r_info);
/
/
符号的索引
template<typename ElfRelIteratorT>
bool
soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
for
(size_t idx
=
0
; rel_iterator.has_next();
+
+
idx) {
const auto rel
=
rel_iterator.
next
();
if
(rel
=
=
nullptr) {
return
false;
}
ElfW(Word)
type
=
ELFW(R_TYPE)(rel
-
>r_info);
ElfW(Word) sym
=
ELFW(R_SYM)(rel
-
>r_info);
ElfW(Addr) reloc
=
static_cast<ElfW(Addr)>(rel
-
>r_offset
+
load_bias);
ElfW(Addr) sym_addr
=
0
;
const char
*
sym_name
=
nullptr;
ElfW(Addr) addend
=
get_addend(rel, reloc);
DEBUG(
"Processing \"%s\" relocation at index %zd"
, get_realpath(), idx);
if
(
type
=
=
R_GENERIC_NONE) {
continue
;
}
const ElfW(Sym)
*
s
=
nullptr;
soinfo
*
lsi
=
nullptr;
if
(sym !
=
0
) {
sym_name
=
get_string(symtab_[sym].st_name);
...
...
}
switch (
type
) {
/
/
arch64的导入符号重定位就在这里,我们可以直接将linker的relocate源码拷贝过来,拿来所用
case R_GENERIC_JUMP_SLOT:
count_relocation(kRelocAbsolute);
MARK(rel
-
>r_offset);
TRACE_TYPE(RELO,
"RELO JMP_SLOT %16p <- %16p %s\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(sym_addr
+
addend), sym_name);
*
reinterpret_cast<ElfW(Addr)
*
>(reloc)
=
(sym_addr
+
addend);
break
;
case R_GENERIC_GLOB_DAT:
count_relocation(kRelocAbsolute);
MARK(rel
-
>r_offset);
TRACE_TYPE(RELO,
"RELO GLOB_DAT %16p <- %16p %s\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(sym_addr
+
addend), sym_name);
*
reinterpret_cast<ElfW(Addr)
*
>(reloc)
=
(sym_addr
+
addend);
break
;
case R_GENERIC_RELATIVE:
count_relocation(kRelocRelative);
MARK(rel
-
>r_offset);
TRACE_TYPE(RELO,
"RELO RELATIVE %16p <- %16p\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(load_bias
+
addend));
*
reinterpret_cast<ElfW(Addr)
*
>(reloc)
=
(load_bias
+
addend);
break
;
}
template<typename ElfRelIteratorT>
bool
soinfo::relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
for
(size_t idx
=
0
; rel_iterator.has_next();
+
+
idx) {
const auto rel
=
rel_iterator.
next
();
if
(rel
=
=
nullptr) {
return
false;
}
ElfW(Word)
type
=
ELFW(R_TYPE)(rel
-
>r_info);
ElfW(Word) sym
=
ELFW(R_SYM)(rel
-
>r_info);
ElfW(Addr) reloc
=
static_cast<ElfW(Addr)>(rel
-
>r_offset
+
load_bias);
ElfW(Addr) sym_addr
=
0
;
const char
*
sym_name
=
nullptr;
ElfW(Addr) addend
=
get_addend(rel, reloc);
DEBUG(
"Processing \"%s\" relocation at index %zd"
, get_realpath(), idx);
if
(
type
=
=
R_GENERIC_NONE) {
continue
;
}
const ElfW(Sym)
*
s
=
nullptr;
soinfo
*
lsi
=
nullptr;
if
(sym !
=
0
) {
sym_name
=
get_string(symtab_[sym].st_name);
...
...
}
switch (
type
) {
/
/
arch64的导入符号重定位就在这里,我们可以直接将linker的relocate源码拷贝过来,拿来所用
case R_GENERIC_JUMP_SLOT:
count_relocation(kRelocAbsolute);
MARK(rel
-
>r_offset);
TRACE_TYPE(RELO,
"RELO JMP_SLOT %16p <- %16p %s\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(sym_addr
+
addend), sym_name);
*
reinterpret_cast<ElfW(Addr)
*
>(reloc)
=
(sym_addr
+
addend);
break
;
case R_GENERIC_GLOB_DAT:
count_relocation(kRelocAbsolute);
MARK(rel
-
>r_offset);
TRACE_TYPE(RELO,
"RELO GLOB_DAT %16p <- %16p %s\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(sym_addr
+
addend), sym_name);
*
reinterpret_cast<ElfW(Addr)
*
>(reloc)
=
(sym_addr
+
addend);
break
;
case R_GENERIC_RELATIVE:
count_relocation(kRelocRelative);
MARK(rel
-
>r_offset);
TRACE_TYPE(RELO,
"RELO RELATIVE %16p <- %16p\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(load_bias
+
addend));
*
reinterpret_cast<ElfW(Addr)
*
>(reloc)
=
(load_bias
+
addend);
break
;
}
admin@C02D7132MD6R bionic
%
adb shell
angler:
/
$ ps |grep superhook
u0_a69
7680
540
1620436
71348
SyS_epoll_
0000000000
S com.example.superhook
angler:
/
$ su
angler:
/
12c00000
-
12e08000
rw
-
p
00000000
00
:
04
16462
/
dev
/
ashmem
/
dalvik
-
main space (deleted)
12e08000
-
13008000
rw
-
p
00208000
00
:
04
16462
/
dev
/
ashmem
/
dalvik
-
main space (deleted)
13008000
-
1ec00000
-
-
-
p
00408000
00
:
04
16462
/
dev
/
ashmem
/
dalvik
-
main space (deleted)
32c00000
-
32c01000
rw
-
p
00000000
00
:
04
16463
/
dev
/
ashmem
/
dalvik
-
main space
1
(deleted)
32c01000
-
3ec00000
-
-
-
p
00001000
00
:
04
16463
/
dev
/
ashmem
/
dalvik
-
main space
1
(deleted)
6f7b1000
-
6fa50000
rw
-
p
00000000
fd:
00
278001
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot.art
6fa50000
-
6fbcc000
rw
-
p
00000000
fd:
00
278002
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
core
-
libart.art
6fbcc000
-
6fc01000
rw
-
p
00000000
fd:
00
278003
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
conscrypt.art
6fc01000
-
6fc3a000
rw
-
p
00000000
fd:
00
278004
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
okhttp.art
6fc3a000
-
6fc3d000
rw
-
p
00000000
fd:
00
278005
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
core
-
junit.art
6fc3d000
-
6fc83000
rw
-
p
00000000
fd:
00
278006
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
bouncycastle.art
6fc83000
-
6fcc5000
rw
-
p
00000000
fd:
00
278007
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
ext.art
6fcc5000
-
70484000
rw
-
p
00000000
fd:
00
278008
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
framework.art
70484000
-
70516000
rw
-
p
00000000
fd:
00
278009
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
telephony
-
common.art
70516000
-
7051e000
rw
-
p
00000000
fd:
00
278010
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
voip
-
common.art
7051e000
-
7052a000
rw
-
p
00000000
fd:
00
278011
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
ims
-
common.art
7052a000
-
7054d000
rw
-
p
00000000
fd:
00
278012
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
apache
-
xml.art
7054d000
-
70574000
rw
-
p
00000000
fd:
00
278013
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
org.apache.http.legacy.boot.art
77b4a3c000
-
77b4a59000
r
-
-
s
00000000
103
:
0b
837
/
system
/
fonts
/
NotoNaskhArabicUI
-
Regular.ttf
77b4a59000
-
77b4aaa000
r
-
-
s
00000000
103
:
0b
949
/
system
/
fonts
/
Roboto
-
BoldItalic.ttf
77b4aaa000
-
77b4af5000
r
-
-
s
00000000
103
:
0b
948
/
system
/
fonts
/
Roboto
-
Bold.ttf
77b4af5000
-
77b4b46000
r
-
-
s
00000000
103
:
0b
947
/
system
/
fonts
/
Roboto
-
BlackItalic.ttf
77b4b46000
-
77b4b91000
r
-
-
s
00000000
103
:
0b
946
/
system
/
fonts
/
Roboto
-
Black.ttf
77b4b91000
-
77b4be2000
r
-
-
s
00000000
103
:
0b
954
/
system
/
fonts
/
Roboto
-
MediumItalic.ttf
77b4be2000
-
77b4c2d000
r
-
-
s
00000000
103
:
0b
953
/
system
/
fonts
/
Roboto
-
Medium.ttf
77b4c2d000
-
77b4c7e000
r
-
-
s
00000000
103
:
0b
950
/
system
/
fonts
/
Roboto
-
Italic.ttf
77b4c7e000
-
77b4cc9000
r
-
-
s
00000000
103
:
0b
955
/
system
/
fonts
/
Roboto
-
Regular.ttf
77b4cc9000
-
77b61f6000
r
-
-
s
00000000
103
:
0b
2205
/
system
/
usr
/
icu
/
icudt56l.dat
77b61f6000
-
77b61f8000
r
-
xp
00000000
fd:
00
531594
/
data
/
app
/
com.example.superhook
-
1
/
lib
/
arm64
/
libtestLib.so
77b61f8000
-
77b61f9000
r
-
-
p
00001000
fd:
00
531594
/
data
/
app
/
com.example.superhook
-
1
/
lib
/
arm64
/
libtestLib.so
77b61f9000
-
77b61fa000
rw
-
p
00002000
fd:
00
531594
/
data
/
app
/
com.example.superhook
-
1
/
lib
/
arm64
/
libtestLib.so
77b6200000
-
77b6400000
rw
-
p
00000000
00
:
00
0
[anon:libc_malloc]
77b6400000
-
77b6600000
rw
-
p
00000000
00
:
00
0
[anon:libc_malloc]
77b6600000
-
77b6602000
r
-
-
s
00000000
103
:
0b
910
/
system
/
fonts
/
NotoSansRejang
-
Regular.ttf
77b6602000
-
77b660b000
r
-
-
s
00000000
103
:
0b
883
/
system
/
fonts
/
NotoSansKhmerUI
-
Bold.ttf
77b660b000
-
77b6619000
r
-
-
s
00000000
103
:
0b
894
/
system
/
fonts
/
NotoSansMalayalamUI
-
Bold.ttf
77b6619000
-
77b666b000
r
-
-
s
00000000
103
:
0b
952
/
system
/
fonts
/
Roboto
-
LightItalic.ttf
77b666b000
-
77b66b7000
r
-
-
s
00000000
103
:
0b
951
/
system
/
fonts
/
Roboto
-
Light.ttf
77b66b7000
-
77b66b8000
r
-
-
p
00000000
00
:
00
0
[anon:linker_alloc]
77b66b8000
-
77b66d8000
rw
-
p
00000000
00
:
04
16053
/
dev
/
ashmem
/
dalvik
-
CompilerMetadata (deleted)
77b66d8000
-
77b66f8000
rw
-
p
00000000
00
:
04
16052
/
dev
/
ashmem
/
dalvik
-
CompilerMetadata (deleted)
admin@C02D7132MD6R bionic
%
adb shell
angler:
/
$ ps |grep superhook
u0_a69
7680
540
1620436
71348
SyS_epoll_
0000000000
S com.example.superhook
angler:
/
$ su
angler:
/
12c00000
-
12e08000
rw
-
p
00000000
00
:
04
16462
/
dev
/
ashmem
/
dalvik
-
main space (deleted)
12e08000
-
13008000
rw
-
p
00208000
00
:
04
16462
/
dev
/
ashmem
/
dalvik
-
main space (deleted)
13008000
-
1ec00000
-
-
-
p
00408000
00
:
04
16462
/
dev
/
ashmem
/
dalvik
-
main space (deleted)
32c00000
-
32c01000
rw
-
p
00000000
00
:
04
16463
/
dev
/
ashmem
/
dalvik
-
main space
1
(deleted)
32c01000
-
3ec00000
-
-
-
p
00001000
00
:
04
16463
/
dev
/
ashmem
/
dalvik
-
main space
1
(deleted)
6f7b1000
-
6fa50000
rw
-
p
00000000
fd:
00
278001
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot.art
6fa50000
-
6fbcc000
rw
-
p
00000000
fd:
00
278002
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
core
-
libart.art
6fbcc000
-
6fc01000
rw
-
p
00000000
fd:
00
278003
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
conscrypt.art
6fc01000
-
6fc3a000
rw
-
p
00000000
fd:
00
278004
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
okhttp.art
6fc3a000
-
6fc3d000
rw
-
p
00000000
fd:
00
278005
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
core
-
junit.art
6fc3d000
-
6fc83000
rw
-
p
00000000
fd:
00
278006
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
bouncycastle.art
6fc83000
-
6fcc5000
rw
-
p
00000000
fd:
00
278007
/
data
/
dalvik
-
cache
/
arm64
/
system@framework@boot
-
ext.art
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-5-27 19:47
被whulzz编辑
,原因: 添加丢失图片以及附加源码地址