本文只讨论如何调试被加壳的ELF文件,包括调试中的技巧运用及调试过程中可能遇到的问题的解决方法,不包含如何还原加固的DEX本文将以某加壳程序和某加固为目标。

一、ELF格式简介

ELF全称:Executable and Linkable Format,是Linux下的一种可执行文件格式。

此种文件格式和WINDOWS一样,常见分为两种类型:

1.可执行文件(Executable File),对应PE子类型:EXE

2.共享目标文件(Shared Object File),后缀名:.so,对应PE子类型:DLL

二、ELF文件加载大概流程

1.通过Section Header或者Program Header加载需要的镜像数据

和WINDOWS PE加载机制不同,ELF有些文件数据是不会加载到内存镜像中。

2.加载SO NEED LIB和SYM

类似PE的Import_table

3.执行重定位(如果有)

类似PE的Reloc_table

4.执行INIT_ARRAY段或者INIT段(如果有,数组中的地址不等于0xffffffff,0表示结束)

类似PE的TLS,已知的被加壳的ELF,壳代码都出现在这两个段里。

PE中的TLS也常常出现在壳中,例如Vmprotect, Execryptor等。

5.执行入口点代码(如果有)

所有的上述加载流程代码全部包含在linker.so里,可参看安卓源码或逆向linker.so

三、ARM CPU简介
1.指令集简介

ARMCPU采用RISC(精简指令集)架构(X86是CISC,复杂指令集),指令等长,相对CISC架构更加省电,执行效率更高。

2.ARM指令集三种类型

ARM(4字节等长),THUMB(2字节等长),THUMB2(4字节等长)。这三种指令集可以在同一执行程序中切换,切换原则为:

ARM <–>THUMB,THUMB<–>ARM(PC的最高位确定指令集类型:1为THUMB;0为ARM)

THUMB<–>THUMB2(由27-31位决定)

thumb2其实就是thumb的扩展,其目的是为了一条4字节指令完成多条2字节指令

3.寄存器

通用寄存器:r0-r15

特殊寄存器:r13 = SP(栈地址), r14 = LR(函数返回地址), r15 = PC(当前指令流地址)

还包括CPSR,APSR,浮点等寄存器,具体可参照ARM指令集手册。

四、加壳SO的调试

1.ELF代码执行顺序

上面介绍了,加壳的SO的壳代码都在INIT_ARRAY段和INIT段。

那我们先看下一个被加壳以后的SO,在linux下面用readelf-a命令查看ELF信息:

在ELF-HEADER里我们看到有Entry,地址为0x22a8。

在动态段里看到了INIT_ARRAY数组,数组地址为0×21000,大小是12 BYTES。

用IDA看看数组的内容:

上面说了,-1为无效,0代表结束,那INIT有效地址仅是0×2418这个地址。

也就是说,这个SO加载起来以后,会先从0×2418这个地址开始执行,执行完成后再去执行Entry。

我们再来看下某加固的ELF信息:

在ELF-HEADER里我们看到有Entry,地址为0×3860:

IDA打开某加固的文件时,会提示错误,不能打开,后面在Anti Anti Debugger中会讲到为什么。

在动态段里看到了INIT_ARRAY数组,数组地址为0x28CA4,大小是8 BYTES。

我们还看到了INIT段,地址是0×11401。

我们在这里,总结下执行的顺序:

根据linker的代码,当INIT段和INIT_ARRAY段都存在的情况下,先运行INIT段,再运行INIT_ARRAY段,否则单独运行对应指向的函数,最后执行ENTRY:

2.自己准备SO_LOADER

调试SO和PE_DLL其实道理是一样的,都需要一个宿主进程,这里要写一个SO_LOADER,参看代码如下,可通过NDK编译。(代码是王晨同学早期提供的):

3.环境准备

我这里选用IDA6.6做为调试器。

第一步:拷贝调试器到安卓手机上:

命令:adb push android_server /data/local/tmp/and

这里为什么把android_server 改名成and呢~~~,其实就是为了避免被检测出调试器,后面我在Anti Anti Debugger中会详细说一下关于这部分的内容。

第二步:启动调试器

adb shell回车,进入/data/local/tmp/目录,启动调试器,启动后画面。

第三步:重定向调试端口

adb forward tcp:23946 tcp:23946

至此手机端设置完毕,下面来看看IDA里如何设置。

IDA加载我们自己写的so_loader,在854C处,按F2下断点:

选择菜单栏里面的Debuger-Select Debugger,选择Remote Arm linux/Andoid debugger

点击OK,然后F9运行:

在配置里面,Hostname里面填入127.0.0.1,点击OK。

如果你的手机里面没有这个文件,会提示你COPY,点击确定即可,如果有这个文件,会出现下面的选择,一般选择USE FOUND就可以了,如果你要调试的程序有修改,选择COPY NEW覆盖一个新的进去。

然后一路OK,就出现调试状态了~~,当前PC就是刚才我们F2设置的断点:

4.如何断住SO的INIT_ARRAY段和INIT段

上面说了,SO的加载在linker.so里完成,我们要做的,就是把断点设置在linker.so里面。

先找代码,IDA打开linker.so,在string窗口里找。

call_constructors_recursive,双击并查看引用:

双击第二个引用处,然后往上找blx r3(init段的调用),b.w xxxxxxxx(init_array段的调用):

好了,现在我们找到了地址0x54d0, 0x3af0这两个地方,回到刚才调试的IDA里面。

选择菜单栏debugger-Debugger windows-module list打开进程模块列表:

linker.so的base是40002000,分别对应的两个地址就是:

0×40002000+0x54d0 = 0x400074d0

0×40002000+0x3af0 = 0x40005af0

我们在IDA View-PC窗口GO 过去:

在0x74d0处,按C键,变成代码.奇怪,为什么没有反应!!而且在最下面的output window有如下提示:

这里就是我说的很重要的问题了,上面我提到了,被调试的程序可以在3种指令集之间切换,这时的IDA并不知道当前要变成代码的地址是ARM还是THUMB,这时我们需要对照静态的来看,或者你对指令集绝对的熟悉,看到BYTE CODE就知道是哪种指令集:

静态中,显然IDA给的是2字节指令,那必然是THUMB,我们需要把当前地址改成THUMB。

方法:按键盘的ALT+G,呼唤出窗口:

T,DS不用管,我们只需要把VALUE改成1就是THUMB指令集了,变成1点击OK以后。

在原来的地址上出现了CODE16,这时我们再去C一次:

C完以后,就出现代码了!!!ARM和THUMB就是这么切换的,切记,切记:

再看另外一个地址,0x400a5af0,按照同样的方法再来一次:

问题又来了,奇怪了,为什么下面不是指令?!这个是IDA的BUG,6.6版本对THUMB2指令在调试状态的解析就是有问题。。。。,不过没关系,我们往下看:

这段代码才是最重要的,执行每一个init_array中地址的函数,就在blx r2这句。

至此,如何断住INIT段和INIT_ARRAY段,就讲完了,剩下的大家就自己调试吧!

五、Anti Anti Debugger

1.Anti IDA

其实这种问题,是IDA解析ELF和linker解析ELF不一致造成的,IDA更加严格。

用ida打开某加固的so,提示:

这个提示就是说,有个数据描述是无效的,我们来看看,是哪个。

SHT说的就是Section Table,来看看ELF头部数据如下:

shoff就是这个值,我们用16进制编辑器过去看看:

全是0,显然这里有问题,我们首先要把这个值清0,保存文件。

再次加载,还有问题,提示如下:

这次通过调试IDA的ELF插件,发现当PROGRAM HEADER中的物理偏移大于文件大小时,就会出现该错误。

显然,Program Header中的第一组数据,p_offset超过了文件大小,根据ELF结构,定位到该数据偏移,改成0,IDA加载成功。

2.Anti Debugger

通过调试该加壳程序,总结他用到的方法。

方法1:检测父进程的文件名

调用getppid,获取父进程的id, open("/proc/ppid/cmdline")获取父进程名称,检测常用调试器的名字,这就是上面我COPY文件时,为啥要把android_server变成随意一个文件名的原因了。

对策:修改getppid的返回值,随便给一个可以用的就行了。

其实还有其他方法可以获取ppid,比如open("/proc/pid/status"),read这个handle的内容,在里面寻找ppid也行。

方法2:异常陷阱

和WINDOWS的方法类似,设置一个trap,检测调试器。

对策:IDA默认所有的trap都交给调试器处理,所以我们需要修改对应的设置。菜单选择debugger-debugger options,点击edit exceptions按钮。

在trap上,右键编辑改成如下即可:

当然,检测调试器,还有很多方法,见招拆招就可以,这里就不详述了。

浅谈被加壳ELF(即android的so文件)的调试的更多相关文章

  1. 浅谈JVM-类加载器结构与双亲委派机制

    一.类加载器结构 1.引导类加载器(bootstrap class loader) 它用来加载Java的核心库(JAVA_HOME/jre/lib/rt.jar),是用原声代码来实现的,并不继承自ja ...

  2. 浅谈密码加SALT原理(转载)

    原文出处:http://www.2cto.com/Article/201201/117051.html 我们知道,如果直接对密码进行散列,那么黑客可以对通过获得这个密码散列值,然后通过查散列值字典(例 ...

  3. 浅谈密码加SALT原理

    我们知道,如果直接对密码进行散列,那么黑客可以对通过获得这个密码散列值,然后通过查散列值字典(例如MD5密码破解网站),得到某用户的密码.  加Salt可以一定程度上解决这一问题.所谓加Salt方法, ...

  4. Spring5.0源码学习系列之浅谈懒加载机制原理

    前言介绍 附录:Spring源码学习专栏 在上一章的学习中,我们对Bean的创建有了一个粗略的了解,接着本文挑一个比较重要的知识点Bean的懒加载进行学习 1.什么是懒加载? 懒加载(Lazy-ini ...

  5. android apk 防止反编译技术第一篇-加壳技术

    做android framework方面的工作将近三年的时间了,现在公司让做一下android apk安全方面的研究,于是最近就在网上找大量的资料来学习.现在将最近学习成果做一下整理总结.学习的这些成 ...

  6. Android中的Apk的加固(加壳)原理解析和实现

    一.前言 今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理.现阶段.我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk, ...

  7. Android中的Apk的加固(加壳)原理解析和实现(转)

    一.前言 今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理.现阶段.我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk, ...

  8. 【转】Android中的Apk的加固(加壳)原理解析和实现

    一.前言 今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理.现阶段.我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk, ...

  9. android黑科技系列——Apk的加固(加壳)原理解析和实现

    一.前言 今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理.现阶段.我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk, ...

随机推荐

  1. Head插件——学习Elasticsearch的锋刃利器!

    在学习Elasticsearch的过程中,必不可少需要通过一些工具查看es的运行状态以及数据.如果都是通过rest请求,未免太过麻烦,而且也不够人性化. 此时,head可以完美的帮助你快速学习和使用e ...

  2. 基于HT for Web矢量实现2D叶轮旋转

    之前在拓扑上的应用都是些静态的图元,今天我们将在拓扑上设计一个会动的图元——叶轮旋转. 我们先来看下这个叶轮模型长什么样 从模型上看,这个叶轮模型有三个叶片,每一个叶片都是不规则图形,显然无法用上我们 ...

  3. ES6笔记(7)-- Promise异步编程

    系列文章 -- ES6笔记系列 很久很久以前,在做Node.js聊天室,使用MongoDB数据服务的时候就遇到了多重回调嵌套导致代码混乱的问题. JS异步编程有利有弊,Promise的出现,改善了这一 ...

  4. EasyUI的datagrid分页

    EasyUI的datagrid分页 前台代码: <script type="text/javascript"> $(function () { //查询 search( ...

  5. windbg学习进阶之——windbg环境变量配置

    接触性能调优以来一直想学下windbg分析dump,每次看老师几个命令就能找到很底层的问题原因那简直就是羡慕加崇拜啊~但是这接近一年了,愣是没啥进展呢,主要就是在今天整理的这部分卡住了...这理由找的 ...

  6. Delphi Mac App 名称支持国际化多语显示

    作用:在 OSX 图标下方显示 App 中文繁体或简体的名称(系统自动选取) 适用:XE7, XE8 for OSX 操作: 创建一个新工程. 在工程目录下创建二个文件夹(zh_??.lproj)文件 ...

  7. 点我吧工作总结(技术篇) Velocity

    1. 什么是velocity Velocity[vəˈlɑ:səti],名称字面翻译为:速度.速率.迅速.该项目的开源地址:http://velocity.apache.org/,它是一个基于Java ...

  8. Windows Git中文文件名乱码

    在Windows下使用git,安装包如下: https://git-for-windows.github.io/ 在使用git bash时git 默认中文文件名是 xx% 是因为 对0x80以上的字符 ...

  9. opencart 添加新模型

    1,修改模板页,复制category_list.tpl,category_form.tpl,修改成新的名称. category_list.tpl是列出页面,category_form.tpl是添加和修 ...

  10. MAC使用CocoaPods

    前言,還是那句話,按照濤叔下面畫黃色的步驟順序執行就好了 使用CocoaPods兩種方式:使用之前安裝的插件&命令行. 一.利用插件 1.創建項目后添加CocoaPods 2.在文本框中輸入如 ...