1. Inject code into the target process (inject so and call a function in the so). First call the ptrace function to debug the com.android.browser process. Here we need to traverse the libc.so loaded by the process. Here are the addresses of the dlopen, dlsym and other functions we need. We first interrupt com.android.phone and modify it. Register, push parameters such as our so path, and push the previously found dlopen address into the register. Directly operate blx, and the target process can call dlopen to load our so. In the same way, dlsym calls the function in our so.
The following is what I did, the redirection function implements the hook.
2.com.android.phone program called xxx.so when making a call and waiting for network connection. This so maintains a got table and rel.plt table. The rel.plt table stores the addresses of external dependent functions, and the got table stores the addresses of functions defined by this so. The so injected above is already in the same process space as com.android.phone and can execute a piece of code we set. Our code should do this. We also load xxx.so. It will not be actually loaded here because it has already been loaded, but we can get the handle of xxx.so and then find the dial function entry in the rel.plt table. Then load a myxxx.so we wrote, which contains our own defined mydial function. Note that the signatures of the two functions must be consistent. In the same way, we find the address after the mydial function is loaded, and then replace the function address of the previous dial entry of xxx.so with the address of our mydial function. Note that when replacing the address, you need to call the mprotect function first to break through the write protection of the so memory space.
In the mydial function, we copied all the code of the dial function, but there is one change. That is to change the target phone number to the number we specify.
The code to find the function address table entry is
//handle is the handle of the target so, name is the target function name
void* getaddr(void *handle, const char *name)
{
if(!handle)
return;
Soinfo *si = (Soinfo*)handle ;
Elf32_Sym *symtab = si-gt; symtab;
const char *strtab = si-gt; strtab;
Elf32_Rel *rel = si-gt ;plt_rel;
unsigned count = si-gt;plt_rel_count;
unsigned idx;
for(idx=0; idxlt; count; idx ) // External dependency functions are in rel_plt
{
unsigned type = ELF32_R_TYPE(rel-gt; r_info);
unsigned sym = ELF32_R_SYM(rel-gt; r_info) );
unsigned reloc = (unsigned)(rel-gt; r_offset si-gt; base);
char *sym_name = (char *)(strtab symtab[sym]. st_name);
if(strcmp(sym_name, name)==0)
{
printf("\"plt_rel\" idx: 2d type: 2d sym: 2d sym_name: -30s addr: 0x\n", idx, type, sym, sym_name, *((unsigned*)reloc));
return (void *)*((unsigned* )reloc);
}
rel;
}
for(idx=0; idxlt; si-gt; nchain; idx ) //Custom function in symtab
{
unsigned type = ELF32_R_TYPE(symtab[idx].st_info);
unsigned sym = ELF32_R_SYM( symtab[idx].st_info);
char *sym_name = (char *)(strtab symtab[idx].st_name);
if(strcmp(sym_name, name)== 0)
{
printf("\"got\" idx: 2d sym_name: -30s st_value: 0x base: 0x\n", idx, sym_name, symtab[idx] .st_value,si-gt;base);
return (void *)(symtab[id
x].st_value si-gt; base);
}
};
return NULL; //not found
}
As for replacing the function execution address, it is to modify the target function address to the previously found function address that is used to replace the target function execution. Note that relative to the base value of so in the got table, you need to add or subtract the base difference between the two so. The rel.plt table contains absolute addresses.
From a security perspective, we can hook key functions to implement permission operation restrictions.
--------------------------------------------- -------------------------------------------------- -----------
Ideas to prevent injection:
1. Set android: debuggable to false to prohibit ptrace;
2. Modify the addresses of mmap, dlopen and other functions to prevent them from being called by other processes;
3. Dynamically monitor whether other so is loaded, and uninstall it if so