#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
#include <elf.h>
#include <fcntl.h>
#include <sys/mman.h>
#define LOG_TAG "DEBUG"
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
EGLBoolean (*old_eglSwapBuffers)(EGLDisplay dpy, EGLSurface surf) = -1;
EGLBoolean new_eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
{
LOGD("New eglSwapBuffers\n");
if (old_eglSwapBuffers == -1)
LOGD("error\n");
return old_eglSwapBuffers(dpy, surface);
}
void* get_module_base(pid_t pid, const char* module_name)
{
FILE *fp;
long addr = 0;
char *pch;
char filename[32];
char line[1024];
if (pid < 0) {
/* self process */
snprintf(filename, sizeof(filename), "/proc/self/maps", pid);
} else {
snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
}
fp = fopen(filename, "r");
if (fp != NULL) {
while (fgets(line, sizeof(line), fp)) {
if (strstr(line, module_name)) {
pch = strtok( line, "-" );
addr = strtoul( pch, NULL, 16 );
if (addr == 0x8000)
addr = 0;
break;
}
}
fclose(fp) ;
}
return (void *)addr;
}
#define LIBSF_PATH "/system/lib/libsurfaceflinger.so"
int hook_eglSwapBuffers()
{
old_eglSwapBuffers = eglSwapBuffers;
LOGD("Orig eglSwapBuffers = %p\n", old_eglSwapBuffers);
void * base_addr = get_module_base(getpid(), LIBSF_PATH); //获取 libsurfaceflinger.so 加载到 本进程后的地址
LOGD("libsurfaceflinger.so address = %p\n", base_addr);
int fd;
fd = open(LIBSF_PATH, O_RDONLY); //打开 libsurfaceflinger.so文件
if (-1 == fd) {
LOGD("error\n");
return -1;
}
Elf32_Ehdr ehdr; //elf 文件头结构
/*
#define EI_NIDENT
typedef struct{
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
}Elf32_Ehdr;
*/
//ELF文件由4部分组成,分别是ELF头(ELF header)、程序头表(Program header table)、节(Section)和节头表(Section header table)。
read(fd, &ehdr, sizeof(Elf32_Ehdr)); //从 libsurfaceflinger.so 中读取so 库的 elf 文件头
unsigned long shdr_addr = ehdr.e_shoff; //节区头部表格的偏移量(按字节计算)
int shnum = ehdr.e_shnum; //节区头部表格的表项数目。可以为0。
int shent_size = ehdr.e_shentsize; //e_shentsize 表示Section header table中的每一个条目的大小
unsigned long stridx = ehdr.e_shstrndx; //包含节名称的字符串是第几个节(从零开始计数)
Elf32_Shdr shdr; //每个“Elf32_Shdr”结构体对应一个段 Elf32_Shdr”又被称为段描述符(Section Descriptor)
/*
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr; 假如该section将出现在进程的内存映象空间里,该成员给出了一个该section在内存中的位置。
Elf32_Off sh_offset; 该section的字节偏移量(从文件开始计数)
Elf32_Word sh_size; 该成员给你了section的字节大小
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize; 一些sections保存着一张固定大小入口的表,就象符号表。对于这样一个 section来说,该成员给出了每个入口的字节大小。
} Elf32_Shdr;
*/
lseek(fd, shdr_addr + stridx * shent_size, SEEK_SET); //SEEK_SET 将读写位置指向文件头后再增加offset个位移量
read(fd, &shdr, shent_size); //lseek 定位到 某一节区 后读取
char * string_table = (char *)malloc(shdr.sh_size); //创建字符表 大小为Elf段的大小
lseek(fd, shdr.sh_offset, SEEK_SET); //定位到某一个段
read(fd, string_table, shdr.sh_size);
lseek(fd, shdr_addr, SEEK_SET); //定位到节区头
int i;
uint32_t out_addr = 0;
uint32_t out_size = 0;
uint32_t got_item = 0;
int32_t got_found = 0;
for (i = 0; i < shnum; i++) { //遍历所有的段
read(fd, &shdr, shent_size);
if (shdr.sh_type == SHT_PROGBITS) { //如果段的类型是程序段
int name_idx = shdr.sh_name; //段的名字
if (strcmp(&(string_table[name_idx]), ".got.plt") == 0 || strcmp(&(string_table[name_idx]), ".got") == 0) {
out_addr = base_addr + shdr.sh_addr; //so库加载的地址+段的地址
out_size = shdr.sh_size; //大小仍然不变
LOGD("out_addr = %lx, out_size = %lx\n", out_addr, out_size);
for (i = 0; i < out_size; i += 4) { //步长为4位
got_item = *(uint32_t *)(out_addr + i);
if (got_item == old_eglSwapBuffers) {
LOGD("Found eglSwapBuffers in got\n"); //已经找到了交换缓冲区
got_found = 1;
//对于uint32_t类型的说明 http://blog.youkuaiyun.com/kiddy19850221/article/details/6655066
uint32_t page_size = getpagesize(); //4字节
uint32_t entry_page_start = (out_addr + i) & (~(page_size - 1)); //找到进入页面的地址
mprotect((uint32_t *)entry_page_start, page_size, PROT_READ | PROT_WRITE);
*(uint32_t *)(out_addr + i) = new_eglSwapBuffers; //替换地址
break;
} else if (got_item == new_eglSwapBuffers) { //如果已经替换成新的缓冲交换表
LOGD("Already hooked\n");
break;
}
}
if (got_found)
break;
}
}
}
free(string_table);
close(fd);
}
int hook_entry(char * a){
LOGD("Hook success\n");
LOGD("Start hooking\n");
hook_eglSwapBuffers();
return 0;
}
/*#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <android/log.h>
#include <elf.h>
#include <fcntl.h>
#include <sys/user.h>
#include <asm/ptrace.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <dirent.h>
#include <string.h>
#define LOG_TAG "DEBUG"
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
uint32_t* got;
int hook_api() {
//使用打开动态库的方式得到动态库的soinfo结构
soinfo* si =(soinfo*)::dlopen("/system/bin/libbinder.so",RTLD_NOW);
if(si == NULL || si->strtab == NULL || si->plt_rel == NULL)
{
return -1 ;
}
for (uint32_t i = 0; i < si->plt_rel_count;i++) {
//查找重定位表中ioctl所在的项
if(strcmp(si->symtab[ELF32_R_SYM(si->plt_rel[i].r_info)].st_name+ si->strtab, "ioctl") == 0){
//计算对应的GOT表项的地址
got = (uint32_t*)(si->base +si->plt_rel[i].r_offset);
if(*(got) != new_ioctl) {
//把GOT表项的地址属性改为可写
uint32_tpagesize = sysconf(_SC_PAGE_SIZE);
void*start =(void*)(((uint32_t)got)/pagesize*pagesize);
if(mprotect(start, pagesize * 2, PROT_READ|PROT_WRITE) == -1){
returnfalse;
}
*(got) = new_ioctl; //填入新地址
mprotect(start,pagesize * 2, PROT_READ|PROT_WRITE);
}
return 0;
}
}
}
//******************************************************************************************************************************
void new_ioctl()
{
}
int hook_entry(char * a){
LOGD("Hook success, pid = %d\n", getpid());
LOGD("Hello %s\n", a);
return 0;
} */
NDK注入存档
最新推荐文章于 2024-02-27 14:40:33 发布