参考: 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. windows下用vscode写C++

    [本文参考:https://www.cnblogs.com/zhuzhenwei918/p/9057289.html  和 https://www.zhihu.com/question/3031589 ...

  2. binary-tree-zigzag-level-order-traversal——二叉树分层输出

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...

  3. Archlinux 下的 VMWare Workstation 维护笔记

    印象中 Archlinux 下的 VMWare Workstation 总是出问题, 因此写这个帖子, 记录出问题时间/原因/解决方案. PS: 每次更新内核后可能需要重新编译 vmware 的内核模 ...

  4. struts2获取ServletContext对象

      CreateTime--2017年9月7日09:24:40 Author:Marydon struts2获取ServletContext对象 需要导入: import javax.servlet. ...

  5. socket连接和TCP连接的关系

    我们在数据传输时,能够仅仅使用(传输层)TCP/IP协议,可是那样的话,假设没有应用层.便无法识别数据内容,假设想要使传输的数据有意义.则必须使用到应用层协议,应用层协议有非常多,比方HTTP.FTP ...

  6. (一)关于jQuery的网上资源

    jQuery官网: http://jquery.com/ jQuery API: http://jquery.cuishifeng.cn/ w3school学习网站:http://www.w3scho ...

  7. robotframework使用之 下拉框的选择

    选择下拉框有几种方式处理,首先在浏览器F12选择下拉框 1. F12后看见下拉框的源码是<option xxx> <select class="w_60" dat ...

  8. 转:DDR中端接技术基本概念

    DDR中端接技术基本概念  版权声明:转载请注明出处:http://blog.csdn.net/lg2lh https://blog.csdn.net/lg2lh/article/details/90 ...

  9. linux下安装redis报错问题。

    1.使用tar -xzvf redis-2.4.5.tar.gz来解压安装包 2.使用make命令来编译Redis 如果出现错误需要查看是否缺少gcc gcc-c++ zmalloc.h:50:31: ...

  10. Web网页开发常见经典问题

    1.网络请求参数共享 转发dispatcher和重定向redirect 对于参数共享的区别 Redirect和Dispatcher 区别