Introduction to the

For Android SO files, there are three types of ELF files: Got table hook, Sym table hook, and inline hook. When the target process calls the hook function, it actually executes its own function. When the target process calls the hook function, it executes its own function. When the target process calls the hook function, it executes its own function.

Androd so injection and function Hook(based on got table) step:

1. Ptrace additional target PID process; 2. In the target PID process, find the memory space (the path to the so file to be injected and the name or shellcode of the function called in so); 3. Call dlopen, DLSYm and other functions in the target PID process to load so file and realize the injection of Android SO and Hook of the function; 4. Release the additional target PID process and uninstall the injected SO file.

Code implementation

The following uses the fopen function to get hook as an example.

// Obtain the module address function implementation
void* getModuleBase(pid_t pid, const char* module_name){
    FILE* fp;
    long address = 0;
    char* pch;
    char filename[32];
    char line[1024];

    // Format string to get "/proc/pid/maps"
    if(pid < 0) {snprintf(filename, sizeof(filename), "/proc/self/maps");
    }else{
        snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
    }

    // Open the /proc/pid/maps file to obtain the memory module information loaded by the specified PID process
    fp = fopen(filename, "r");
    if(fp ! =NULL) {// Read the contents of the /proc/pid/maps file one line at a time
        while(fgets(line, sizeof(line), fp)){
            // Find the specified so module
            if(strstr(line, module_name)){
                // Split the string
                pch = strtok(line, "-");
                // String length integer
                address = strtoul(pch, NULL.16);
               
                }
                break; }}}fclose(fp);
    return (void*)address;
}



Copy the code
// Hook fopen to implement(the libxxxx.so file is the ELF32 file)#define LIB_PATH "/data/app-lib/com.xxxx/libxxxx.so"

int hookFopen(a){

    // Obtain the "/data/app-lib/com.xxxx/libxxxx.so" module loading address in the target PID process
    void* base_addr = getModuleBase(getpid(), LIB_PATH);
    LOGD("[+] libxxxx.so address = %p \n", base_addr);

    // Save the original call address of the Hook target function
    old_fopen = fopen;
    
    int fd;
    // open memory module file "/data/app-lib/com.xxxx/libxxxx.so"
    fd = open(LIB_PATH, O_RDONLY);
    if(- 1 == fd){
        return - 1;
    }

     // Elf32 file header structure Elf32_Ehdr
    Elf32_Ehdr ehdr;
    // Read the header information of the elf32 file "/data/app-lib/com.xxxx/libxxxx.so"
    read(fd, &ehdr, sizeof(Elf32_Ehdr));

    // The file offset of the section area table structure in the elf32 file
    unsigned long shdr_addr = ehdr.e_shoff;
    // Number of section area table information structures in the elf32 file
    int shnum = ehdr.e_shnum;
    // The size of the individual information structures in each section table information structure in the elf32 file (the size of the structure that describes the information in each section)
    int shent_size = ehdr.e_shentsize;

    // elf32 The name of each section in the section table is stored in the section name string table, and the ordinal number in the section table is index
    unsigned long stridx = ehdr.e_shstrndx;

    // the structure of each cell in the section area table in the elf32 file.
    Elf32_Shdr shdr;
    // elf32 file to locate the string table containing each section name information struct. shstrtab
    lseek(fd, shdr_addr + stridx * shent_size, SEEK_SET);
    // Read the structure in the elf32 file that describes the information about each section (here is the name string of each section in the ELf32 file)
    read(fd, &shdr, shent_size);

    // Allocate memory space for all section name strings that hold elf32 files
    char * string_table = (char *)malloc(shdr.sh_size);
    // Locate the file offset where all the standoscope name strings of the elf32 file are stored
    lseek(fd, shdr.sh_offset, SEEK_SET);
    read(fd, string_table, shdr.sh_size);
    lseek(fd, shdr_addr, SEEK_SET);

    int i;
    uint32_t out_addr = 0;
    uint32_t out_size = 0;
    uint32_t got_item = 0;
    int32_t got_found = 0;

    // Loop through the section extenttable of the elf32 file (the structure that describes each section extentinformation)
    for(i = 0; i<shnum; i++){
        // Read each structure in the extents table that describes the extents in turn
        read(fd, &shdr, shent_size);
        // Check whether the current section description structure is of SHT_PROGBITS type
        // The. Got section of type SHT_PROGBITS contains the global offset table
        if(shdr.sh_type == SHT_PROGBITS){
            // Get the ordinal number in the section name string segment that holds all section names. Shstrtab
            int name_idx = shdr.sh_name;

            // Check whether the section name is ".got. PLT "or ".got".
            if(strcmp(&(string_table[name_idx]), ".got.plt") = =0
                || strcmp(&(string_table[name_idx]), ".got") = =0) {// Get the actual memory location of the section ".got" or ".got. PLT"
                out_addr = base_addr + shdr.sh_addr;
                // Get the size of the node area ".got" or ".got. PLT"
                out_size = shdr.sh_size;

                int j = 0;
                // Iterate over the section ".got" or ".got. PLT "to get the saved global function call address
                for(j = 0; j<out_size; j += 4) {// Get the address of a single function in the section ".got" or ".got. PLT"
                    got_item = *(uint32_t*)(out_addr + j);
                    // Check whether the address of the function call in the section ".got" or ".got. PLT "is the address of the target function to be hooked
                    if(got_item == old_fopen){
                        LOGD("[+] Found fopen in got.\n");
                        got_found = 1;
                        // Get the size of the current memory page
                        uint32_t page_size = getpagesize(a);// Get the start address of the page (requires memory alignment)
                        uint32_t entry_page_start = (out_addr + j) & (~(page_size - 1));
                        LOGD("[+] entry_page_start = %lx, page size = %lx\n", entry_page_start, page_size);
                        // Modify the memory properties to be readable, writable and executable
                        if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_WRITE | PROT_EXEC) == - 1) {LOGD("mprotect false.\n");
                            return - 1;
                        }
                        LOGD("[+] %s, old_fopen = %lx, new_fopen = %lx\n"."before hook function", got_item, new_fopen);

                        // The Hook function is a function defined by ourselves
                        got_item = new_fopen;
                        LOGD("[+] %s, old_fopen = %lx, new_fopen = %lx\n"."after hook function", got_item, new_fopen);
                        // Restore the memory properties to be readable and executable
                        if(mprotect((uint32_t*)entry_page_start, page_size, PROT_READ | PROT_EXEC) == - 1) {LOGD("mprotect false.\n");
                            return - 1;
                        }
                        break;
                    // At this point, the target function's call address has been hooked
                    }else if(got_item == new_fopen){
                        LOGD("[+] Already hooked.\n");
                        break; }}// Hook the target function succeeds and breaks the loop
                if(got_found)
                    break; }}}free(string_table);
    close(fd);
}
Copy the code