首页
社区
课程
招聘
[原创]四.Android ELF系列:实现一些小功能(模块操作,dump so)
2019-2-24 16:14 7413

[原创]四.Android ELF系列:实现一些小功能(模块操作,dump so)

2019-2-24 16:14
7413
  1. Android ELF系列:ELF文件格式简析和linker的链接so文件原理分析
  2. Android ELF系列:实现一个so文件加载器
  3. Android ELF系列:手写一个so文件(包含两个导出函数)
    4. Android ELF系列:实现一些小功能
  4. Android ELF系列:实现一个so的加密壳
  5. 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世界

收藏
点赞4
打赏
分享
打赏 + 1.00雪花
打赏次数 1 雪花 + 1.00
 
赞赏  junkboy   +1.00 2019/02/25 感谢分享~
最新回复 (5)
雪    币: 17842
活跃值: (59778)
能力值: (RANK:125 )
在线值:
发帖
回帖
粉丝
Editor 2019-2-24 17:26
2
0
感谢分享!期待后续!
雪    币: 6569
活跃值: (3823)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
LowRebSwrd 4 2019-2-24 21:14
3
0
赞!
雪    币: 163
活跃值: (504)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
刘lhhh 2019-2-25 09:20
4
0
elf so结构分析加这种详细代码的文章还是比较少的,感谢作者的分析,期待后续!
雪    币: 2128
活跃值: (6645)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
爱吃菠菜 2 2019-2-25 10:24
5
0
好啊,写成一个系列了。
雪    币: 11
活跃值: (106)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Lessmore 2019-3-3 09:28
6
0
非常好,期待后面的自制shell。
游客
登录 | 注册 方可回帖
返回