前言
在学习计算机之前,想象中的工程师什么样子呢?大概就是电影里黑客的样子吧。然而真正入行之后才发现,乾坤未定,你我皆是牛马罢了。。
虚假的工程师
动不动就攻破什么网站啊,破解什么APP啊,破解什么密码啊之类的,似乎在他们面前,互联网了无秘密。
真实的工程师
ctrl+C,ctrl+ V,sql boy,工具使用者,代码搬运工。。
但是那又如何呢,写需求是为了求生,学技术是为了理想。蝼蚁尚且偷生,青蛙坐井仍渴望蓝天。走进逆向,尝试破解程序,掌握底层技术,也许能满足心中对技术的一丝向往吧。
逆向前置知识
我们都知道,上线的程序都是经过编译的,逆向的话,就需要把这些编译的程序进行反编译,所以反编译工具,二进制文件处理,汇编指令等都是要掌握的。
网络抓包
第一步当然是要先抓包。我们逆向都会有一个出发点,比如出发点是想拿某个功能的返回或者想了解某个功能是怎么实现的,那么网络抓包就是第一步。
抓包工具推荐:mitmproxy
安装使用参考:11.2-mitmproxy的使用 - Python3网络爬虫开发实战
linux基础知识
博主是在linux环境下,因此常用的linux命令是需要掌握的,特别是文件操作部分。
例如以下命令:
bash
ls resources/lib/armeabi-v7a/*.so | xargs nm -A 2>&1 | grep -v "no symbols" | c++filt | grep getZipSecret
- ls列出目录下的所有.so文件
- 以ls的结果作为输入,nm 命令用来列出目标文件中的符号。-A 选项使得 nm 在显示符号信息时,会同时显示其来源的文件名。
- nm 命令在处理某些文件时,如果没有找到任何符号,就会输出 "no symbols"。grep -v是过滤作用
- C++ 符号在编译后的名称可能非常难以阅读和理解,c++filt 主要用于 "demangling" C++ 符号。例如,ZNK3MapI10StringName3RefI14ResourceFormatLoaderENS_8HashTypeIS0_E10DEFAULT_ES5_E3hasERKS0 实际上是一个被装饰(也称为 "mangled")的 C++ 符号,它在 demangled 后,对应的函数签名可能类似于 Map<StringName, Ref >::has(StringName const&) const。
- 实际的grep搜索
Android反编译工具
我们拿到APK包之后,要做的事情就是反编译了,拿到反编译后有限的源码。反编译之后的产物可以看下面的Android前置知识。
常用反编译工具:jadx
学习参考: github.com/skylot/jadx
www.cnblogs.com/aniugg/arti...
编程语言要求
读源代码的能力
例如Android是java写的,那么反编译之后拿到源码,就需要有基础的读代码能力,这块不需要太深入,一般有编程基础的话,就能大概看懂。
写脚本的能力
在实际的逆向过程中,源代码大概率是不能直接跑的,我们有时候需要自己写python脚本来模拟一些操作。因此掌握基本的python能力,能有利于我们去实现逆向的目标。
二进制文件分析
Android程序中部分代码是在native层写的,这部分代码反编译之后会是.so库的形式。需要我们去分析.so库,也就是分析二进制文件。现在常用的二进制分析工具比较多样,推荐以下几篇博客,可以学习下。
binutils: 二进制文件分析工具。 参考:软件开发|GNU binutils 里的九种武器
分析二进制文件的10种工具:参考:技术|在 Linux 上分析二进制文件的 10 种方法
更专业的二进制文件分析工具radare2: GitHub - radareorg/radare2: UNIX-like reverse engineering framework and command-line toolset
博主这里使用的就是radare2工具,因此下面介绍下常用命令及含义:
- aaaa:r2会尝试分析这个二进制文件,包括:分析函数,变量,引用,指针等。
- aaaa的输出是代表r2执行的顺序
- i : 查看分析的.so文件的详细信息
- s function: 跳转到指定的函数位址
- s 地址: 也可以跳转到指定的地址去
- pdf:查看反汇编代码,比如跳转到函数的开头之后,通过pdf查看函数的反汇编代码。
- 反汇编代码是从机器码(汇编代码)转化回人类可读的中间级别代码,和你最初写的源代码有一定的差距,但比直接阅读汇编代码要友好得多。
汇编相关知识
通过二进制分析工具,我们反汇编之后就能看到实际的汇编语言指令。不需要对汇编特别熟,不过需要能看懂基本的汇编指令含义,例如读取变量,变量存储,函数调用等。
例如:
以上知识涉及不少工具和知识面,说实话,这还只是Android的初步逆向,可想而之,深入下去需要学习的点更多,简直是,太棒了!
Android逆向前置知识
认识Android
想要逆向Android APP,不了解Android必然是寸步难行,我们不需要了解太多,起码的目录结构,代码层次构成就足够了。
native层介绍
Android Native层是指Android操作系统的底层,包括Linux内核和各种C/C++库,例如SurfaceFlinger、libc、libm等。这些库提供了Android框架层(包括Java应用层)所需的基础服务,例如资源管理、网络通信、图形渲染等。
在Android开发过程中,Native层通常与Java层进行交互,使用Java Native Interface(JNI)机制在Java层和Native层之间传递数据和调用方法。通常情况下,Native层被用来处理一些计算密集型或者需要高性能的任务,以提升应用的性能。
java中加载native层的文件: System.loadLibrary( "xxx");
怎么知道是nativa层的函数
- 函数签名上有native
- 在so文件的导出函数里面一般以java_开头
native层函数怎么来的
当你创建一个使用 NDK(Native Development Kit)的应用时,你的本地 C++ 或 C 代码将被编译成 .so 文件。
你可以编写自己的 C/C++ 代码,然后通过 Android 的 NDK 来编译这些代码,生成对应的 .so 文件。在 Jni 目录下创建 C/C++ 源文件,并且在项目的 CMakeLists.txt 文件中指明这些源文件,NDK 就会在构建时将这些文件编译成 .so 文件。
armeabi-v7a/libnative-lib.so文件
当你编写了一些通过 JNI(Java Native Interface)使用的 native 代码,并通过 NDK 去编译时,NDK 会为支持的每一种 CPU 架构生成对应的 .so 文件,并且放在对应的目录下。在这个过程中,NDK 会根据你的 Application.mk 或 build.gradle 文件中定义的 APP_ABI 值来确定需要支持哪些架构,并为每一个架构生成对应的目录。armeabi-v7a 就是其中一种常见的 ARM 架构的目录。
Android加壳和解壳
参考:APP加壳原理及常用脱壳方法介绍_app脱壳-CSDN博客
很多APP为了安全,可能会选择对APP进行加壳活着代码混淆处理。建议先大概了解下什么是加壳,解壳。
判断是否加壳
- 使用加固检测软件检测,如:ApkScan-PKID
- 使用代码查看工具查看apk的目录结构,如:jadx
反编译出来,然后看能不能看到源代码就就知道有没有加壳了,最直接的办法是查看清单文件里的主Activity的名字,然后到反编译目录里看有没有这个Activity,没有的话就表明加壳了,通常加了壳的Apk都只有一个外壳Application,然后在里面加载了一个so,解密代码都放在里面,很容易判断的。
判断是否代码混淆
混淆过的代码类名和变量名都是abcdefg这种毫无意义东西,让你搞不懂它究竟是干嘛用的。
解壳方式
这里列举三个常用的脱壳软件:
一、反射大师 (需要搭建xposed环境)
二、DumpDex (需要搭建xposed环境且在真机下运行)
三、FRIDA-DEXDump(需要搭建frida环境)
博主逆向的APP不涉及加壳解壳,所以这块没有深入进去,有兴趣的同学可以多搜搜相关知识。
jadx反编译的产物
sources目录
这个文件夹存储的是反编译生成的java源码文件。这些文件以.java文件的形式存储,包括应用程序的所有类和接口。在这里找到一些类库和框架的使用,例如RxJava,OKHttp,Retrofit等。
- android 目录下通常是Android系统自带或系统级别的类库和API,比如一些基础的视图库,网络库等。
- butterknife, bolts, okhttp3, retrofit2, rx等这些名字看起来像是一些流行的第三方库。
- cn, com, de, io, jp, me, net, org, pl, uk 这些都是常见的顶级域名,通常应用程序的包名会以它们开始,通常这些目录下存放的是各自的业务代码或者相关第三方库的代码。
业务源码一般是在com下,但是com目录有可能会有非常多的目录结构。那么如何找到实际的源码位置呢? 可以根据APK的名字来找,例如APK叫:magicxx, 那么就可以在com下搜索这个名字:
bash
find ./com -type d -iname "*magic*"
./com/xxx/magicxx
比较巧,搜索结果只有一个,而这个目录也是实际的存放源码的目录。
resources目录
这个文件夹存储的是应用程序的所有原始资源文件,比如XML布局文件,图片,音频,本地化字符串,样式以及主题等等。这些文件通常以其原始格式存储,例如.png或.jpg的图片文件,.xml的布局或者字符串资源文件等。
- AndroidManifest.xml:这个是每个Android应用必须具备的文件,描述了应用的基本信息,例如应用的包名,主Activity,权限需求等。
- 这里通过包名,也能确定源码确实是在./com/qjtc/magicalar这个目录下面。
- assets:这个文件夹通常包含那些需要直接通过文件I/O进行访问的文件,如预先准备好的数据库文件或者本地的html文件等。
- lib:这个文件夹用于存放用C或C++语言编写的本地库(.so文件)
- res: 这个目录包含了所有的应用资源如图标,界面布局,动画,颜色,样式等等。
整体上说,sources和resources这两个文件夹包含了APK文件的主要内容。我们主要也是从这两个目录中找到我们想要的东西。
总结
了解完前置知识之后,我们就要开始正式的逆向之旅了。从最简单的逆向开始,依赖我们学习的前置知识,经历一遍完整的流程。下一篇我们再见!
end