Last active
February 28, 2025 04:40
-
-
Save jimmy947788/43b05c8f7c0e4e9325dc7356583a2050 to your computer and use it in GitHub Desktop.
frida 腳本hook so的 .init_array 區段的執行函數,再接著跑stalker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 來源:frida hook init_array自吐新解 | |
// https://bbs.kanxue.com/thread-280135.htm | |
const TARGET_SO_NAME = "libaaaaaaaa.so"; | |
function start_stalker(tragetAddress){ | |
const module = Process.findModuleByAddress(tragetAddress); | |
console.log(`[start_stalker] tragetAddress: ${tragetAddress} module: ${module.name} base: ${module.base} size: ${module.size}`); | |
Interceptor.attach(tragetAddress, { | |
onEnter: function (args) { | |
var curTid = Process.getCurrentThreadId(); | |
Stalker.follow(curTid, { | |
transform: function (iterator) { | |
let instruction = iterator.next(); | |
const baseFirstAddress = instruction.address; | |
//可以判读是否在当前模块内 | |
const isModuleCode = baseFirstAddress.compare(module.base) >= 0 && | |
baseFirstAddress.compare(module.base.add(module.size)) <= 0; | |
//const module = Process.findModuleByAddress(baseFirstAddress); | |
if (isModuleCode) { | |
if (module) { | |
const name = module.name; | |
const offset = baseFirstAddress.sub(module.base); | |
const base = module.base; | |
console.log(`[transform] start: ${baseFirstAddress} name:${name} offset: ${offset} base: ${base}`); | |
} else { | |
console.log(`[transform] start: ${baseFirstAddress}`); | |
} | |
} | |
do { | |
const curRealAddr = instruction.address; | |
const curOffset = curRealAddr.sub(baseFirstAddress); | |
const curOffsetInt = curOffset.toInt32() | |
const instructionStr = instruction.toString() | |
const realOffset = curRealAddr.sub(module.base); | |
if (isModuleCode){ | |
console.log("\t" + curRealAddr + "(" + realOffset +") <+" + curOffsetInt + ">: " + instructionStr); | |
} | |
iterator.keep(); | |
} while ((instruction = iterator.next()) !== null); | |
if (isModuleCode){ | |
console.log() | |
} | |
} | |
}) | |
}, | |
onLeave: function (retval) { | |
console.warn("===== stalker 结束 ====="); | |
Stalker.unfollow(); | |
Stalker.garbageCollect(); | |
} | |
}) | |
} | |
let cm_include = ` | |
#include <stdio.h> | |
#include <gum/gumprocess.h> | |
` | |
let cm_code = ` | |
#if defined(__LP64__) | |
#define USE_RELA 1 | |
#endif | |
// http://aosp.app/android-14.0.0_r1/xref/bionic/libc/include/link.h | |
#if defined(__LP64__) | |
#define ElfW(type) Elf64_ ## type | |
#else | |
#define ElfW(type) Elf32_ ## type | |
#endif | |
// http://aosp.app/android-14.0.0_r1/xref/bionic/libc/kernel/uapi/asm-generic/int-ll64.h | |
typedef signed char __s8; | |
typedef unsigned char __u8; | |
typedef signed short __s16; | |
typedef unsigned short __u16; | |
typedef signed int __s32; | |
typedef unsigned int __u32; | |
typedef signed long long __s64; | |
typedef unsigned long long __u64; | |
// http://aosp.app/android-14.0.0_r1/xref/bionic/libc/kernel/uapi/linux/elf.h | |
typedef __u32 Elf32_Addr; | |
typedef __u16 Elf32_Half; | |
typedef __u32 Elf32_Off; | |
typedef __s32 Elf32_Sword; | |
typedef __u32 Elf32_Word; | |
typedef __u64 Elf64_Addr; | |
typedef __u16 Elf64_Half; | |
typedef __s16 Elf64_SHalf; | |
typedef __u64 Elf64_Off; | |
typedef __s32 Elf64_Sword; | |
typedef __u32 Elf64_Word; | |
typedef __u64 Elf64_Xword; | |
typedef __s64 Elf64_Sxword; | |
typedef struct dynamic { | |
Elf32_Sword d_tag; | |
union { | |
Elf32_Sword d_val; | |
Elf32_Addr d_ptr; | |
} d_un; | |
} Elf32_Dyn; | |
typedef struct { | |
Elf64_Sxword d_tag; | |
union { | |
Elf64_Xword d_val; | |
Elf64_Addr d_ptr; | |
} d_un; | |
} Elf64_Dyn; | |
typedef struct elf32_rel { | |
Elf32_Addr r_offset; | |
Elf32_Word r_info; | |
} Elf32_Rel; | |
typedef struct elf64_rel { | |
Elf64_Addr r_offset; | |
Elf64_Xword r_info; | |
} Elf64_Rel; | |
typedef struct elf32_rela { | |
Elf32_Addr r_offset; | |
Elf32_Word r_info; | |
Elf32_Sword r_addend; | |
} Elf32_Rela; | |
typedef struct elf64_rela { | |
Elf64_Addr r_offset; | |
Elf64_Xword r_info; | |
Elf64_Sxword r_addend; | |
} Elf64_Rela; | |
typedef struct elf32_sym { | |
Elf32_Word st_name; | |
Elf32_Addr st_value; | |
Elf32_Word st_size; | |
unsigned char st_info; | |
unsigned char st_other; | |
Elf32_Half st_shndx; | |
} Elf32_Sym; | |
typedef struct elf64_sym { | |
Elf64_Word st_name; | |
unsigned char st_info; | |
unsigned char st_other; | |
Elf64_Half st_shndx; | |
Elf64_Addr st_value; | |
Elf64_Xword st_size; | |
} Elf64_Sym; | |
typedef struct elf32_phdr { | |
Elf32_Word p_type; | |
Elf32_Off p_offset; | |
Elf32_Addr p_vaddr; | |
Elf32_Addr p_paddr; | |
Elf32_Word p_filesz; | |
Elf32_Word p_memsz; | |
Elf32_Word p_flags; | |
Elf32_Word p_align; | |
} Elf32_Phdr; | |
typedef struct elf64_phdr { | |
Elf64_Word p_type; | |
Elf64_Word p_flags; | |
Elf64_Off p_offset; | |
Elf64_Addr p_vaddr; | |
Elf64_Addr p_paddr; | |
Elf64_Xword p_filesz; | |
Elf64_Xword p_memsz; | |
Elf64_Xword p_align; | |
} Elf64_Phdr; | |
// http://aosp.app/android-14.0.0_r1/xref/bionic/linker/linker_soinfo.h | |
typedef void (*linker_dtor_function_t)(); | |
typedef void (*linker_ctor_function_t)(int, char**, char**); | |
#if defined(__work_around_b_24465209__) | |
#define SOINFO_NAME_LEN 128 | |
#endif | |
typedef struct { | |
#if defined(__work_around_b_24465209__) | |
char old_name_[SOINFO_NAME_LEN]; | |
#endif | |
const ElfW(Phdr)* phdr; | |
size_t phnum; | |
#if defined(__work_around_b_24465209__) | |
ElfW(Addr) unused0; // DO NOT USE, maintained for compatibility. | |
#endif | |
ElfW(Addr) base; | |
size_t size; | |
#if defined(__work_around_b_24465209__) | |
uint32_t unused1; // DO NOT USE, maintained for compatibility. | |
#endif | |
ElfW(Dyn)* dynamic; | |
#if defined(__work_around_b_24465209__) | |
uint32_t unused2; // DO NOT USE, maintained for compatibility | |
uint32_t unused3; // DO NOT USE, maintained for compatibility | |
#endif | |
void* next; | |
uint32_t flags_; | |
const char* strtab_; | |
ElfW(Sym)* symtab_; | |
size_t nbucket_; | |
size_t nchain_; | |
uint32_t* bucket_; | |
uint32_t* chain_; | |
#if !defined(__LP64__) | |
ElfW(Addr)** unused4; // DO NOT USE, maintained for compatibility | |
#endif | |
#if defined(USE_RELA) | |
ElfW(Rela)* plt_rela_; | |
size_t plt_rela_count_; | |
ElfW(Rela)* rela_; | |
size_t rela_count_; | |
#else | |
ElfW(Rel)* plt_rel_; | |
size_t plt_rel_count_; | |
ElfW(Rel)* rel_; | |
size_t rel_count_; | |
#endif | |
linker_ctor_function_t* preinit_array_; | |
size_t preinit_array_count_; | |
linker_ctor_function_t* init_array_; | |
size_t init_array_count_; | |
linker_dtor_function_t* fini_array_; | |
size_t fini_array_count_; | |
linker_ctor_function_t init_func_; | |
linker_dtor_function_t fini_func_; | |
} soinfo; | |
void tell_init_info(soinfo* ptr, void (*cb)(int, void*, void*)) { | |
cb(ptr->init_array_count_, ptr->init_array_, ptr->init_func_); | |
} | |
` | |
let cm = null; | |
let tell_init_info = null; | |
function setup_cmodule() { | |
if (Process.pointerSize == 4) { | |
cm_code = cm_include + "#define __work_around_b_24465209__ 1" + cm_code; | |
} else { | |
cm_code = cm_include + "#define __LP64__ 1" + cm_code; | |
} | |
cm = new CModule(cm_code, {}); | |
tell_init_info = new NativeFunction(cm.tell_init_info, "void", ["pointer", "pointer"]); | |
} | |
function get_addr_info(addr) { | |
let mm = new ModuleMap(); | |
let info = mm.find(addr); | |
if (info == null) return "null"; | |
return `[${info.name} + ${addr.sub(info.base)}]`; | |
} | |
function hook_call_constructors() { | |
let get_soname = null; | |
let call_constructors_addr = null; | |
let hook_call_constructors_addr = true; | |
let linker = null; | |
if (Process.pointerSize == 4) { | |
linker = Process.findModuleByName("linker"); | |
} else { | |
linker = Process.findModuleByName("linker64"); | |
} | |
let symbols = linker.enumerateSymbols(); | |
for (let index = 0; index < symbols.length; index++) { | |
let symbol = symbols[index]; | |
if (symbol.name == "__dl__ZN6soinfo17call_constructorsEv") { | |
call_constructors_addr = symbol.address; | |
} else if (symbol.name == "__dl__ZNK6soinfo10get_sonameEv") { | |
get_soname = new NativeFunction(symbol.address, "pointer", ["pointer"]); | |
} | |
} | |
if (hook_call_constructors_addr && call_constructors_addr && get_soname) { | |
Interceptor.attach(call_constructors_addr,{ | |
onEnter: function(args){ | |
let soinfo = args[0]; | |
let soname = get_soname(soinfo).readCString(); | |
tell_init_info(soinfo, new NativeCallback((count, init_array_ptr, init_func) => { | |
console.log(`[call_constructors] ${soname} count:${count}`); | |
console.log(`[call_constructors] init_array_ptr:${init_array_ptr}`); | |
console.log(`[call_constructors] init_func:${init_func} -> ${get_addr_info(init_func)}`); | |
for (let index = 0; index < count; index++) { | |
let init_array_func = init_array_ptr.add(Process.pointerSize * index).readPointer(); | |
let func_info = get_addr_info(init_array_func); | |
if (func_info.indexOf(TARGET_SO_NAME) >= 0) { | |
console.warn(`[call_constructors] init_array:${index} ${init_array_func} -> ${func_info}`); | |
start_stalker(init_array_func); | |
}else{ | |
console.log(`[call_constructors] init_array:${index} ${init_array_func} -> ${func_info}`); | |
} | |
} | |
}, "void", ["int", "pointer", "pointer"])); | |
} | |
}); | |
} | |
} | |
function main(){ | |
setup_cmodule(); | |
hook_call_constructors(); | |
} | |
setImmediate(main); | |
// frida -U -f pkg_name -l hook.js -o hook.log |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment