Skip to content

Commit 22f2390

Browse files
committed
Resolve OEM inline hook veneers to prevent infinite recursion
On heavily customized Android ROMs, the OEM dynamically hotpatches libart.so methods using a 16-byte ARM64 veneer (`ldr x16/17, pc+8; br x16/17`). When Dobby attempts to hook these pre-applied veneers, its literal relocator handles the `ldr x, pc+offset` instruction incorrectly by reading the overwritten literal pool at runtime, resulting in an infinite recursion loop and a SIGSEGV (stack overflow) in system_server. This commit introduces a workaround for ARM64: we actively check if the target address starts with this known trampoline signature. If found, we extract the absolute address from `pc+8` and apply our hook directly to the OEM's real implementation. This safely chains our hooks onto the OEM's hotpatch framework. Currently experimental and primarily for testing purposes.
1 parent 8db1921 commit 22f2390

1 file changed

Lines changed: 30 additions & 0 deletions

File tree

native/include/core/native_api.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,38 @@ bool InstallNativeAPI(const lsplant::HookHandler &handler);
111111
*/
112112
void RegisterNativeLib(const std::string &library_name);
113113

114+
#if defined(__aarch64__)
115+
inline void *ResolveOEMVeneer(void *target) {
116+
if (!target) return nullptr;
117+
118+
auto *insn = static_cast<uint32_t *>(target);
119+
120+
// Check for 'ldr x17, pc+8' (0x58000051) followed by 'br x17' (0xd61f0220)
121+
if (insn[0] == 0x58000051 && insn[1] == 0xd61f0220) {
122+
void *real_target = *reinterpret_cast<void **>(insn + 2);
123+
LOGW("OEM veneer (x17) detected at {}, resolving to {}", target, real_target);
124+
return real_target;
125+
}
126+
127+
// Check for 'ldr x16, pc+8' (0x58000050) followed by 'br x16' (0xd61f0200)
128+
if (insn[0] == 0x58000050 && insn[1] == 0xd61f0200) {
129+
void *real_target = *reinterpret_cast<void **>(insn + 2);
130+
LOGW("OEM veneer (x16) detected at {}, resolving to {}", target, real_target);
131+
return real_target;
132+
}
133+
134+
return target;
135+
}
136+
#else
137+
inline void *ResolveOEMVeneer(void *target) { return target; }
138+
#endif
139+
114140
/**
115141
* @brief A wrapper around DobbyHook.
116142
*/
117143
inline int HookInline(void *original, void *replace, void **backup) {
144+
original = ResolveOEMVeneer(original);
145+
118146
if constexpr (kIsDebugBuild) {
119147
Dl_info info;
120148
if (dladdr(original, &info)) {
@@ -132,6 +160,8 @@ inline int HookInline(void *original, void *replace, void **backup) {
132160
* @brief A wrapper around DobbyDestroy.
133161
*/
134162
inline int UnhookInline(void *original) {
163+
original = ResolveOEMVeneer(original);
164+
135165
if constexpr (kIsDebugBuild) {
136166
Dl_info info;
137167
if (dladdr(original, &info)) {

0 commit comments

Comments
 (0)