当前位置:   article > 正文

android elf 加固_Android so加固的简单脱壳

so 加固

Android应用的so库文件的加固一直存在,也比较常见,特地花时间整理了一下Android so库文件加固方面的知识。本篇文章主要是对看雪论坛《简单的so脱壳器》这篇文章的思路和代码的分析,很久之前就阅读过这篇文章但是一直没有时间来详细分析它的代码,最近比较有空来分析一下这篇文章中提到的Android

so脱壳器的代码udog,github下载地址为:https://github.com/devilogic/udog,Android so加固的一般手法就是去除掉外壳Android so库文件的 ELF 链接视图 相关的信息,例如区节头表的偏移、区节头表的项数、区节头表名称字符串表的序号等,这样处理以后将Android so加固的外壳so库文件拖到IDA中去分析的时候,直接提示区节头表无效的错误,IDA工具不能对Android

so加固的外壳so库文件进行分析,达到抗IDA工具静态分析的目的。

Android so加固中被保护的Android so库文件是由外壳Android so库文件在.init段或者.init_array段的构造函数里自定linker进行内存加载和解密的,被保护的Android so库文件自定义内存加载、映射完成以后将外壳Android so库文件的soinfo*(dlopen函数返回的)修改为被保护Android so库文件的soinfo*,这样被保护的Android so库文件的内存加载就成功了并且就可以被调用了。尽管被加固保护的Android

so库文件被加密保护起来了,但是该Android so库文件还是会在内存中进行解密出来,因此我们可以在被加固保护的Android so库文件内存解密时进行内存dump处理,然后对dump出来的Android so库文件进行ELF文件格式的调整和修复以及section区节头表的重建,就可以实现被保护的Android so库文件的脱壳了。

简单so脱壳器这篇文章中提到的so脱壳器udog的代码比较简单,之前以为udog的代码比较复杂,后来整理了一下作者玩命的代码发现很多代码都是废弃的,核心关键的代码部分不是很复杂但是对于学习Android so加固的脱壳很有作用,也是Android so加固脱壳和内存dump后修复的第一步,玩命版主主要实现了被加固Android so库文件的内存dump和ELF文件格式部分参数的修复处理,对于脱壳后ELF文件的section区节头表等的重建并没有实现。

udog代码的入口 main函数 在linker.cpp文件中如下图所示:

在linker.cpp文件中,main函数工作流程是: 先对用户输入的命令行参数进行解析处理得到 用户参数解析结果描述结构体options_t,然后根据用户输入的命令参数解析的结果options_t 进行Android so的脱壳相关的操作。udog脱壳器中帮助命令行在文件options.cpp中实现,如下图所示:

用户输入的命令行参数解析结果保存结构体options_t中,如下图代码所示:

// 保存用户输入命令行参数的解析结果

struct options_t {

bool call_dt_init;

bool call_dt_init_array;

bool call_dt_finit;

bool call_dt_finit_array;

bool load_pre_libs;

bool load_needed_libs;

bool load;

bool not_relocal; /* 不对重定位表进行修复 */

bool make_sectabs; /* 重建elf文件的区节头表 */

bool dump;

bool help;

bool version;

bool debug;

bool check;

bool clear_entry;

int debuglevel;

unsigned xct_offset;

unsigned xct_size;

char dump_file[128];

char target_file[128];

};

对用户输入的命令行参数进行解析处理的操作在函数handle_arguments中实现,如下图代码所示:

// main函数在linker.cpp类

int main(int argc, char* argv[]) {

// 解析用户输入的命令行参数

g_opts = handle_arguments(argc, argv);// 解析用户输入的命令行参数

struct options_t* handle_arguments(int argc, char* argv[]) {

// 保存命令行参数解析后的结果

static struct options_t opts;

// 清零

memset(&opts, 0, sizeof(opts));

// 默认参数的设置

opts.call_dt_init = true;

opts.call_dt_init_array = true;

opts.call_dt_finit = true;

opts.call_dt_finit_array = true;

opts.load_pre_libs = true;

opts.load_needed_libs = true;

int opt;

int longidx;

int dump = 0, help = 0, version = 0,

debug = 0, check = 0, xcto = 0,

xcts = 0, clear_entry = 0;

if (argc == 1) {

return NULL;

}

// 输入参数选项的解析顺序和规则

// 该数据结构包括了所有要定义的短选项,每一个选项都只用单个字母表示。

// 如果该选项需要参数,则其后跟一个冒号

co

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/872299
推荐阅读
相关标签
  

闽ICP备14008679号