Skip to content

Commit c9ff65f

Browse files
committed
Optimize the performance of shadowhook_hook_sym_addr function in arm64.
1 parent e9f9f75 commit c9ff65f

File tree

10 files changed

+82
-76
lines changed

10 files changed

+82
-76
lines changed

shadowhook/src/main/cpp/arch/arm/sh_inst.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "sh_config.h"
3535
#include "sh_enter.h"
3636
#include "sh_exit.h"
37+
#include "sh_linker.h"
3738
#include "sh_log.h"
3839
#include "sh_sig.h"
3940
#include "sh_t16.h"
@@ -462,11 +463,15 @@ static int sh_inst_hook_arm_without_exit(sh_inst_t *self, uintptr_t target_addr,
462463
}
463464

464465
int sh_inst_hook(sh_inst_t *self, uintptr_t target_addr, xdl_info_t *dlinfo, uintptr_t new_addr,
465-
uintptr_t *orig_addr, uintptr_t *orig_addr2) {
466+
uintptr_t *orig_addr, uintptr_t *orig_addr2, bool ignore_symbol_check) {
467+
int r;
468+
if (NULL == dlinfo->dli_fbase) {
469+
if (0 != (r = sh_linker_get_dlinfo_by_addr((void *)target_addr, dlinfo, ignore_symbol_check))) return r;
470+
}
471+
466472
self->enter_addr = sh_enter_alloc();
467473
if (0 == self->enter_addr) return SHADOWHOOK_ERRNO_HOOK_ENTER;
468474

469-
int r;
470475
if (SH_UTIL_IS_THUMB(target_addr)) {
471476
#ifdef SH_CONFIG_TRY_WITH_EXIT
472477
if (0 == (r = sh_inst_hook_thumb_with_exit(self, target_addr, dlinfo, new_addr, orig_addr, orig_addr2)))

shadowhook/src/main/cpp/arch/arm/sh_inst.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// Created by Kelun Cai ([email protected]) on 2021-04-11.
2323

2424
#pragma once
25+
#include <stdbool.h>
2526
#include <stdint.h>
2627

2728
#include "xdl.h"
@@ -37,7 +38,7 @@ typedef struct {
3738
} sh_inst_t;
3839

3940
int sh_inst_hook(sh_inst_t *self, uintptr_t target_addr, xdl_info_t *dlinfo, uintptr_t new_addr,
40-
uintptr_t *orig_addr, uintptr_t *orig_addr2);
41+
uintptr_t *orig_addr, uintptr_t *orig_addr2, bool ignore_symbol_check);
4142
int sh_inst_unhook(sh_inst_t *self, uintptr_t target_addr);
4243

4344
void sh_inst_free_after_dlclose(sh_inst_t *self, uintptr_t target_addr);

shadowhook/src/main/cpp/arch/arm64/sh_inst.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "sh_config.h"
3232
#include "sh_enter.h"
3333
#include "sh_exit.h"
34+
#include "sh_linker.h"
3435
#include "sh_log.h"
3536
#include "sh_sig.h"
3637
#include "sh_util.h"
@@ -84,7 +85,8 @@ static int sh_inst_hook_with_exit(sh_inst_t *self, uintptr_t target_addr, xdl_in
8485
uintptr_t pc = target_addr;
8586
self->backup_len = 4;
8687

87-
if (dlinfo->dli_ssize < self->backup_len) return SHADOWHOOK_ERRNO_HOOK_SYMSZ;
88+
// Any function should have at least one instruction,
89+
// so the arm64 function symbol size must be greater than or equal to 4.
8890

8991
// alloc an exit for absolute jump
9092
sh_a64_absolute_jump_with_br(self->exit, new_addr);
@@ -155,17 +157,26 @@ static int sh_inst_hook_without_exit(sh_inst_t *self, uintptr_t target_addr, xdl
155157
}
156158

157159
int sh_inst_hook(sh_inst_t *self, uintptr_t target_addr, xdl_info_t *dlinfo, uintptr_t new_addr,
158-
uintptr_t *orig_addr, uintptr_t *orig_addr2) {
160+
uintptr_t *orig_addr, uintptr_t *orig_addr2, bool ignore_symbol_check) {
159161
self->enter_addr = sh_enter_alloc();
160162
if (0 == self->enter_addr) return SHADOWHOOK_ERRNO_HOOK_ENTER;
161163

162164
int r;
163165
#ifdef SH_CONFIG_TRY_WITH_EXIT
164166
if (0 == (r = sh_inst_hook_with_exit(self, target_addr, dlinfo, new_addr, orig_addr, orig_addr2))) return r;
165167
#endif
168+
169+
if (NULL == dlinfo->dli_fbase) {
170+
if (ignore_symbol_check) {
171+
dlinfo->dli_ssize = 1024; // big enough
172+
} else {
173+
if (0 != (r = sh_linker_get_dlinfo_by_addr((void *)target_addr, dlinfo, false))) goto err;
174+
}
175+
}
166176
if (0 == (r = sh_inst_hook_without_exit(self, target_addr, dlinfo, new_addr, orig_addr, orig_addr2)))
167177
return r;
168178

179+
err:
169180
// hook failed
170181
if (NULL != orig_addr) *orig_addr = 0;
171182
if (NULL != orig_addr2) *orig_addr2 = 0;

shadowhook/src/main/cpp/arch/arm64/sh_inst.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ typedef struct {
3838
} sh_inst_t;
3939

4040
int sh_inst_hook(sh_inst_t *self, uintptr_t target_addr, xdl_info_t *dlinfo, uintptr_t new_addr,
41-
uintptr_t *orig_addr, uintptr_t *orig_addr2);
41+
uintptr_t *orig_addr, uintptr_t *orig_addr2, bool ignore_symbol_check);
4242
int sh_inst_unhook(sh_inst_t *self, uintptr_t target_addr);
4343

4444
void sh_inst_free_after_dlclose(sh_inst_t *self, uintptr_t target_addr);

shadowhook/src/main/cpp/sh_exit.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,8 @@ static void sh_exit_init_out_library(void) {
6565
sh_trampo_init_mgr(&sh_exit_trampo_mgr, SH_EXIT_PAGE_NAME, SH_EXIT_SZ, SH_EXIT_DELAY_SEC);
6666
}
6767

68-
static int sh_exit_alloc_out_library(uintptr_t *exit_addr, uintptr_t pc, xdl_info_t *dlinfo, uint8_t *exit,
69-
size_t range_low, size_t range_high) {
70-
(void)dlinfo;
71-
68+
static int sh_exit_alloc_out_library(uintptr_t *exit_addr, uintptr_t pc, uint8_t *exit, size_t range_low,
69+
size_t range_high) {
7270
uintptr_t addr = sh_trampo_alloc_near(&sh_exit_trampo_mgr, pc, range_low, range_high);
7371
if (0 == addr) return -1;
7472

@@ -321,10 +319,10 @@ static int sh_exit_alloc_in_library(uintptr_t *exit_addr, uintptr_t pc, xdl_info
321319
sh_exit_elf_info_t *elfinfo = sh_exit_find_elf_info_by_pc(pc);
322320
if (NULL == elfinfo) {
323321
// get dlinfo by pc
324-
if (NULL == dlinfo) {
325-
xdl_info_t dlinfo_obj;
326-
dlinfo = &dlinfo_obj;
327-
if (0 != (r = sh_linker_get_dlinfo_by_addr((void *)pc, dlinfo, NULL, 0, NULL, 0, true))) goto end;
322+
if (NULL == dlinfo->dli_fbase || NULL == dlinfo->dlpi_phdr) {
323+
xdl_info_t dlinfo_tmp;
324+
dlinfo = &dlinfo_tmp;
325+
if (0 != (r = sh_linker_get_dlinfo_by_addr((void *)pc, dlinfo, true))) goto end;
328326
}
329327

330328
// create elfinfo by dlinfo
@@ -406,7 +404,7 @@ int sh_exit_alloc(uintptr_t *exit_addr, uint16_t *exit_type, uintptr_t pc, xdl_i
406404

407405
// (1) try out-library mode first. Because ELF gaps are a valuable non-renewable resource.
408406
*exit_type = SH_EXIT_TYPE_OUT_LIBRARY;
409-
r = sh_exit_alloc_out_library(exit_addr, pc, dlinfo, exit, range_low, range_high);
407+
r = sh_exit_alloc_out_library(exit_addr, pc, exit, range_low, range_high);
410408
if (0 == r) goto ok;
411409

412410
// (2) try in-library mode.

shadowhook/src/main/cpp/sh_linker.c

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -209,11 +209,11 @@ int sh_linker_register_dlopen_post_callback(sh_linker_dlopen_post_t post) {
209209
}
210210

211211
// do hook
212-
int (*hook)(uintptr_t, uintptr_t, uintptr_t *, size_t *, xdl_info_t *) =
212+
int (*hook)(uintptr_t, uintptr_t, uintptr_t *, size_t *, xdl_info_t *, bool) =
213213
SHADOWHOOK_IS_SHARED_MODE ? sh_switch_hook : sh_switch_hook_invisible;
214214
size_t backup_len = 0;
215215
int r = hook((uintptr_t)dlinfo.dli_saddr, (uintptr_t)sh_linker_proxy_dlopen,
216-
(uintptr_t *)&sh_linker_orig_dlopen, &backup_len, &dlinfo);
216+
(uintptr_t *)&sh_linker_orig_dlopen, &backup_len, &dlinfo, false);
217217

218218
// do record
219219
sh_recorder_add_hook(r, true, (uintptr_t)dlinfo.dli_saddr, SH_LINKER_BASENAME, dlinfo.dli_sname,
@@ -492,7 +492,7 @@ static int sh_linker_hook_call_ctors_dtors(xdl_info_t *call_constructors_dlinfo,
492492
int r_hook_dtors = INT_MAX;
493493
size_t backup_len_ctors = 0;
494494
size_t backup_len_dtors = 0;
495-
int (*hook)(uintptr_t, uintptr_t, uintptr_t *, size_t *, xdl_info_t *) =
495+
int (*hook)(uintptr_t, uintptr_t, uintptr_t *, size_t *, xdl_info_t *, bool) =
496496
SHADOWHOOK_IS_SHARED_MODE ? sh_switch_hook : sh_switch_hook_invisible;
497497

498498
#if !SH_LINKER_HOOK_WITH_DL_MUTEX
@@ -505,9 +505,9 @@ static int sh_linker_hook_call_ctors_dtors(xdl_info_t *call_constructors_dlinfo,
505505

506506
// hook soinfo::call_constructors()
507507
SH_LOG_INFO("linker: hook soinfo::call_constructors");
508-
r_hook_ctors =
509-
hook((uintptr_t)call_constructors_dlinfo->dli_saddr, (uintptr_t)sh_linker_proxy_soinfo_call_ctors,
510-
(uintptr_t *)&sh_linker_orig_soinfo_call_ctors, &backup_len_ctors, call_constructors_dlinfo);
508+
r_hook_ctors = hook(
509+
(uintptr_t)call_constructors_dlinfo->dli_saddr, (uintptr_t)sh_linker_proxy_soinfo_call_ctors,
510+
(uintptr_t *)&sh_linker_orig_soinfo_call_ctors, &backup_len_ctors, call_constructors_dlinfo, false);
511511
if (__predict_false(0 != r_hook_ctors)) {
512512
#if SH_LINKER_HOOK_WITH_DL_MUTEX
513513
pthread_mutex_unlock(g_dl_mutex);
@@ -519,7 +519,7 @@ static int sh_linker_hook_call_ctors_dtors(xdl_info_t *call_constructors_dlinfo,
519519
SH_LOG_INFO("linker: hook soinfo::call_destructors");
520520
r_hook_dtors =
521521
hook((uintptr_t)call_destructors_dlinfo->dli_saddr, (uintptr_t)sh_linker_proxy_soinfo_call_dtors,
522-
(uintptr_t *)&sh_linker_orig_soinfo_call_dtors, &backup_len_dtors, call_destructors_dlinfo);
522+
(uintptr_t *)&sh_linker_orig_soinfo_call_dtors, &backup_len_dtors, call_destructors_dlinfo, false);
523523
if (__predict_false(0 != r_hook_dtors)) {
524524
#if SH_LINKER_HOOK_WITH_DL_MUTEX
525525
pthread_mutex_unlock(g_dl_mutex);
@@ -718,8 +718,9 @@ int sh_linker_unregister_dl_fini_callback(shadowhook_dl_info_t pre, shadowhook_d
718718
return 0;
719719
}
720720

721-
int sh_linker_get_dlinfo_by_addr(void *addr, xdl_info_t *dlinfo, char *lib_name, size_t lib_name_sz,
722-
char *sym_name, size_t sym_name_sz, bool ignore_symbol_check) {
721+
int sh_linker_get_dlinfo_by_addr(void *addr, xdl_info_t *dlinfo, bool ignore_symbol_check) {
722+
memset(dlinfo, 0, sizeof(xdl_info_t));
723+
723724
// dladdr()
724725
bool crashed = false;
725726
void *dlcache = NULL;
@@ -777,18 +778,16 @@ int sh_linker_get_dlinfo_by_addr(void *addr, xdl_info_t *dlinfo, char *lib_name,
777778
r = SHADOWHOOK_ERRNO_HOOK_SYMSZ;
778779
goto end;
779780
}
780-
781-
if (NULL != lib_name) strlcpy(lib_name, dlinfo->dli_fname, lib_name_sz);
782-
if (NULL != sym_name) strlcpy(sym_name, dlinfo->dli_sname, sym_name_sz);
783781
r = 0;
784782

785783
end:
786784
xdl_addr_clean(&dlcache);
787785
return r;
788786
}
789787

790-
int sh_linker_get_dlinfo_by_sym_name(const char *lib_name, const char *sym_name, xdl_info_t *dlinfo,
791-
char *real_lib_name, size_t real_lib_name_sz) {
788+
int sh_linker_get_dlinfo_by_sym_name(const char *lib_name, const char *sym_name, xdl_info_t *dlinfo) {
789+
memset(dlinfo, 0, sizeof(xdl_info_t));
790+
792791
// open library
793792
bool crashed = false;
794793
void *handle = NULL;
@@ -839,6 +838,5 @@ int sh_linker_get_dlinfo_by_sym_name(const char *lib_name, const char *sym_name,
839838
dlinfo->dli_sname = sym_name;
840839
dlinfo->dli_saddr = addr;
841840
dlinfo->dli_ssize = sym_size;
842-
if (NULL != real_lib_name) strlcpy(real_lib_name, dlinfo->dli_fname, real_lib_name_sz);
843841
return 0;
844842
}

shadowhook/src/main/cpp/sh_linker.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,5 @@ int sh_linker_register_dl_fini_callback(shadowhook_dl_info_t pre, shadowhook_dl_
4545
int sh_linker_unregister_dl_fini_callback(shadowhook_dl_info_t pre, shadowhook_dl_info_t post, void *data);
4646

4747
// linker utils
48-
int sh_linker_get_dlinfo_by_addr(void *addr, xdl_info_t *dlinfo, char *lib_name, size_t lib_name_sz,
49-
char *sym_name, size_t sym_name_sz, bool ignore_symbol_check);
50-
int sh_linker_get_dlinfo_by_sym_name(const char *lib_name, const char *sym_name, xdl_info_t *dlinfo,
51-
char *real_lib_name, size_t real_lib_name_sz);
48+
int sh_linker_get_dlinfo_by_addr(void *addr, xdl_info_t *dlinfo, bool ignore_symbol_check);
49+
int sh_linker_get_dlinfo_by_sym_name(const char *lib_name, const char *sym_name, xdl_info_t *dlinfo);

shadowhook/src/main/cpp/sh_switch.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ static void sh_switch_dump_enter(sh_switch_t *self) {
124124
}
125125

126126
static int sh_switch_hook_unique(uintptr_t target_addr, uintptr_t new_addr, uintptr_t *orig_addr,
127-
size_t *backup_len, xdl_info_t *dlinfo) {
127+
size_t *backup_len, xdl_info_t *dlinfo, bool ignore_symbol_check) {
128128
sh_switch_t *self = sh_switch_find(target_addr);
129129
if (NULL != self) return SHADOWHOOK_ERRNO_HOOK_DUP;
130130

@@ -148,7 +148,8 @@ static int sh_switch_hook_unique(uintptr_t target_addr, uintptr_t new_addr, uint
148148
(NULL != safe_orig_addr_addr && 0 == __atomic_load_n(safe_orig_addr_addr, __ATOMIC_ACQUIRE))
149149
? safe_orig_addr_addr
150150
: NULL;
151-
if (0 != (r = sh_inst_hook(&self->inst, target_addr, dlinfo, new_addr, orig_addr, orig_addr2))) {
151+
if (0 != (r = sh_inst_hook(&self->inst, target_addr, dlinfo, new_addr, orig_addr, orig_addr2,
152+
ignore_symbol_check))) {
152153
RB_REMOVE(sh_switch_tree, &sh_switches, self);
153154
useless = self;
154155
goto end;
@@ -163,7 +164,7 @@ static int sh_switch_hook_unique(uintptr_t target_addr, uintptr_t new_addr, uint
163164
}
164165

165166
static int sh_switch_hook_shared(uintptr_t target_addr, uintptr_t new_addr, uintptr_t *orig_addr,
166-
size_t *backup_len, xdl_info_t *dlinfo) {
167+
size_t *backup_len, xdl_info_t *dlinfo, bool ignore_symbol_check) {
167168
int r;
168169

169170
pthread_rwlock_rdlock(&sh_switches_lock); // SYNC(read) - start
@@ -201,8 +202,9 @@ static int sh_switch_hook_shared(uintptr_t target_addr, uintptr_t new_addr, uint
201202
} else {
202203
// do hook
203204
uintptr_t *safe_orig_addr_addr = sh_safe_get_orig_addr_addr(target_addr);
204-
if (0 != (r = sh_inst_hook(&self->inst, target_addr, dlinfo, hub_trampo,
205-
sh_hub_get_orig_addr_addr(self->hub), safe_orig_addr_addr))) {
205+
if (0 !=
206+
(r = sh_inst_hook(&self->inst, target_addr, dlinfo, hub_trampo, sh_hub_get_orig_addr_addr(self->hub),
207+
safe_orig_addr_addr, ignore_symbol_check))) {
206208
RB_REMOVE(sh_switch_tree, &sh_switches, self);
207209
useless = self;
208210
goto end;
@@ -231,12 +233,12 @@ static int sh_switch_hook_shared(uintptr_t target_addr, uintptr_t new_addr, uint
231233
}
232234

233235
int sh_switch_hook(uintptr_t target_addr, uintptr_t new_addr, uintptr_t *orig_addr, size_t *backup_len,
234-
xdl_info_t *dlinfo) {
236+
xdl_info_t *dlinfo, bool ignore_symbol_check) {
235237
int r;
236238
if (SHADOWHOOK_IS_UNIQUE_MODE)
237-
r = sh_switch_hook_unique(target_addr, new_addr, orig_addr, backup_len, dlinfo);
239+
r = sh_switch_hook_unique(target_addr, new_addr, orig_addr, backup_len, dlinfo, ignore_symbol_check);
238240
else
239-
r = sh_switch_hook_shared(target_addr, new_addr, orig_addr, backup_len, dlinfo);
241+
r = sh_switch_hook_shared(target_addr, new_addr, orig_addr, backup_len, dlinfo, ignore_symbol_check);
240242

241243
if (0 == r)
242244
SH_LOG_INFO("switch: hook in %s mode OK: target_addr %" PRIxPTR ", new_addr %" PRIxPTR,
@@ -251,7 +253,7 @@ static int sh_switch_hook_unique_invisible(uintptr_t target_addr, uintptr_t new_
251253

252254
// do hook
253255
sh_inst_t inst;
254-
int r = sh_inst_hook(&inst, target_addr, dlinfo, new_addr, orig_addr, NULL);
256+
int r = sh_inst_hook(&inst, target_addr, dlinfo, new_addr, orig_addr, NULL, false);
255257

256258
pthread_rwlock_unlock(&sh_switches_lock); // SYNC - end
257259

@@ -260,12 +262,14 @@ static int sh_switch_hook_unique_invisible(uintptr_t target_addr, uintptr_t new_
260262
}
261263

262264
int sh_switch_hook_invisible(uintptr_t target_addr, uintptr_t new_addr, uintptr_t *orig_addr,
263-
size_t *backup_len, xdl_info_t *dlinfo) {
265+
size_t *backup_len, xdl_info_t *dlinfo, bool ignore_symbol_check) {
266+
(void)ignore_symbol_check;
267+
264268
int r;
265269
if (SHADOWHOOK_IS_UNIQUE_MODE)
266270
r = sh_switch_hook_unique_invisible(target_addr, new_addr, orig_addr, backup_len, dlinfo);
267271
else
268-
r = sh_switch_hook_shared(target_addr, new_addr, orig_addr, backup_len, dlinfo);
272+
r = sh_switch_hook_shared(target_addr, new_addr, orig_addr, backup_len, dlinfo, false);
269273

270274
if (0 == r)
271275
SH_LOG_INFO("switch: hook(invisible) in %s mode OK: target_addr %" PRIxPTR ", new_addr %" PRIxPTR,

shadowhook/src/main/cpp/sh_switch.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,16 @@
2222
// Created by Kelun Cai ([email protected]) on 2021-04-11.
2323

2424
#pragma once
25+
#include <stdbool.h>
2526
#include <stdint.h>
2627

2728
#include "xdl.h"
2829

2930
int sh_switch_hook(uintptr_t target_addr, uintptr_t new_addr, uintptr_t *orig_addr, size_t *backup_len,
30-
xdl_info_t *dlinfo);
31+
xdl_info_t *dlinfo, bool ignore_symbol_check);
3132
int sh_switch_unhook(uintptr_t target_addr, uintptr_t new_addr);
3233

3334
int sh_switch_hook_invisible(uintptr_t target_addr, uintptr_t new_addr, uintptr_t *orig_addr,
34-
size_t *backup_len, xdl_info_t *dlinfo);
35+
size_t *backup_len, xdl_info_t *dlinfo, bool ignore_symbol_check);
3536

3637
void sh_switch_free_after_dlclose(xdl_info_t *dlinfo);

0 commit comments

Comments
 (0)