Search code examples
androidhooksystem-callsfunction-interpositionlibrary-interposition

How to hook system calls of my android app


I want to intercept the connect() system call and use my own custom implementation. The custom implementation will do some action like printing a log for simplicity and then call the system implementation further.

I looked at Audrey's blog where the approach is to patch the PLT. But unfortunately this code is crashing when trying to change the address in the relocation table.

After goggling a while i came across This already answered question. But the approach described here gives me the following error.

*****jump to case label [-fpermissive] jni/test.cpp:107:20: error: crosses initialization of 'uint32_t entry_page_start' jni/test.cpp:106:15: error: crosses initialization of 'uint32_t page_size'*****

the hook call method from the Andrey's blog after the suggested changes Here, looks like this.

int hook_call(char *soname, char *symbol, unsigned newval) {  
soinfo *si = NULL;  
Elf32_Rel *rel = NULL;  
Elf32_Sym *s = NULL;   
unsigned int sym_offset = 0;  
if (!soname || !symbol || !newval)  
 return 0;  
si = (soinfo*) dlopen(soname, 0);  
if (!si)  
 return 0;  
s = soinfo_elf_lookup(si, elfhash(symbol), symbol);  
if (!s)  
 return 0;  
sym_offset = s - si->symtab;  
rel = si->plt_rel;  
/* walk through reloc table, find symbol index matching one we've got */  
for (int i = 0; i < si->plt_rel_count; i++, rel++) {  
  unsigned type = ELF32_R_TYPE(rel->r_info);  
  unsigned sym = ELF32_R_SYM(rel->r_info);  
  unsigned reloc = (unsigned)(rel->r_offset + si->base);  
  unsigned oldval = 0;  
  if (sym_offset == sym) {  
   switch(type) {  
     case R_ARM_JUMP_SLOT:
      // YOUR LINES
      uint32_t page_size = getpagesize();
      uint32_t entry_page_start = reloc& (~(page_size - 1));
      mprotect((uint32_t *)entry_page_start, page_size, PROT_READ | PROT_WRITE);

      /* we do not have to read original value, but it would be good   
       idea to make sure it contains what we are looking for */  
     oldval = *(unsigned*) reloc;  
     *((unsigned*)reloc) = newval;  
     return 1;  
   default:  
     return 0;  
}  

What wrong am I doing, Am i putting the mProtect() method at some wrong place ? do we have anyone who has done it with the help of Andrey's blog ? Any other approach ? I am blocked. Any help would be appreciated.


Solution

  • The error hast nothing to do with the mProtect(). This is actually the exact same place I have placed the code snippet as well. Here is my code and it works fine:

    void* hook_call(char *soname, char *symbol, void* newval) {
     soinfo *si = NULL;
       Elf32_Rel *rel = NULL;
       Elf32_Sym *s = NULL;
       unsigned int sym_offset = 0;
       if (!soname || !symbol || !newval)
          return 0;
    
       si = (soinfo*) dlopen(soname, RTLD_LAZY);
       if (!si)
        return 0;
    
    
       s = soinfo_elf_lookup(si, elfhash(symbol), symbol);
       if (!s)
         return 0;
    
       sym_offset = s - si->symtab;
       rel = si->plt_rel;
    
    
       const char *strtab = si->strtab;
       Elf32_Sym *symtab = si->symtab;
    
       /* walk through reloc table, find symbol index matching one we've got */
       int i;
    
       for (i = 0; i < si->plt_rel_count; i++, rel++) {
        unsigned type = ELF32_R_TYPE(rel->r_info);
        unsigned sym = ELF32_R_SYM(rel->r_info);
        unsigned reloc = (unsigned)(rel->r_offset + si->base);
        //unsigned oldval = 0;
        void* pOldFun;
    
        if (sym_offset == sym) {
    
         switch(type) {
           case R_ARM_JUMP_SLOT:
              //Set appropriate memory access rights
              uint32_t page_size = getpagesize();
              uint32_t entry_page_start = reloc& (~(page_size - 1));
              mprotect((uint32_t *)entry_page_start, page_size, PROT_READ | PROT_WRITE);
    
             pOldFun = (void *)*((unsigned *)reloc);
    
              *((unsigned int*)reloc)= (unsigned)newval;  
    
              return pOldFun;
           default:
              return 0;
         }
        }
       }
       return 0;
    

    }

    The *jump to case label ... error: crosses initialization normally occurs when variables are not correctly initilized when using the switch case i.e. initialized in one case and used in another. Have a look at this question. A similar error occurred and was resolved.