【逆向安全】- so动态调试之寻找某应用签名密钥

背景

公司某同事,想通过python脚本自动调用某应用接口,以达到自己的目的(你懂得)。但是通过抓包发现,几乎所有接口里面都两个公共字段"timestamp"和"sign"。timestamp是时间戳很好得到,但是"sign"却不停在变化,猜测后端会根据"sign"字段值,对数据做校验。于是开启了对该App逆向路程。

内容

  • 逆向工具
  • 原生层逆向
  • so逆向
  • so动态调试

逆向工具

  • apktools

    1. apktool d [apk]
      将apk反编译smali文件形式,通过这种方式,得到的资源文件不会出现乱码的,并且可以重新编译成apk,签名安装。
    2. apktool b [smali目录]
      重新生成apk文件,记得要重新签名,不然安装不了。
  • dex2jar
    将apk解压得到的dex文件反编译成jar文件,方便查看

    1. ./dex2jar/d2j-dex2jar.sh [dex文件]
      生成jar文件
  • jd-gui
    查看jar文件,配合搜索可以方便快速定位代码位置

  • jadx
    除了可以像jd-gui查看jar文件,还可以对混淆字段重新取名字,更加方便查看,更多功能请自行查看。

  • ida
    查看so文件,so动态调试等功能

原生层逆向

  • dex生成jar文件
    更具前面介绍,接口请求参数里面都会添加"sign"字段,那么我们可以全局搜索"sign",查看跳转路径,找到"sign"字段值生成的地方,最终发现native层把接口传递参数转成json字符串后,调用JNI层方法返回一个字符串,这个字符串就是"sign"的值。这下无可奈何了。

  • apk生成smali文件
    为了确定"sign"值就是调用JNI方法生成的,于是我找到了登录页面,找到登录按钮,通过这里查看调用逻辑。

    1. 如何快速定位到“登录按钮”点击事件处理的地方
      由于点击事件监听处,都是10进字的常量值,所有并不知道那个是“登录按钮”,而且该apk的资源文件混淆,无法直接找到登录页面的布局文件。

      这时,可以借助Android Studio查看apk功能,找到resources.arsc,把10进字转换成16进字,然后在resources.arsc中找到对应的文件,属性名。


      截屏2020-12-17 下午3.42.54.png

so逆向

用ida打开so文件,入下图:


截屏2020-12-17 下午3.47.26.png

该apk调用的是getApiSign这个jni方法,返回的"sign"值。

  • arm转c
    F5快捷键可以将arm指令转化成可读的C语言


    截屏2020-12-17 下午4.35.08.png

转成C语音后,就是这样,如果能够看懂,当然可以直接找出计算"sign"值算法,如果看不懂,那么可以使用so动态调试,查看相应的变量值。

注意:这里要用32的ida,64位不支持转换且动态调试会报错。

so动态调试

so动态调试,需要root手机一台。

  • 复制android_server(IDA目录>dbgsrv>android_server)到设备中

    1. adb push android_server /sdcard
    2. adb shell
    3. mount -o rw,remount /system (出于安全考虑,操作完之后,把文件改回只读属性:mount -o ro,remount /system)
    4. mv /sdcard/android_server /system/bin
    5. chmod 777  /system/bin/android_server
    
  • 启动android_server

    1. su do 切换到root权限(如果不是root权限,后面ida调试找不到应用进程)
    2. ./android_server (root权限下启动服务 )
    3. 新启命令行执行:adb forward tcp:23946 tcp:23946建立端口转发。
    • adb forward --list
      查看端口映射列表
    • adb forward --remove tcp:23946
      移除建立的端口转发
  • 在手机上运行该apk
    由于其它原因,我把计算"sign"字段的so库导入我自己新建的android工程,然后写了一个简单的点击事件去调用该jni方法。


    截屏2020-12-17 下午5.01.21.png
  • ida动态调试so
    打开32位ida,点击"go"打开一个空白页,选择要调试的进程。


    截屏2020-12-17 下午5.03.36.png
截屏2020-12-17 下午5.03.49.png
截屏2020-12-17 下午5.04.18.png
  1. 使用Ctrl+S找到需要调试so的基地址:EF606000


    截屏2020-12-17 下午5.07.25.png
  2. 然后通过另外一个IDA打开so文件(可以用64位的打开so),查看函数的相对地址:1794

    截屏2020-12-17 下午5.10.50.png

那么得到了函数的绝对地址就是:EF607794,使用G键快速跳转到这个绝对地址:

截屏2020-12-17 下午5.15.11.png

点击左边蓝点,下断点,点击运行,然后在应用点击,调用getApiSign JNI方法。


截屏2020-12-17 下午5.20.30.png

触发getApiSign JNI方法调用后名,程序执行到图中红框地方,按F8进行单步调试,F9运行,通过R0寄存器找到算法使用的密钥。

拿得密钥后,就可以用其它语言实现。整个破解过程就到这里。

  • 其它配置
    这里是so在调试之前就已经加载,如果要停留在so加载的地方,那么可以打开Debugger setup,配置如下:


    截屏2020-12-17 下午5.26.32.png
  • 使用am命令
    adb am start -D -n com.example.testarm/com.example.testarm.MainActivity
    启动应用,让进程处于等待调试中,然后用ida attach进程,进行调试,适用在apk启动时就加载so并且需要断点so加载过程。

  • 这里为什么会断在libc.so中呢
    android系统中libc是c层中最基本的函数库,libc中封装了io、文件、socket等基本系统调用。所有上层的调用都需要经过libc封装层。所以libc.so是最基本的,所以会断在这里,而且我们还需要知道一些常用的系统so,比如linker

    我们知道,这个linker是用于加载so文件的模块,所以后面我们在分析如何在.init_array处下断点

    还有一个就是libdvm.so文件,他包含了DVM中所有的底层加载dex的一些方法,我们在后面动态调试需要dump出加密之后的dex文件,就需要调试这个so文件了。

你可能感兴趣的:(【逆向安全】- so动态调试之寻找某应用签名密钥)