app的启动在很早期的阶段会经由zygote进程fork出子进程, 该过程在android源码中搜索nativeForkAndSpecialize
可以找到.
通过lief之类的工具感染android系统库令zygote加载我们的so, 并在so中用pthread_atfork
捕获fork行为, 之后可以进行app包名的判断, 然后干点啥 (比如加载frida-gadget).
在这个过程中有小踩了几个坑, 分别是:
较高版本的android的链接器命名空间机制导致不能将so随便放(比如/data/local/tmp/
),就算指定绝对路进行加载, 在开启了selinux的情况下仍然会报错找不到库从而加载失败. 解决方式可以看看 https://github.com/hack0z/byOpen 或者关闭selinux, 或者老老实实把库放在/system/lib(64)/
目录下面.
在fork之后不能马上进行用户或app的判断(此时还是root用户)和线程的创建(加载frida-gadget会创建线程), 否则会发生selinux_context的切换失败导致app无法启动. 解决方式是通过setitimer和signal延迟一段时间等它切换完了再执行. 在自机上测的是使用ITIMER_PROF的话等待60毫秒就可以了, 可以再长些因为之后还要等它将cmdline切换至app的进程名.
frida-gadget配置使用v8环境时在调用dlopen进行初始化时需要一个足够大的栈空间, 否则v8会初始化失败, 错误原因是栈空间不足, 可以通过手动指定一个足够大的栈空间解决.
源码见 https://github.com/tacesrever/easy-frida/tree/master/gadget
完整食用方式
编译 gadget-loader.cpp
可以使用自己常用的IDE新建一个android C++库项目导入gadget-loader.h
, gadget-loader.cpp
和 nlohmann/json.hpp
在/proc/zygote's pid/maps
中找一个看着顺眼的库, 以libpng.so为例
使用adb pull
将该库的32位与64位版本都pull下来, 先做个备份
使用lief分别为它们添加一个依赖库, 库名称可以随便起, 看自己喜好
鉴于使用现在的0.11.5版本的LIEF库注入android库会出现问题(参考issue#396),提一下当时使用的环境是LIEF版本为0.10.1,系统为android 9
如issue#396仍未解决,且加载修改后的android库出现bad relocation header
问题,可以使用如下代码对inject后的so进行修补:
将编译完后的gadget-loader
库名改为你起的名字, 和注入后的libpng.so, 下载下来改名后的frida-gadget.so一起用adb push放进/system/lib(64)/下面, 注意32位和64位的分别放一起,别放错了
参考gadget文档, 在/system/lib(64)/下分别新建与frida-gadget.so同名的扩展名为.config的文件, 内容为
运行adb shell pkill -f zygote
, 等待手机从黑屏重新恢复, 这一步不会断开adb连接, 如果万一这一步手机黑屏醒不过来就要用到备份的libpng.so恢复, 错误原因可以使用logcat自查.
等手机重新亮起来后运行adb shell ps -ef | grep zygote
得到zygote的pid, 再运行adb shell cat /proc/zygote的pid/maps | grep gadget-loader.so(你起的库名)
看到有输出就成功了.
import
lief
bin
=
lief.parse(
"libpng.so"
)
bin
.add_library(
"gadget-loader.so"
)
bin
.write(
"libpng.so"
)
import
lief
bin
=
lief.parse(
"libpng.so"
)
bin
.add_library(
"gadget-loader.so"
)
bin
.write(
"libpng.so"
)
import
lief
def
read_sleb128(content, offset):
value
=
0
len
=
0
shift
=
0
while
1
:
a_byte
=
content[offset]
offset
+
=
1
value
+
=
(a_byte &
0x7f
) << shift
shift
+
=
7
len
+
=
1
if
a_byte <
128
:
break
return
(value,
len
)
def
encode_leb128(value):
if
value
=
=
0
:
return
[
0
]
ret
=
[]
while
value !
=
0
:
a_byte
=
value &
0x7F
value >>
=
7
if
value >
0
:
a_byte |
=
0x80
ret.append(a_byte)
return
ret
def
add_library_for_androidso(target_path, libname):
output_path
=
target_path
+
".injected.so"
sofile
=
lief.parse(target_path)
if
sofile.
type
=
=
sofile.
type
.CLASS32:
addr_size
=
4
else
:
addr_size
=
8
sofile.add_library(libname)
sofile.write(output_path)
seg_relr
=
sofile.get_section(
".relr.dyn"
)
seg_relro
=
sofile.get_section(
".data.rel.ro"
)
sofile.patch_address(seg_relr.virtual_address, seg_relro.virtual_address, addr_size)
sofile.patch_address(seg_relro.virtual_address, seg_relro.virtual_address, addr_size)
seg_got
=
sofile.get_section(
".got"
)
seg_rel
=
None
if
sofile.
type
=
=
sofile.
type
.CLASS32:
seg_rel
=
sofile.get_section(
".rel.dyn"
)
else
:
seg_rel
=
sofile.get_section(
".rela.dyn"
)
content
=
seg_rel.content
current_pos
=
4
for
i
in
range
(
4
):
tmp_value,
len
=
read_sleb128(content, current_pos)
current_pos
+
=
len
encoded_gotaddr
=
encode_leb128(seg_got.virtual_address)
sofile.patch_address(seg_rel.virtual_address
+
current_pos, encoded_gotaddr)
for
e
in
sofile.dynamic_entries:
if
e.tag.value
=
=
0x6000000f
:
e.value
=
seg_rel.virtual_address
elif
e.tag.value
=
=
0x24
:
e.value
=
seg_relr.virtual_address
elif
e.tag.value
=
=
0x60000011
:
e.value
=
seg_rel.virtual_address
sofile.write(output_path)
import
lief
def
read_sleb128(content, offset):
value
=
0
len
=
0
shift
=
0
while
1
:
a_byte
=
content[offset]
offset
+
=
1
value
+
=
(a_byte &
0x7f
) << shift
shift
+
=
7
len
+
=
1
if
a_byte <
128
:
break
return
(value,
len
)
def
encode_leb128(value):
if
value
=
=
0
:
return
[
0
]
ret
=
[]
while
value !
=
0
:
a_byte
=
value &
0x7F
value >>
=
7
if
value >
0
:
a_byte |
=
0x80
ret.append(a_byte)
return
ret
def
add_library_for_androidso(target_path, libname):
output_path
=
target_path
+
".injected.so"
sofile
=
lief.parse(target_path)
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2022-4-21 10:56
被tacesrever编辑
,原因: 更新lief相关问题