逆向学习(二)

安卓逆向

0、准备工作和大纲

JAVA环境、apktool、android APK、JADX、keytool、jarsigner(最后两个为JAVASDK自带工具)

java基本知识:源代码文件为XXX.java;是编译性语言,编译后才可以运行(PYTHON是解释性语言,直接可以运行);JAVA编译后的文件是XXX.class,class文件是可执行文件;JAVA虚拟机运行可以运行XXX.class方法为java XXX.class
安卓下面的xxx.dex dex是安卓里可执行文件

安卓软件包:APK。即一个压缩文件,用zip压缩解压。

JADX:把dex文件转化为java代码。

APKTOOL:反编译apk包。

签名

adb命令使用
adb devices    安卓设备列表
adb shell    进入安卓shell
adb logcat    adb logcat -s keyword    安卓日志
adb push    把文件推送进安卓设备
adb shell dumpsys activity top    adb shell dumpsys package packagename    打印AndroidManifest.xml
adb install XXX.apk    adb uninstall XXX.apk    安装卸载apk
adb pull android-path local-path    拉取安卓文件到本地
adb push local-path android-path    推送本地文件到安卓
网易模拟器:adb connect 127.0.0.1:7555

smali语法

破解安装签名校验

APK启动加载

APP四大组件

加固后的APK包

加固原理

脱壳

java编译运行

反混淆:
混淆工具:proguard;自己混淆。
jadx jeb2 日志打印
站在程序设计的角度上思考,程序要健壮、安全、性能高。
isNetworkAvailable

APP抓包。
代理被检测如何抓包;使用xpose模块;手动该smali

Frida开发
基础开发;Hook安装签名;Hook token;Hook so文件。

IDA动态调试:
网易模拟器:adb connect 127.0.0.1:7555
IDA动态调试配置:
adb push android_x86_server(cpu型号要对应,模拟器是x86)/data/local/tmp/    把本地文件推送进手机目录
adb shell    进入手机shell
cd /data/local/tmp/    进入tmp目录
ls -l    查看文件是否存在和确定文件权限。
chomd 777 android_x86_server    修改权限需要确定有root权限
./android_x86_server    运行
adb forward tcp:23946 tcp:23946    在本地执行adb做端口转发
静态调试,动态调试,反调试

IDA手动脱壳

1、安卓基础与逆向工具

安卓项目目录结构为:
assets:资源文件(图片,网页,视频)不会被编译。
res:资源文件(静态文本,图片,关键资源)汉化,要被编译。
lib:.so库,系统库,自己打包的库。有的把加密/token生成方式放在.so文件里
META-INF:签名信息
AndroidManifest.xml:配置信息(关键),举例:修改权限
classes.dex:android dalvik虚拟机可执行文件
resources.arsc:资源索引/对应文件

APP四大组件:
Activity:一个Activity通常就是一个界面。
Service:后台服务,播放音乐,处理数据等。
Broadcase receiver:异步接收广播
Content provider:内容共享

JADX:把dex文件转化为java代码。

APKTOOL:反编译apk包。用法:apktool d test.apk。结构:
AndroidManifest.xml    APP权限配置,也是程序入口
smali文件(一种汇编代码)    .smali可以和.dex相互转换;修改apk代码通常修改smali文件(重新修改.java源代码的话重新编译的困难太大);baksmali.jar smali.jar对dex和smali文件做转换
classes.dex    源代码在classes.dex文件里,可以反编译出.java代码
过程:.smali--->.dex---->.java
利用APKTOOL漏洞的apk会反编译失败,只能等升级或者找老版本。
重新打包apk方法:apktool b 目录

签名:keytool jarsigner 工具是JAVAJDK自带的。
生成证书:keytool -genkey -keystore my-release-key.keystore -alias my_alias -keyalg RSA -keysize 4096 -validity 10000
用证书给apk签名:jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore my-release-key.keystore -signedjar com.dahuodong.veryevent_4.6.2_60_sign.apk com.dahuodong.veryevent)4.6.2_60.apk my_alias
未签名APK不能再安卓手机上安装,APP在启动时会对签名进行校验,要逆APP就要跳过校验。

2、smali基本语法,安卓加载原理,破解安装签名

smali是Dex文件逆向后的一种语法,一种反汇编语言。smali代码和.java代码对应看会比较容易。.line和.java的代码行数对应。

下面是网上找的一篇关于smali的语法的简单介绍:
文章来源:http://www.brogrammer.cn/android/smali/

安卓加载
1、Dex加载流程(安卓源代码):
Davlivk虚拟机加载dex文件
  Java层Dex加载流程:BootClassLoader ---> PathClassLoader ----> DexClassLoader
  Native层Dex加载流程:libdvm.so(重编译system.img) OpenDexFileNative
2、点击图标,APP加载流程:一个APK只有一个Application。每个Apk运行时都需要有一个Application对象。Application对象执行onCreate方法时,APP就开始运行。
逆向学习(二)_第1张图片

破解安装签名:修改smali文件;hook技术
用apktool反编译apk,得到AndroidManifests.xml,找到程序入口Application,对比java代码(使用jadx打开apk,查找程序入口对应的Application名),然后找Sig,sign等签名相关内容,最后在smali文件中找到对应的Application文件,将Java 代码中执行检查操作的代码的行数对应的smali代码删掉/改掉,让他不执行,之后用apktool打包。

3、加固脱壳,破解app请求token

加固apk的特征(各家.so文件名特征,需使用软件检测)(腾讯乐加固,360,梆梆,爱加密等);三方加固/自己加固(一般在哪家应用市场发布就要用哪家的加固方案);为什么要加固(一定程度保护源代码);加固方式(.dex/.so加固)
不同厂商对APP的加固特征:
爱加密:libexec.so, libexecmain.so, ijiami.dat
梆梆:libsecexe.so, libsecmain.so, libDexHelper.so
360:libprotectClass.so, libjiagu.so, libjiagu_art.so, libjiagu_x86.so
百度:libbaiduprotect.so
腾讯:libshellx-2.10.6.0.so, libBugly.so, libtup.so, libexec.so, libshell.so
网易易盾:libnesec.so

加固原理:源APK加密后+脱壳Dex = 新的Dex = 新的Apk
新APK运行:先加载壳APP--->壳APP读Dex文件末尾的源APKD大小--->在内存中壳APP解密出源APP--->运行源APP
壳APK有自己的Application对象,源APK由自己的Application对象,壳APK启动时,在AndroidManifest.xml里找源APK的Application执行它的onCreate方法,启动源APK。

脱壳:
脱壳原理:在壳APK解密源APK后,源APK被加载前,拦截这个过程中的系统函数,把内存中Dex,dump出来

方法:Hook:先取得要Hook函数/方法的控制权,这样不用破坏程序;动态调试:反编译,汇编,计算内存地址。
Hook技术(系统进程注入):在系统每调用函数前,通过HOOK技术,先得到该函数的控制权,实现该函数的逻辑改写,要Hook java层系统函数,要Hook应用对象方法(先知道应用对象源代码)

手动脱壳:通过动态调试,跟踪计算Dex源文件的内存偏移地址,从内存中Dump中Dex文件。此法难度大,要了解寄存器、汇编、反调试、反读写,利用IDA调试工具
工具脱壳:HOOK技术/内存特征寻找;简单易操作。DexExtractor Fdex2(重写libdvm.so dexFileParse函数 Hook ClassLoader) ZjDroid
  基础工具:xposed(java编译,Fdex2通用脱壳,dumpDex(https://github.com/WrBug/dumpDex))frida(python javascript代码注入)主要系统函数都已HOOK/基于xposed frida开发脱壳工具/有大神已开发上层应用模块。
  开发工具要了解APP启动加载过程的原理和细节。路径有两个:一是沿着APP加载启动过程,HOOK关键系统函数;二是Dalivk虚拟机层,需要刷system.image或改写系统.so文件,改写虚拟机层解析。
Dex文件的函数:使用已有工具,技术晚半代至一代。脱老版本的APP。
HookClassLoader的loadClass方法,反射调用getDex方法取得Dex(com.android.dex.Dex类对象),再将里面的dex写出。
  重写底层函数:DexExtractor(重写libdvm.so dexFileParse函数,用于梆梆、爱加密)
在线执行脱壳:http://www.dooccn.com/java

破解app的token:
先抓包,然后找到想要的数据的请求,接着确定要破解的token名称,使用jadx打开apk,搜索token名称,找到形似的地方,开始分析(可以使用jadx的反混淆,将变量名等做一个唯一化处理),找到生成方式后可使用python的jpype库调用jar包运行得到结果。
javajdk环境:sudo apt install default-jdk
编译:javac XXX.java
将class做成jar包:jar cvf XXX.jar *    java -cp XXX.jar XXX    此文件内需要有main函数
jpype调用jar包:from jpype import *    jvmpath = getDefaultJVMPath()    jarpath = 'jar包路径'    startJVM(jvmpath, "-ea", "-Djava.class.path=%s" %(jarpath + "jar包名称"))    JDClass = JClass("class名")    jd = JDClass()    res = jd.方法名(参数)    shutdownJVM()

4、frida逆向开发,hook——java层

Hook:改变程序执行流程的一种技术,在函数/方法被调用前,通过Hook技术,先得到该函数/方法的控制权,实现函数/方法的逻辑改写。

Hook的框架:
    xposed:Java语言开发的,只能hook应用层,开发经常需要重启设备,开发效率低,与安卓无缝对接。
    frida:C语言开发的,能Hook 安卓 IOS windows 应用层 native层,可以使你用JS和python代码完成Hook,不需要重启设备,编译,开发效率高,与安卓的数据类型转换比较麻烦。需要设备root权限

Hook的先决条件:要知道Hook哪个方法,哪个函数,要有源代码(方法定义原型)
Frida组成部分:Frida-server运行在设备上;Frida,python模块;Frida-tool提供cli工具命令,跟Frida-server交互。
官方文档:https://www.frida.re/docs/javascript-api
查看APP加载了那些so文件:cat /proc/[pid]/maps

常用模块API:
Java模块:Hook Java层的类、方法相关
Process模块:处理当前线程
Interceptor模块:操作指针相关,多用来Hook Native相关
Memory模块:内存操作相关
Module模块:处理so相关

Java.perform(function(){})方法
Java.use('类名')方法,用于劫持类包,将返回一个类实例对象。类实例对象.要更改的函数名.implentation = function (){};重写函数。

python需要安装frida和frida-tools。还需要下载server文件放到手机上执行(下载地址:https://github.com/frida/frida/releases)。
下载好之后需要解压。
操作步骤:adb push frida-server-12.6.8-android-x86 /data/loca/tmp/
    adb shell
    cd /data/local/tmp
    chmod 777 frida-server-12.6.8-android-x86
    ./frida-server-12.6.8-android-x86
在电脑上运行frida -ps -U。如果弹出一堆包,则表示成功。
转发端口到PC:
adb forward tcp:27043 tcp:27043
adb forward tcp:27042 tcp:27042

Hook通用思路
基础开发:
    Frida开发接口
    固定模式:
        python+js:python负责和frida-server通信,把js传给frida-server,起控制作用,写法固定;js负责hook操作

import sys, frida


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


jscode = """
Java.perform(function () {
// Function to hook is defined here
varMainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity');

// Whenever button is clicked
MainActivity.onClick.implementation = function (v) {
// Show a message to know that the function got called
send('onClick');

// Call the original on Click handler
this.m.value = 0;
this.n.value = 1;
this.cnt.value = 999;

// Log to the console that it's done, and we should have the flag!
// console.log('Done:' + JSON.stringify(this.cnt));
};
});
"""

process = frida.get_usb_device().attach('com.example.seccon2015.rock_paper_scissors')
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running CTF')
script.load()
sys.stdin.read()

应用要处于打开状态/已加载状态才能Hook。

Hook流程:
遇到需要Hook的情况;
使用jadx打开apk;
脱壳(如果需要);
反编译apk得到AndroidManifest.xml,找到入口类;
对应到jadx中的java代码,根据遇到的情况不同使用不同的方式进行分析处理(可以直接删除对应代码(smali代码),但需要考虑签名、重打包等问题;也可以通过js注入修改对应函数逻辑;查找所需密码)。

5、hook——native层

需要hook native层标识:方法/函数前使用native修饰。

API调用示例:
各种app应用由应用层API(安卓层)封装,安卓层由系统层API(SO层)封装得到。
如何Hook应用软件Java层。

简单了解.so库  libcrackme.so    IDA(软件)静态方法调试so
如何Hook so库:
    Module模块:
        .findExportByName(moduleName|null, exportName);    lib名称,函数名称。返回值是exportName的地址。
        .findBaseAddress(moduleName);    lib名称。返回lib的基地址
    Process模块:
        .findModuleByAddress(address);  lib的指针地址。返回一个Module对象
    Momery模块:
        .readCString(pointer);  指针地址。吧pointer还原成字符串。
        .readUtf8String(pointer);  
        .readAnsiString(pointer);
    Interceptor模块:监听
        .attach(target, callbacks);  指针地址,回调函数(onEnter, onLeave)。
        .replace(target, replacement);  
常用Hook的系统so库
    libc.so长调用函数:void * dlopen(const char *filename, int flag);    加载动态链接库。

如何Hook APP启动阶段的方法/函数:
Hook 打印堆栈信息:追踪方法的调用关系。
    send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
Hook 常见加密类:要知道java中有哪些常见的加密类。HookMD5 RSA之类的,要得到加密的源字符串需要得到加密的调用地方。
如何Hook重载的方法:在implementation之前使用.overload('[B')来声明其是重载(参数有:byte    byte[]    byte[] int int    ByteBuffer四种)。
Hook SSl
Hook 常用安卓: icity signature

Hook系统Java层
Hook系统so文件
Hook动态加载so
    https://www.breakyizhan.com/java/4982.html
    java.lang.Runtime:每个Java应用程序都有一个Runtime类实例,Runtime.getRuntime().loadLibrary()加载lib。

6、frida——hook——md5

了解安卓API/Java API:
http://tool.oschina.net/apidocs/apidoc?api=jdk-zh
https://developer.android.google.cn/reference/packages
https://www.android-doc.com/reference/android/content/pm/PackageInfo.html

java md5常用加密类:

java.security.MessageDigest
常用方法为:.getInstance 有三个重载。  .update() 有四个重载。需要全部hook

正常的分析手段:
抓包分析头信息的组成
拆解哪些头信息可以直接组装(app-version, device-id)
分析不能组装的数据的格式。(token    signature)
    正常分析token的逻辑
        反编译APP(先脱壳)
        通过关键字,或者其他手段,定位到token加密的地方
        分析是如何加密的

耍赖手段:
    思维习惯:不管token如何变化,如何加密,token有多复杂,总要调用一种或多种加密算法(md5 base64 rsa sha)来对源token进行处理,这种算法通常是调用第三方库或者java/android自带的库来做加密。所以直接hook常用的加密类,在加密的方法里面直接做打印,就可以得到源token;在加密的方法里调用堆栈打印,就可以知道是哪个方法在做加密操作,就可以找到这个方法。
    称为盲狙。要想成功率达需要大范围搞事。要覆盖常用的md5/base64/rsa/sha等常用方法。
    还有一种叫抓包耍赖:
    用fiddler抓包 APP有检测代理抓包,经常抓不到包。于是Hook网络请求库,得到URL、头信息、返回的数据格式。
    req = Java.use('requests')
    req.get.implementation = function(){
        send(url);
        var r = this.get(str);
        send(r.code);
        send(r.text);
    }

Hook 操作:
    不要改写方法的内部逻辑,要用它原来逻辑正常执行。
    Java.use('A')
    A.get_sig[.overload(参数类型)].implementation = function(str){
        send(str);
        var ss = this.get_sig(str);
        return ss;
    }

7、网络抓包

TCP/IP协议分七层,每一层都可以抓包(应用层-表示层-会话层-传输层-网络层-数据链路层-物理层)。
TCP/IP协议栈:由一系列网络协议组成,是网络通信的核心,所有设备的网络通信都依赖TCP/IP协议。电脑/手机/路由器/物联网设备。

抓包方式:
一、代理抓包模式(中间人攻击) Fiddler Charles VPN 192.168.0.5
    能抓Http/Https/WebSocket,属于应用层。优点是配置简单/抓取解析SSL方便;缺点是APP对代理抓包的检测屏蔽越来越强。
    原理:在客户端和服务端之间添加一层代理,并在代理处进行一些操作。
    HTTPS:HTTP是明文传播,容易被拦截,容易被修改,比如网页弹广告;HTTPS在HTTP的基础上加了安全层(SSL或TSL)
        特点:数据加密,不再使用明文传播;使用数字证书(CA)做身份校验,防止数据被截获,只有合法证书持有者才能读取数据;数据完整性强,防止数据被篡改,对数据做签名。
        HTTP OVER SSL传输数据前要SSL加密处理
        SSL握手协议:先商量好加密方式,交换证书,用证书加密,开始发送数据(用证书来给数据加密)
        Client Hello发给服务端:一串随机数和客户端支持哪些加密算法,一般是RSA加密
        Server Hello发给客户端:一串随机数和确定使用哪种加密算法
        Certificate:服务端把公钥证书发给客户端
        Client key Exchange:客户端把自己的证书发给服务端
        Session Ticket:开始传输数据/用key 给http数据加密,传输给服务端。
代理抓不到包的几种原因:
    1、请求没有走代理(可以设置走自己的代理,安卓系统会有先走APP设定的代理。http.route.default-proxy)
        判断依据:设置wifi代理后关闭fiddler,如果APP还能正常访问就是没走代理。
        解决方法:ProxyDroid APP 全局代理,强制把IP转发到指定端口上。原理是使用iptable命令实现端口转发,mumu虚拟起iptable会报错。
    2、ssl pining(ssl证书验证)目前大部分是这种导致抓不到包
        APP对服务端证书做校验,校验服务器的证书和域名(也叫单向认证),Fiddler/Charles的证书肯定是校验不过的。
        判断依据:在抓包工具中,请求方式为CONNECT,状态为Failed。
        解决办法:使用Hook手段将APP段网络请求库对ssl证书的判断方法hook掉(借助xposed的justtrustme。https://github.com/Fuzion24/JustTrustMe;或者frida的DroidSSLUnpinning https://github.com/WooyunDota/DroidSSLUnpinning);逆向APP扣除里面的证书放到charles里,让charles使用真实的证书做代理。
        部分sslpinning失效原因:
            Hook失败,APP的网络请求库被混淆,或者大厂自己实现了一套网络请求库。
            解决办法:逆向APP,找到证书验证的地方,修改xposed的justtrustme或者frida的DroidSSLUnpinning代码。
    3、双向认证(少用,会影响服务器性能):客户端对服务端发来的证书做校验;真实的服务端也对客户端证书做校验
        判断依据:soul app 做了ssl unpinning后报400的错误。
        解决办法:客户端校验依然适用SSL UNPinning方法;服务端校验要把APP里的证书导入到代理软件中,让代理抓包工具使用真实的APP证书。charles比较方便。
    4、socket通信:是IP层,fiddler/charles抓不到,使用wireshark抓包。解析soket通信数据比较麻烦,需要分析APP协议解析部分。
    5、似有协议:wireshark能抓到,不知道协议细节,解不了包,需要分析APP协议解析部分。
如何找到APP里的证书:
    反编译APP在assert文件夹中有.p12 .pem之类的文件 cer ssl
    反编译后,在源代码里大量搜索
    Hook 监听Assert文件夹,知道读了哪些文件
    可能有密码,Hook java.security.KeyStore查看密码
二、网卡混杂模式(wireshark HTTPS):wireshark 不需要对客户端做改变,是对网卡抓包,作用在传输层/网络层,抓TCP包。
如何抓手机上的数据:电脑上开wifi热点,手机连电脑的热点,公用一个网卡(虚拟机可以直接抓包,不用热点)
特点:抓https需要吧ssl证书倒入到wireshark,不过难操作。tcp以上的数据都能抓,http/https/socket。
过滤方式:
    根据目的IP抓包:ip.dst == 192.168.0.1    ip.addr == 192.168.0.1
    按端口过滤:tcp.port == 80
    按协议过滤:ssl
    关联过滤:ssl and ip.addr
三、路由器抓包(网络组网方式):有访问追踪功能的路由器可以使用。设置路由器抓发到本机的fiddler上,也需要配置ssl证书,难度较大。
四、Hook 域名 把https 改成 http:让app强行发http,请求可能会失败,抓不到response,但能抓到请求包。通用性差
五、Hook网络请求库: urlib urllib3 aiohttp requests:请求钱打印处请求参数,响应后打印出返回数据。通用性差。

PS:
   
安卓7.0及以后安卓系统不再信任用户安装的证书。解决方案是:1、root手机,把代理证书放到系统证书目录下。缺点在于有些手机的分区只能读取,不能写入。2、hook系统方法,强行让系统信任用户证书。
    所以:优先使用安卓系统低版本抓包(4.0 5.0 6.0);优先使用APP低版本抓包(历史版本https://wap.ppcn/apkpure.com);工具准备充分(包括但不限于fiddler/charles/wirseshark/模拟器4.0 5.0 6.0/root的安卓/苹果)

8、frida脱壳

function_address = Module.findExportByName(libname, function);
Interceptor.attach(address, func);
Interceptor.attach(address, onEnter:function(args){}, onLeave:function(retval){})

// File 模块 写文件流程
    new File(filepath, mode)
    write(data)
    flush()
    close()

file = new File("xxx.dex", "wb")
// data是字符串或者arrayBuffer //readByteArray() 返回的是arrayBuffer
file.write(data)
file.flush()
file.close()

// 把内存里的值转换为字符串
Memory.readUtf8String()

// 把内存里的值转换为整型
Memory.readInt()

// 以begin为起始位置,从内存中读length长度的数据出来。返回ArrayBuffer类型
Memory.readByteArray(begin, length)

// 把地址转换成NativePointer类型,frida里操作内存地址需要NativePointer类型
ptr()

// JS api
parseInt(num, radix) // 把其他禁止转换成10进制

dex文件格式:
不同的文件格式都有自己的格式定义(.txt .xml .xls)
文件的每个字节都有固定含义,存放固定内容(https://www.jianshu.com/p/f7f0a712ddfe
由:
    Header    dex文件头部,记录整个dex文件的相关属性
    String_ids    字符串数据索引,记录了每个字符串在数据区的偏移量
    Type_ids    类似数据索引,记录了每个类型字符串的索引
    Proto_ids    原型数据索引,记录了方法声明的字符串,返回类型字符串,参数列表
    Fields    字段数据索引,记录了所属类,类型以及方法名
    Methods    类方法索引,记录方法所属雷鸣,方法声明以及方法名等信息
    Classes    类定义数据索引,记录指定类各类信息,包括接口,超类,类数据偏移量
    Data    数据区,保存了各个类的真实数据
    link_data    链接数据区
组成,会精确到规定每个字节的含义。

逆向学习(二)_第2张图片

dexheader每个字节的含义:

逆向学习(二)_第3张图片

逆向学习(二)_第4张图片

脱壳原理:源dex文件最终会加载进内存。Hook加载Dex的函数,把Dex从内存中dump出来。Hook DexFile::OpenMemory()    DexFile::OpenMemory(const uint8_t* base, size_t size, const std::string& location, uint32_t location_checksum, MemMap* mem_map, const OatDexFile* oat_dex_file, std::string* error_msg)
如何找到Hook的点:熟悉安卓原理,熟悉代码层级;借助工具 查阅资料,摸清安坐加载dex代码级流程。
脱壳关键:熟悉安卓虚拟机加载dex文件的流程:https://www.jianshu.com/p/f81242ad8cb7

JNI动态注册:hook coolpai;分析代码的方法;关键字搜索法/片段关键字搜索;系统函数搜索法;分着交互流程,分析代码流程

Java的动态加载:在Java中声明函数原型,在.so中国呢具体实现
代码特征:
    public static native String getAS(Context context, String str);
    static {
        System.loadLibrary("native-lib");
    }
    libnative-lib.so

9、ida静态调试

NDK开发:Android NDK:是一套允许使用C和C++等语言,以原声带吗实现部分应用的工具机。用来做Native开发。
    https://developer.android.com/ndk
Java调用so库里的方法/函数:
    JNI:Java Native Interface。用java调用so库就叫JNI。方法如下:
        public static native String securityCheck(Context context, String str);    // 在java中申明一个Native方法
        static {    System.loadLibrary("native-lib");}    //使用System.loadLibrary()加载so库,全称是libnative-lib.so
        .so文件里对应的securityCheck名称是:Java_com_yaotong_crackme_MainActivity_securityCheck()    (即Java_类名_方法名())
        .so文件里对应的函数名称不一致:手动注册native方法。函数对应的名称是在JNI_ONLoad()函数里注册。

######手动注册native方法。

System.loadLibrary()加载so文件流程:
    先读取so文件的.init_array段;
    再执行JNI_OnLoad函数;
    JNI_ONLoad是.so文件的初始函数;
    然后调用具体的native方法。

IDA静态调试:
    点击New按钮,选择一个so文件打开。
    面板功能介绍
    静态调试技巧:
       
面板左侧函数列表可以查看每个函数的偏移量(相较于.so文件头的偏移量);
        F5(windows fn+f5)把汇编代码转成C代码
        shift+f12查看so文件中所有常量字符串的值,有的密码可能就在里面
        ctrl+s查看so文件段信息
        JNI函数方法名还原:选中v3,按y键(作用是类型还原)。v3 + 676 前面是一个指针,比如*(_DWORD *)v3 + 676表示v3是JNIEnv *类型。形如*(_DWORD *)vX + YYY皆是。
            可选中v3按y键进行类型替换,替换为JNIEnv *
        变量重命名,代码家住姐。

10、ida动态调试

将server文件推送至手机,更改其权限为777,运行服务器,在本地做端口转发(端口号为23946)
本地打开IDA,选中Go。
选择Debugger--->Attach--->Remote ARMLinux/Android debugger(真机);Remote Linux debugger(模拟器)
弹出窗口中输入IP+Port,点击OK
弹出Choose process to attach to窗口,选择要调试的进程/APP
等待加载,ctrl+s找到要调试的so文件,选择用X字样(可执行的)。
按键盘的G键,输入绝对地址,跳转到要调试的函数处。(绝对地址 = so文件的基地址 + 该函数的偏移量)(基地址:ctrl+s打开Choose segment to jump窗口,Start列是so文件基地址。)(函数偏移量:静态方式打开so文件,函数列表中。)
跳转至目标函数后,设置断点(F2或fn+F2),然后点击左上角开始(▶️)按钮运行。等待APP运行到断点处即可开始调试。
F7单步调试,要进入函数。F8单步调试,不进入函数。

so反调试:
IDA调试原理是利用Linux系统ptrace来实现。当应用被调试时,应用内存里的TracePid字段就不为0.
进入设备查看ptrace字段:
    adb shell
    ps | grep 包名
    cat /proc/pid/status
        打印内容中TracerPid为0代表没有被调试,不为0代表正在被调试
    反调试即检测TracerPid是否被占用。
so文件反调试的手段就是:新建一个线程,不停的检测TracePid这个字段是否不为0,不为0立即退出程序。
linux创建进程的函数:pthread_create()

反反调试:
动态调试,找到检测TracerPid的代码,选择不执行此代码。
方法:此检查代码一般在.init_array和JNI_OnLoad两处;在JNI_OnLoad函数处大断电调试,找到检测TracerPid的代码,不执行此代码。
    IDA调试反调试小经验——如何找到反调试代码:结合IDA静态时的代码,观察程序逻辑,指令一般会整个执行完,直到函数末尾。多次IDA中,如果指令在中途某个地方退出了,说明该处就是反调试指令。
    IDA调试反调试小经验——如何在JNI_OnLoad函数打断点:so文件在加载阶段会执行JNI_OnLoad,此后不再执行,要在so文件加载阶段才能给JNI_OnLoad打断点。
        一:修改APP AndroidMenifest.xml文件,APP加上可调式权限(android:debuggable="true"),重新打包app,签名,安装。
        二:检查flags中是否有应许debug项(adb shell dumpsys package com.yaotong.crackme)输出内容中的flags列表。
        三:以调试模式启动APP,APP此时会挂住(adb shell am start -D -n 包名/.类名)如:
            adb shell am start -D -n com.yaotong.crackme/.MainActivity
        四:.DebuggerOptions里勾选Suspend on thread start/exit Suspend on library load/unload。JNI_OnLoad函数是lib刚加载时就会执行,必须要在lib载入时就让程序停下来,才能调试JNI_OnLoad
        五:点击运行按钮
        六:在设备里查看APP的进程ID。要adb shell先进入设备运行如下命令,过滤出该应用信息:ps | grep 应用包名
        七:使用JDB命令让APP恢复运行:adb forward tcp:8700 jdwp:873(app的PID)    jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
        八:在so文件被加载时,IDA会停止住,使用ctrl+s查看目标so文件是否加载。若加载点选目标so文件,计算JNI_OnLoad的绝对地址,按G键跳转到JNI_OnLoad处设置断点,恢复APP执行,找到反调试代码处。(找反调试代码:关键地方可以F5转成C语言辅助;反复按F8单步执行,程序退出处(前面),极为反调试处)(不让反调试代码执行:让该指令变为空指令,即NOP。NOP指令的16禁止是00 00 00 00。记住反调试处的汇编指令,同时以静态方式再打开一个IDA(也叫双开)打开so文件在静态ida里找到此汇编指令,鼠标选中后面寄存器,然后切换到Hex View,会现实该指令的16进制。复制该16进制,在用文本工具打开so文件,找到该16进制处,替换成空指令。保存so文件,重新打包,签名,安装。)

动态调试libcrackme拿到密码:
    分析出密码判断的函数是哪个;IDA静态分析此函数,理清脉络;在此函数处下断点调试;单步调试,观察指令执行流程;密码不对事,指令会跨越执行,不再顺序执行;动态调试在关键指令处F5,转C代码辅助分析;动态调试时把鼠标移动到寄存器上,会显示该寄存器里的值;将指令转换为C代码,把鼠标移动到C代码的变量上,也会现实该变量的值。

补充:
C语言字符串操作
IDA动态调试按源码调试

11、ida——frida联合开发

so逆向总结:
逆向APK,找到加载的是哪个so文件,以及调用的是哪个native方法:System.loadLibrary()里是so文件名。声明的方法前有native关键字代表native方法
用ida以静态方式打开so文件
对函数里的JNIEnv *方法还原,让函数更容易理解
先看函数里的return break while等逻辑控制语句和有字面意义的函数调用,大治理清楚函数逻辑,对变量重命令让程序更容易看。
再用IDA动态调试,查看关键变量的值;或者使用frida找到hook点打印出关键变量的值。

12、小程序抓取流程

    小程序抓包:使用低版本安卓(4.4)和低版本微信(6.7),使用fiddler配置代理抓包。

    小程序组成部分:
        微信小程序是一种基于微信的前端开发框架,跟网页前端的组成部分相似。
        微信小程序前端组成:.wxml(控制页面结构).wxss(控制页面样式).js(控制交互).json(配置数据)
        小程序官方开发文档:https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/
        小程序的组成:https://developers.weixin.qq.com/miniprogram/dev/framework/structure.html
            根目录下由app.js  app.json  app.wxss组成。小程序页面由四个文件组成(js, wxml[, json][, wxss])。在pages目录中,小程序页面有多少,其子目录就有多少。
            pkg_XXX 子包。小程序由大小限制,把小程序拆分成多个子包,按需要加载,提高运行效率。
            分包介绍:https://developers.weixin.qq.com/miniprogram/dev/framework/subpackages.html
    解包.wxapkg
    在微信中点击小程序时,改小程序的前端代码会下载到手机里。下载到手机上的时被编译后的小程序包XXXXXX.wxapkg。
    解包流程:从手机上的/data/data/com.tencent.mm/MicroMsg/微信号id文件夹/appbrand/pkg/到处目标小程序的wxapkg文件。
        安装node.js并下载解包程序。https://nodejs.org/en/    https://github.com/qwerty472123/wxappUnpacker    
        改进版解包程序:https://enterprise.gitee.com/_being/wxappUnpacker/blob/master/README.md#
        安装依赖包:esprima  css-tree  cssbeautify  vm2  uglify-es  js-beautify  escodegen
        运行解包程序node wuWxapkg.js xxxxxwx.apkg(解包要先解主包)
    解分包:node wuWxapkg.js 分包.wxapkg -s=主包目录
    成功标识:根目录下生成:app.js  app.json  app.wxss

调试小程序:
申请小程序开发者账号;下载开发者工具;登陆开发者工具,导入解包小程序;调试方式和chrome一致,要在详情里选中,不校验https证书。

抓取难点:
必须微信登陆的小程序,需要由大量微信账号的登陆token。

小程序登陆流程:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

你可能感兴趣的:(学习过程)