- Android ELF系列:ELF文件格式简析和linker的链接so文件原理分析
- Android ELF系列:实现一个so文件加载器
- Android ELF系列:手写一个so文件(包含两个导出函数)
4. Android ELF系列:实现一些小功能
- Android ELF系列:实现一个so的加密壳
- Android ELF系列:待续............
最简单的模块操作
我们都知道soinfo信息都会有指向下一个soinfo的信息.通过这个单向链表我们就可以定位所有的so文件.
那么要定位所有的so文件,首先要找到链表的第一个.
其实非常简单就是somain.
获取somain也非常简单,调用dlopen时name传入null即可.
代码如下:
- 定义soinfo结构
```
#include <jni.h>
#include <string>
#include <elf.h>
#include <dlfcn.h>
#include <android/log.h>
#define TAG "chpsoapply"
#define LOGD(...) android_log_print(ANDROID_LOG_DEBUG, TAG, VA_ARGS__)
#define SOINFO_NAME_LEN 128
typedef void (*linker_function_t)();
struct link_map_t {
uintptr_t l_addr;
char l_name;
uintptr_t l_ld;
link_map_t l_next;
link_map_t* l_prev;
};
struct soinfo {
public:
char name[SOINFO_NAME_LEN];
const Elf32_Phdr* phdr;
size_t phnum;
Elf32_Addr entry;
Elf32_Addr base;
unsigned size;
uint32_t unused1; // DO NOT USE, maintained for compatibility.
Elf32_Dyn* dynamic;
uint32_t unused2; // DO NOT USE, maintained for compatibility
uint32_t unused3; // DO NOT USE, maintained for compatibility
soinfo* 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_t* preinit_array;
size_t preinit_array_count;
linker_function_t* init_array;
size_t init_array_count;
linker_function_t* fini_array;
size_t fini_array_count;
linker_function_t init_func;
linker_function_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;
link_map_t link_map;
bool constructors_called;
// When you read a virtual address from the ELF file, add this
// value to get the corresponding address in the process' address space.
Elf32_Addr load_bias;
bool has_text_relocations;
bool has_DT_SYMBOLIC;
void CallConstructors();
void CallDestructors();
void CallPreInitConstructors();
private:
void CallArray(const char array_name, linker_function_t functions, size_t count, bool reverse);
void CallFunction(const char* function_name, linker_function_t function);
};
soinfo getsolist()
{
return (soinfo )dlopen(0,0);
}
1. 遍历所有模块
//两行代码遍历所有的模块,而且信息更加的细致
void printAllModule()
{
soinfo somain = (soinfo )dlopen(0,0);
while(somain){LOGD("%s",somain->name);somain = somain->next;};
}
2. 查找模块信息
static soinfo find_loaded_library(const char name)
{
soinfo si;
const char bname;
// TODO: don't use basename only for determining libraries
// http://code.google.com/p/android/issues/detail?id=6670
bname = strrchr(name, '/');
bname = bname ? bname + 1 : name;
for (si = getsolist(); si != NULL; si = si->next) {
if (!strcmp(bname, si->name)) {
return si;
}
}
return NULL;
}
3. 查找一个内存地址属于哪个模块
soinfo find_containing_library(const void p) {
Elf32_Addr address = reinterpret_cast<Elf32_Addr>(p);
for (soinfo si = (soinfo )dlopen(0,0); si != NULL; si = si->next) {
if (address >= si->base && address - si->base < si->size) {
return si;
}
}
return NULL;
}
4. 实现一个自己的dlsym
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 Elf32_Sym soinfo_elf_lookup(soinfo si, unsigned hash, const char name) {
Elf32_Sym symtab = si->symtab;
const char* strtab = si->strtab;
TRACE_TYPE(LOOKUP, "SEARCH %s in %s@0x%08x %08x %d",
name, si->name, si->base, hash, hash % si->nbucket);
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
Elf32_Sym* s = symtab + n;
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;
}
TRACE_TYPE(LOOKUP, "FOUND %s in %s (%08x) %d",
name, si->name, s->st_value, s->st_size);
return s;
}
}
return NULL;
}
void my_dlsym(soinfo si,const char name)
{
Elf32_Sym s = soinfo_elf_lookup(si,elfhash(name),name);
if(sym)
{
return (void *)(s->st_value + si->load_bias);
}
else
{
return nullptr;
}
}
5. dump 已经加载的so模块
bool dumpso(soinfo so,const char savepath)
{
const Elf32_Phdr phdr;
char Filemem = (char *)malloc(so->size);
Elf32_Addr loadbias = so->load_bias;
size_t fileSize = 0;
if(!Filemem)
return false;
for(int i=0;i<so->phnum;i++)
{
phdr = &(so->phdr[i]);
if(phdr->p_type != PT_LOAD)
{
continue;
}
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;
fileSize+=file_length;
memcpy(&Filemem[file_page_start],(void *)seg_page_start,file_length);
}
FILE *f = fopen(savepath,"w");
if(!f)
{
free(Filemem);
return false;
}
fwrite(Filemem,fileSize,1,f);
free(Filemem);
return true;
}
```
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界