bytedance / android-inline-hook

:fire: ShadowHook is an Android inline hook library which supports thumb, arm32 and arm64.
https://github.com/bytedance/android-inline-hook/tree/main/doc
MIT License
1.7k stars 295 forks source link

有一种特殊情况,不知道能否优化下,因为substrate是正常的(测试过安卓11,安卓13都是这样) #42

Open shuajinanhai opened 1 year ago

shuajinanhai commented 1 year ago

ShadowHook Version

1.0.7

Android OS Version

13

Android ABIs

armeabi-v7a

Device Manufacturers and Models

魅族18s 小米6

Describe the Bug

有一种特殊情况,不知道能否优化下,因为substrate是正常的

情景1:使用shadowhook_hook_func_addr hook u3d游戏里一个函数,不会崩溃 情景2:使用substrate hook u3d游戏里一个函数,然后再使用AndHook AKHookFunction hook该函数并不会崩溃 情景3:使用shadowhook_hook_func_addr hook u3d游戏里一个函数,然后再使用AndHook AKHookFunction hook该函数会崩溃

情况是这样的,拿到一个包,里面有别人用AndHook AKHookFunction hook过, 然后我想改一些东西,使用substrate hook该函数,并且时机比别人早,不会崩溃,也可以成功修改别人一些东西 但是使用shadowhook,同样是hook该函数,时机也比别人早,会崩溃

pid: 5624, tid: 5660, name: UnityMain >>> com.PoxelStudios.DudeTheftAuto <<< uid: 10142 signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xda7c9000 r0 af2a5a18 r1 db1f5000 r2 00000000 r3 dae4b450 r4 af2a5a18 r5 dae48c50 r6 af2bead0 r7 bf0cdc70 r8 af2a5a18 r9 00000003 r10 00000000 r11 dae4b468 ip 00000000 sp dae48c50 lr db9d1be8 pc da7c9000 backtrace: NOTE: Function names and BuildId information is missing for some frames due NOTE: to unreadable libraries. For unwinds of apps, only shared libraries NOTE: found under the lib/ directory are readable. NOTE: On this device, run setenforce 0 to make the libraries readable. NOTE: Unreadable libraries:

XMDS commented 1 year ago

@shuajinanhai 因为用了多个hook框架hook同一个位置。

AndHook的跳板指令和sub hook是一样的, 并且没有额外的其它处理,所以它们是兼容的,但是shadow hook虽然跳板指令一样,shared模式有一些额外处理,例如trampoline,所以导致冲突崩溃。 用unique模式试试。(顺便说下,如果是thumb 和arm32,sub hook其实备份了10/12字节,而shadow hook应该是8/10字节)

如果还是不兼容,不要使用多个不同的inline hook框架。 还有其他办法解决你目前的问题,例如使用plt/got hook。也可以hook 上级调用。或者先计算出and hook注入的代理函数地址,然后使用shadow hook注入,这样你在自己继续hook是完全兼容的

shuajinanhai commented 1 year ago

@shuajinanhai我最开始也有同样的问题,因为用了多个hook框架hook同一个位置。

AndHook的跳板指令和sub hook是一样的,而且没有前端的其他处理,所以它们是包容的,但是shadow hook虽然跳板指令一样,共享模式有一些前端处理,例如蹦床,所以导致冲击崩溃。使用独特的 模式试试。(顺便说下,如果是thumb 和arm32,sub hook其实现部分了10/12字节,而shadow hook应该是8/10字节)

如果还是不包括,不要使用多个不同的内联hook框架。 还有其他方法解决你目前的问题,例如使用plt/got hook。也可以使用hook上一级调用。先计算出并钩注输入的代理函数地址,然后使用shadow hook注册,这样你在自己继续hook是完全包容的

shared、unique两种模式我都试过,都会崩溃哈

XMDS commented 1 year ago

@shuajinanhai我最开始也有同样的问题,因为用了多个hook框架hook同一个位置。

AndHook的跳板指令和sub hook是一样的,而且没有前端的其他处理,所以它们是包容的,但是shadow hook虽然跳板指令一样,共享模式有一些前端处理,例如蹦床,所以导致冲击崩溃。使用独特的 模式试试。(顺便说下,如果是thumb 和arm32,sub hook其实现部分了10/12字节,而shadow hook应该是8/10字节)

如果还是不包括,不要使用多个不同的内联hook框架。 还有其他方法解决你目前的问题,例如使用plt/got hook。也可以使用hook上一级调用。先计算出并钩注输入的代理函数地址,然后使用shadow hook注册,这样你在自己继续hook是完全包容的

shared、unique两种模式我都试过,都会崩溃哈

你不应该同时使用多个inline hook项目。它们之间不兼容是必然的(简单的inlinehook框架除外),因为它们覆盖的指令字节数、跳板指令、对代理函数的处理不同。对于游戏hook你只使用subhook就够了,因为它很简单。另外,像我上面说的,您可以自己处理兼容,把别人使用AndHook AKHookFunction注入的代理函数地址取出来,在使用shadow hook注入。这样你就可以兼容只使用shadow hook框架

caikelun commented 1 year ago

理论上来说,只要各个 inlinehook 库的指令修复操作都正确,并且各个代理函数都正确调用了“原函数”,就可以同一个位置用多个 inlinehook 库先后 hook,不会有问题,后 hook 的代理函数会先执行。

@shuajinanhai 看你的描述,有点像是 AndHook 对 “shadowhook hook 之后的原函数头部的指令” 的修复有问题。armeabi-v7a 中,shadowhook 会先尝试用一个 4 字节的相对跳转,如果不可行,会用 8 或 10 字节的绝对跳转。substrate 应该始终是用绝对跳转,所以可能是 AndHook 对 “shadowhook 在原函数头部写入的 4 字节相对跳转” 的指令修复有问题。你可以关闭 shadowhook 的 “4 字节相对跳转功能” 再试试。(把 这里SH_CONFIG_TRY_WITH_EXIT 宏注释掉)。

另外,调试时建议用 shadowhook 的 unique mode。但是这个问题和 unique mode 还是 shared mode 应该没啥关系。

XMDS commented 1 year ago

理论上来说,只要各个 inlinehook 库的指令修复操作都正确,并且各个代理函数都正确调用了“原函数”,就可以同一个位置用多个 inlinehook 库先后 hook,不会有问题,后 hook 的代理函数会先执行。

@shuajinanhai 看你的描述,有点像是 AndHook 对 “shadowhook hook 之后的原函数头部的指令” 的修复有问题。armeabi-v7a 中,shadowhook 会先尝试用一个 4 字节的相对跳转,如果不可行,会用 8 或 10 字节的绝对跳转。substrate 应该始终是用绝对跳转,所以可能是 AndHook 对 “shadowhook 在原函数头部写入的 4 字节相对跳转” 的指令修复有问题。你可以关闭 shadowhook 的 “4 字节相对跳转功能” 再试试。(把 这里SH_CONFIG_TRY_WITH_EXIT 宏注释掉)。

另外,调试时建议用 shadowhook 的 unique mode。但是这个问题和 unique mode 还是 shared mode 应该没啥关系。

补充一下,substrate在thumb模式下不会和shadow hook兼容。因为substrate的跳板指令和shadow hook不同,它为了完美对齐备份并覆盖了函数前10/12字节。 substrate 跳板指令:

bx pc
nop
ldr pc, [pc, #-4](sub不管t还是a都使用arm指令)
addr

10字节就是去掉bx pc

它们是不兼容的

XMDS commented 1 year ago

@caikelun 关于备份指令我有一个问题。 shadow hook在4字节对齐的地址上备份8字节,否则则填充2字节nop 备份10字节。 那么它是如何处理下面这种函数首指令情况:

2+4+4+2
(2代表2字节T16指令,4代表T32指令)

这里如果首地址处于4字节对齐的情况下,备份8字节会导致第3个T32指令被截断。只能备份10字节,可是不应该是检测hook处地址处于不对齐情况下,才备份10字节吗? 当然还有其他情况,例如2+4+2+4,假设处于2字节对齐的地址上,备份10字节又会对最后一个T32指令截断。

caikelun commented 1 year ago

理论上来说,只要各个 inlinehook 库的指令修复操作都正确,并且各个代理函数都正确调用了“原函数”,就可以同一个位置用多个 inlinehook 库先后 hook,不会有问题,后 hook 的代理函数会先执行。 @shuajinanhai 看你的描述,有点像是 AndHook 对 “shadowhook hook 之后的原函数头部的指令” 的修复有问题。armeabi-v7a 中,shadowhook 会先尝试用一个 4 字节的相对跳转,如果不可行,会用 8 或 10 字节的绝对跳转。substrate 应该始终是用绝对跳转,所以可能是 AndHook 对 “shadowhook 在原函数头部写入的 4 字节相对跳转” 的指令修复有问题。你可以关闭 shadowhook 的 “4 字节相对跳转功能” 再试试。(把 这里SH_CONFIG_TRY_WITH_EXIT 宏注释掉)。 另外,调试时建议用 shadowhook 的 unique mode。但是这个问题和 unique mode 还是 shared mode 应该没啥关系。

补充一下,substrate在thumb模式下不会和shadow hook兼容。因为substrate的跳板指令和shadow hook不同,它为了完美对齐备份并覆盖了函数前10/12字节。 substrate 跳板指令:

bx pc
nop
ldr pc, [pc, #-4](sub不管t还是a都使用arm指令)
addr

10字节就是去掉bx pc

它们是不兼容的

嗯嗯,你是对的,确实可能不兼容。如果遇到这种指令序列中包含数据的情况,或者指令覆盖一半的情况,第二个 inlinehook 库就很难处理了,是可能会有问题。

caikelun commented 1 year ago

@caikelun 关于备份指令我有一个问题。 shadow hook在4字节对齐的地址上备份8字节,否则则填充2字节nop 备份10字节。 那么它是如何处理下面这种函数首指令情况:

2+4+4+2
(2代表2字节T16指令,4代表T32指令)

这里如果首地址处于4字节对齐的情况下,备份8字节会导致第3个T32指令被截断。只能备份10字节,可是不应该是检测hook处地址处于不对齐情况下,才备份10字节吗? 当然还有其他情况,例如2+4+2+4,假设处于2字节对齐的地址上,备份10字节又会对最后一个T32指令截断。

以你举的例子 2+4+4+2(首地址4字节对齐)。这时会:备份 8 字节(2 + 4 + 4的前半部分),修复前3个指令(2,4,4),修复操作会在一个新的内存区域写入一组指令序列,完成 2+4+4 的逻辑。调用原函数时,执行完修复区的指令序列后,会直接跳转到 2+4+4+2 中最后一个 2 指令继续执行。相当于 hook 后,被“截断”的 4 指令的后半部分就不会再被执行到了。unhook 时将备份的 8 字节恢复回去就行了。

在做指令修复前,是会判断下一个要修复的 thumb 指令是 2 字节还是 4 字节的。

shuajinanhai commented 1 year ago

注释掉可以了,没问题了,不过会导致另外一款游戏(arm64),安卓11 原来使用shadowhook 单独 hook没问题,注释后单独使用shadowhook hook会崩溃 pid: 4158, tid: 4232, name: UnityMain >>> com.WandaSoftware.TruckersofEurope3 <<< uid: 10452 signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 0x726d3366d4 (*pc=0x77b5b630)

substrate单独hook也是有问题,shadowhook没法完美多框架hook同一个函数,如果能再优化下就好了, substrate这款游戏是报错(arm64 安卓11测试) https://github.com/Rprop/And64InlineHook/issues/11

caikelun commented 1 year ago

注释掉可以了,没问题了,不过会导致另外一款游戏(arm64),安卓11 原来使用shadowhook 单独 hook没问题,注释后单独使用shadowhook hook会崩溃 pid: 4158, tid: 4232, name: UnityMain >>> com.WandaSoftware.TruckersofEurope3 <<< uid: 10452 signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 0x726d3366d4 (*pc=0x77b5b630)

substrate单独hook也是有问题,shadowhook没法完美多框架hook同一个函数,如果能再优化下就好了, substrate这款游戏是报错(arm64 安卓11测试) Rprop/And64InlineHook#11

感谢提供的信息。目前看来,情况大致如此:

问题原因:shadowhook 对 thumb 函数执行 hook 时,“4 字节相对跳转指令” 覆盖了 “后续的 4 字节指令的前 2 个字节”,导致指令截断。于是第二个 hook 库再 hook 时,在指令识别和修复时肯定就会有问题。

影响范围:只影响 thumb。

修复方案:对 thumb 函数执行 hook 时,在做指令覆盖时,始终保证后续指令不会被截断。

可能引起的问题:会增加跳板指令的长度,对 hook 瞬间的稳定性有负面影响,同时,对于原函数长度有了更长的要求。

预期的处理方案:增加新的 CONFIG 项(或者运行时初始化参数),可选的开启这种 “保证后续指令不会被截断” 的支持(默认不开启,shadowhook 还是以线上稳定性为优先的)。我们尽量在下个版本加上这个功能。

其他问题:要保证同一个函数被多个 hook 库先后 hook 都兼容,还有一些其他潜在的问题,比如 hook 时可能写入绝对地址值,这些值在后续 hook 时可能会被错误的识别为某些指令,于是被错误的修复。在现实场景中,函数指令的前几个字节中就出现“数值”的情况是极少发生的,所以 hook 库一般都不会去处理这种情况。如果要处理的话,那指令修复时解析原指令的逻辑就更复杂了。

shuajinanhai commented 1 year ago

大佬有空能能否帮忙修复下And64InlineHook,感觉And64InlineHook bug挺多的

---原始邮件--- 发件人: "Kelun @.> 发送时间: 2023年6月6日 15:18:00 收件人: @.>; 抄送: @.**@.>; 主题: Re: [bytedance/android-inline-hook] 有一种特殊情况,不知道能否优化下,因为substrate是正常的(测试过安卓11,安卓13都是这样) (Issue #42)

注释掉可以了,没问题了,不过会导致另外一款游戏(arm64),安卓11 原来使用shadowhook 单独 hook没问题,注释后单独使用shadowhook hook会崩溃 pid: 4158, tid: 4232, name: UnityMain >>> com.WandaSoftware.TruckersofEurope3 <<< uid: 10452 signal 4 (SIGILL), code 1 (ILL_ILLOPC), fault addr 0x726d3366d4 (*pc=0x77b5b630)

substrate单独hook也是有问题,shadowhook没法完美多框架hook同一个函数,如果能再优化下就好了, substrate这款游戏是报错(arm64 安卓11测试) Rprop/And64InlineHook#11

感谢提供的信息。目前看来,情况大致如此:

问题原因:shadowhook 对 thumb 函数执行 hook 时,“4 字节相对跳转指令” 覆盖了 “后续的 4 字节指令的前 2 个字节”,导致指令截断。于是第二个 hook 库再 hook 时,在指令识别和修复时肯定就会有问题。

影响范围:只影响 thumb。

修复方案:对 thumb 函数执行 hook 时,在做指令覆盖时,始终保证后续指令不会被截断。

可能引起的问题:会增加跳板指令的长度,对 hook 瞬间的稳定性有负面影响,同时,对于原函数长度有了更长的要求。

预期的处理方案:增加新的 CONFIG 项(或者运行时初始化参数),可选的开启这种 “保证后续指令不会被截断” 的支持(默认不开启,shadowhook 还是以线上稳定性为优先的)。我们尽量在下个版本加上这个功能。

其他问题:要保证同一个函数被多个 hook 库先后 hook 都兼容,还有一些其他潜在的问题,比如 hook 时可能写入绝对地址值,这些值在后续 hook 时可能会被错误的识别为某些指令,于是被错误的修复。在现实场景中,函数指令的前几个字节中就出现“数值”的情况是极少发生的,所以 hook 库一般都不会去处理这种情况。如果要处理的话,那指令修复时解析原指令的逻辑就更复杂了。

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>