参考: http://www.itdadao.com/articles/c15a190757p0.html

一. 为什么要调试init_array

init_array的用途

1. 一些全局变量的初始化 (我这里试过, 一些全局变量的初始化,会统一用一个init_array表项来完成初始化)

2. 通过__attribute__ ((constructor)) 声明的函数 (可以定义n个)

通过so加载流程来看,init_array是我们程序代码可以控制的最早的时机了, 其次才加载Jni_onload

所以有些样本会在init_array做一些反调试和相关环境检测的活, 所以我们需要在init_array中和对方兵戎相见

当然网上已有很多教我们如何在init_array下断的函数, 但是却都只教了方法, 没有细说原理, 最后我们可能只学会了几个快捷键, 空有招式却无内功, 知其然却不知其所以然, 下面我们就姿势和知识这2方面来进行讨论

二. 断init_array的姿势

1. 定位调试进程中linker的dlopen函数地址

把调试机器中的linker拷贝出来, 路径为/system/bin/linker, 然后开一个IDA分析

在Shift+F12在字符串窗口中查找"dlopen", 跟踪引用到一个函数, 如下图

得到其文件偏移为0xF30

附加上调试器后, 我们得到linker加载到内存的起始地址为400BD000

所以我们在代码窗口Go过去看看400BD000 + F30 = 400BDF30

发现全部是DCB形式的代码(代码没有解析出来), 这个时候我们需要对linker进行分析, 操作如下: 右键->Analyze Module

go过去我们发现和静态分析中的一样,  在函数头部下一个断点


2. 定位到calling相关代码

同样在拷贝出来的ida搜索字符串calling

同样定位到代码,得到文件偏移 2720

那么我们内存中的地址就是 400BD000 + 2720 = 400BF720

同样在调试的ida中下好断点, 第2个断点就是调用.init_array数组的代码

然后按F9,注意观察寄存器窗口, 当有显示调试的是你想要断的so的时候开始注意

当断点断在BLX R4的时候,下一步就是调用init_array数组了, 所以F7跟进去

在直接把我们想要分析的so拖到ida分析进行验证, 代码一样, 说明我们成功的断点在了init_array数组

二. 断init_array的知识

通过上面的操作我们学会了招式, 内功心法却不见修习, 下面我们通过Android的系统源码来一探究竟

环境介绍

源码环境: Android 6.0.1

没有下载源码的同学可以去androidxref在线看源码也很方面

http://androidxref.com/

1. 回到源头看问题

我们都知道我们要在apk中要加载一个so我们可以通过

System.loadLibrary("libname");

System.load("lib_path");

这2者区别如下:

(1). System.load参数必须为库文件的绝对路径,可以是任意路径;

(2). System.loadLibrary参数为库文件名,不包含库文件的扩展名,必须是在JVM属性Java.library.path所指向的路径中,路径可以通过System.getProperty('java.library.path')

2. java层到native层的过程

我们把android_source\libcore\luni部分的源码作为单独的部分丢进Source Insight进行分析

定位到android_source\libcore\luni\src\main\java\java\lang\System.java, 搜索loadLibrary, 就可以开始分析了

java层代码主要是一些路径, 和标记值的初始化

最后比较关键的函数是JavaVMExt.LoadNativeLibrary, 该函数主要完成如下事情

1. 调用linker的dlopen完成加载

2. 调用dlsym获取目标so的JniOnload地址并调用

3. 初始化SharedLibrary对象并添加到表中, 下次加载相同的so则不在重复加载

linker之前的函数调用流程图如下:

3. linker的dlopen简易分析

android系统通过调用linker的dlopen来完成so的转载

把aosp\bionic目录添加到source insight中进行分析

配合AndroidXref站点我们找到, dlopen定义在dlfcn.cpp中

dlopen函数定义如下, 只是简单的调用了dlopen_ext

跟进dlopen_ext函数, 该函数返回一个soinfo的结构体指针
而且这个指针最后作为函数返回值返回了

do_dlopen简单的判断了一下参数, 然后调用find_library进行转载链接so文件

加载成功后,返回soinfo对象指针,同时调用soinfo的成员函数call_constructors来调用so中的init_array

call_constructors先完成其他模块的加载,然后调用call_array()来调用init_array数组的调用

call_array循环调用call_funtion来进行加载

最后call_function只是简单的调用传进来的函数指针, 可以看到我们上面的下断点的字符串就来自于下面 
 

由于篇幅问题,大致介绍下linker的调用流程, 函数调用流程如下:

1. 在do_dlopen中通过find_library进行加载so

在加载完so后通过call_constructors完成init_array的加载

2. find_library最后调用load_libray完成so的转载

3. 最后通过load_library的elf_reader.load完成so的装载

四.总结

由于android是开源的操作系统, android中的很多问题我们都可以通过分析源码来了解细节, 解决问题, 并知其所以然

同时我们还可以通过编译源码来定制我们想要的功能, 达到我们想要的目的

IDA调试android so的.init_array数组的更多相关文章

  1. IDA调试android so文件.init_array和JNI_OnLoad

    我们知道so文件在被加载的时候会首先执行.init_array中的函数,然后再执行JNI_OnLoad()函数.JNI_Onload()函数因为有符号表所以非常容易找到,但是.init_array里的 ...

  2. ida 调试 android fork

    在使用ida 调试android native代码时经常会碰见fork子进程的情况出现,而运行一个 android_server只能对一个进程进行调试或者attach,而ida 默认端口是23946, ...

  3. IDA 调试 Android 方法及简单的脱壳实现

    IDA 调试 Android 方法及简单的脱壳实现 标签: android原创逆向调试dalvik 2016-05-24 14:24 9286人阅读 评论(3) 收藏 举报 分类: 原创(25) An ...

  4. IDA 调试 Android

    最近都在学一些反编译安卓相关的东西,其实网上有很多教程关于用 IDA 调试 Android 的过程,主要记录一下我遇到的坑 首先 Android手机要是root过的 还要注意的一点是apk中的 And ...

  5. 【转】IDA 调试 Android

    最近都在学一些反编译安卓相关的东西,其实网上有很多教程关于用 IDA 调试 Android 的过程,主要记录一下我遇到的坑 首先 Android手机要是root过的 还要注意的一点是apk中的 And ...

  6. ida调试 android so

    C:\Documents and Settings\Administrator>adb shellshell@htc_v2_dtg:/ $ susushell@htc_v2_dtg:/ # cd ...

  7. ida 调试android之路

    系统: Mac OSX 调试环境:IDA7.0,  adb 手机环境:红米手机 android 4.4.4 前提条件: 红米手机root之路:https://www.cnblogs.com/dzqdz ...

  8. IDA动态调试Android的DEX文件

    Android程序的dex文件的动态调试确实是个大问题,网上也有一些教程但是不是特别的详细,今天用到了IDA动态调试Android的DEX文件,特此记录一下. IDA 6.6新添加了对dex文件的调试 ...

  9. Android动态方式破解apk进阶篇(IDA调试so源码)

    一.前言 今天我们继续来看破解apk的相关知识,在前一篇:Eclipse动态调试smali源码破解apk 我们今天主要来看如何使用IDA来调试Android中的native源码,因为现在一些app,为 ...

随机推荐

  1. OpenCV头文件包含问题

    opencv从2.2版本以后<opencv root>include下有两个文件夹 opencv 和opencv2.从官方的意思来看,它逐渐喜欢用opencv2里面的那种包含头文件的方式. ...

  2. 时间迭代和BigDecimal操作

    常规小操作的代码: import java.math.BigDecimal; import java.sql.Timestamp; import java.text.SimpleDateFormat; ...

  3. MAT使用及OOM分析

    知识及工具推荐 1.Android资源监控工具 2.Android内存管理机制 http://blog.csdn.net/hexieshangwang/article/details/47188987

  4. Shiro学习(7)与Web整合

    Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截须要安全控制的URL.然后进行对应的控制,ShiroFilter相似于如Strut2/SpringMVC这样的web框架的 ...

  5. nginx+keepalived实现双机热备高可用性

    搭建准备: 机器两台 ip分别为192.168.100.128 192.168.100.129(能够用虚拟机測试.虚拟机网络模式为NET模式.且为静态ip) 另外须要准备一个虚拟ip对外提供服务.即通 ...

  6. JQuery EasyUI DataGrid动态合并单元格

    /**        * EasyUI DataGrid根据字段动态合并单元格        * @param fldList 要合并table的id        * @param fldList ...

  7. SpringMVC hibernate增加多数据源 (SSHE/SYPRO增加多数据源为例)

    SpringMVC hibernate增加多数据源 (以类SSHE/SYPRO增加多数据源为例作说明) 注:适用与SpringMVC + Hibernate的项目.其它框架的仅仅能说作參考用 配置Sp ...

  8. Redis闲谈(1):构建知识图谱

    场景:Redis面试 (图片来源于网络) 面试官: 我看到你的简历上说你熟练使用Redis,那么你讲一下Redis是干嘛用的? 小明: (心中窃喜,Redis不就是缓存吗?)Redis主要用作缓存,通 ...

  9. 链接脚本使用一例2---将二进制文件 如图片、MP3音乐、词典一类的东西作为目标文件中的一个段

    参考文章: <程序员的自我修养——链接.转载与库> P68 这里介绍两种方法,实现将将一张图片作为二进制可执行程序的一个段,其中第一种方法在我之前的博客中已经有所介绍,不过,那是采用的是交 ...

  10. 利用expload 分割字符串 变成数组

    #admin_abc去掉下划线 =>>变成 array('admin','abc') $table_Name=explode('_', $table_Name);