android自定义linker实现安全加固
转:https://blog.****.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 %[email protected]%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 %[email protected]%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语言实现