0x0 前言
现在很多安全插件,都会用本地文件和系统的内存进行校验,来防止修改code内存的hook,
或者一些其他的原因,无法注入,无法hook,又不想麻烦的编译android源码,
那我要怎么办呢?
用伪造so的方式注入,
尤其对注入时机比较关注的玩家,这种注入方式最棒
如果hook系统的so,则需要root,源码在0x5部分
若是有图片看不清,那就下载附件吧
-------------------------------------------------------------------
0x1 选择目标so文件,得到导出函数列表
比如我在android 7中,想注入dex2oat来达到不可告人的目的,
我需要用ida打开dex2oat,看看dex2oat都需要哪些so
然后选择目标so文件,遵循如下几个标准,
如果能遵守标准,注入成功的几率就大一些
a.目标so的导出函数最好全部是 C 导出(不强求)
C++的导出:_Z32register_android_hardware_CameraP7_JNIEnv
C导出: register_android_hardware_Camera
b.导出的函数越少越好(不强求)
根据上面的标准,我认为伪造libsigchain.so,最靠谱。
然后需要获得libsigchain.so的导出函数列表,步骤如下
在linux用 readelf -s libsigchain.so 得到导出函数列表,
或者在ida的Export窗口复制粘贴。
这里要说一下,如果so中的导出函数是C++格式的,那么从ida窗口复制出来的导出函数列表,就是不准确的
这里我用 readelf -s libsigchain.so | grep "13 " 得到libsigchain.so的导出函数列表
用notepad++,处理一下文本
得到导出函数表
InvokeUserSignalHandler
ClaimSignalChain
UnclaimSignalChain
EnsureFrontOfChain
InitializeSignalChain
SetSpecialSignalHandlerFn
------------------------------------------------------------------------------
0x2 使用方法
打开notepad++,新建文档,把导出函数表复制进去
复制 __attribute__((visibility("default"))) JmpStruct
用上面介绍的按住alt的方法,一次性粘贴到,导出函数列表前面
并用同样的方法,在末尾把 分号“ ; ” 加上
上面的步骤用excel也能轻松做到
经过处理后,得到
__attribute__((visibility("default"))) JmpStruct InvokeUserSignalHandler;
__attribute__((visibility("default"))) JmpStruct ClaimSignalChain;
__attribute__((visibility("default"))) JmpStruct UnclaimSignalChain;
__attribute__((visibility("default"))) JmpStruct EnsureFrontOfChain;
__attribute__((visibility("default"))) JmpStruct InitializeSignalChain;
__attribute__((visibility("default"))) JmpStruct SetSpecialSignalHandlerFn;
打开hook_demo.c,把上面的信息,粘贴到对应的位置
用同样的方法得到GetProcessAddress( xxxxx );
GetProcessAddress( InvokeUserSignalHandler );
GetProcessAddress( ClaimSignalChain );
GetProcessAddress( UnclaimSignalChain );
GetProcessAddress( EnsureFrontOfChain );
GetProcessAddress( InitializeSignalChain );
GetProcessAddress( SetSpecialSignalHandlerFn );
并把得到的信息,复制粘贴到,hook_demo.c的my_init(void)函数中的对应位置
并把,原始libsigchain.so,复制到/system/lib/libsigchain_me.so
如果要跑在Android 7上,由于android的本身的安全性的要求,还需要,把引用的so放到导入表中,具体方法参见Android.mk
----------------------------------------------------------------------------------
0x3 编译并替换/system/lib/libsigchain.so
adb push进去就行了,然后重启机器,让替换生效,
(别忘了把原始libsigchain.so,复制成/system/lib/libsigchain_me.so)
-----------------------------------------------------------------------------------
0x4 原理部分
先来看一段汇编代码
push {pc} ;把pc入栈(1)
push {r0} ;把r0入栈,备份r0(2)
push {pc} ;把pc入栈(3)
pop {r0} ;把(3)处的pc值赋值给r0
ldr r0,[r0,#16] ;读取xxxxxxx到r0,xxxxxxx之后会被替换成函数地址
str r0,[sp,#8] ;用xxxxxxx,替换(1)处的栈中的pc
pop {r0} ;还原r0(2)
pop {pc} ;跳转到xxxxxxx函数开始执行
xxxxxxx ;指向函数的地址
上面的代码,执行之后,会跳转到xxxxxxx函数执行,
这里假设此时的xxxxxxx,就是 原始的libsigchain.so 中的 原始函数InvokeUserSignalHandler
我们在 伪造的libsigchain.so 中,导出 伪造的InvokeUserSignalHandler 函数,
让伪造的InvokeUserSignalHandler在一开始就执行上面的汇编代码,
那么执行之后,就自然而然的跳转到原始的InvokeUserSignalHandler中了,
这样一来,我们的so也注入进去了,原始的系统函数也能得到执行,我们的目的就达到了
在代码中的,JmpCode部分,就是上面的汇编
如何伪造的InvokeUserSignalHandler函数?
在代码中,我定义了一个JmpStruct结构
我需要,
把 JmpCode 赋值给 JmpStruct.code
把 原始的InvokeUserSignalHandler地址,赋值给 JmpStruct.address
然后,再在代码中,用 JmpStruct 声明 冒牌货InvokeUserSignalHandler 就好了
-----------------------------------------------------------------------------------------
0x5 show me the fuck code
链接: https://pan.baidu.com/s/1hs7WWtu 密码: 9bmy
------------------------------------------------------------------------------------------
0x6 如何hook libEGL.so 中的 eglChooseConfig 函数?
这部分由于工作原因,我就不能放源码了,见谅
首先,我们把所有的libEGL.so的导出函数,都用JmpStruct声明,但是就是不声明eglChooseConfig
然后我们把所有的伪造的libEGL.so函数,都用GetProcessAddress填充一下,但是就是不填充eglChooseConfig
然后我们自己实现一个eglChooseConfig函数
本文由看雪论坛 zeif 原创 转载请注明来自看雪社区