android自定义linker实现安全加固

转:https://blog.csdn.net/liumengdeqq/article/details/79247091

mmap的用户层应用
void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
具体参数含义
start :  指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
length:  代表将文件中多大的部分映射到内存。
prot  :  映射区域的保护方式。可以为以下几种方式的组合:
                    PROT_EXEC 映射区域可被执行
                    PROT_READ 映射区域可被读取
                    PROT_WRITE 映射区域可被写入
                    PROT_NONE 映射区域不能存取
flags :  影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。
                    MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
                    MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
                    MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
                    MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
                    MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
                    MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
fd    :  要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,
          然后对该文件进行映射,可以同样达到匿名内存映射的效果。
offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是PAGE_SIZE的整数倍。

返回值:
      若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

错误代码:
            EBADF  参数fd 不是有效的文件描述词
            EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。
            EINVAL 参数start、length 或offset有一个不合法。
            EAGAIN 文件被锁住,或是有太多内存被锁住。
            ENOMEM 内存不足。
用户层的调用很简单,其具体功能就是直接将物理内存直接映射到用户虚拟内存,使用户空间可以直接对物理空间操作。

 

开源代码地址:https://github.com/liumengdeqq/CustomLinker.git        

壳加密ShellUtil

main.c

//
//  main.c
//  Goblin_Shell_4.1.2
//
//  Created by liu meng on 2018/1/30.
//  Copyright © 2018年 com.qunar. All rights reserved.
//

//#include <stdio.h>
//#include "Utils.h"
#include "Encryption.h"
//char *white[]={"/system/lib/libc.so","/system/lib/liblog.so","/system/lib/libm.so","/system/lib/libdl.so","/system/lib/libstdc++.so"};
//int iswhite(char* name){
//    for(int i=0;i<strlen(white);i++){
//        if(strcmp(name, white[i])==0){
//            return 1;
//        }
//    }
//    return 0;
//}
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)   //PAGE = 0x1000
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define PAGE_MASK (~(PAGE_SIZE-1))      //PAGE_MASK = 0xFFFFF000
// Returns the address of the page containing address 'x'.
#define PAGE_START(x)  ((x) & PAGE_MASK)

// Returns the offset of address 'x' in its page.
#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)

// Returns the address of the next page after address 'x', unless 'x' is
// itself at the start of a page.
#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
#define BIONIC_ALIGN(value, alignment) \
(((value) + (alignment) - 1) & ~((alignment) - 1))
#define UINT32_MAX       (4294967295U)
#  define dddd_MAX    INT32_MAX
int main(int argc, const char * argv[]) {
    // insert code here...
//    printf("Hello, World!\n");
//    printf("%0x",(0xffffffba));
//    size_t rounded = BIONIC_ALIGN(4294967296, PAGE_SIZE);
//    if (rounded < 4097 || rounded > dddd_MAX) {
//        printf("ddddd");
//    }
//    printf("%ul\n",PAGE_SIZE);
    encryption("/Users/liumeng/shell/shell/shell/libdata.so");
    
//    pid_t pid=getpid();
//    MemoryMap myMap;
//    char *name="/system/lib/libc.so";
//    if(iswhite(name)==1){
//         hookSoAddress(pid,myMap,name);
//    }

    return 0;
}
Encryption.h
//
//  Encryption.h
//  shell
//
//  Created by liu meng on 2018/2/4.
//  Copyright © 2018年 liu mengcom.example. All rights reserved.
//

#ifndef Encryption_h
#define Encryption_h
#include "elf.h"
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int encryption(char *path);
#endif /* Encryption_h */

 Encryption.c

#include "Encryption.h"
typedef struct _funcInfo{
    Elf32_Addr st_value;
    Elf32_Word st_size;
}funcInfo;

Elf32_Ehdr ehdr;
char flag = -1, *dynstr;
int i;
Elf32_Sym funSym;
Elf32_Phdr phdr;
Elf32_Off dyn_off;
Elf32_Word dyn_size, dyn_strsz;
Elf32_Dyn dyn;
Elf32_Addr dyn_symtab, dyn_strtab, dyn_hash;
unsigned funHash, nbucket, nchain, funIndex;
//For Test
static void print_all(char *str, int len){
    int i;
    for(i=0;i<len;i++)
    {
        if(str[i] == 0)
            puts("");
        else
            printf("%c", str[i]);
    }
}

static unsigned elfhash(const char *_name)
{
    const unsigned char *name = (const unsigned char *) _name;
    unsigned h = 0, g;
    
    while(*name) {
        h = (h << 4) + *name++;
        g = h & 0xf0000000;
        h ^= g;
        h ^= g >> 24;
    }
    return h;
}

static char getTargetFuncInfo(int fd, const char *funcName, funcInfo *info){
    lseek(fd, 0, SEEK_SET);
    if(read(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
        puts("Read ELF header error");
        goto _error;
    }

    lseek(fd, ehdr.e_phoff, SEEK_SET);
    for(i=0;i < ehdr.e_phnum; i++){
        if(read(fd, &phdr, sizeof(Elf32_Phdr)) != sizeof(Elf32_Phdr)){
            puts("Read segment failed");
            goto _error;
        }
        if(phdr.p_type ==  PT_DYNAMIC){
            dyn_size = phdr.p_filesz;
            dyn_off = phdr.p_offset;
            flag = 0;
            printf("Find section %s, size = 0x%x, addr = 0x%x\n", ".dynamic", dyn_size, dyn_off);
            break;
        }
    }
    if(flag){
        puts("Find .dynamic failed");
        goto _error;
    }
    flag = 0;
    
    lseek(fd, dyn_off, SEEK_SET);
    for(i=0;i < dyn_size / sizeof(Elf32_Dyn); i++){
        if(read(fd, &dyn, sizeof(Elf32_Dyn)) != sizeof(Elf32_Dyn)){
            puts("Read .dynamic information failed");
            goto _error;
        }
        if(dyn.d_tag == DT_SYMTAB){
            dyn_symtab = dyn.d_un.d_ptr;
            flag += 1;
            printf("Find .dynsym, addr = 0x%x\n", dyn_symtab);
        }
        //    if(dyn.d_tag == DT_GNU_HASH){ //For Android: DT_HASH
        if(dyn.d_tag == DT_HASH){
            dyn_hash = dyn.d_un.d_ptr;
            flag += 2;
            printf("Find .hash, addr = 0x%x\n", dyn_hash);
        }
        if(dyn.d_tag == DT_STRTAB){
            dyn_strtab = dyn.d_un.d_ptr;
            flag += 4;
            printf("Find .dynstr, addr = 0x%x\n", dyn_strtab);
        }
        if(dyn.d_tag == DT_STRSZ){
            dyn_strsz = dyn.d_un.d_val;
            flag += 8;
            printf("Find .dynstr size, size = 0x%x\n", dyn_strsz);
        }
    }
    if((flag & 0x0f) != 0x0f){
        puts("Find needed .section failed\n");
        goto _error;
    }
    
    dynstr = (char*) malloc(dyn_strsz);
    if(dynstr == NULL){
        puts("Malloc .dynstr space failed");
        goto _error;
    }
    
    lseek(fd, dyn_strtab, SEEK_SET);
    if(read(fd, dynstr, dyn_strsz) != dyn_strsz){
        puts("Read .dynstr failed");
        goto _error;
    }
    //  print_all(dynstr, dyn_strsz);
    
    funHash = elfhash(funcName);
    printf("Function %s hashVal = 0x%x\n", funcName, funHash);
    
    lseek(fd, dyn_hash, SEEK_SET);
    if(read(fd, &nbucket, 4) != 4){
        puts("Read hash nbucket failed\n");
        goto _error;
    }
    printf("nbucket = %d\n", nbucket);
    
    if(read(fd, &nchain, 4) != 4){
        puts("Read hash nchain failed\n");
        goto _error;
    }
    //  printf("nchain = %d\n", nchain);
    
    funHash = funHash % nbucket;
    printf("funHash mod nbucket = %d \n", funHash);
    
    lseek(fd, funHash * 4, SEEK_CUR);
    if(read(fd, &funIndex, 4) != 4){
        puts("Read funIndex failed\n");
        goto _error;
    }
    
    lseek(fd, dyn_symtab + funIndex * sizeof(Elf32_Sym), SEEK_SET);
    if(read(fd, &funSym, sizeof(Elf32_Sym)) != sizeof(Elf32_Sym)){
        puts("Read funSym failed");
        goto _error;
    }
    
    if(strcmp(dynstr + funSym.st_name, funcName) != 0){
        while(1){
            lseek(fd, dyn_hash + 4 * (2 + nbucket + funIndex), SEEK_SET);
            if(read(fd, &funIndex, 4) != 4){
                puts("Read funIndex failed\n");
                goto _error;
            }
            
            if(funIndex == 0){
                puts("Cannot find funtion!\n");
                goto _error;
            }
            
            lseek(fd, dyn_symtab + funIndex * sizeof(Elf32_Sym), SEEK_SET);
            if(read(fd, &funSym, sizeof(Elf32_Sym)) != sizeof(Elf32_Sym)){
                             puts("In FOR loop, Read funSym failed");
                             goto _error;
                         }
            
            if(strcmp(dynstr + funSym.st_name, funcName) == 0){
                             break;
                         }
        }
    }
    
    printf("Find: %s, offset = 0x%x, size = 0x%x\n", funcName, funSym.st_value, funSym.st_size);
    info->st_value = funSym.st_value;
    info->st_size = funSym.st_size;
    free(dynstr);
    return 0;
    
_error:
    free(dynstr);
    return -1;
}

int encryption(char *path){
    char funcName[] = "JNI_OnLoad";
    char *content = NULL;
    int fd, i;
    Elf32_Off secOff;
    funcInfo info;
    fd = open(path, O_RDWR);
    if(fd < 0){
        goto _error;
    }

    if(getTargetFuncInfo(fd, funcName, &info) == -1){
        printf("Find function %s failed\n", funcName);
        goto _error;
    }
    
    content = (char*) malloc(info.st_size);
    if(content == NULL){
        puts("Malloc space failed");
        goto _error;
    }

    //thumb指令
    lseek(fd, info.st_value - 1, SEEK_SET);
    if(read(fd, content, info.st_size) != info.st_size){
        puts("Malloc space failed");
        goto _error;
    }

     // 这里最后一个字节并没有加密
    for(i=0;i<info.st_size-1;i++){
        printf("%x\n",content[i]);
        content[i] = ~content[i];
        printf("%x\n",content[i]);
    }
    printf("\n");
    lseek(fd, info.st_value-1, SEEK_SET);


    if(write(fd, content, info.st_size) != info.st_size){
        puts("Write modified content to .so failed");
        goto _error;
    }
    puts("Complete!");
    
_error:
    free(content);
    close(fd);
    return 0;
}

types.h

//
//  types.h
//  Goblin_Shell_4.1.2
//
//  Created by liu meng on 2018/1/30.
//  Copyright © 2018年 com.qunar. All rights reserved.
//


typedef unsigned short umode_t;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef __signed__ char __s8;
typedef unsigned char __u8;
typedef __signed__ short __s16;
typedef unsigned short __u16;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef __signed__ int __s32;
typedef unsigned int __u32;
typedef __signed__ long long __s64;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef unsigned long long __u64;

auxvec.h
//
//  auxvec.h
//  Goblin_Shell_4.1.2
//
//  Created by liu meng on 2018/1/30.
//  Copyright © 2018年 com.qunar. All rights reserved.
//

#ifndef _LINUX_AUXVEC_H
#define _LINUX_AUXVEC_H



/* Symbolic values for the entries in the auxiliary table
 put on the initial stack */
#define AT_NULL   0    /* end of vector */
#define AT_IGNORE 1    /* entry should be ignored */
#define AT_EXECFD 2    /* file descriptor of program */
#define AT_PHDR   3    /* program headers for program */
#define AT_PHENT  4    /* size of program header entry */
#define AT_PHNUM  5    /* number of program headers */
#define AT_PAGESZ 6    /* system page size */
#define AT_BASE   7    /* base address of interpreter */
#define AT_FLAGS  8    /* flags */
#define AT_ENTRY  9    /* entry point of program */
#define AT_NOTELF 10    /* program is not ELF */
#define AT_UID    11    /* real uid */
#define AT_EUID   12    /* effective uid */
#define AT_GID    13    /* real gid */
#define AT_EGID   14    /* effective gid */
#define AT_PLATFORM 15  /* string identifying CPU for optimizations */
#define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
#define AT_CLKTCK 17    /* frequency at which times() increments */

#define AT_SECURE 23   /* secure mode boolean */

#define AT_VECTOR_SIZE  44 /* Size of auxiliary table.  */

#endif /* _LINUX_AUXVEC_H */

elf-em.h

//
//  elf-em.h
//  Goblin_Shell_4.1.2
//
//  Created by liu meng on 2018/1/30.
//  Copyright © 2018年 com.qunar. All rights reserved.
//

#ifndef _LINUX_ELF_EM_H
#define _LINUX_ELF_EM_H

/* These constants define the various ELF target machines */
#define EM_NONE        0
#define EM_M32        1
#define EM_SPARC    2
#define EM_386        3
#define EM_68K        4
#define EM_88K        5
#define EM_486        6    /* Perhaps disused */
#define EM_860        7
#define EM_MIPS        8    /* MIPS R3000 (officially, big-endian only) */
/* Next two are historical and binaries and
 modules of these types will be rejected by
 Linux.  */
#define EM_MIPS_RS3_LE    10    /* MIPS R3000 little-endian */
#define EM_MIPS_RS4_BE    10    /* MIPS R4000 big-endian */

#define EM_PARISC    15    /* HPPA */
#define EM_SPARC32PLUS    18    /* Sun's "v8plus" */
#define EM_PPC        20    /* PowerPC */
#define EM_PPC64    21       /* PowerPC64 */
#define EM_SH        42    /* SuperH */
#define EM_SPARCV9    43    /* SPARC v9 64-bit */
#define EM_IA_64    50    /* HP/Intel IA-64 */
#define EM_X86_64    62    /* AMD x86-64 */
#define EM_S390        22    /* IBM S/390 */
#define EM_CRIS        76    /* Axis Communications 32-bit embedded processor */
#define EM_V850        87    /* NEC v850 */
#define EM_M32R        88    /* Renesas M32R */
#define EM_H8_300    46    /* Renesas H8/300,300H,H8S */
#define EM_FRV        0x5441    /* Fujitsu FR-V */

/*
 * This is an interim value that we will use until the committee comes
 * up with a final number.
 */
#define EM_ALPHA    0x9026

/* Bogus old v850 magic number, used by old tools. */
#define EM_CYGNUS_V850    0x9080
/* Bogus old m32r magic number, used by old tools. */
#define EM_CYGNUS_M32R    0x9041
/* This is the old interim value for S/390 architecture */
#define EM_S390_OLD    0xA390


#endif /* _LINUX_ELF_EM_H */

 

elf.h

//
//  elf.h
//  Goblin_Shell_4.1.2
//
//  Created by liu meng on 2018/1/30.
//  Copyright © 2018年 com.qunar. All rights reserved.
//

#ifndef _LINUX_ELF_H
#define _LINUX_ELF_H
#include "types.h"
#include "auxvec.h"
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#include "elf-em.h"

#define EM_ARM 40
#ifndef elf_read_implies_exec
#define elf_read_implies_exec(ex, have_pt_gnu_stack) 0
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#endif
typedef __u32 Elf32_Addr;
typedef __u16 Elf32_Half;
typedef __u32 Elf32_Off;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef __s32 Elf32_Sword;
typedef __u32 Elf32_Word;
typedef __u64 Elf64_Addr;
typedef __u16 Elf64_Half;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef __s16 Elf64_SHalf;
typedef __u64 Elf64_Off;
typedef __s32 Elf64_Sword;
typedef __u32 Elf64_Word;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef __u64 Elf64_Xword;
typedef __s64 Elf64_Sxword;
#define R_ARM_NONE 0
#define PT_NULL 0
#define PT_LOAD 1
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define PT_PHDR 6
#define PT_TLS 7
#define PT_LOOS 0x60000000
#define PT_HIOS 0x6fffffff
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ET_CORE 4
#define ET_LOPROC 0xff00
#define ET_HIPROC 0xffff
#define DT_NULL 0
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_LOPROC 0x70000000
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define DT_HIPROC 0x7fffffff
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define STT_FILE 4
#define STT_COMMON 5
#define STT_TLS 6
#define ELF_ST_BIND(x) ((x) >> 4)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf)
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
typedef struct dynamic{
    Elf32_Sword d_tag;
    union{
        /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
        Elf32_Sword d_val;
        Elf32_Addr d_ptr;
    } d_un;
} Elf32_Dyn;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef struct {
    Elf64_Sxword d_tag;
    union {
        Elf64_Xword d_val;
        /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
        Elf64_Addr d_ptr;
    } d_un;
} Elf64_Dyn;
#define ELF32_R_SYM(x) ((x) >> 8)
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ELF32_R_TYPE(x) ((x) & 0xff)
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
typedef struct elf32_rel {
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Addr r_offset;
    Elf32_Word r_info;
} Elf32_Rel;
typedef struct elf64_rel {
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Addr r_offset;
    Elf64_Xword r_info;
} Elf64_Rel;
typedef struct elf32_rela{
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Addr r_offset;
    Elf32_Word r_info;
    Elf32_Sword r_addend;
} Elf32_Rela;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
typedef struct elf64_rela {
    Elf64_Addr r_offset;
    Elf64_Xword r_info;
    Elf64_Sxword r_addend;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} Elf64_Rela;
typedef struct elf32_sym{
    Elf32_Word st_name;
    Elf32_Addr st_value;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Word st_size;
    unsigned char st_info;
    unsigned char st_other;
    Elf32_Half st_shndx;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} Elf32_Sym;
typedef struct elf64_sym {
    Elf64_Word st_name;
    unsigned char st_info;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    unsigned char st_other;
    Elf64_Half st_shndx;
    Elf64_Addr st_value;
    Elf64_Xword st_size;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} Elf64_Sym;
#define EI_NIDENT 16
typedef struct elf32_hdr{
    unsigned char e_ident[EI_NIDENT];
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Half e_type;
    Elf32_Half e_machine;
    Elf32_Word e_version;
    Elf32_Addr e_entry;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Off e_phoff;
    Elf32_Off e_shoff;
    Elf32_Word e_flags;
    Elf32_Half e_ehsize;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Half e_phentsize;
    Elf32_Half e_phnum;
    Elf32_Half e_shentsize;
    Elf32_Half e_shnum;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf64_hdr {
    unsigned char e_ident[16];
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Half e_type;
    Elf64_Half e_machine;
    Elf64_Word e_version;
    Elf64_Addr e_entry;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Off e_phoff;
    Elf64_Off e_shoff;
    Elf64_Word e_flags;
    Elf64_Half e_ehsize;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Half e_phentsize;
    Elf64_Half e_phnum;
    Elf64_Half e_shentsize;
    Elf64_Half e_shnum;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Half e_shstrndx;
} Elf64_Ehdr;
#define PF_R 0x4
#define PF_W 0x2
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define PF_X 0x1
typedef struct elf32_phdr{
    Elf32_Word p_type;
    Elf32_Off p_offset;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Addr p_vaddr;
    Elf32_Addr p_paddr;
    Elf32_Word p_filesz;
    Elf32_Word p_memsz;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Word p_flags;
    Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Word p_type;
    Elf64_Word p_flags;
    Elf64_Off p_offset;
    Elf64_Addr p_vaddr;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Addr p_paddr;
    Elf64_Xword p_filesz;
    Elf64_Xword p_memsz;
    Elf64_Xword p_align;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} Elf64_Phdr;
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHT_DYNSYM 11
#define SHT_NUM 12
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHF_EXECINSTR 0x4
#define SHF_MASKPROC 0xf0000000
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xff00
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHN_LOPROC 0xff00
#define SHN_HIPROC 0xff1f
#define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define SHN_HIRESERVE 0xffff
typedef struct {
    Elf32_Word sh_name;
    Elf32_Word sh_type;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Word sh_flags;
    Elf32_Addr sh_addr;
    Elf32_Off sh_offset;
    Elf32_Word sh_size;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Word sh_link;
    Elf32_Word sh_info;
    Elf32_Word sh_addralign;
    Elf32_Word sh_entsize;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} Elf32_Shdr;
typedef struct elf64_shdr {
    Elf64_Word sh_name;
    Elf64_Word sh_type;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Xword sh_flags;
    Elf64_Addr sh_addr;
    Elf64_Off sh_offset;
    Elf64_Xword sh_size;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Word sh_link;
    Elf64_Word sh_info;
    Elf64_Xword sh_addralign;
    Elf64_Xword sh_entsize;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
} Elf64_Shdr;
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define EI_OSABI 7
#define EI_PAD 8
#define ELFMAG0 0x7f
#define ELFMAG1 'E'
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFMAG "\177ELF"
#define SELFMAG 4
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ELFCLASSNONE 0
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASSNUM 3
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ELFDATANONE 0
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define EV_NONE 0
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define EV_CURRENT 1
#define EV_NUM 2
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#ifndef ELF_OSABI
#define ELF_OSABI ELFOSABI_NONE
#endif
#define NT_PRSTATUS 1
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define NT_PRXFPREG 0x46e62b7f
typedef struct elf32_note {
    Elf32_Word n_namesz;
    Elf32_Word n_descsz;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf32_Word n_type;
} Elf32_Nhdr;
typedef struct elf64_note {
    Elf64_Word n_namesz;
    /* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
    Elf64_Word n_descsz;
    Elf64_Word n_type;
} Elf64_Nhdr;
#if ELF_CLASS == ELFCLASS32
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define elfhdr elf32_hdr
#define elf_phdr elf32_phdr
#define elf_note elf32_note
#else
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define elfhdr elf64_hdr
#define elf_phdr elf64_phdr
#define elf_note elf64_note
#endif
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#endif

加密后的结果

libfoo.so的JNI_OnLoad

int __fastcall JNI_OnLoad(_JavaVM *vm, void *reserved)
{
  _JNIEnv *env_; // r5
  jclass clazz; // r1
  int result; // r0
  _JNIEnv *env; // [sp+4h] [bp-14h]

  env = 0;
  if ( !vm->functions->GetEnv(&vm->functions, (JNIEnv **)&env, 0x10004)
    && (env_ = env) != 0
    && (clazz = (jclass)((int (__fastcall *)(_JNIEnv *, const char *))env->functions->FindClass)(
                          env,
                          "com/example/memloadertest/MainActivity")) != 0 )
  {
    result = (((int (__fastcall *)(_JNIEnv *, jclass, char **, signed int))env_->functions->RegisterNatives)(
                env_,
                clazz,
                gMethods,
                1) >> 31) | 0x10004;
  }
  else
  {
    result = -1;
  }
  return result;
}

内存加载解密流程

MainActivity.java

package com.example.memloadertest;

import android.graphics.Color;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

//      CustomTextView customTextView=(CustomTextView)findViewById(R.id.ringView);
//      List<Integer> colors=new ArrayList();
//      colors.add(Color.RED);
//      colors.add(Color.BLUE);
//      List<Float> rate=new ArrayList();
//      rate.add(50.0f);
//      rate.add(50.0f);
//      customTextView.setShow(colors,rate,true,true);
         Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(getString());

    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String getString();
}

native-lib.c

#include "linker7_0.h"
#include "linker4_4.h"
#include "XorUtils.h"
#include <sys/system_properties.h>
#include <android/asset_manager_jni.h>


static void fix_cmdline(char *buf) {
    int length = strlen(buf);

    DL_ERR("length=%d", length);

    //TODO fix :remote bug
    while (length > -1) {
        if (buf[length] == ':') {
            buf[length] = '\0';
            break;
        }
        length--;
    }

}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {


    char buf[200];

    FILE *fp;
    int pid = getpid();
    sprintf(buf,"/proc/%d/cmdline", pid);
    fp = fopen(buf, "r");
    if(fp == NULL)
    {
        DL_ERR("Open error!!");
    }

    while(fgets(buf, sizeof(buf), fp)){
        DL_ERR("cmdline=%s", buf);
        fix_cmdline(buf);           //获取包名
        DL_ERR("cmdline=%s", buf);
    }
    fclose(fp);

    char desFile[400];
    sprintf(desFile, "/data/data/%s/lib/libdata.so", buf);
    DL_ERR("open file is %s", desFile);
    // jint (*real_JNI_OnLoad)(JavaVM*, void*);
    // real_JNI_OnLoad = (jint (*)(JavaVM*, void*))(gbdlsym(si,"JNI_OnLoad"));
    // if(real_JNI_OnLoad == NULL){
    //  DL_ERR("cannot find sym %s\n", "JNI_OnLoad");
    // }
    // return real_JNI_OnLoad(vm, reserved);
    //4.1.2 end

    __system_property_get("ro.build.version.sdk", buf);
    int version = 0;
    sscanf(buf, "%d", &version);
    if (version < 24) {
        //4.4 start
        //加载,链接,调用constructor
        soinfo4_4 *soinfo4_4 = find_library_internal4_4(desFile);
        if (soinfo4_4 == NULL) {
            DL_ERR("find soinfo fail");
            return JNI_VERSION_1_4;
        }
        DL_ERR("find soinfo success");

        //解密JNI_OnLoad
        xor_code(soinfo4_4->base,start_page_address4_4,start_page_filelength4_4);

        //调用解密后的JNI_OnLoad,并替换结果
        jint (*real_JNI_OnLoad4_4)(JavaVM *, void *);
        real_JNI_OnLoad4_4 = (jint (*)(JavaVM *, void *)) (lookup_in_library4_4(soinfo4_4,
                                                                                "JNI_OnLoad"));
        if (real_JNI_OnLoad4_4 == NULL) {
            DL_ERR("cannot find sym %s\n", "JNI_OnLoad");
        } else {
            return real_JNI_OnLoad4_4(vm, reserved);
        }
        //4.4 end
    } else {
         //加载,链接,调用constructor
        soinfo7_0 *soinfo7_0 = find_library_internal7_0(desFile);
        if (soinfo7_0 == NULL) {
            DL_ERR("find soinfo fail");
            return JNI_VERSION_1_4;
        }
        DL_ERR("find soinfo success");

         //解密JNI_OnLoad
        xor_code(soinfo7_0->base,start_page_address7_0,start_page_filelength7_0);

         //调用解密后的JNI_OnLoad,并替换结果
        jint (*real_JNI_OnLoad7_0)(JavaVM *, void *);
        real_JNI_OnLoad7_0 = (jint (*)(JavaVM *, void *)) (lookup_in_library7_0(soinfo7_0,
                                                                                "JNI_OnLoad"));
        if (real_JNI_OnLoad7_0 == NULL) {
            DL_ERR("cannot find sym %s\n", "JNI_OnLoad");
        } else {
            return real_JNI_OnLoad7_0(vm, reserved);
        }
        //7.0 end
    }
    return JNI_VERSION_1_4;
}

linker4-4.h

#ifndef _LINKER4_4_H_
#define _LINKER4_4_H_
#include <unistd.h>
#include <sys/types.h>
#include "elf.h"
#include "exec_elf.h"
#include "auxvec.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <pthread.h>
#include <jni.h>
#include <sys/mman.h>
#include "public.h"
#include "elf_arm_const.h"
//#define PAGE_SHIFT 12
//#define PAGE_Y_SIZE (1UL << PAGE_SHIFT)
//#define PAGE_Y_MASK (~(PAGE_Y_SIZE-1))
#define PAGE_START(x)  ((x) & PAGE_MASK)
#define PAGE_OFFSET(x) ((x) & ~PAGE_MASK)
#define PAGE_END(x)    PAGE_START((x) + (PAGE_SIZE-1))
#ifdef __LP64__
typedef long           intptr_t;
typedef unsigned long  uintptr_t;
#else
typedef int           intptr_t;
typedef unsigned int  uintptr_t;
#endif
typedef struct soinfo4_4 soinfo4_4;
struct link_map_4_4_t {
  uintptr_t l_addr;
  char*  l_name;
  uintptr_t l_ld;
  struct link_map_4_4_t* l_next;
  struct link_map_4_4_t* l_prev;
};
void* start_page_address4_4;
Elf32_Addr start_page_filelength4_4;
#define ANDROID_ARM_LINKER "arm"
typedef void (*linker_function4_4_t)();
struct soinfo4_4 {
  char name[SOINFO_NAME_LEN];
  const Elf32_Phdr* phdr;
  size_t phnum;
  Elf32_Addr entry;
  Elf32_Addr base;
  unsigned size;

  uint32_t unused1;  

  Elf32_Dyn* dynamic;

  uint32_t unused2; 
  uint32_t unused3; 

  soinfo4_4* next;
  unsigned flags;

  const char* strtab;
  Elf32_Sym* symtab;

  size_t nbucket;
  size_t nchain;
  unsigned* bucket;
  unsigned* chain;

  unsigned* plt_got;

  Elf32_Rel* plt_rel;
  size_t plt_rel_count;

  Elf32_Rel* rel;
  size_t rel_count;

  linker_function4_4_t* preinit_array;
  size_t preinit_array_count;

  linker_function4_4_t* init_array;
  size_t init_array_count;
  linker_function4_4_t* fini_array;
  size_t fini_array_count;

 linker_function4_4_t init_func;
  linker_function4_4_t fini_func;
#if defined(ANDROID_ARM_LINKER)
  // ARM EABI section used for stack unwinding.
  unsigned* ARM_exidx;
  size_t ARM_exidx_count;
#elif defined(ANDROID_MIPS_LINKER)
  unsigned mips_symtabno;
  unsigned mips_local_gotno;
  unsigned mips_gotsym;
#endif

  size_t ref_count;
  struct link_map_4_4_t link_map;

  unsigned char constructors_called;
  Elf32_Addr load_bias;
  unsigned char has_text_relocations;
  unsigned char has_DT_SYMBOLIC;
};
soinfo4_4* find_library_internal4_4(const char* name);
void *lookup_in_library4_4(soinfo4_4 *si, const char *name);
#endif

linker4-4.c

#include "linker4_4.h"
int pid;
#define SO_MAX 128
static int socount4_4 = 0;
static soinfo4_4 sopool4_4[SO_MAX];
static soinfo4_4 *freelist4_4 = NULL;
static unsigned elfhash4_4(const char *_name)
{
    const unsigned char *name = (const unsigned char *) _name;
    unsigned h = 0, g;
    
    while(*name) {
        h = (h << 4) + *name++;
        g = h & 0xf0000000;
        h ^= g;
        h ^= g >> 24;
    }
    return h;
}

static soinfo4_4 *alloc_info4_4(const char *name)
{
    soinfo4_4 *soinfo4_4=NULL;
    
    if(strlen(name) >= SOINFO_NAME_LEN) {
        DL_ERR("library name %s too long",name);
        return NULL;
    }
     if (!freelist4_4) {
        if(socount4_4 == SO_MAX) {
            DL_ERR("too many libraries when loading %s", name);
            return NULL;
        }
        freelist4_4 = sopool4_4 + socount4_4++;
        freelist4_4->next = NULL;
    }
    
    soinfo4_4 = freelist4_4;
    freelist4_4 = freelist4_4->next;
     DL_ERR("library name %s new ",name);
    memset(soinfo4_4, 0, sizeof(soinfo4_4));

    strlcpy((char*) soinfo4_4->name, name, sizeof(soinfo4_4->name));
   
    soinfo4_4->next = NULL;
    return soinfo4_4;
}
static void free_info4_4(soinfo4_4 *si)
{
     si->next = freelist4_4;
     freelist4_4 = si;
}
static int
_phdr_table_set_load_prot4_4(const Elf32_Phdr* phdr_table,
                          int               phdr_count,
                          Elf32_Addr        load_bias,
                          int               extra_prot_flags)
{
    const Elf32_Phdr* phdr = phdr_table;
    const Elf32_Phdr* phdr_limit = phdr + phdr_count;

    for (; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0)
            continue;

        Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
        Elf32_Addr seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
        DL_ERR("segments ------=%08x",seg_page_start);
        int ret = mprotect((void*)seg_page_start,
                           seg_page_end - seg_page_start,
                           PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
        if (ret < 0) {
            return -1;
        }
    }
    return 0;
}
int
phdr_table_protect_segments4_4(const Elf32_Phdr* phdr_table,
                            int               phdr_count,
                            Elf32_Addr        load_bias)
{
    return _phdr_table_set_load_prot4_4(phdr_table, phdr_count,
                                      load_bias, 0);
}

int
phdr_table_unprotect_segments4_4(const Elf32_Phdr* phdr_table,
                              int               phdr_count,
                              Elf32_Addr        load_bias)
{
    return _phdr_table_set_load_prot4_4(phdr_table, phdr_count,
                                      load_bias, PROT_WRITE);
}
static int
_phdr_table_set_gnu_relro_prot4_4(const Elf32_Phdr* phdr_table,
                               int               phdr_count,
                               Elf32_Addr        load_bias,
                               int               prot_flags)
{
    const Elf32_Phdr* phdr = phdr_table;
    const Elf32_Phdr* phdr_limit = phdr + phdr_count;

    for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_GNU_RELRO)
            continue;
        Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr) + load_bias;
        Elf32_Addr seg_page_end   = PAGE_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
        DL_ERR("_phdr_table_set_gnu_relro_prot GNU=%08x",seg_page_start);
        int ret = mprotect((void*)seg_page_start,
                           seg_page_end - seg_page_start,
                           prot_flags);
        if (ret < 0) {
            return -1;
        }
    }
    return 0;
}
int
phdr_table_protect_gnu_relro4_4(const Elf32_Phdr* phdr_table,
                             int               phdr_count,
                             Elf32_Addr        load_bias)
{
    return _phdr_table_set_gnu_relro_prot4_4(phdr_table,
                                          phdr_count,
                                          load_bias,
                                          PROT_READ);
}

static Elf32_Sym* soinfo_elf_lookup4_4(soinfo4_4* si, unsigned hash, const char* name) {
    Elf32_Sym* symtab = si->symtab;
    const char* strtab = si->strtab;
    unsigned n=0;
    DL_ERR("SEARCH %s in %s@0x%08x %08x %d=====%08x",
               name, si->name, si->base, hash, hash % si->nbucket,si->nbucket);
    
    for (n= si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
        Elf32_Sym* s = symtab + n;
        // DL_ERR("NAME %s",strtab + s->st_name);
        if (strcmp(strtab + s->st_name, name)) continue;

            /* only concern ourselves with global and weak symbol definitions */
        switch(ELF32_ST_BIND(s->st_info)){
        case STB_GLOBAL:
        case STB_WEAK:
            if (s->st_shndx == SHN_UNDEF) {
                continue;
            }

            DL_ERR("FOUND %s in %s (%08x) %d",
                       name, si->name, s->st_value, s->st_size);
            return s;
        }
    }
    // DL_ERR("NULL");

    return NULL;
}
static Elf32_Sym* soinfo_do_lookup4_4(soinfo4_4* si, const char* name, soinfo4_4** lsi, soinfo4_4* needed[]) {
    unsigned elf_hash = elfhash4_4(name);
    Elf32_Sym* s = NULL;
    int i;
    for (i= 0; needed[i] != NULL; i++) {
        DEBUG("%s: looking up %s in %s",
              si->name, name, needed[i]->name);
        s = soinfo_elf_lookup4_4(needed[i], elf_hash, name);
        if (s != NULL) {
            *lsi = needed[i];
            goto done;
        }
    }

done:
    if (s != NULL) {
        DL_ERR("si %s sym %s s->st_value = 0x%08x, "
                   "found in %s, base = 0x%08x, load bias = 0x%08x",
                   si->name, name, s->st_value,
                   (*lsi)->name, (*lsi)->base, (*lsi)->load_bias);
        return s;
    }

    return NULL;
}
static int soinfo_relocate4_4(soinfo4_4* si, Elf32_Rel* rel, unsigned count,
                           soinfo4_4* needed[])
{
    Elf32_Sym* symtab = si->symtab;
    const char* strtab = si->strtab;
    Elf32_Sym* s;
    Elf32_Rel* start = rel;
    soinfo4_4* lsi;
    size_t idx; 

    for (idx= 0; idx < count; ++idx, ++rel) {
        unsigned type = ELF32_R_TYPE(rel->r_info);
        unsigned sym = ELF32_R_SYM(rel->r_info);
        Elf32_Addr reloc = (Elf32_Addr)(rel->r_offset + si->load_bias);
        Elf32_Addr sym_addr = 0;
        char* sym_name = NULL;

        DEBUG("Processing '%s' relocation at index %d", si->name, idx);
        if (type == 0) { // R_*_NONE
            continue;
        }
        if (sym != 0) {
            sym_name = (char *)(strtab + symtab[sym].st_name);
            s = soinfo_do_lookup4_4(si, sym_name, &lsi, needed);

            if (s == NULL) {
                
                /* We only allow an undefined symbol if this is a weak
                   reference..   */
                s = &symtab[sym];
                if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
                    DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, si->name);
                    return -1;
                }
               if(s!=NULL){
                  DL_ERR(" %s is not null",sym_name);
                }
                switch (type) {
                case R_ARM_JUMP_SLOT:
                case R_ARM_GLOB_DAT:
                case R_ARM_ABS32:
                case R_ARM_RELATIVE:    /* Don't care. */

                    /* sym_addr was initialized to be zero above or relocation
                       code below does not care about value of sym_addr.
                       No need to do anything.  */
                    break;



                case R_ARM_COPY:
                    /* Fall through.  Can't really copy if weak symbol is
                       not found in run-time.  */
                default:
                    DL_ERR("unknown weak reloc type %d @ %p (%d)",
                                 type, rel, (int) (rel - start));
                    return -1;
                }
            } else {
                // if(lsi->load_bias!=NULL){
    	           //     lsi->base=lsi->load_bias;
                //  }
                sym_addr = (Elf32_Addr)(s->st_value + lsi->base);
            }
        } else {
            s = NULL;
        }
       

        switch(type){

        case R_ARM_JUMP_SLOT:

            DL_ERR("RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
            *((Elf32_Addr *)reloc)= sym_addr;
            break;
        case R_ARM_GLOB_DAT:

            DL_ERR("RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
            *((Elf32_Addr *)reloc)=sym_addr;
            break;
        case R_ARM_ABS32:

            DL_ERR("RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
            *((Elf32_Addr *)reloc) += sym_addr;
            break;
        case R_ARM_REL32:

            DL_ERR("RELO REL32 %08x <- %08x - %08x %s",
                       reloc, sym_addr, rel->r_offset, sym_name);
            *((Elf32_Addr *)reloc) += sym_addr - rel->r_offset;
            break;



        case R_ARM_RELATIVE:


            if (sym) {
                DL_ERR("odd RELATIVE form...");
                return -1;
            }
            DL_ERR("RELO RELATIVE %08x <- +%08x", reloc, si->base);
            *((Elf32_Addr*)reloc) += si->base;
            break;



        case R_ARM_COPY:
            if ((si->flags & FLAG_EXE) == 0) {
 
                DL_ERR("%s R_ARM_COPY relocations only supported for ET_EXEC", si->name);
                return -1;
            }

            DL_ERR("RELO %08x <- %d @ %08x %s", reloc, s->st_size, sym_addr, sym_name);
            if (reloc == sym_addr) {
                Elf32_Sym *src = soinfo_do_lookup4_4(NULL, sym_name, &lsi, needed);

                if (src == NULL) {
                    DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", si->name);
                    return -1;
                }
                if (lsi->has_DT_SYMBOLIC) {
                    DL_ERR("%s invalid R_ARM_COPY relocation against DT_SYMBOLIC shared "
                           "library %s (built with -Bsymbolic?)", si->name, lsi->name);
                    return -1;
                }
                if (s->st_size < src->st_size) {
                    DL_ERR("%s R_ARM_COPY relocation size mismatch (%d < %d)",
                           si->name, s->st_size, src->st_size);
                    return -1;
                }
                memcpy((void*)reloc, (void*)(src->st_value + lsi->load_bias), src->st_size);
            } else {
                DL_ERR("%s R_ARM_COPY relocation target cannot be resolved", si->name);
                return -1;
            }
            break;


        default:
            DL_ERR("unknown reloc type %d @ %p (%d)",
                   type, rel, (int) (rel - start));
            return -1;
        }
    }
    return 1;
}

#ifdef ANDROID_MIPS_LINKER
static int mips_relocate_got4_4(soinfo* si, soinfo* needed[]) {
    unsigned* got = si->plt_got;
    if (got == NULL) {
        return true;
    }
    unsigned local_gotno = si->mips_local_gotno;
    unsigned gotsym = si->mips_gotsym;
    unsigned symtabno = si->mips_symtabno;
    Elf32_Sym* symtab = si->symtab;


    if ((si->flags & FLAG_LINKER) == 0) {
        size_t g = 0;
        got[g++] = 0xdeadbeef;
        if (got[g] & 0x80000000) {
            got[g++] = 0xdeadfeed;
        }
        /*
         * Relocate the local GOT entries need to be relocated
         */
        for (; g < local_gotno; g++) {
            got[g] += si->load_bias;
        }
    }

    /* Now for the global GOT entries */
    Elf32_Sym* sym = symtab + gotsym;
    got = si->plt_got + local_gotno;
    for (size_t g = gotsym; g < symtabno; g++, sym++, got++) {
        const char* sym_name;
        Elf32_Sym* s;
        soinfo* lsi;

        /* This is an undefined reference... try to locate it */
        sym_name = si->strtab + sym->st_name;
        s = soinfo_do_lookup4_4(si, sym_name, &lsi, needed);
        if (s == NULL) {
            /* We only allow an undefined symbol if this is a weak
               reference..   */
            s = &symtab[g];
            if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
                DL_ERR("cannot locate \"%s\"...", sym_name);
                return -1;
            }
            *got = 0;
        }
        else {
       
             *got = lsi->load_bias + s->st_value;
        }
    }
    return 1;
}
#endif

#ifdef ANDROID_ARM_LINKER

#  ifndef PT_ARM_EXIDX
#    define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
#  endif
int
phdr_table_get_arm_exidx4_4(const Elf32_Phdr* phdr_table,
                         int               phdr_count,
                         Elf32_Addr        load_bias,
                         Elf32_Addr**      arm_exidx,
                         unsigned*         arm_exidx_count)
{
    const Elf32_Phdr* phdr = phdr_table;
    const Elf32_Phdr* phdr_limit = phdr + phdr_count;

    for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_ARM_EXIDX)
            continue;

        *arm_exidx = (Elf32_Addr*)(load_bias + phdr->p_vaddr);
        *arm_exidx_count = (unsigned)(phdr->p_memsz / 8);
        return 0;
    }
    *arm_exidx = NULL;
    *arm_exidx_count = 0;
    return -1;
}
#endif /* ANDROID_ARM_LINKER */
static void phdr_table_get_dynamic_section4_4(const Elf32_Phdr* phdr_table,
                               int               phdr_count,
                               Elf32_Addr        load_bias,
                               Elf32_Dyn**       dynamic,
                               size_t*           dynamic_count,
                               Elf32_Word*       dynamic_flags)
{
    const Elf32_Phdr* phdr = phdr_table;
    const Elf32_Phdr* phdr_limit = phdr + phdr_count;

    for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_DYNAMIC) {
            continue;
        }

        *dynamic = (Elf32_Dyn*)(load_bias + phdr->p_vaddr);
        if (dynamic_count) {
            *dynamic_count = (unsigned)(phdr->p_memsz / 8);
        }
        if (dynamic_flags) {
            *dynamic_flags = phdr->p_flags;
        }
        return;
    }
    *dynamic = NULL;
    if (dynamic_count) {
        *dynamic_count = 0;
    }
}
//soinfo4_4* find_library_internal4_4(const char* name);
static int soinfo_link_image4_4(soinfo4_4* si) {
    /* "base" might wrap around UINT32_MAX. */
    Elf32_Addr base = si->load_bias;
    const Elf32_Phdr *phdr = si->phdr;
    int phnum = si->phnum;
    int relocating_linker = (si->flags & FLAG_LINKER) ;

    /* We can't debug anything until the linker is relocated */
    if (!relocating_linker) {
        INFO("[ linking %s ]", si->name);
        DEBUG("si->base = 0x%08x si->flags = 0x%08x", si->base, si->flags);
    }

    /* Extract dynamic section */
    size_t dynamic_count;
    Elf32_Word dynamic_flags;
    phdr_table_get_dynamic_section4_4(phdr, phnum, base, &si->dynamic,
                                   &dynamic_count, &dynamic_flags);
    if (si->dynamic == NULL) {
        if (!relocating_linker) {
            DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name);
        }
        return -1;
    } else {
        if (!relocating_linker) {
            DEBUG("dynamic = %p", si->dynamic);
        }
    }
    #ifdef ANDROID_ARM_LINKER
    (void) phdr_table_get_arm_exidx4_4(phdr, phnum, base,
                                    &si->ARM_exidx, &si->ARM_exidx_count);
    #endif
      // Extract useful information from dynamic section.
    uint32_t needed_count = 0;
    Elf32_Dyn* d;
    for (d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x", d, d->d_tag, d->d_un.d_val);
        switch(d->d_tag){
        case DT_HASH:
            si->nbucket = ((unsigned *) (base + d->d_un.d_ptr))[0];
            si->nchain = ((unsigned *) (base + d->d_un.d_ptr))[1];
            si->bucket = (unsigned *) (base + d->d_un.d_ptr + 8);
            si->chain = (unsigned *) (base + d->d_un.d_ptr + 8 + si->nbucket * 4);
            break;
        case DT_STRTAB:
            si->strtab = (const char *) (base + d->d_un.d_ptr);
            break;
        case DT_SYMTAB:
            si->symtab = (Elf32_Sym *) (base + d->d_un.d_ptr);
            break;
        case DT_PLTREL:
            if (d->d_un.d_val != DT_REL) {
                DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
                return -1;
            }
            break;
        case DT_JMPREL:
            si->plt_rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
            DL_ERR("plt_rel=%p",si->plt_rel);
            break;
        case DT_PLTRELSZ:
            si->plt_rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
            DL_ERR("plt_rel_count=%08x",si->plt_rel_count);
            break;
        case DT_REL:
            si->rel = (Elf32_Rel*) (base + d->d_un.d_ptr);
            break;
        case DT_RELSZ:
            si->rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
            break;
        case DT_PLTGOT:
            /* Save this in case we decide to do lazy binding. We don't yet. */
            si->plt_got = (unsigned *)(base + d->d_un.d_ptr);
            break;
        case DT_DEBUG:
            // Set the DT_DEBUG entry to the address of _r_debug for GDB
            // if the dynamic table is writable
            /*
            if ((dynamic_flags & PF_W) != 0) {
                d->d_un.d_val = (int) &_r_debug;
            }*/
            break;
         case DT_RELA:
            DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
            return -1;
        case DT_INIT:
            si->init_func = (void (*)(void))(base + d->d_un.d_ptr);
            DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func);
            break;
        case DT_FINI:
            si->fini_func = (void (*)(void))(base + d->d_un.d_ptr);
            DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func);
            break;
        case DT_INIT_ARRAY:
            si->init_array = (unsigned *)(base + d->d_un.d_ptr);
            DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
            break;
        case DT_INIT_ARRAYSZ:
            si->init_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
            break;
        case DT_FINI_ARRAY:
            si->fini_array = (unsigned *)(base + d->d_un.d_ptr);
            DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
            break;
        case DT_FINI_ARRAYSZ:
            si->fini_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
            break;
        case DT_PREINIT_ARRAY:
            si->preinit_array = (unsigned *)(base + d->d_un.d_ptr);
            DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name, si->preinit_array);
            break;
        case DT_PREINIT_ARRAYSZ:
            si->preinit_array_count = ((unsigned)d->d_un.d_val) / sizeof(Elf32_Addr);
            break;
        case DT_TEXTREL:
            si->has_text_relocations = 1;
            break;
        case DT_SYMBOLIC:
            si->has_DT_SYMBOLIC = 1;
            break;
        case DT_NEEDED:
            ++needed_count;
            break;
#if defined DT_FLAGS
        // TODO: why is DT_FLAGS not defined?
        case DT_FLAGS:
            if (d->d_un.d_val & DF_TEXTREL) {
                si->has_text_relocations = 1;
            }
            if (d->d_un.d_val & DF_SYMBOLIC) {
                si->has_DT_SYMBOLIC = 1;
            }
            break;
#endif
#if defined(ANDROID_MIPS_LINKER)
        case DT_STRSZ:
        case DT_SYMENT:
        case DT_RELENT:
             break;
        case DT_MIPS_RLD_MAP:
            // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
            {
              r_debug** dp = (r_debug**) d->d_un.d_ptr;
              *dp = &_r_debug;
            }
            break;
        case DT_MIPS_RLD_VERSION:
        case DT_MIPS_FLAGS:
        case DT_MIPS_BASE_ADDRESS:
        case DT_MIPS_UNREFEXTNO:
            break;

        case DT_MIPS_SYMTABNO:
            si->mips_symtabno = d->d_un.d_val;
            break;

        case DT_MIPS_LOCAL_GOTNO:
            si->mips_local_gotno = d->d_un.d_val;
            break;

        case DT_MIPS_GOTSYM:
            si->mips_gotsym = d->d_un.d_val;
            break;

        default:
            DEBUG("Unused DT entry: type 0x%08x arg 0x%08x", d->d_tag, d->d_un.d_val);
            break;
#endif
        }
    }

    DEBUG("si->base = 0x%08x, si->strtab = %p, si->symtab = %p",
          si->base, si->strtab, si->symtab);
   
    // Sanity checks.
    if (relocating_linker && needed_count != 0) {
        DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
        return -1;
    }
    if (si->nbucket == 0) {
        DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name);
        return -1;
    }
    if (si->strtab == 0) {
        DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name);
        return -1;
    }
    if (si->symtab == 0) {
        DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name);
        return -1;
    }
     soinfo4_4** needed = (soinfo4_4**) alloca((1 + needed_count) * sizeof(soinfo4_4*));
    soinfo4_4** pneeded = needed;
    // Elf32_Dyn* dd;
    for ( d= si->dynamic; d->d_tag != DT_NULL; ++d) {
        if (d->d_tag == DT_NEEDED) {
            const char* library_name = si->strtab + d->d_un.d_val;
            DEBUG("%s needs %s", si->name, library_name);
            soinfo4_4* lsi = (soinfo4_4*)dlopen(library_name,0);       // ¼ÓÔØÆäËûÒÀÀµµÄso, ÕâÀïÖ±½Óµ÷ÓÃÔ­Éúlinker
            if (lsi == NULL) {
                // strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by ",
                       library_name, si->name);
                return -1;
            }
            DL_ERR(" soname=%s , nbucket=%08x",lsi->name,lsi->nbucket);
            *pneeded++ = lsi;
        }
    }
    *pneeded = NULL;
    
    if (si->has_text_relocations) {
        DL_ERR("%s has text relocations. This is wasting memory and is "
                "a security risk. Please fix.", si->name);
        if (phdr_table_unprotect_segments4_4(si->phdr, si->phnum, si->load_bias) < 0) {
            DL_ERR("can't unprotect loadable segments for \"%s\": %s",
                   si->name, strerror(errno));
            return -1;
        }
    }

    if (si->plt_rel != NULL) {
        DEBUG("[ relocating %s plt ] count=%08x", si->name,si->plt_rel_count);
        if (soinfo_relocate4_4(si, si->plt_rel, si->plt_rel_count, needed)!=1) {
            DL_ERR("relocate fail");
            return -1;
        }
    }
    if (si->rel != NULL) {
        DEBUG("[ relocating %s ]", si->name );
        if (soinfo_relocate4_4(si, si->rel, si->rel_count, needed)!=1) {
            DL_ERR("relocate fail");
            return -1;
        }
    }
    #ifdef ANDROID_MIPS_LINKER
    if (!mips_relocate_got4_4(si, needed)) {
        return -1;
    }
    #endif

    si->flags |= FLAG_LINKED;
    DEBUG("[ finished linking %s ]", si->name);

      DL_ERR("has_text_relocations is %08x",si->has_text_relocations);
    if (si->has_text_relocations==1) {
        /* All relocations are done, we can protect our segments back to
         * read-only. */
       
        if (phdr_table_protect_segments4_4(si->phdr, si->phnum, si->load_bias) < 0) {
            DL_ERR("can't protect segments for \"%s\": %s",
                   si->name, strerror(errno));
            return -1;
        }
    }
    if (phdr_table_protect_gnu_relro4_4(si->phdr, si->phnum, si->load_bias) < 0) {
        DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
               si->name, strerror(errno));
        return -1;
    }
    return 1;
}
static Elf32_Phdr* CheckPhdr4_4(Elf32_Addr loaded,int fd_,const char *name_,const Elf32_Phdr* phdr_table_,size_t phdr_num_,Elf32_Addr load_bias_) {
   const Elf32_Phdr* loaded_phdr_;
   Elf32_Phdr* phdr;
  const Elf32_Phdr* phdr_limit = phdr_table_ + phdr_num_;
  Elf32_Addr loaded_end = loaded + (phdr_num_ * sizeof(Elf32_Phdr));
  for ( phdr= phdr_table_; phdr < phdr_limit; ++phdr) {
    if (phdr->p_type != PT_LOAD) {
      continue;
    }
    Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
    Elf32_Addr seg_end = phdr->p_filesz + seg_start;
    if (seg_start <= loaded && loaded_end <= seg_end) {
      loaded_phdr_ =(Elf32_Phdr*)loaded;
      return loaded_phdr_;
    }
  }
  DL_ERR("\"%s\" loaded phdr %x not in loadable segment", name_, loaded);
  return NULL;
}
static Elf32_Phdr* FindPhdr4_4(int fd_,const char *name_,const Elf32_Phdr* phdr_table_,size_t phdr_num_,Elf32_Addr load_bias_) {
  const Elf32_Phdr* phdr_limit = phdr_table_ + phdr_num_;
  const Elf32_Phdr* phdr;
  // If there is a PT_PHDR, use it directly.
  for ( phdr= phdr_table_; phdr < phdr_limit; ++phdr) {
    if (phdr->p_type == PT_PHDR) {
      return CheckPhdr4_4(load_bias_ + phdr->p_vaddr,fd_,name_,phdr_table_,phdr_num_,load_bias_);
    }
  }
  for (phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
    if (phdr->p_type == PT_LOAD) {
      if (phdr->p_offset == 0) {
        Elf32_Addr  elf_addr = load_bias_ + phdr->p_vaddr;
        const Elf32_Ehdr* ehdr = (const Elf32_Ehdr*)(void*)elf_addr;
        Elf32_Addr  offset = ehdr->e_phoff;
        return CheckPhdr4_4((Elf32_Addr)ehdr + offset,fd_,name_,phdr_table_,phdr_num_,load_bias_);
      }
      break;
    }
  }

  DL_ERR("can't find loaded phdr for \"%s\"", name_);
  return NULL;
}
soinfo4_4 *soinfos = NULL;
static int LoadSegments4_4(int fd_,const char *name_,const Elf32_Phdr* phdr_table_,size_t phdr_num_,void* load_start_,Elf32_Addr load_size_,Elf32_Addr load_bias_) {
  size_t i;
  const Elf32_Phdr* loaded_phdr_;
   const char *bname;
  for(i = 0; i < phdr_num_; ++i) {
    const Elf32_Phdr* phdr = &phdr_table_[i];

    if (phdr->p_type != PT_LOAD) {
      continue;
    }

    // Segment addresses in memory.
    Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
    Elf32_Addr seg_end   = seg_start + phdr->p_memsz;

    Elf32_Addr seg_page_start = PAGE_START(seg_start);
    Elf32_Addr seg_page_end   = PAGE_END(seg_end);

    Elf32_Addr seg_file_end   = seg_start + phdr->p_filesz;

    // File offsets.
    Elf32_Addr file_start = phdr->p_offset;
    Elf32_Addr file_end   = file_start + phdr->p_filesz;

    Elf32_Addr file_page_start = PAGE_START(file_start);
    Elf32_Addr file_length = file_end - file_page_start;

    if (file_length != 0) {
        /* Ô­Éú: ÕâÀïÖ±½ÓmapÎļþfd, µ¼ÖÂ/proc/pid/mapsÖб©Â¶ÁËÒѼÓÔØÄ£¿é
        void* seg_addr = mmap((void*)seg_page_start,
                              file_length,
                              PFLAGS_TO_PROT(phdr->p_flags),
                              MAP_FIXED|MAP_PRIVATE,
                              fd_,
                              file_page_start);
      if (seg_addr == MAP_FAILED) {
        DL_ERR("couldn't mmap \"%s\" segment %d: %s", name_, i, strerror(errno));
        return false;
      }*/

       // Ð޸ĺó: ÏÈmmapÒ»¿éÎÞfdÄÚ´æ, È»ºóʹÓÃread¶Á³öÖ¸¶¨ÇøÓòÄÚÈÝÌî³äµ½mmapµÄÄÚ´æ´¦, ×îºó½«mmapµÄÄÚ´æÊôÐÔÉèÖÃΪsegmentµÄÊôÐÔ.
       DL_ERR("seg_page_start==%08x. file_length=%08x",seg_page_start,file_length);

       void* seg_addr = mmap((void*)seg_page_start,
                              file_length,
                              PROT_WRITE|PROT_READ,
                              MAP_FIXED|MAP_PRIVATE| MAP_ANONYMOUS,
                              0,
                              0);
      if (seg_addr == MAP_FAILED) {
         DL_ERR("couldn't mmap1 \"%s\" segment %d: %s", name_, i, strerror(errno));
         return -1;
      }
  
      if(lseek( fd_ , file_page_start, SEEK_SET ) == -1L ) {
          DL_ERR("couldn't lseek1 \"%s\" segment %d: %s", name_, i, strerror(errno));
          return -1;
      }

      if(-1 == read(fd_, seg_addr, file_length)) {
          DL_ERR("couldn't read \"%s\" segment %d: %s", name_, i, strerror(errno));
          return -1;
      }
        if(start_page_filelength4_4==0){
            start_page_address4_4=seg_addr;
            start_page_filelength4_4=file_length;
        }
        DL_ERR("LoadSegments seg_addr=%0x  flag=%08x", (unsigned)seg_addr,PFLAGS_TO_PROT(phdr->p_flags));
      if( -1 == mprotect(seg_addr, file_length, PFLAGS_TO_PROT(phdr->p_flags))) {
          DL_ERR("couldn't mprotect \"%s\" segment %d: %s", name_, i, strerror(errno));
          return -1;
        }

        DL_ERR("LoadSegments succeed:%s!", name_);
    }

    // if the segment is writable, and does not end on a page boundary,
    // zero-fill it until the page limit.
    if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
      memset((void*)seg_file_end, 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end));
    }

    seg_file_end = PAGE_END(seg_file_end);

    // seg_file_end is now the first page address after the file
    // content. If seg_end is larger, we need to zero anything
    // between them. This is done by using a private anonymous
    // map for all extra pages.
    if (seg_page_end > seg_file_end) {
      void* zeromap = mmap((void*)seg_file_end,
                           seg_page_end - seg_file_end,
                           PFLAGS_TO_PROT(phdr->p_flags),
                           MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
                           -1,
                           0);
      if (zeromap == MAP_FAILED) {
        DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
        return -1;
      }
    }
  }
  loaded_phdr_=FindPhdr4_4(fd_,name_,phdr_table_,phdr_num_,load_bias_);
  if(loaded_phdr_!=NULL){
      DL_ERR("findphdr success");
     bname = strrchr(name_, '/');
      DL_ERR("findphdr success %s",bname);
     soinfos = alloc_info4_4(bname ? bname + 1 : name_);
     if (soinfos == NULL){
        goto fail;
     }
     DL_ERR("  soinfos fail ");
     soinfos->flags = 0;
     soinfos->entry = 0;
 
     soinfos->dynamic = (unsigned *)-1;
     soinfos->phdr=loaded_phdr_;
     soinfos->load_bias=load_bias_;
     soinfos->phnum=phdr_num_;
     // soinfos->base1=load_start_;
     soinfos->base=load_start_;
     soinfos->size=load_size_;
     DL_ERR("base1----->>%08x ,size---->>%08x",load_start_,load_size_);
      close(fd_);
      return 1;
fail:
   DL_ERR("  alloc_info4_4 fail ");
    close(fd_); 
    if (soinfos){
       free_info4_4(soinfos);  
       return -1;
    } 
    
   }
  return 1;
}
static size_t phdr_table_get_load_size4_4(const Elf32_Phdr* phdr_table,
                                size_t phdr_count,
                                Elf32_Addr* out_min_vaddr,
                                Elf32_Addr* out_max_vaddr)
{
    Elf32_Addr min_vaddr = 0xFFFFFFFFU;
    Elf32_Addr max_vaddr = 0x00000000U;
    size_t i;
    int found_pt_load = -1;
    for (i=0; i < phdr_count; ++i) {
        const Elf32_Phdr* phdr = &phdr_table[i];

        if (phdr->p_type != PT_LOAD) {
            continue;
        }
        found_pt_load = 1;

        if (phdr->p_vaddr < min_vaddr) {
            min_vaddr = phdr->p_vaddr;
        }

        if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
            max_vaddr = phdr->p_vaddr + phdr->p_memsz;
        }
    }
    if (found_pt_load!=1) {
        min_vaddr = 0x00000000U;
    }

    min_vaddr = PAGE_START(min_vaddr);
    max_vaddr = PAGE_END(max_vaddr);
    DL_ERR(" min=%08x,max=%08x", min_vaddr,max_vaddr);
    if (out_min_vaddr != NULL) {
        *out_min_vaddr = min_vaddr;
    }
    if (out_max_vaddr != NULL) {
        *out_max_vaddr = max_vaddr;
    }
    return max_vaddr - min_vaddr;
}
static int ReserveAddressSpace4_4(int fd_,const char *name_,const Elf32_Phdr* phdr_table_,size_t phdr_num_) {
	  Elf32_Addr min_vaddr;
	  Elf32_Addr max_vaddr;
	  Elf32_Addr load_size_;
	  Elf32_Addr load_bias_;
	   void* load_start_;
	  load_size_ = phdr_table_get_load_size4_4(phdr_table_, phdr_num_, &min_vaddr,&max_vaddr);
	  if (load_size_ == 0) {
	    DL_ERR("\"%s\" has no loadable segments", name_);
	    return -1;
	  }
	   uint8_t* addr = (uint8_t*)min_vaddr;
	  int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
	   void* start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
	  if (start == MAP_FAILED) {
	    DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_);
	    return -1;
	  }
	  load_start_ = start;
	  load_bias_ = (uint8_t*)start - addr; 
	   DL_ERR("load_start %p,load_bias %p", load_start_,load_bias_);
	   if(LoadSegments4_4(fd_,name_,phdr_table_,phdr_num_,load_start_,load_size_,load_bias_)!=1){
	     DL_ERR("load segments error");
	   }else{
	     DL_ERR("load segments success");
	   }
	  return 1;
}
static int VerifyElfHeader4_4(const char *name_,Elf32_Ehdr header_) {
  if (header_.e_ident[EI_MAG0] != ELFMAG0 ||
      header_.e_ident[EI_MAG1] != ELFMAG1 ||
      header_.e_ident[EI_MAG2] != ELFMAG2 ||
      header_.e_ident[EI_MAG3] != ELFMAG3) {
    DL_ERR("\"%s\" has bad ELF magic", name_);
    return -1;
  }

  if (header_.e_ident[EI_CLASS] != ELFCLASS32) {
    DL_ERR("\"%s\" not 32-bit: %d", name_, header_.e_ident[EI_CLASS]);
    return -1;
  }
  if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
    DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
    return -1;
  }

  if (header_.e_type != ET_DYN) {
    DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
    return -1;
  }

  if (header_.e_version != EV_CURRENT) {
    DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
    return -1;
  }

  if (header_.e_machine !=
      EM_ARM
  ) {
    DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
    return -1;
  }
  DL_ERR("verify elf success");
  return 1;
}
static int ReadProgramHeader4_4(int fd_, const char *name_,Elf32_Ehdr header_,size_t phdr_num_){
    Elf32_Addr phdr_size_;
    Elf32_Phdr* phdr_table_;
   if (phdr_num_ < 1 || phdr_num_ > 65536/sizeof(Elf32_Phdr)) {
     DL_ERR("\"%s\" has invalid e_phnum: %d", name_, phdr_num_);
     return -1;
    }
	  Elf32_Addr page_min = PAGE_START(header_.e_phoff);
	  Elf32_Addr page_max = PAGE_END(header_.e_phoff + (phdr_num_ * sizeof(Elf32_Phdr)));
	  Elf32_Addr page_offset = PAGE_OFFSET(header_.e_phoff);
	  DL_ERR("page_min  --->>>%08x,page_max  --->>>%08x",page_min,page_max);
	  phdr_size_ = page_max - page_min;
	  DL_ERR("phdr_size_  --->>>%08x",phdr_size_);  
	  void* mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
	  if (mmap_result == MAP_FAILED) {
	      DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
	      return -1;
	   }   
	  if(VerifyElfHeader4_4(name_,header_)!=1){
	    DL_ERR("verify elf fail");
	    return -1;
	  }
	   phdr_table_ = (Elf32_Phdr*)((char*)mmap_result + page_offset);
	  if(ReserveAddressSpace4_4(fd_,name_,phdr_table_,phdr_num_)==-1){
	     DL_ERR("reserve address fail");
	    return -1;
	  }
  return 1;
 
}
static int ReadElfHeader4_4(int fd_,const char *name_) {
  Elf32_Ehdr header_;
  
   size_t phdr_num_;
   ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, &header_, sizeof(header_)));
   phdr_num_ = header_.e_phnum;
   DL_ERR("\"%s\" is e_phnum: %d", name_, phdr_num_);
  if (rc < 0) {
    DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
    return -1;
  }
  if (rc != sizeof(header_)) {
    DL_ERR("\"%s\" is too small to be an ELF executable", name_);
    return -1;
  }
  if(ReadProgramHeader4_4(fd_,name_,header_,phdr_num_)==1){
        DL_ERR("success1 %08x",phdr_num_);
  }else{
          DL_ERR("fail1 %08x",phdr_num_);
  }
  return 1;
}

static soinfo4_4 *load_library4_4(const char *name){
    
   int fd = open_library(name);
    if(ReadElfHeader4_4(fd,name)==1){
      DL_ERR("success");
    
    }else{
      DL_ERR("fail");
    }
   

    return soinfos;
}
#define likely4_4(expr)   __builtin_expect (expr, 1)
#define unlikely4_4(expr) __builtin_expect (expr, 0)
void *lookup_in_library4_4(soinfo4_4 *si, const char *name)
{
    soinfo4_4 *found;
    Elf32_Sym *sym;
    unsigned bind;
    found=si;
	sym=soinfo_elf_lookup4_4(si, elfhash4_4(name), name);
	 if(likely4_4(sym != 0)) {
        bind = ELF32_ST_BIND(sym->st_info);
        if(likely4_4((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
            unsigned ret = sym->st_value + found->base;
            return (void*)ret;
        }
    }
    return NULL;
}
static void call_constructors_array4_4(unsigned *ctor, int count, int reverse)
{
    int n, inc = 1;
    
    if (reverse) {
        ctor += (count-1);
        inc   = -1;
    }
    
    for(n = count; n > 0; n--) {
        DL_ERR("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid,
              reverse ? "dtor" : "ctor",
              (unsigned)ctor, (unsigned)*ctor);
        void (*func)() = (void (*)()) *ctor;
        ctor += inc;
        if(((int) func == 0) || ((int) func == -1)) continue;
        DL_ERR("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func);
        func();
        DL_ERR(" func %s",strerror(errno));
    }
}

void init_constructors4_4(soinfo4_4 *si)
{
    if (si->constructors_called)
        return;
    DL_ERR("init");
    si->constructors_called = 1;
    
    if (si->flags & FLAG_EXE) {
        DL_ERR("[ ------%5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n",
              pid, (unsigned)si->preinit_array, si->preinit_array_count,
              si->name);
        call_constructors_array4_4(si->preinit_array, si->preinit_array_count, 0);
        DL_ERR("[ -------%5d Done calling preinit_array for '%s' ]\n", pid, si->name);
    } else {
        if (si->preinit_array) {
            DL_ERR("--------%5d Shared library '%s' has a preinit_array table @ 0x%08x."
                   " This is INVALID.", pid, si->name,
                   (unsigned)si->preinit_array);
        }
    }
    
    if (si->init_func) {
        DL_ERR("[--------%5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
              (unsigned)si->init_func, si->name);
        si->init_func();
        DL_ERR("[ --------%5d Done calling init_func for '%s' ]\n", pid, si->name);
    }
    
    if (si->init_array) {
        DL_ERR("[ -------%5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
              (unsigned)si->init_array, si->init_array_count, si->name);
        call_constructors_array4_4(si->init_array, si->init_array_count, 0);
        DL_ERR("[ --------%5d Done calling init_array for '%s' ]\n", pid, si->name);
    }
    
}
soinfo4_4* find_library_internal4_4(const char* name) {
   soinfo4_4 *soinfo4_4=load_library4_4(name);
   if (soinfo4_4 == NULL) {
      return NULL;
   }
   DL_ERR("[ init_library base=0x%08x sz=0x%08x name='%s' ]",
   soinfo4_4->base, soinfo4_4->size, soinfo4_4->name);
  if (soinfo_link_image4_4(soinfo4_4)!=1) {
	    munmap((void*)(soinfo4_4->base), soinfo4_4->size);
	    free_info4_4(soinfo4_4);
	    return NULL;
  }
  if(soinfo4_4!=NULL){
  	init_constructors4_4(soinfo4_4);
  }
   DL_ERR("LINK IMAGE SUCCESS");
  return soinfo4_4;
}
XorUtils.h
//
//  XorUtils.h
//  Goblin_Shell_4.1.2
//
//  Created by liu meng on 2018/2/6.
//  Copyright © 2018年 com.qunar. All rights reserved.
//

#ifndef XorUtils_h
#define XorUtils_h
#include <jni.h>
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include "elf.h"
#include <sys/mman.h>
#define DEBUG

typedef struct _funcInfo{
  Elf32_Addr st_value;
  Elf32_Word st_size;
}funcInfo;
int xor_code(Elf32_Addr baseParam,void* start_page_address,Elf32_Addr start_page_filelength);

#endif /* XorUtils_h */

XorUtils.c

#include "XorUtils.h"
static void print_debug(const char *msg){
#ifdef DEBUG
    __android_log_print(ANDROID_LOG_INFO, "liumeng", "%s", msg);
#endif
}

static unsigned elfhash(const char *_name)
{
    const unsigned char *name = (const unsigned char *) _name;
    unsigned h = 0, g;

    while(*name) {
        h = (h << 4) + *name++;
        g = h & 0xf0000000;
        h ^= g;
        h ^= g >> 24;
    }
    return h;
}

static unsigned int getLibAddr(){
  unsigned int ret = 0;
  char name[] = "libdata.so";
  char buf[4096], *temp;
  int pid;
  FILE *fp;
  pid = getpid();
  sprintf(buf, "/proc/%d/maps", pid);
  fp = fopen(buf, "r");
  if(fp == NULL)
  {
    puts("open failed");
    goto _error;
  }
  while(fgets(buf, sizeof(buf), fp)){
    if(strstr(buf, name)){
      temp = strtok(buf, "-");
      ret = strtoul(temp, NULL, 16);
      break;
    }
  }
_error:
  fclose(fp);
  return ret;
}

static char getTargetFuncInfo(unsigned long base, const char *funcName, funcInfo *info){
    char flag = -1, *dynstr;
    int i;
    Elf32_Ehdr *ehdr;
    Elf32_Phdr *phdr;
    Elf32_Off dyn_vaddr;
    Elf32_Word dyn_size, dyn_strsz;
    Elf32_Dyn *dyn;
    Elf32_Addr dyn_symtab, dyn_strtab, dyn_hash;
    Elf32_Sym *funSym;
    unsigned funHash, nbucket;
    unsigned *bucket, *chain;

    ehdr = (Elf32_Ehdr *)base;
    phdr = (Elf32_Phdr *)(base + ehdr->e_phoff);
//    __android_log_print(ANDROID_LOG_INFO, "JNITag", "phdr =  0x%p, size = 0x%x\n", phdr, ehdr->e_phnum);
    for (i = 0; i < ehdr->e_phnum; ++i) {
//      __android_log_print(ANDROID_LOG_INFO, "JNITag", "phdr =  0x%p\n", phdr);
        if(phdr->p_type ==  PT_DYNAMIC){
            flag = 0;
            print_debug("Find .dynamic segment");
            break;
        }
        phdr ++;
    }
    if(flag)
        goto _error;
    dyn_vaddr = phdr->p_vaddr + base;
    dyn_size = phdr->p_memsz;
    __android_log_print(ANDROID_LOG_INFO, "liumeng", "dyn_vadd =  0x%x, dyn_size =  0x%x", dyn_vaddr, dyn_size);
    flag = 0;
    for (i = 0; i < dyn_size / sizeof(Elf32_Dyn); ++i) {
        dyn = (Elf32_Dyn *)(dyn_vaddr + i * sizeof(Elf32_Dyn));
        if(dyn->d_tag == DT_SYMTAB){
            dyn_symtab = (dyn->d_un).d_ptr;
            flag += 1;
            __android_log_print(ANDROID_LOG_INFO, "liumeng", "Find .dynsym section, addr = 0x%x\n", dyn_symtab);
        }
        if(dyn->d_tag == DT_HASH){
            dyn_hash = (dyn->d_un).d_ptr;
            flag += 2;
            __android_log_print(ANDROID_LOG_INFO, "liumeng", "Find .hash section, addr = 0x%x\n", dyn_hash);
        }
        if(dyn->d_tag == DT_STRTAB){
            dyn_strtab = (dyn->d_un).d_ptr;
            flag += 4;
            __android_log_print(ANDROID_LOG_INFO, "liumeng", "Find .dynstr section, addr = 0x%x\n", dyn_strtab);
        }
        if(dyn->d_tag == DT_STRSZ){
            dyn_strsz = (dyn->d_un).d_val;
            flag += 8;
            __android_log_print(ANDROID_LOG_INFO, "liumeng", "Find strsz size = 0x%x\n", dyn_strsz);
        }
    }
    if((flag & 0x0f) != 0x0f){
        print_debug("Find needed .section failed\n");
        goto _error;
    }
    dyn_symtab += base;
    dyn_hash += base;
    dyn_strtab += base;

    funHash = elfhash(funcName);
    funSym = (Elf32_Sym *) dyn_symtab;
    dynstr = (char*) dyn_strtab;
    nbucket = *((int *) dyn_hash);
    bucket = (int *)(dyn_hash + 8);
    chain = (unsigned int *)(dyn_hash + 4 * (2 + nbucket));

    flag = -1;
    __android_log_print(ANDROID_LOG_INFO, "liumeng", "hash = 0x%x, nbucket = 0x%x\n", funHash, nbucket);
    for(i = bucket[funHash % nbucket]; i != 0; i = chain[i]){
        __android_log_print(ANDROID_LOG_INFO, "liumeng", "Find index = %d\n", i);
        if(strcmp(dynstr + (funSym + i)->st_name, funcName) == 0){
            flag = 0;
            __android_log_print(ANDROID_LOG_INFO, "liumeng", "Find %s\n", funcName);
            break;
        }
    }
    if(flag) goto _error;
    info->st_value = (funSym + i)->st_value;
    info->st_size = (funSym + i)->st_size;
    __android_log_print(ANDROID_LOG_INFO, "liumeng", "st_value = %d, st_size = %d", info->st_value, info->st_size);
    return 0;
_error:
    return -1;
}


int xor_code(Elf32_Addr baseParam,void* start_page_address,Elf32_Addr start_page_filelength){
    const char target_fun[] = "JNI_OnLoad";
    funcInfo info;
    int i;
    // unsigned int npage, base = getLibAddr();
    Elf32_Addr base=baseParam;
    __android_log_print(ANDROID_LOG_INFO, "liumeng", "base addr =  0x%x", base);
    if(getTargetFuncInfo(base, target_fun, &info) == -1){
      print_debug("Find JNI_OnLoad failed");
      return 0;
    }
    if(mprotect(start_page_address, start_page_filelength, PROT_READ | PROT_EXEC | PROT_WRITE) != 0){
        print_debug("mem privilege change failed");
    }

    for(i=0;i< info.st_size - 1; i++){
        char *addr = (char*)(base + info.st_value-1  +  i);
        *addr = ~(*addr);
    }

    if(mprotect(start_page_address, start_page_filelength,PROT_READ | PROT_EXEC) != 0){
        print_debug("mem privilege change failed");
    }
     print_debug("mem success");
    return 1;
}



linker7_0.h

#ifndef _LINKER7_0_H_
#define _LINKER7_0_H_
#include <unistd.h>
#include <sys/types.h>
#include "elf.h"
#include "exec_elf.h"
#include "auxvec.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <pthread.h>
#include <jni.h>
#include <sys/mman.h>
#include "public.h"

#define PAGE_S_SIZE 4096
#define PAGE_S_MASK (~(PAGE_S_SIZE-1))

// Returns the address of the page containing address 'x'.
#define PAGE_S_START(x) ((x) & PAGE_S_MASK)

#define PAGE_S_OFFSET(x) ((x) & ~PAGE_S_MASK)

#define PAGE_S_END(x) PAGE_S_START((x) + (PAGE_S_SIZE-1))
#ifndef __cplusplus
#define alignas _Alignas
#define alignof _Alignof
#endif
#if __LP64__
#define ElfW(type) Elf64_ ## type
#else
#define ElfW(type) Elf32_ ## type
#endif

#ifdef __LP64__
typedef long           intptr_t;
typedef unsigned long  uintptr_t;
#else
typedef int           intptr_t;
typedef unsigned int  uintptr_t;
#endif

void* start_page_address7_0;
Elf32_Addr start_page_filelength7_0;
typedef struct soinfo7_0 soinfo7_0;
struct link_map_t7_0 {
  uintptr_t l_addr;
  char*  l_name;
  uintptr_t l_ld;
  struct link_map_t7_0* l_next;
  struct link_map_t7_0* l_prev;
};

typedef void (*linker_function_t7_0)();
struct soinfo7_0 {
  char name[SOINFO_NAME_LEN];
  const Elf32_Phdr* phdr;
  size_t phnum;
  Elf32_Addr entry;
  Elf32_Addr base;
  unsigned size;

  uint32_t unused1;  

  Elf32_Dyn* dynamic;

  uint32_t unused2; 
  uint32_t unused3; 

  soinfo7_0* next;
  unsigned flags;

  const char* strtab;
  Elf32_Sym* symtab;

  size_t nbucket;
  size_t nchain;
  unsigned* bucket;
  unsigned* chain;

  unsigned* plt_got;

  Elf32_Rel* plt_rel;
  size_t plt_rel_count;

  Elf32_Rel* rel;
  size_t rel_count;

  linker_function_t7_0* preinit_array;
  size_t preinit_array_count;

  linker_function_t7_0* init_array;
  size_t init_array_count;
  linker_function_t7_0* fini_array;
  size_t fini_array_count;

  linker_function_t7_0 init_func;
  linker_function_t7_0 fini_func;
#if defined(ANDROID_ARM_LINKER)
  // ARM EABI section used for stack unwinding.
  unsigned* ARM_exidx;
  size_t ARM_exidx_count;
#elif defined(ANDROID_MIPS_LINKER)
  unsigned mips_symtabno;
  unsigned mips_local_gotno;
  unsigned mips_gotsym;
#endif

  size_t ref_count_;
  struct link_map_t7_0 link_map_head;

  unsigned char constructors_called;
  Elf32_Addr load_bias;
    unsigned char has_text_relocations;
    unsigned char  has_DT_SYMBOLIC;
    size_t strtab_size_;
};
static const char ANDROID_LIBDL_STRTAB1[] =
        // 0000000 00011111 111112 22222222 2333333 3333444444444455555555556666666 6667777777777888888888899999 99999
        // 0123456 78901234 567890 12345678 9012345 6789012345678901234567890123456 7890123456789012345678901234 56789
        "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0android_update_LD_LIBRARY_PATH\0android_get_LD_LIBRARY_PATH\0dl_it"
                // 00000000001 1111111112222222222 3333333333444444444455555555556666666666777 777777788888888889999999999
                // 01234567890 1234567890123456789 0123456789012345678901234567890123456789012 345678901234567890123456789
                "erate_phdr\0android_dlopen_ext\0android_set_application_target_sdk_version\0android_get_application_tar"
                // 0000000000111111 111122222222223333333333 4444444444555555555566666 6666677 777777778888888888
                // 0123456789012345 678901234567890123456789 0123456789012345678901234 5678901 234567890123456789
                "get_sdk_version\0android_init_namespaces\0android_create_namespace\0dlvsym\0android_dlwarning\0"
#if defined(__arm__)
                // 290
                "dl_unwind_find_exidx\0"
#endif
;
static unsigned g_libdl_buckets1[1] = { 1 };
#if defined(__arm__)
static unsigned g_libdl_chains1[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
#else
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
#endif





soinfo7_0* find_library_internal7_0(const char* name);
void *lookup_in_library7_0(soinfo7_0 *si, const char *name);
#endif

linker7_0.c

#include "linker7_0.h"
#include "sys_dlopen.h"

static int socounts7_0 = 0;
static soinfo7_0 sopools7_0[128];
static soinfo7_0 *freelists7_0 = NULL;

static soinfo7_0 *alloc_info7_0(const char *name) {
    soinfo7_0 *soinfo7_0 = NULL;

    if (strlen(name) >= SOINFO_NAME_LEN) {
        DL_ERR("library name %s too long", name);
        return NULL;
    }
    if (!freelists7_0) {
        if (socounts7_0 == SO_MAX) {
            DL_ERR("too many libraries when loading %s", name);
            return NULL;
        }
        freelists7_0 = sopools7_0 + socounts7_0++;
        freelists7_0->next = NULL;
    }

    soinfo7_0 = freelists7_0;
    freelists7_0 = freelists7_0->next;
    DL_ERR("library name %s new ", name);
    memset(soinfo7_0, 0, sizeof(soinfo7_0));

    strlcpy((char *) soinfo7_0->name, name, sizeof(soinfo7_0->name));

    soinfo7_0->next = NULL;
    return soinfo7_0;
}

static void free_info7_0(soinfo7_0 *si) {
    si->next = freelists7_0;
    freelists7_0 = si;
}

static Elf32_Phdr *
CheckPhdr7_0(Elf32_Addr loaded, int fd_, const char *name_, const Elf32_Phdr *phdr_table_,
             size_t phdr_num_, Elf32_Addr load_bias_) {
    const Elf32_Phdr *loaded_phdr_;
    Elf32_Phdr *phdr;
    const Elf32_Phdr *phdr_limit = phdr_table_ + phdr_num_;
    Elf32_Addr loaded_end = loaded + (phdr_num_ * sizeof(Elf32_Phdr));
    for (phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
        if (phdr->p_type != PT_LOAD) {
            continue;
        }
        Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
        Elf32_Addr seg_end = phdr->p_filesz + seg_start;
        if (seg_start <= loaded && loaded_end <= seg_end) {
            loaded_phdr_ = (Elf32_Phdr *) loaded;
            return loaded_phdr_;
        }
    }
    DL_ERR("\"%s\" loaded phdr %x not in loadable segment", name_, loaded);
    return NULL;
}

static Elf32_Phdr *
FindPhdr7_0(int fd_, const char *name_, const Elf32_Phdr *phdr_table_, size_t phdr_num_,
            Elf32_Addr load_bias_) {
    const Elf32_Phdr *phdr_limit = phdr_table_ + phdr_num_;
    const Elf32_Phdr *phdr;
    // If there is a PT_PHDR, use it directly.
    for (phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
        if (phdr->p_type == PT_PHDR) {
            return CheckPhdr7_0(load_bias_ + phdr->p_vaddr, fd_, name_, phdr_table_, phdr_num_,
                                load_bias_);
        }
    }
    for (phdr = phdr_table_; phdr < phdr_limit; ++phdr) {
        if (phdr->p_type == PT_LOAD) {
            if (phdr->p_offset == 0) {
                Elf32_Addr elf_addr = load_bias_ + phdr->p_vaddr;
                const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *) (void *) elf_addr;
                Elf32_Addr offset = ehdr->e_phoff;
                return CheckPhdr7_0((Elf32_Addr) ehdr + offset, fd_, name_, phdr_table_, phdr_num_,
                                    load_bias_);
            }
            break;
        }
    }

    DL_ERR("can't find loaded phdr for \"%s\"", name_);
    return NULL;
}

static soinfo7_0 *
LoadSegments7_0(int fd_, const char *name_, const Elf32_Phdr *phdr_table_, size_t phdr_num_,
                void *load_start_, Elf32_Addr load_size_, Elf32_Addr load_bias_) {
    size_t i;
    const Elf32_Phdr *loaded_phdr_;
    const char *bname;
    soinfo7_0 *soinfos = NULL;
    int count=0;
    for (i = 0; i < phdr_num_; ++i) {
        const Elf32_Phdr *phdr = &phdr_table_[i];

        if (phdr->p_type != PT_LOAD) {
            continue;
        }
        count++;
        // Segment addresses in memory.
        Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
        Elf32_Addr seg_end = seg_start + phdr->p_memsz;

        Elf32_Addr seg_page_start = PAGE_S_START(seg_start);
        Elf32_Addr seg_page_end = PAGE_S_END(seg_end);

        Elf32_Addr seg_file_end = seg_start + phdr->p_filesz;

        // File offsets.
        Elf32_Addr file_start = phdr->p_offset;
        Elf32_Addr file_end = file_start + phdr->p_filesz;

        Elf32_Addr file_page_start = PAGE_S_START(file_start);
        Elf32_Addr file_length = file_end - file_page_start;

        if (file_length != 0) {
            DL_ERR("seg_page_start==%08x. file_length=%08x", seg_page_start, file_length);
            void *seg_addr = mmap((void *) seg_page_start,
                                  file_length,
                                  PROT_WRITE | PROT_READ,
                                  MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
                                  0,
                                  0);
            if (seg_addr == MAP_FAILED) {
                DL_ERR("couldn't mmap1 \"%s\" segment %d: %s", name_, i, strerror(errno));
                return soinfos;
            }

            if (lseek(fd_, file_page_start, SEEK_SET) == -1L) {
                DL_ERR("couldn't lseek1 \"%s\" segment %d: %s", name_, i, strerror(errno));
                return soinfos;
            }

            if (-1 == read(fd_, seg_addr, file_length)) {
                DL_ERR("couldn't read \"%s\" segment %d: %s", name_, i, strerror(errno));
                return soinfos;
            }
            DL_ERR("LoadSegments seg_addr=%0x  flag=%08x", (unsigned) seg_addr,
                   PFLAGS_TO_PROT(phdr->p_flags));
            if(start_page_filelength7_0==0){
                start_page_address7_0=seg_addr;
                start_page_filelength7_0=file_length;
            }
            if (-1 == mprotect(seg_addr, file_length, PFLAGS_TO_PROT(phdr->p_flags))) {
                DL_ERR("couldn't mprotect \"%s\" segment %d: %s", name_, i, strerror(errno));
                return soinfos;
            }

            DL_ERR("LoadSegments succeed:%s!", name_);
        }
        if ((phdr->p_flags & PF_W) != 0 && PAGE_S_OFFSET(seg_file_end) > 0) {
            memset((void *) seg_file_end, 0, PAGE_S_SIZE - PAGE_S_OFFSET(seg_file_end));
        }

        seg_file_end = PAGE_S_END(seg_file_end);
        if (seg_page_end > seg_file_end) {
            void *zeromap = mmap((void *) seg_file_end,
                                 seg_page_end - seg_file_end,
                                 PFLAGS_TO_PROT(phdr->p_flags),
                                 MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
                                 -1,
                                 0);
            if (zeromap == MAP_FAILED) {
                DL_ERR("couldn't zero fill \"%s\" gap: %s", name_, strerror(errno));
                return soinfos;
            }
        }
    }
    loaded_phdr_ = FindPhdr7_0(fd_, name_, phdr_table_, phdr_num_, load_bias_);
    if (loaded_phdr_ != NULL) {
        DL_ERR("findphdr success");
        bname = strrchr(name_, '/');
        DL_ERR("findphdr success %s", bname);
        soinfos = alloc_info7_0(bname ? bname + 1 : name_);
        if (soinfos == NULL) {
            goto fail;
        }
        soinfos->flags = 0;
        soinfos->entry = 0;

        soinfos->dynamic = (unsigned *) -1;
        soinfos->phdr = loaded_phdr_;
        soinfos->load_bias = load_bias_;
        soinfos->phnum = phdr_num_;
        // soinfos->base1=load_start_;
        soinfos->base = load_start_;
        soinfos->size = load_size_;
        DL_ERR("base1----->>%08x ,size---->>%08x", load_start_, load_size_);
        close(fd_);
        return soinfos;
        fail:
        DL_ERR("  alloc_info4_4 fail ");
        close(fd_);
    }
    return soinfos;
}

static size_t phdr_table_get_load_size7_0(const Elf32_Phdr *phdr_table,
                                          size_t phdr_count,
                                          Elf32_Addr *out_min_vaddr,
                                          Elf32_Addr *out_max_vaddr) {
    Elf32_Addr min_vaddr = 0xFFFFFFFFU;
    Elf32_Addr max_vaddr = 0x00000000U;
    size_t i;
    int found_pt_load = -1;
    for (i = 0; i < phdr_count; ++i) {
        const Elf32_Phdr *phdr = &phdr_table[i];

        if (phdr->p_type != PT_LOAD) {
            continue;
        }
        found_pt_load = 1;

        if (phdr->p_vaddr < min_vaddr) {
            min_vaddr = phdr->p_vaddr;
        }

        if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
            max_vaddr = phdr->p_vaddr + phdr->p_memsz;
        }
    }
    if (found_pt_load != 1) {
        min_vaddr = 0x00000000U;
    }

    min_vaddr = PAGE_S_START(min_vaddr);
    max_vaddr = PAGE_S_END(max_vaddr);
    DL_ERR(" min=%08x,max=%08x", min_vaddr, max_vaddr);
    if (out_min_vaddr != NULL) {
        *out_min_vaddr = min_vaddr;
    }
    if (out_max_vaddr != NULL) {
        *out_max_vaddr = max_vaddr;
    }
    return max_vaddr - min_vaddr;
}

static soinfo7_0 *ReserveAddressSpace7_0(int fd_, const char *name_, const Elf32_Phdr *phdr_table_,
                                         size_t phdr_num_) {
    Elf32_Addr min_vaddr;
    Elf32_Addr max_vaddr;
    Elf32_Addr load_size_;
    Elf32_Addr load_bias_;
    soinfo7_0 *soinfo = NULL;
    void *load_start_;
    load_size_ = phdr_table_get_load_size7_0(phdr_table_, phdr_num_, &min_vaddr, &max_vaddr);
    if (load_size_ == 0) {
        DL_ERR("\"%s\" has no loadable segments", name_);
        return soinfo;
    }
    uint8_t *addr = (uint8_t *) min_vaddr;
    int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
    void *start = mmap(addr, load_size_, PROT_NONE, mmap_flags, -1, 0);
    if (start == MAP_FAILED) {
        DL_ERR("couldn't reserve %d bytes of address space for \"%s\"", load_size_, name_);
        return soinfo;
    }
    load_start_ = start;
    load_bias_ = (uint8_t *) start - addr;
    DL_ERR("load_start %p,load_bias %p", load_start_, load_bias_);
    soinfo = LoadSegments7_0(fd_, name_, phdr_table_, phdr_num_, load_start_, load_size_,
                             load_bias_);
    if (soinfo != NULL) {
        DL_ERR("load segments success");
    } else {
        DL_ERR("load segments error");
    }
    return soinfo;
}

static int VerifyElfHeader7_0(const char *name_, Elf32_Ehdr header_) {
    if (header_.e_ident[EI_MAG0] != ELFMAG0 ||
        header_.e_ident[EI_MAG1] != ELFMAG1 ||
        header_.e_ident[EI_MAG2] != ELFMAG2 ||
        header_.e_ident[EI_MAG3] != ELFMAG3) {
        DL_ERR("\"%s\" has bad ELF magic", name_);
        return -1;
    }

    if (header_.e_ident[EI_CLASS] != ELFCLASS32) {
        DL_ERR("\"%s\" not 32-bit: %d", name_, header_.e_ident[EI_CLASS]);
        return -1;
    }
    if (header_.e_ident[EI_DATA] != ELFDATA2LSB) {
        DL_ERR("\"%s\" not little-endian: %d", name_, header_.e_ident[EI_DATA]);
        return -1;
    }

    if (header_.e_type != ET_DYN) {
        DL_ERR("\"%s\" has unexpected e_type: %d", name_, header_.e_type);
        return -1;
    }

    if (header_.e_version != EV_CURRENT) {
        DL_ERR("\"%s\" has unexpected e_version: %d", name_, header_.e_version);
        return -1;
    }

    if (header_.e_machine != EM_ARM) {
        DL_ERR("\"%s\" has unexpected e_machine: %d", name_, header_.e_machine);
        return -1;
    }
    DL_ERR("verify elf success");
    return 1;
}

static soinfo7_0 *
ReadProgramHeader7_0(int fd_, const char *name_, Elf32_Ehdr header_, size_t phdr_num_) {
    Elf32_Addr phdr_size_;
    Elf32_Phdr *phdr_table_;
    soinfo7_0 *soinfo = NULL;
    if (phdr_num_ < 1 || phdr_num_ > 65536 / sizeof(Elf32_Phdr)) {
        DL_ERR("\"%s\" has invalid e_phnum: %d", name_, phdr_num_);
        return soinfo;
    }
    Elf32_Addr page_min = PAGE_S_START(header_.e_phoff);
    Elf32_Addr page_max = PAGE_S_END(header_.e_phoff + (phdr_num_ * sizeof(Elf32_Phdr)));
    Elf32_Addr page_offset = PAGE_S_OFFSET(header_.e_phoff);
    DL_ERR("page_min  --->>>%08x,page_max  --->>>%08x", page_min, page_max);
    phdr_size_ = page_max - page_min;
    DL_ERR("phdr_size_  --->>>%08x", phdr_size_);
    void *mmap_result = mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE, fd_, page_min);
    if (mmap_result == MAP_FAILED) {
        DL_ERR("\"%s\" phdr mmap failed: %s", name_, strerror(errno));
        return soinfo;
    }
    if (VerifyElfHeader7_0(name_, header_) != 1) {
        DL_ERR("verify elf fail");
        return soinfo;
    }
    phdr_table_ = (Elf32_Phdr *) ((char *) mmap_result + page_offset);
    soinfo = ReserveAddressSpace7_0(fd_, name_, phdr_table_, phdr_num_);
    if (soinfo != NULL) {
        DL_ERR("reserve address success");
    }
    return soinfo;

}

static soinfo7_0 *ReadElfHeader7_0(int fd_, const char *name_) {
    Elf32_Ehdr header_;
    size_t phdr_num_;
    ssize_t rc = TEMP_FAILURE_RETRY(read(fd_, &header_, sizeof(header_)));
    phdr_num_ = header_.e_phnum;
    DL_ERR("\"%s\" is e_phnum: %d", name_, phdr_num_);
    if (rc < 0) {
        DL_ERR("can't read file \"%s\": %s", name_, strerror(errno));
        return NULL;
    }
    if (rc != sizeof(header_)) {
        DL_ERR("\"%s\" is too small to be an ELF executable", name_);
        return NULL;
    }
    soinfo7_0 *soinfo = ReadProgramHeader7_0(fd_, name_, header_, phdr_num_);
    if (soinfo != NULL) {
        DL_ERR("success1 %08x", phdr_num_);
    } else {
        DL_ERR("fail1 %08x", phdr_num_);
    }
    return soinfo;
}

static void phdr_table_get_dynamic_section7_0(const Elf32_Phdr *phdr_table,
                                              int phdr_count,
                                              Elf32_Addr load_bias,
                                              Elf32_Dyn **dynamic,
                                              size_t *dynamic_count,
                                              Elf32_Word *dynamic_flags) {
    const Elf32_Phdr *phdr = phdr_table;
    const Elf32_Phdr *phdr_limit = phdr + phdr_count;

    for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_DYNAMIC) {
            continue;
        }

        *dynamic = (Elf32_Dyn *) (load_bias + phdr->p_vaddr);
        if (dynamic_count) {
            *dynamic_count = (unsigned) (phdr->p_memsz / 8);
        }
        if (dynamic_flags) {
            *dynamic_flags = phdr->p_flags;
        }
        return;
    }
    *dynamic = NULL;
    if (dynamic_count) {
        *dynamic_count = 0;
    }
}

static int
_phdr_table_set_load_prot7_0(const Elf32_Phdr *phdr_table,
                             int phdr_count,
                             Elf32_Addr load_bias,
                             int extra_prot_flags) {
    const Elf32_Phdr *phdr = phdr_table;
    const Elf32_Phdr *phdr_limit = phdr + phdr_count;

    for (; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_LOAD || (phdr->p_flags & PF_W) != 0)
            continue;

        Elf32_Addr seg_page_start = PAGE_S_START(phdr->p_vaddr) + load_bias;
        Elf32_Addr seg_page_end = PAGE_S_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
        DL_ERR("segments ------=%08x", seg_page_start);
        int ret = mprotect((void *) seg_page_start,
                           seg_page_end - seg_page_start,
                           PFLAGS_TO_PROT(phdr->p_flags) | extra_prot_flags);
        if (ret < 0) {
            return -1;
        }
    }
    return 0;
}

int
phdr_table_protect_segments7_0(const Elf32_Phdr *phdr_table,
                               int phdr_count,
                               Elf32_Addr load_bias) {
    return _phdr_table_set_load_prot7_0(phdr_table, phdr_count,
                                        load_bias, 0);
}

int
phdr_table_unprotect_segments7_0(const Elf32_Phdr *phdr_table,
                                 int phdr_count,
                                 Elf32_Addr load_bias) {
    return _phdr_table_set_load_prot7_0(phdr_table, phdr_count,
                                        load_bias, PROT_WRITE);
}

static int
_phdr_table_set_gnu_relro_prot7_0(const Elf32_Phdr *phdr_table,
                                  int phdr_count,
                                  Elf32_Addr load_bias,
                                  int prot_flags) {
    const Elf32_Phdr *phdr = phdr_table;
    const Elf32_Phdr *phdr_limit = phdr + phdr_count;

    for (phdr = phdr_table; phdr < phdr_limit; phdr++) {
        if (phdr->p_type != PT_GNU_RELRO)
            continue;
        Elf32_Addr seg_page_start = PAGE_S_START(phdr->p_vaddr) + load_bias;
        Elf32_Addr seg_page_end = PAGE_S_END(phdr->p_vaddr + phdr->p_memsz) + load_bias;
        DL_ERR("_phdr_table_set_gnu_relro_prot GNU=%08x", seg_page_start);
        int ret = mprotect((void *) seg_page_start,
                           seg_page_end - seg_page_start,
                           prot_flags);
        if (ret < 0) {
            return -1;
        }
    }
    return 0;
}

int
phdr_table_protect_gnu_relro7_0(const Elf32_Phdr *phdr_table,
                                int phdr_count,
                                Elf32_Addr load_bias) {
    return _phdr_table_set_gnu_relro_prot7_0(phdr_table,
                                             phdr_count,
                                             load_bias,
                                             PROT_READ);
}

static Elf32_Sym *soinfo_elf_lookup7_0(soinfo7_0 *si, unsigned hash, const char *name) {
    Elf32_Sym *symtab = si->symtab;
    const char *strtab = si->strtab;
    unsigned n = 0;
    DL_ERR("SEARCH %s in %s@0x%08x %08x %d=====%08x",
           name, si->name, si->base, hash, hash % si->nbucket, si->nbucket);

    for (n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
        Elf32_Sym *s = symtab + n;
        // DL_ERR("NAME %s",strtab + s->st_name);
        if (strcmp(strtab + s->st_name, name)) continue;

        /* only concern ourselves with global and weak symbol definitions */
        switch (ELF32_ST_BIND(s->st_info)) {
            case STB_GLOBAL:
            case STB_WEAK:
                if (s->st_shndx == SHN_UNDEF) {
                    continue;
                }

                DL_ERR("FOUND %s in %s (%08x) %d",
                       name, si->name, s->st_value, s->st_size);
                return s;
        }
    }
    // DL_ERR("NULL");

    return NULL;
}

static unsigned elfhash7_0(const char *_name) {
    const unsigned char *name = (const unsigned char *) _name;
    unsigned h = 0, g;

    while (*name) {
        h = (h << 4) + *name++;
        g = h & 0xf0000000;
        h ^= g;
        h ^= g >> 24;
    }
    return h;
}

static Elf32_Sym *
soinfo_do_lookup7_0(soinfo7_0 *si, const char *name, soinfo7_0 **lsi, soinfo7_0 *needed[]) {
    unsigned elf_hash = elfhash7_0(name);
    Elf32_Sym *s = NULL;
    int i;
    for (i = 0; needed[i] != NULL; i++) {
        DEBUG("%s: looking up %s in %s",
              si->name, name, needed[i]->name);
        s = soinfo_elf_lookup7_0(needed[i], elf_hash, name);
        if (s != NULL) {
            *lsi = needed[i];
            goto done;
        }
    }

    done:
    if (s != NULL) {
        DL_ERR("si %s sym %s s->st_value = 0x%08x, "
                       "found in %s, base = 0x%08x, load bias = 0x%08x",
               si->name, name, s->st_value,
               (*lsi)->name, (*lsi)->base, (*lsi)->load_bias);
        return s;
    }

    return NULL;
}

static int soinfo_relocate7_0(soinfo7_0 *si, Elf32_Rel *rel, unsigned count,
                              soinfo7_0 *needed[]) {
    Elf32_Sym *symtab = si->symtab;
    const char *strtab = si->strtab;
    Elf32_Sym *s;
    Elf32_Rel *start = rel;
    soinfo7_0 *lsi;
    size_t idx;

    for (idx = 0; idx < count; ++idx, ++rel) {
        unsigned type = ELF32_R_TYPE(rel->r_info);
        unsigned sym = ELF32_R_SYM(rel->r_info);
        Elf32_Addr reloc = (Elf32_Addr) (rel->r_offset + si->load_bias);
        Elf32_Addr sym_addr = 0;
        char *sym_name = NULL;

        DEBUG("Processing '%s' relocation at index %d", si->name, idx);
        if (type == 0) { // R_*_NONE
            continue;
        }
        if (sym != 0) {
            sym_name = (char *) (strtab + symtab[sym].st_name);
            s = soinfo_do_lookup7_0(si, sym_name, &lsi, needed);

            if (s == NULL) {

                /* We only allow an undefined symbol if this is a weak
                   reference..   */
                s = &symtab[sym];
                if (ELF32_ST_BIND(s->st_info) != STB_WEAK) {
                    DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name,
                           si->name);
                    return -1;
                }
                if (s != NULL) {
                    DL_ERR(" %s is not null", sym_name);
                }
                switch (type) {
                    case 22:
                        DL_ERR("unknown weak reloc type %d @ %p (%d)",
                               type, rel, (int) (rel - start));
                    case 21:
                        DL_ERR("unknown weak reloc type %d @ %p (%d)",
                               type, rel, (int) (rel - start));
                    case 2:
                        DL_ERR("unknown weak reloc type %d @ %p (%d)",
                               type, rel, (int) (rel - start));
                    case 23:
                        DL_ERR("unknown weak reloc type %d @ %p (%d)",
                               type, rel, (int) (rel - start));
                        break;
                    case 20:
                        DL_ERR("unknown weak reloc type %d @ %p (%d)",
                               type, rel, (int) (rel - start));
                    default:
                        DL_ERR("unknown weak reloc error type %d @ %p (%d)",
                               type, rel, (int) (rel - start));
                        return -1;
                }
            } else {
                // if(lsi->load_bias!=NULL){
                //     lsi->base=lsi->load_bias;
                //  }
                sym_addr = (Elf32_Addr) (s->st_value + lsi->base);
            }
//            count_relocation(kRelocSymbol);
        } else {
            s = NULL;
        }

/* TODO: This is ugly. Split up the relocations by arch into
 * different files.
 */
        switch (type) {
            case 22:

                DL_ERR("RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
                *((Elf32_Addr *) reloc) = sym_addr;
                break;
            case 21:

                DL_ERR("RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
                *((Elf32_Addr *) reloc) = sym_addr;
                break;
            case 2:

                DL_ERR("RELO ABS %08x <- %08x %s", reloc, sym_addr, sym_name);
                *((Elf32_Addr *) reloc) += sym_addr;
                break;
            case 3:

                DL_ERR("RELO REL32 %08x <- %08x - %08x %s",
                       reloc, sym_addr, rel->r_offset, sym_name);
                *((Elf32_Addr *) reloc) += sym_addr - rel->r_offset;
                break;
            case 7:

                DL_ERR("RELO JMP_SLOT %08x <- %08x %s", reloc, sym_addr, sym_name);
                *((Elf32_Addr *) reloc) = sym_addr;
                break;
            case 6:

                DL_ERR("RELO GLOB_DAT %08x <- %08x %s", reloc, sym_addr, sym_name);
                *((Elf32_Addr *) reloc) = sym_addr;
                break;


            case 23:
//            count_relocation(kRelocRelative);
                MARK(rel->r_offset);
                if (sym) {
                    DL_ERR("odd RELATIVE form...");
                    return -1;
                }
                DL_ERR("RELO RELATIVE %08x <- +%08x", reloc, si->base);
                *((Elf32_Addr *) reloc) += si->base;
                break;

#

            case 20:
                if ((si->flags & FLAG_EXE) == 0) {

                    DL_ERR("%s R_ARM_COPY relocations only supported for ET_EXEC", si->name);
                    return -1;
                }

                DL_ERR("RELO %08x <- %d @ %08x %s", reloc, s->st_size, sym_addr, sym_name);
                if (reloc == sym_addr) {
                    Elf32_Sym *src = soinfo_do_lookup7_0(NULL, sym_name, &lsi, needed);

                    if (src == NULL) {
                        DL_ERR("%s R_ARM_COPY relocation source cannot be resolved", si->name);
                        return -1;
                    }
                    if (lsi->has_DT_SYMBOLIC) {
                        DL_ERR("%s invalid R_ARM_COPY relocation against DT_SYMBOLIC shared "
                                       "library %s (built with -Bsymbolic?)", si->name, lsi->name);
                        return -1;
                    }
                    if (s->st_size < src->st_size) {
                        DL_ERR("%s R_ARM_COPY relocation size mismatch (%d < %d)",
                               si->name, s->st_size, src->st_size);
                        return -1;
                    }
                    memcpy((void *) reloc, (void *) (src->st_value + lsi->load_bias), src->st_size);
                } else {
                    DL_ERR("%s R_ARM_COPY relocation target cannot be resolved", si->name);
                    return -1;
                }
                break;


            default:
                DL_ERR("unknown reloc type %d @ %p (%d)",
                       type, rel, (int) (rel - start));
                return -1;
        }
    }
    return 1;
}

static const char *select_sys_lib(const char *name) {
    if (strcmp(name, "libc.so") == 0) {
        return "/system/lib/libc.so";
    }
    if (strcmp(name, "libz.so") == 0) {
        return "/system/lib/libz.so";
    }
    if (strcmp(name, "liblog.so") == 0) {
//        return "/vendor/lib/liblog.so";
        return "/system/lib/liblog.so";
    }
    if (strcmp(name, "libm.so") == 0) {
        return "/system/lib/libm.so";
    }
//    if(strcmp(name,"libdl.so")==0){
//        return "/system/lib/libdl.so";
//    }
    if (strcmp(name, "libstdc++.so") == 0) {
        return "/system/lib/libstdc++.so";
    }
    return NULL;
}

static const char *select_vendor_lib(const char *name) {
    if (strcmp(name, "libc.so") == 0) {
        return "/vendor/lib/libc.so";
    }

    if (strcmp(name, "liblog.so") == 0) {
//        return "/vendor/lib/liblog.so";
        return "/vendor/lib/liblog.so";
    }
    if (strcmp(name, "libm.so") == 0) {
        return "/vendor/lib/libm.so";
    }

    if (strcmp(name, "libz.so") == 0) {
        return "/vendor/lib/libz.so";
    }
//    if(strcmp(name,"libdl.so")==0){
//        return "/system/lib/libdl.so";
//    }
    if (strcmp(name, "libstdc++.so") == 0) {
        return "/vendor/lib/libstdc++.so";
    }
    return NULL;
}


static Elf32_Sym libdl_symtab1[] = {
        // total length of libdl_info.strtab, including trailing 0
        // This is actually the the STH_UNDEF entry. Technically, it's
        // supposed to have st_name == 0, but instead, it points to an index
        // in the strtab with a \0 to make iterating through the symtab easier.
        {st_name: sizeof(ANDROID_LIBDL_STRTAB1) - 1,
        },
        {st_name: 0,   // starting index of the name in libdl_info.strtab
                st_value: (Elf32_Addr) &dlopen,
                st_info: STB_GLOBAL << 4,
                st_shndx: 1,
        },
        {st_name: 7,
                st_value: (Elf32_Addr) &dlclose,
                st_info: STB_GLOBAL << 4,
                st_shndx: 1,
        },
        {st_name: 15,
                st_value: (Elf32_Addr) &dlsym,
                st_info: STB_GLOBAL << 4,
                st_shndx: 1,
        },
        {st_name: 21,
                st_value: (Elf32_Addr) &dlerror,
                st_info: STB_GLOBAL << 4,
                st_shndx: 1,
        },
        {st_name: 29,
                st_value: (Elf32_Addr) &dladdr,
                st_info: STB_GLOBAL << 4,
                st_shndx: 1,
        }
};


soinfo7_0 libdl_info1 = {
        name: "libdl.so",
        flags: FLAG_LINKED,
        strtab: ANDROID_LIBDL_STRTAB1,
        symtab: libdl_symtab1,

        nbucket: sizeof(g_libdl_buckets1) / sizeof(unsigned),
        nchain: sizeof(g_libdl_buckets1) / sizeof(unsigned),
        bucket: g_libdl_buckets1,
        chain: g_libdl_chains1,
        ref_count_:1,
        strtab_size_:sizeof(ANDROID_LIBDL_STRTAB1),

};

static int soinfo_link_image7_0(soinfo7_0 *si) {
    /* "base" might wrap around UINT32_MAX. */
    Elf32_Addr base = si->load_bias;
    const Elf32_Phdr *phdr = si->phdr;
    int phnum = si->phnum;
    int relocating_linker = (si->flags & FLAG_LINKER);

    /* We can't debug anything until the linker is relocated */
    if (!relocating_linker) {
        INFO("[ linking %s ]", si->name);
        DEBUG("si->base = 0x%08x si->flags = 0x%08x", si->base, si->flags);
    }

    /* Extract dynamic section */
    size_t dynamic_count;
    Elf32_Word dynamic_flags;
    phdr_table_get_dynamic_section7_0(phdr, phnum, base, &si->dynamic,
                                      &dynamic_count, &dynamic_flags);
    if (si->dynamic == NULL) {
        if (!relocating_linker) {
            DL_ERR("missing PT_DYNAMIC in \"%s\"", si->name);
        }
        return -1;
    } else {
        if (!relocating_linker) {
            DEBUG("dynamic = %p", si->dynamic);
        }
    }
#ifdef ANDROID_ARM_LINKER
    (void) phdr_table_get_arm_exidx4_4(phdr, phnum, base,
                                    &si->ARM_exidx, &si->ARM_exidx_count);
#endif
    // Extract useful information from dynamic section.
    uint32_t needed_count = 0;
    Elf32_Dyn *d;
    for (d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        DEBUG("d = %p, d[0](tag) = 0x%08x d[1](val) = 0x%08x", d, d->d_tag, d->d_un.d_val);
        switch (d->d_tag) {
            case DT_HASH:
                si->nbucket = ((unsigned *) (base + d->d_un.d_ptr))[0];
                si->nchain = ((unsigned *) (base + d->d_un.d_ptr))[1];
                si->bucket = (unsigned *) (base + d->d_un.d_ptr + 8);
                si->chain = (unsigned *) (base + d->d_un.d_ptr + 8 + si->nbucket * 4);
                break;
            case DT_STRTAB:
                si->strtab = (const char *) (base + d->d_un.d_ptr);
                break;
            case DT_SYMTAB:
                si->symtab = (Elf32_Sym *) (base + d->d_un.d_ptr);
                break;
            case DT_PLTREL:
                if (d->d_un.d_val != DT_REL) {
                    DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
                    return -1;
                }
                break;
            case DT_JMPREL:
                si->plt_rel = (Elf32_Rel *) (base + d->d_un.d_ptr);
                DL_ERR("plt_rel=%p", si->plt_rel);
                break;
            case DT_PLTRELSZ:
                si->plt_rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
                DL_ERR("plt_rel_count=%08x", si->plt_rel_count);
                break;
            case DT_REL:
                si->rel = (Elf32_Rel *) (base + d->d_un.d_ptr);
                break;
            case DT_RELSZ:
                si->rel_count = d->d_un.d_val / sizeof(Elf32_Rel);
                break;
            case DT_PLTGOT:
                /* Save this in case we decide to do lazy binding. We don't yet. */
                si->plt_got = (unsigned *) (base + d->d_un.d_ptr);
                break;
            case DT_DEBUG:
                // Set the DT_DEBUG entry to the address of _r_debug for GDB
                // if the dynamic table is writable
                /*
                if ((dynamic_flags & PF_W) != 0) {
                    d->d_un.d_val = (int) &_r_debug;
                }*/
                break;
            case DT_RELA:
                DL_ERR("unsupported DT_RELA in \"%s\"", si->name);
                return -1;
            case DT_INIT:
                si->init_func = (void (*)(void)) (base + d->d_un.d_ptr);
                DEBUG("%s constructors (DT_INIT) found at %p", si->name, si->init_func);
                break;
            case DT_FINI:
                si->fini_func = (void (*)(void)) (base + d->d_un.d_ptr);
                DEBUG("%s destructors (DT_FINI) found at %p", si->name, si->fini_func);
                break;
            case DT_INIT_ARRAY:
                si->init_array = (unsigned *) (base + d->d_un.d_ptr);
                DEBUG("%s constructors (DT_INIT_ARRAY) found at %p", si->name, si->init_array);
                break;
            case DT_INIT_ARRAYSZ:
                si->init_array_count = ((unsigned) d->d_un.d_val) / sizeof(Elf32_Addr);
                break;
            case DT_FINI_ARRAY:
                si->fini_array = (unsigned *) (base + d->d_un.d_ptr);
                DEBUG("%s destructors (DT_FINI_ARRAY) found at %p", si->name, si->fini_array);
                break;
            case DT_FINI_ARRAYSZ:
                si->fini_array_count = ((unsigned) d->d_un.d_val) / sizeof(Elf32_Addr);
                break;
            case DT_PREINIT_ARRAY:
                si->preinit_array = (unsigned *) (base + d->d_un.d_ptr);
                DEBUG("%s constructors (DT_PREINIT_ARRAY) found at %p", si->name,
                      si->preinit_array);
                break;
            case DT_PREINIT_ARRAYSZ:
                si->preinit_array_count = ((unsigned) d->d_un.d_val) / sizeof(Elf32_Addr);
                break;
            case DT_TEXTREL:
                si->has_text_relocations = 1;
                break;
            case DT_SYMBOLIC:
                si->has_DT_SYMBOLIC = 1;
                break;
            case DT_NEEDED:
                ++needed_count;
                break;
#if defined DT_FLAGS
                // TODO: why is DT_FLAGS not defined?
            case DT_FLAGS:
                if (d->d_un.d_val & DF_TEXTREL) {
                    si->has_text_relocations = 1;
                }
                if (d->d_un.d_val & DF_SYMBOLIC) {
                    si->has_DT_SYMBOLIC = 1;
                }
                break;
#endif
#if defined(ANDROID_MIPS_LINKER)
            case DT_STRSZ:
        case DT_SYMENT:
        case DT_RELENT:
             break;
        case DT_MIPS_RLD_MAP:
            // Set the DT_MIPS_RLD_MAP entry to the address of _r_debug for GDB.
            {
              r_debug** dp = (r_debug**) d->d_un.d_ptr;
              *dp = &_r_debug;
            }
            break;
        case DT_MIPS_RLD_VERSION:
        case DT_MIPS_FLAGS:
        case DT_MIPS_BASE_ADDRESS:
        case DT_MIPS_UNREFEXTNO:
            break;

        case DT_MIPS_SYMTABNO:
            si->mips_symtabno = d->d_un.d_val;
            break;

        case DT_MIPS_LOCAL_GOTNO:
            si->mips_local_gotno = d->d_un.d_val;
            break;

        case DT_MIPS_GOTSYM:
            si->mips_gotsym = d->d_un.d_val;
            break;

        default:
            DEBUG("Unused DT entry: type 0x%08x arg 0x%08x", d->d_tag, d->d_un.d_val);
            break;
#endif
        }
    }

    DEBUG("si->base = 0x%08x, si->strtab = %p, si->symtab = %p",
          si->base, si->strtab, si->symtab);

    // Sanity checks.
    if (relocating_linker && needed_count != 0) {
        DL_ERR("linker cannot have DT_NEEDED dependencies on other libraries");
        return -1;
    }
    if (si->nbucket == 0) {
        DL_ERR("empty/missing DT_HASH in \"%s\" (built with --hash-style=gnu?)", si->name);
        return -1;
    }
    if (si->strtab == 0) {
        DL_ERR("empty/missing DT_STRTAB in \"%s\"", si->name);
        return -1;
    }
    if (si->symtab == 0) {
        DL_ERR("empty/missing DT_SYMTAB in \"%s\"", si->name);
        return -1;
    }
    soinfo7_0 **needed = (soinfo7_0 **) alloca((1 + needed_count) * sizeof(soinfo7_0 *));
    soinfo7_0 **pneeded = needed;
    // Elf32_Dyn* dd;
    for (d = si->dynamic; d->d_tag != DT_NULL; ++d) {
        if (d->d_tag == DT_NEEDED) {
            soinfo7_0 *lsi = NULL;
            const char *library_name = si->strtab + d->d_un.d_val;
            DEBUG("%s needs %s", si->name, library_name);
            if (strcmp(library_name, "libdl.so") == 0) {
                lsi = &libdl_info1;
            }
            const char *soname = select_sys_lib(library_name);
            if (soname != NULL) {
                lsi = sys_dlopen(soname);
                if (lsi == NULL) {
                    soname = select_vendor_lib(library_name);
                    if (soname != NULL) {
                        lsi = sys_dlopen(soname);
                    }
                }
            }
            if (lsi == NULL) {
                // strlcpy(tmp_err_buf, linker_get_error_buffer(), sizeof(tmp_err_buf));
                DL_ERR("could not load library \"%s\" needed by \"%s\"; caused by ",
                       library_name, si->name);
                return -1;
            } else {
                *pneeded++ = lsi;
            }
            DL_ERR(" soname=%s , nbucket=%08x", lsi->name, lsi->nbucket);

        }
    }
    *pneeded = NULL;

    if (si->has_text_relocations) {
        DL_ERR("%s has text relocations. This is wasting memory and is "
                       "a security risk. Please fix.", si->name);
        if (phdr_table_unprotect_segments7_0(si->phdr, si->phnum, si->load_bias) < 0) {
            DL_ERR("can't unprotect loadable segments for \"%s\": %s",
                   si->name, strerror(errno));
            return -1;
        }
    }

    if (si->plt_rel != NULL) {
        DEBUG("[ relocating %s plt ] count=%08x", si->name, si->plt_rel_count);
        if (soinfo_relocate7_0(si, si->plt_rel, si->plt_rel_count, needed) != 1) {
            DL_ERR("relocate fail");
            return -1;
        }
    }
    if (si->rel != NULL) {
        DEBUG("[ relocating %s ]", si->name);
        if (soinfo_relocate7_0(si, si->rel, si->rel_count, needed) != 1) {
            DL_ERR("relocate fail");
            return -1;
        }
    }
#ifdef ANDROID_MIPS_LINKER
    if (!mips_relocate_got4_4(si, needed)) {
        return -1;
    }
#endif

    si->flags |= FLAG_LINKED;
    DEBUG("[ finished linking %s ]", si->name);

    DL_ERR("has_text_relocations is %08x", si->has_text_relocations);
    if (si->has_text_relocations == 1) {
        /* All relocations are done, we can protect our segments back to
         * read-only. */

        if (phdr_table_protect_segments7_0(si->phdr, si->phnum, si->load_bias) < 0) {
            DL_ERR("can't protect segments for \"%s\": %s",
                   si->name, strerror(errno));
            return -1;
        }
    }
    if (phdr_table_protect_gnu_relro7_0(si->phdr, si->phnum, si->load_bias) < 0) {
        DL_ERR("can't enable GNU RELRO protection for \"%s\": %s",
               si->name, strerror(errno));
        return -1;
    }
    return 1;
}

static soinfo7_0 *load_library7_0(const char *name) {
    int fd = open_library(name);
    soinfo7_0 *soinfo = ReadElfHeader7_0(fd, name);
    return soinfo;
}

int pid = 0;

static void call_constructors_array7_0(unsigned *ctor, int count, int reverse) {
    int n, inc = 1;

    if (reverse) {
        ctor += (count - 1);
        inc = -1;
    }

    for (n = count; n > 0; n--) {
        DL_ERR("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid,
               reverse ? "dtor" : "ctor",
               (unsigned) ctor, (unsigned) *ctor);
        void (*func)() = (void (*)()) *ctor;
        ctor += inc;
        if (((int) func == 0) || ((int) func == -1)) continue;
        DL_ERR("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned) func);
        func();
        DL_ERR(" func %s", strerror(errno));
    }
}

void init_constructors7_0(soinfo7_0 *si) {
    if (si->constructors_called)
        return;
    DL_ERR("init");
    si->constructors_called = 1;

    if (si->flags & FLAG_EXE) {
        DL_ERR("[ Calling preinit_array @ 0x%08x [%d] for '%s' ]\n", (unsigned) si->preinit_array,
               si->preinit_array_count,
               si->name);
        call_constructors_array7_0(si->preinit_array, si->preinit_array_count, 0);
        DL_ERR("[ -------%5d Done calling preinit_array for '%s' ]\n", pid, si->name);
    } else {
        if (si->preinit_array) {
            DL_ERR("--------%5d Shared library '%s' has a preinit_array table @ 0x%08x."
                           " This is INVALID.", pid, si->name,
                   (unsigned) si->preinit_array);
        }
    }

    if (si->init_func) {
        DL_ERR("[--------%5d Calling init_func @ 0x%08x for '%s' ]\n", pid,
               (unsigned) si->init_func, si->name);
        si->init_func();
        DL_ERR("[ --------%5d Done calling init_func for '%s' ]\n", pid, si->name);
    }

    if (si->init_array) {
        DL_ERR("[ -------%5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid,
               (unsigned) si->init_array, si->init_array_count, si->name);
        call_constructors_array7_0(si->init_array, si->init_array_count, 0);
        DL_ERR("[ --------%5d Done calling init_array for '%s' ]\n", pid, si->name);
    }

}

soinfo7_0 *find_library_internal7_0(const char *name) {
    soinfo7_0 *soinfo7_0 = load_library7_0(name);
    if (soinfo7_0 == NULL) {
        return NULL;
    }
    DL_ERR("[ init_library base=0x%08x sz=0x%08x name='%s' ]", soinfo7_0->base, soinfo7_0->size,
           soinfo7_0->name);
    if (soinfo_link_image7_0(soinfo7_0) != 1) {
        munmap((void *) (soinfo7_0->base), soinfo7_0->size);
        free_info7_0(soinfo7_0);
        return NULL;
    }
    if (soinfo7_0 != NULL) {
        init_constructors7_0(soinfo7_0);
    }
    DL_ERR("LINK IMAGE SUCCESS");
    return soinfo7_0;
}

#define likely7_0(expr)   __builtin_expect (expr, 1)
#define unlikely7_0(expr) __builtin_expect (expr, 0)

void *lookup_in_library7_0(soinfo7_0 *si, const char *name) {
    soinfo7_0 *found;
    Elf32_Sym *sym;
    unsigned bind;
    found = si;
    sym = soinfo_elf_lookup7_0(si, elfhash7_0(name), name);
    if (likely7_0(sym != 0)) {
        bind = ELF32_ST_BIND(sym->st_info);
        if (likely7_0((bind == STB_GLOBAL) && (sym->st_shndx != 0))) {
            unsigned ret = sym->st_value + found->base;
            return (void *) ret;
        }
    }
    return NULL;
}

public.h

//
//  public.h
//  goblin4.4.2
//
//  Created by liu meng on 2018/2/26.
//  Copyright © 2018年 com.qunar. All rights reserved.
//

#ifndef public_h
#define public_h
#define FLAG_LINKED     0x00000001
#define FLAG_ERROR      0x00000002
#define FLAG_EXE        0x00000004 // The main executable
#define FLAG_LINKER     0x00000010 // The linker itself
#include <android/log.h>
#define LOG_TAG "liumeng"
#define SOINFO_NAME_LEN 128
enum RelocationKind {
    kRelocAbsolute = 0,
    kRelocRelative,
    kRelocCopy,
    kRelocSymbol,
    kRelocMax
};
#define MARK(x) do {} while (0)
#define MAYBE_MAP_FLAG(x,from,to)    (((x) & (from)) ? (to) : 0)
#define PFLAGS_TO_PROT(x)            (MAYBE_MAP_FLAG((x), PF_X, PROT_EXEC) | \
MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
#if STATS
struct linker_stats_t {
    int count[kRelocMax];
};

static linker_stats_t linker_stats;

static void count_relocation(RelocationKind kind) {
    ++linker_stats.count[kind];
}
#else
static void count_relocation(RelocationKind) {
}
#endif

enum {
    RT_CONSISTENT,
    RT_ADD,
    RT_DELETE
};
#ifdef ANDROID_ARM_LINKER

#define R_ARM_COPY       20
#define R_ARM_GLOB_DAT   21
#define R_ARM_JUMP_SLOT  22
#define R_ARM_RELATIVE   23

/* According to the AAPCS specification, we only
 * need the above relocations. However, in practice,
 * the following ones turn up from time to time.
 */
#define R_ARM_ABS32      2
#define R_ARM_REL32      3

#elif defined(ANDROID_X86_LINKER)

#define R_386_32         1
#define R_386_PC32       2
#define R_386_GLOB_DAT   6
#define R_386_JUMP_SLOT  7
#define R_386_RELATIVE   8

#endif

#ifndef DT_INIT_ARRAY
#define DT_INIT_ARRAY      25
#endif

#ifndef DT_FINI_ARRAY
#define DT_FINI_ARRAY      26
#endif

#ifndef DT_INIT_ARRAYSZ
#define DT_INIT_ARRAYSZ    27
#endif

#ifndef DT_FINI_ARRAYSZ
#define DT_FINI_ARRAYSZ    28
#endif

#ifndef DT_PREINIT_ARRAY
#define DT_PREINIT_ARRAY   32
#endif

#ifndef DT_PREINIT_ARRAYSZ
#define DT_PREINIT_ARRAYSZ 33
#endif
#define format_buffer(b, s, f, p...) sprintf(b, f, p);
static const char *sopaths[] = {
        "/vendor/lib",
        "/system/lib",
        0
};
static int _open_lib(const char *name)
{
    int fd;
    struct stat filestat;

    if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) {
        if ((fd = open(name,O_RDONLY | O_CLOEXEC)) >= 0)
            return fd;
    }

    return -1;
}

static int open_library(const char *name)
{
    int fd;
    char buf[512];
    const char **path;
    int n;
    if(name == 0) return -1;
    if(strlen(name) > 256) return -1;

    if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0))
        return fd;


    for (path = sopaths; *path; path++) {
        n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name);
        if (n < 0 || n >= (int)sizeof(buf)) {
            continue;
        }
        if ((fd = _open_lib(buf)) >= 0)
            return fd;
    }

    return -1;
}

#define DL_ERR(fmt, args...)    __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,fmt, ##args)
#define DEBUG(fmt, args...)    __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,fmt, ##args)
#define INFO(fmt, args...)    __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,fmt, ##args)

#endif /* public_h */

       

三.难点分析

       (1).在android 7.0之后dlopen不返回soinfo结构体,通过读取maps 获取基地址读取系统so的结构体

       (2).在android5.1之后 出现read被pread64函数读取so的结构

       (3).在android4.1.2 5.0 7.0等page_size 也是内存大小有改变

       (4).在android4.4之后都是c++ 考虑安全问题 用c语言实现

 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值