0%

T1:请求头控制

首先开始抓包,发现一直显示"爬虫模式",不知道哪儿出现了问题
但是看标题说是请求头的反爬,就先注释掉一些请求头,发现不带 cache-control 这个字段就能够拿到数据了
挺简单的,代码如下:

样本地址: aHR0cHM6Ly93d3cud2FuZG91amlhLmNvbS9hcHBzLzMwNjY3Mw==

抓包分析

当抓到 login 这个包的时候,会发现在请求体中有一个 signature 的参数,今天我们的目标就是它

84c7dd50e8192db401cfbc4b2d6b0565f41fd2e0 这个格式的字符串,长度 40 位,感觉有很大可能是 sha1 算法,不知道魔改没 打开 jadx,搜索一下 signature 这个字段,但是发现搜索出来了很多关键词,那就拿其他相关的关键词进行搜索
fdsOtp 这个字段挺特殊的,直接在 jadx 中搜索,发现了 3 个地方 进去之后发现就找到了 signature 这个字段,它调用了 LoginRequest 这个类的 b 方法
跟进去,最后就直接跟到了是 WTWEctUfLf 这个方法返回的结果

安卓启动流程

先总的从下面这个图中来学习一下安卓的启动流程吧

Bootloader 引导阶段

当按下电源键后,芯片从固化在 ROM(Read-Only Memory)中预设的(BOOT ROM)开始执行,这个阶段是纯硬件操作,代码负责加载引导程序 BootLoader 到 RAM(Random Access Memory)中
BootLoader 是操作系统运行之前的一小段程序,类似于 PC 上的 BIOS,主要功能大致有:

简介

DES 算法是最早的对称加密算法,虽然已经被 AES 所取代了,但是在安卓逆向的过程中还是有可能会遇到这个算法,所以对它有一定了解还是必要的

基本参数:

  • 分组大小:64 位(8 字节)
  • 密钥长度:56 位有效密钥(实际 64 位,含 8 位奇偶校验)
  • 迭代轮数:16 轮
  • 工作模式:ECB,CBC,CFB,OFB 等 DES 分成两部分,一部分是明文的处理,另一部分是密钥的编排

第一部分:密钥的编排(子密钥生成)

密钥编排是指从 64 位的主密钥生成 16 个 48 位主密钥的过程,使用官方测试向量:

简介

RC4 算法是一种流密码,它与之前学习的 MD5,SHA,HMAC,DES 等有根本区别,先与分组加密 DES 做个对比吧:

特性分组加密(DES)流密码(RC4)
处理方式固定大小分组(如 64 位)逐位或逐字节
加密方式分组加密与伪随机密钥流异或
算法结构Feistel 网络/SPN伪随机数生成器
密钥流固定依赖于密钥和状态

核心思想:RC4 生成一个伪随机的密钥流,然后与明文进行逐字节异或操作得到密文

在吾爱破解上看到个合适的案例,学习一下

初始化

先搭一个 unidbg 的架子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.md5;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;

import java.io.File;

//必须继承AbstractJni
public class modMd5 extends AbstractJni {
    public static AndroidEmulator emulator;  // 静态属性,以后对象和类都可以直接使用
    public static Memory memory;
    public static VM vm;
    public static DvmClass MainActivity;
    public static Module module;
    // 1 构造方法--》用来初始化
    public modMd5(){
        // 1.创建设备(32位或64位模拟器), 具体看so文件在哪个目录。 在armeabi-v7a就选择32位
        // 传进设备时,如果是32位,后面so文件就要用32位,同理需要用64位的
        // 这个名字可以随便写,一般写成app的包名    以后可能会动
        emulator = AndroidEmulatorBuilder.for64Bit().setProcessName("").build();

        // 2.获取内存对象(可以操作内存)
        memory = emulator.getMemory();

        //3.设置安卓sdk版本(只支持19、23)
        memory.setLibraryResolver(new AndroidResolver(23));

        // 4.创建虚拟机(运行安卓代码需要虚拟机,就想运行py代码需要python解释器一样)    以后会动
        vm = emulator.createDalvikVM(new File("apks/md5/md5-release.apk"));
        vm.setJni(this); // 后期补环境会用,把要补的环境,写在当前这个类中,执行这个代码即可,但是必须继承AbstractJni
        vm.setVerbose(true); //是否展示调用过程的细节

        // 5.加载so文件
        DalvikModule dm = vm.loadLibrary("native-lib", false);   // 以后会动
        dm.callJNI_OnLoad(emulator); // jni开发动态注册,会执行JNI_OnLoad,如果是动态注册,需要执行一下这个,如果静态注册,这个不需要执行,车智赢案例是静态注册

        MainActivity = vm.resolveClass("com.littleq.cryptography.md5.MainActivity");
        // 6.dm代表so文件,dm.getModule()得到module对象,基于module对象可以访问so中的成员。
        module = dm.getModule(); // 把so文件加载到内存后,后期可以获取基地址,偏移量等,该变量代指so文件
    }
    
    //2 sign 成员方法--》主要用来解密
    public void sign(){
        String str = "123456";
        String result = MainActivity.newObject(null).callJniMethodObject(emulator,"sign(Ljava/lang/String;)Ljava/lang/String;",str).getValue().toString();
        System.out.println(result);
    }

    public void hookConsoleByDebugger(){
//        emulator.attach().addBreakPoint(module.base+0xA3C);
        emulator.attach().addBreakPoint(module.base+0x8D8);
    }

    // 3 main方法---》右键直接运行
    public static void main(String[] args) {
        modMd5 md5=new modMd5();
        md5.hookConsoleByDebugger();
        md5.sign();
    }
}

直接运行就可以出结果,当然,我是来学习算法分析的

SHA256 算法其实跟前面的哈希算法类似,他们所需要经历的步骤是一样的,下面来用一个表格来跟前面的哈希算法做一个对比

特性MD5SHA1SHA256
输出长度128 位160 位256 位
安全性已破解存在碰撞攻击目前安全
块大小512 位512 位512 位
步数64 步80 步64 步
初始化常量4 个5 个8 个
字节序小端序大端序大端序

填充

此步骤与 MD5,SHA1 的规则一致,将原始消息填充至长度恰好是 512 的整数倍,规则几乎相同:

HMAC 可以与任何哈希算法进行结合,在逆向的过程中,经常会遇到 HMAC-MD5/SHA1/SHA256 之类的,类似于哈希算法进行加盐,只不过这里叫做密钥,这里我用 HMAC-SHA1 来进行举例

流程

我选择数据的密钥(盐)的是 123456789abcdef ,数据是 123456

SHA1 算法和 MD5 总体上很类似,算法流程也差不多

原始数据准备

还是以"password"这个字符串的数据为例
转换成十六进制就是: 70 61 73 73 77 6f 72 64,长度 8 个字节,64 位
接下来开始填充,先补一个 1,再补 k 个 0,使得消息满足 ()64+1+k) = 448
64+1+k = 448 即 k=383,需要补一个 1 和 383 个 0
最后 64 位用来表示原始数据的长度,原始数据长度为 8 个字节,64 位,用 0x0000000000000040(16 进制,大端序)
SHA-1 使用大端序,所以这 8 个字节直接按照顺序附加