安卓某加固脱壳
首先反编译apk
看看AndroidManifest.xml情况!
重点看包名
package="com.faloo.BookReader4Android"
还有application下的android:name
android:name="com.tencent.StubShell.TxAppEntry"
看看对应的smali!
smali不熟悉的话,可以反编译dex再转jar 直接用java gui看java代码.
private void a(String paramString)
{
// Byte code:
// 0: aload_0
// 1: invokevirtual 59 com/tencent/StubShell/TxAppEntry:getApplicationInfo ()Landroid/content/pm/ApplicationInfo;
// 4: astore_2
// 5: aload_2
// 6: getfield 64 android/content/pm/ApplicationInfo:dataDir Ljava/lang/String;
// 9: astore_3
// 10: new 66 java/lang/StringBuilder
// 13: dup
// 14: invokespecial 67 java/lang/StringBuilder:<init> ()V
// 17: aload_3
.....
}
有很多 // 开头的 这个是smali 加了 -d 调试选项时 才会出现的. 换jeb看看.
查看smali代码主要是为了找他调用的哪个so来解密dex , 这里代码有点多,没必要花时间去细品代码. 一般so文件都是放在 assets 或者 lib目录下. 先看看 assets 目录
没看到有so文件 可以再看看 lib 目录下
有很多 so 文件! 不出意外的话解密的 so 应该就在其中.
这么多so文件一个个分析也不现实, 为了省事 可以直接上ida查看他加载了哪个so也是一样的.
首先启动ida server 为了防止被检测到 最好将 android_server 改一个名字.
默认的端口也修改一下 命令如下 (有的情况 adb shell su 连着打不能生效,需要进入 adb shell 再 su提权后再执行)
adb shell su ./data/local/tmp/ida7032 -p5555
执行成功提示:
IDA Android 32-bit remote debug server(ST) v1.22. Hex-Rays (c) 2004-2017
Listening on 0.0.0.0:5555...
手机端的服务运行起来 并开了一个 5555 端口, 接着需要将手机端口映射到PC上来
adb forward tcp:6666 tcp:5555
其中5555 是手机里 android_server的端口(需和执行命令时的端口一样)
6666是映射到PC上的端口(理论上是可以1-65535任意端口,前提是没被占用)
注意: 端口转发命令只需运行一次即可. 即使android_server关闭 重开了.也不需要重复运行.可以打如下命令查看是否映射过.
PS > adb forward --list
84B5T15B03002203 tcp:6666 tcp:5555
如果映射过就无需再重复映射.
接着以调试模式启动apk 命令格式是 am start -D -n 包名/入口 具体包名可以通过 AndroidManifest.xml 文件查看. 或者通过如下命令查看.
PS > adb shell dumpsys activity top
TASK com.faloo.BookReader4Android id=120
ACTIVITY com.faloo.BookReader4Android/com.faloo.app.activity.LogoPageActivity 8fc46c9 pid=9911
Failure while dumping the activity: java.io.IOException: Timeout
其中 com.faloo.BookReader4Android/com.faloo.app.activity.LogoPageActivity 是包名+入口
命令连起来则是如下:
PS E:\Android\虚拟机临时使用\临时> adb shell
angler:/ $ su
angler:/ # am start -D -n com.faloo.BookReader4Android/com.faloo.app.activity.BookActivity
Starting: Intent { cmp=com.faloo.BookReader4Android/com.faloo.app.activity.BookActivity }
angler:/ #
执行此命令后 手机上会提示 Walting For Debugger 字样. 因为我们是以调试方式启动 所以 apk 在运行后 PC会在第一条指令处等待 恢复运行.
上IDA
端口输入我们映射后的端口 6666
因为我们要看他加载哪个so来解密so和dex文件. 所以要勾选加载LIB时中断.
如果是多个so解密dex. 这样我们还能观察几个解密so的加载顺序.
点OK后 选择相应的包名.
挂载上去后, 不出意外的话,就能看到如下的画面
直接F9运行.
运行后 手机里面还是 等待状态 这时 需要使用 JDB唤醒进程.
JDB命令如下
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8888
java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at com.sun.tools.jdi.SocketTransportService.attach(SocketTransportService.java:222)
at com.sun.tools.jdi.GenericAttachingConnector.attach(GenericAttachingConnector.java:116)
at com.sun.tools.jdi.SocketAttachingConnector.attach(SocketAttachingConnector.java:90)
at com.sun.tools.example.debug.tty.VMConnection.attachTarget(VMConnection.java:519)
at com.sun.tools.example.debug.tty.VMConnection.open(VMConnection.java:328)
at com.sun.tools.example.debug.tty.Env.init(Env.java:63)
at com.sun.tools.example.debug.tty.TTY.main(TTY.java:1082)
致命错误:
无法附加到目标 VM。
执行后报了一堆错误. 这是因为目标APK没有开启调试选项.
APK拆包后 在 AndroidManiFest.xml 文件中的
application 标签里添加一句 android:debuggable="true"
添加后 再重打包即可. 添加 debuggable 操作是必须的. 否则是无法唤醒进程的.
但是因为一些壳会检测自身是否被修改. 重打包的话, 可能会崩溃.
解决办法就是直接修改系统配置文件
这里直接用 mprop 文件修改 修改之后 所有的APK都不需要手动添加 debuggable 选项 默认就是开启的.
打如下命令查看是否开启调试:
adb shell getprop ro.debuggable
1
返回1 表示开启了 返回0 表示未开启
开启后, 再执行 jdb 命令 发现还是同样的错误提示.
这是因为jdb 的 -connect 也是需要端口操作的. 所以还是需要映射端口.
Forward 本身是可以通过端口映射端口 也可以通过进程映射端口
命令:
adb forward tcp:8888 jdwp:10152
将之前的 tcp 换成了 jdwp 表示通过进程映射. 所以后面的 10152 是我们前面查看的 pid
但这操作有点麻烦, 每次启动都需要执行此命令.
另一种方法可以用 Android Studio 自带的 DDMS 来映射端口.
Android Studio 3.x版本之后 没有将 DDMS 集成到菜单栏中了 需要用Eventthing 搜索 monitor.bat 来启动. 使用DDMS的好处是每次重启APK不需要再有其他操作. 端口一般默认都是 8700 或者 8600 (貌似不能修改默认端口, 容易被检测)
这个时候在执行 jdb 命令就提示成功了.
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8888
设置未捕获的java.lang.Throwable
设置延迟的未捕获的java.lang.Throwable
正在初始化jdb...
看到这个提示表示成功了.
这个时候IDA界面也唤醒了.
当子进程状态发生改变的时候, IDA会抛一个错误码为 11 的提示. 调试期间可能会反复出现类似的提示, 可以通过异常选项里面,忽略掉它.
第一次运行. 不下断点. 因为前面我们已经勾选 lib 加载中断了. 第一次主要看他加载了哪些so. 直接F9 跑起.
模块窗口中看到有两个so 再运行程序就飞了.
因为我们要从SO的入口处开始分析. 所以下的断点一定要精准.否则我们中断后,入口函数可能已经被执行过了.
SO中有一个类似 PE TLS的东西 可以在 main 和构造函数之前执行 就是 init_array
还有一个关键的函数是 JNI_OnLoad
但这两个函数经常被一些壳 给混淆乱序了. 静态是无法分析的.
静态方法定位init_array
方法1:
通过 readelf -d 命令 readelf 是 linux下的程序.
libshella-2.9.0.2.so 文件 INIT_ARRAY 偏移是 0x3e84
libBugly.so 的偏移是 0x176c8
方法2:
直接将目标SO拖入IDA 待IDA加载完后, 直接按CTRL + S
libshella-2.9.0.2.so 文件 INIT_ARRAY 看不到.
libBugly.so 的偏移是 0x176c8
从图中可以看出 IDA 的识别能力明显不如 readelf
但readelf 也不是万能的,很多混淆乱序壳 也是查不出的. 有的查出来 可能也是错误的.
通过IDA可以看到 libBugly.so 没有做处理 而 libshella-2.9.0.2.so 故意隐藏了 init_array 有点此地无银三百两的感觉.
我们重点分析 libshella-2.9.0.2.so 文件. 他的偏移是 0x3e84
IDA运行 待 libshella-2.9.0.2.so 加载后 我们在 image+0x3e84 处下断.
EB686000+0x3e84=0xEB689E84
来到此处
第1个调用的是 libBugly.so 执行的函数:
--------------------------------------------
这个是很早的时候帮朋友写的,整理硬盘的时候发现的,一起发出来.
文章好像没有写完.视频是完整的.
这个是视频地址:
安卓逆向交流企鹅群:八二零464七零五
附件中包含6个文件:
样本APK.
样本脱壳后APK.
样本APK解压后文件.
样本APK解压后dex.
本文文章DOC格式.
本文文章PDF格式.