Frida 注入目标进程后会使用Interceptor.attach对退出进程的方法进行inline hook。此处可以定位三个关键函数:exit、_exit、abort
GitHub源码链接:
470K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3M7X3W2V1j5g2)9J5c8X3k6J5K9h3c8S2i4K6u0V1j5$3!0J5k6g2)9J5c8X3u0D9L8$3u0Q4x3V1j5I4x3o6p5^5j5h3y4S2x3U0S2V1y4o6W2S2j5$3f1J5x3h3y4T1j5U0g2V1y4e0c8V1x3U0x3J5z5r3x3H3x3U0R3K6k6o6x3J5y4$3k6W2i4K6u0r3L8r3W2T1i4K6u0r3M7r3q4&6L8r3!0S2k6q4)9J5c8X3g2^5K9i4c8Q4x3X3c8E0L8$3&6A6N6r3!0J5i4K6u0W2N6X3q4D9j5g2)9J5x3@1H3K6y4l9`.`.
frida 调用了gum_interceptor_replace函数对libc库的signal和sigaction函数进行了inline hook。
GitHub链接:f4dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3M7X3W2V1j5g2)9J5c8X3k6J5K9h3c8S2i4K6u0V1k6%4g2E0i4K6u0r3j5X3I4G2j5W2)9J5c8U0l9$3y4K6q4U0x3U0N6V1z5e0b7I4k6o6M7%4y4o6V1H3k6X3k6X3y4r3y4S2y4X3c8T1j5U0W2U0j5e0p5H3j5e0m8X3z5o6M7J5j5X3u0Q4x3V1k6Y4N6h3#2Q4x3V1k6T1j5h3y4C8k6h3&6V1i4K6u0V1M7r3!0K6K9i4S2Q4x3V1k6Y4N6h3#2W2P5r3y4W2M7s2c8G2M7W2)9J5k6s2m8G2M7$3W2^5i4K6u0W2j5#2)9J5x3@1H3J5x3U0R3`.
前提:已知frida注入目标进程会hook libc库以下目标函数:
{"sigaction", "signal", "exit", "abort", "_exit"}
实现代码如下:
分析源码中frida注入逻辑进行检测,这种方法类似于开卷考试,不过优点明显:针对性很强,检测逻辑复杂度很低,性能开销小。
不知道后续frida会不会修改相关逻辑。
interceptor.attach ((void
*
) Gum.Process.find_module_by_name (
"kernel32.dll"
).find_export_by_name (
"ExitProcess"
),
listener);
var libc
=
Gum.Process.get_libc_module ();
const string[] apis
=
{
"exit"
,
"_exit"
,
"abort"
,
};
foreach (var symbol
in
apis) {
interceptor.attach ((void
*
) libc.find_export_by_name (symbol), listener);
}
interceptor.attach ((void
*
) Gum.Process.find_module_by_name (
"kernel32.dll"
).find_export_by_name (
"ExitProcess"
),
listener);
var libc
=
Gum.Process.get_libc_module ();
const string[] apis
=
{
"exit"
,
"_exit"
,
"abort"
,
};
foreach (var symbol
in
apis) {
interceptor.attach ((void
*
) libc.find_export_by_name (symbol), listener);
}
static void
gum_exceptor_backend_attach (GumExceptorBackend
*
self
)
{
GumInterceptor
*
interceptor
=
self
-
>interceptor;
const gint handled_signals[]
=
{
SIGABRT,
SIGSEGV,
SIGBUS,
SIGILL,
SIGFPE,
SIGTRAP,
SIGSYS,
};
gint highest, i;
struct sigaction action;
highest
=
0
;
for
(i
=
0
; i !
=
G_N_ELEMENTS (handled_signals); i
+
+
)
highest
=
MAX
(handled_signals[i], highest);
g_assert (highest >
0
);
self
-
>num_old_handlers
=
highest
+
1
;
self
-
>old_handlers
=
g_new0 (struct sigaction
*
,
self
-
>num_old_handlers);
action.sa_sigaction
=
gum_exceptor_backend_on_signal;
sigemptyset (&action.sa_mask);
action.sa_flags
=
SA_SIGINFO | SA_NODEFER;
action.sa_flags |
=
SA_ONSTACK;
for
(i
=
0
; i !
=
G_N_ELEMENTS (handled_signals); i
+
+
)
{
gint sig
=
handled_signals[i];
struct sigaction
*
old_handler;
old_handler
=
g_slice_new0 (struct sigaction);
self
-
>old_handlers[sig]
=
old_handler;
gum_original_sigaction (sig, &action, old_handler);
}
gum_interceptor_begin_transaction (interceptor);
gum_interceptor_replace (interceptor, gum_original_signal,
gum_exceptor_backend_replacement_signal,
self
, NULL);
gum_interceptor_replace (interceptor, gum_original_sigaction,
gum_exceptor_backend_replacement_sigaction,
self
, NULL);
gum_interceptor_end_transaction (interceptor);
}
static void
gum_exceptor_backend_attach (GumExceptorBackend
*
self
)
{
GumInterceptor
*
interceptor
=
self
-
>interceptor;
const gint handled_signals[]
=
{
SIGABRT,
SIGSEGV,
SIGBUS,
SIGILL,
SIGFPE,
SIGTRAP,
SIGSYS,
};
gint highest, i;
struct sigaction action;
highest
=
0
;
for
(i
=
0
; i !
=
G_N_ELEMENTS (handled_signals); i
+
+
)
highest
=
MAX
(handled_signals[i], highest);
g_assert (highest >
0
);
self
-
>num_old_handlers
=
highest
+
1
;
self
-
>old_handlers
=
g_new0 (struct sigaction
*
,
self
-
>num_old_handlers);
action.sa_sigaction
=
gum_exceptor_backend_on_signal;
sigemptyset (&action.sa_mask);
action.sa_flags
=
SA_SIGINFO | SA_NODEFER;
action.sa_flags |
=
SA_ONSTACK;
for
(i
=
0
; i !
=
G_N_ELEMENTS (handled_signals); i
+
+
)
{
gint sig
=
handled_signals[i];
struct sigaction
*
old_handler;
old_handler
=
g_slice_new0 (struct sigaction);
self
-
>old_handlers[sig]
=
old_handler;
gum_original_sigaction (sig, &action, old_handler);
}
gum_interceptor_begin_transaction (interceptor);
gum_interceptor_replace (interceptor, gum_original_signal,
gum_exceptor_backend_replacement_signal,
self
, NULL);
gum_interceptor_replace (interceptor, gum_original_sigaction,
gum_exceptor_backend_replacement_sigaction,
self
, NULL);
gum_interceptor_end_transaction (interceptor);
}
/
/
获取函数地址
void
*
get_function_address(void
*
handle, const char
*
func_name) {
void
*
func_addr
=
dlsym(handle, func_name);
if
(!func_addr) {
LOGD(
"[-] Function %s not found in global symbol table"
, func_name);
}
else
{
LOGD(
"[+] Function: %s, addr: 0x%lx"
, func_name, (uintptr_t)func_addr);
}
return
func_addr;
}
/
/
获取函数偏移
uintptr_t get_function_offset(void
*
func_addr) {
Dl_info info;
if
(dladdr(func_addr, &info)
=
=
0
) {
LOGD(
"[-] Unable to get function info"
);
return
0
;
}
return
(uintptr_t)func_addr
-
(uintptr_t)info.dli_fbase;
}
/
/
读取库文件中的字节
bool
read_bytes_from_libso(const char
*
libpath, uintptr_t offset, uint8_t
*
buffer
, size_t size) {
int
fd
=
open
(libpath, O_RDONLY);
if
(fd
=
=
-
1
) {
LOGD(
"[-] Failed to open %s: %s"
, libpath, strerror(errno));
return
false;
}
if
(lseek(fd, offset, SEEK_SET)
=
=
-
1
) {
LOGD(
"[-] Seek failed at %lx in %s: %s"
, (unsigned
long
)offset, libpath, strerror(errno));
close(fd);
return
false;
}
ssize_t bytes_read
=
read(fd,
buffer
, size);
close(fd);
if
(bytes_read !
=
(ssize_t)size) {
LOGD(
"[-] Read %zd bytes, expected %zu from %s at offset %lx"
, bytes_read, size, libpath, (unsigned
long
)offset);
return
false;
}
return
true;
}
/
/
字节数组转十六进制字符串
void bytes_to_hex_string(const uint8_t
*
bytes, size_t size, char
*
hex_string) {
for
(size_t i
=
0
; i < size; i
+
+
) {
sprintf(hex_string
+
i
*
2
,
"%02x"
, bytes[i]);
}
hex_string[size
*
2
]
=
'\0'
;
}
/
/
比较内存中的字节和库文件中的字节
bool
compare_function_bytes(void
*
func_addr, uint8_t
*
file_bytes, size_t size) {
uint8_t mem_bytes[BYTE_BUFFER_SIZE];
memcpy(mem_bytes, func_addr, size);
char mem_hex_string[BYTE_BUFFER_SIZE
*
2
+
1
];
char file_hex_string[BYTE_BUFFER_SIZE
*
2
+
1
];
bytes_to_hex_string(mem_bytes, size, mem_hex_string);
bytes_to_hex_string(file_bytes, size, file_hex_string);
LOGD(
"[*] Memory: %s | File: %s"
, mem_hex_string, file_hex_string);
return
memcmp(mem_bytes, file_bytes, size)
=
=
0
;
}
/
/
Hook 检测函数
bool
detect_hook(void
*
handle, const char
*
lib_path, const char
*
func_name) {
void
*
func_addr
=
get_function_address(handle, func_name);
if
(!func_addr)
return
false;
uintptr_t offset
=
get_function_offset(func_addr);
if
(offset
=
=
0
) {
LOGD(
"[-] Failed to get offset for %s"
, func_name);
return
false;
}
uint8_t file_bytes[BYTE_BUFFER_SIZE];
if
(!read_bytes_from_libso(lib_path, offset, file_bytes, sizeof(file_bytes))) {
LOGD(
"[-] Failed to read bytes for %s"
, func_name);
return
false;
}
bool
is_hooked
=
!compare_function_bytes(func_addr, file_bytes, sizeof(file_bytes));
LOGD(
"[+] %s in %s is %s"
, func_name, lib_path, is_hooked ?
"HOOKED"
:
"NOT HOOKED"
);
return
is_hooked;
}
/
/
执行 Hook 检测
int
do_hook_check() {
const char
*
libpath
=
"/system/lib64/libc.so"
;
void
*
handle
=
dlopen(libpath, RTLD_LAZY);
if
(!handle) {
LOGD(
"[-] Failed to load %s"
, libpath);
return
-
1
;
}
const char
*
funcs[]
=
{
"sigaction"
,
"signal"
,
"exit"
,
"abort"
,
"_exit"
};
bool
hooked
=
false;
for
(size_t i
=
0
; i < sizeof(funcs)
/
sizeof(funcs[
0
]); i
+
+
) {
if
(detect_hook(handle, libpath, funcs[i])) {
hooked
=
true;
}
}
dlclose(handle);
return
hooked;
}
/
/
获取函数地址
void
*
get_function_address(void
*
handle, const char
*
func_name) {
void
*
func_addr
=
dlsym(handle, func_name);
if
(!func_addr) {
LOGD(
"[-] Function %s not found in global symbol table"
, func_name);
}
else
{
LOGD(
"[+] Function: %s, addr: 0x%lx"
, func_name, (uintptr_t)func_addr);
}
return
func_addr;
}
/
/
获取函数偏移
uintptr_t get_function_offset(void
*
func_addr) {
Dl_info info;
if
(dladdr(func_addr, &info)
=
=
0
) {
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课