首页
社区
课程
招聘
[原创]某pp线上超市加密纯算分析
发表于: 2024-11-28 16:05 5662

[原创]某pp线上超市加密纯算分析

2024-11-28 16:05
5662

某线上超市纯算分析完整篇

本文仅作为学习交流,禁止用于商业使用。

图片描述
通过分析抓包请求,可以确定加密参数为 “sign” 和“seal”

首先看下长度,32位,初步猜测为 md5,用算法助手或者 hook 一下 md5,即可得到正常结果。
这个参数大家可以自己尝试了,当作热身的。下面的seal才是咱们的主菜。

图片描述
具体查找过程就不说了,是调用这个so生成的seal

成功执行后多次输出结果:
图片描述
大胆猜测各个密文可能的加密方式:
a: md5+字符串
b: 可变字符串
c:base64(固定字符+随机字符)
d:固定字符串
e:可变字符串

图片描述
图片描述

加密参数a:
图片描述
hook该方法,发现该方法调用两次,分别打印入参
第一次入参:
图片描述
return:17 77 BD BO 29 37 12 3D CB CF 66 4F 72 B1 40 47
第二次入参:
图片描述
return:d92cef65a435b35cd235883f4c65c5e1
md5处理的字节必须是512的整数倍,不足的填充(0x80,0x00)和附加消息长度,否则不做填充
分析结果:a加密即取原文前512bit数据进行第一次md5加密,结果作为第二次md5加密的初始化魔数对原文后半部分进行第二次md5,结果再加上随机数。
加密参数b
入参1-随机数, 入参2-加密长度
图片描述
分析可知,就是对一个随机数再次进行加密,估计后端不会校验,或者校验能否解密
加密参数c
图片描述
查找base64码表
图片描述
由此可见是改了码表的base64,通过该码表解码发现入参不为明文,向上查找明文加密的地方
图片描述
sub_425cc加密:该自写算法就是将明文加密 类似rc4对称算法(生成一个256字节的S-box。再通过算法每次取出S-box中的某一字节K.将K与上一个结果做异或得到密文)
图片描述
至于是不是标准rc4,我没有验证
加密参数d
分析伪代码,调用android的getSharedPreferences
图片描述
通过 getstring 获取config.xml文件key为 db_epidemic_prevention 的值,否认默认为 pbpiy6hrpp323s13
java查找 putstring 方法
图片描述
加密方式为:常量str2 进行md5 作为 aes-ecb 模式的key,对明文进行加密
图片描述
加密参数e
随机数加密,和加密参数b一样

总结:整体难度中等,在无混淆的情况下,结合unidbg进行调试,很容易找到加密函数。逆向时,要熟悉各种加密算法,对一些常见算法的初始化常量,算法特征,源码要基本了解。

package com.pp;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.github.unidbg.virtualmodule.android.JniGraphics;
import java.io.File;
import java.io.UnsupportedEncodingException;
 
 
public class pp_seal extends AbstractJni {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    public pp_seal() {
        // 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验
        emulator = AndroidEmulatorBuilder.for64Bit()
                .addBackendFactory(new Unicorn2Factory(true))
                .setProcessName("com.pupumall.customer")
                .build();
        // 获取模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        emulator.getSyscallHandler().setEnableThreadDispatcher(false);    //  如果报错 [main]W/libc: pthread_create failed: clone failed: Out of memory 采用改代码
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
        vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/pp/pp4.8.8.apk"));
        // 如果提示缺失依赖so
        new AndroidModule(emulator,vm).register(memory);
        new JniGraphics(emulator,vm).register(memory);
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/pp/libwindcharger.so"), false);
        module = dm.getModule();
        vm.setJni(this); // 设置JNI
        vm.setVerbose(true); // 打印日志
        dm.callJNI_OnLoad(emulator); // 调用JNI OnLoad
 
    }
 
    public static void main(String[] args){
        pp_seal test = new pp_seal();
        AndroidEmulator emulator = test.emulator;
        VM vm = test.vm;
        DvmClass cSignUtil = vm.resolveClass("com.pupumall.tinystack.Gears");
        String aa = "{\"sign\":\"c4a2cdc8738a09a5d661c858a66f009e\",\"Owl-TraceId\":\"e7fc7a42c6d04ec4b2dbe889e62f8b24.232.17205818367478832\",\"X-B3-TraceId\":\"e7fc7a42c6d04ec4b2dbe889e62f8b24.232.17205818367478832\",\"X-B3-SpanId\":\"dca2366dec7d0370\",\"timestamp\":\"1720581836741\",\"pp-version\":\"2023023100\",\"pp-suid\":\"e9ce82cf-0933-4221-8ced-649f03e95cef\",\"pp_storeid\":\"b565ec67-fd76-4195-888e-b6ff156b2adc\",\"pp-placeid\":\"1b7d5060-211a-485c-8424-158cccf1df93\",\"req-tag\":\"1720581836780\"}";
 
        DvmClass cContext = vm.resolveClass("android/content/Context");
        DvmClass cContextWrapper = vm.resolveClass("android/content/ContextWrapper", cContext);
        DvmObject<?> cNative = vm.resolveClass("com.pupumall.customer.global.AppTinker", cContextWrapper).newObject(null);
 
        DvmObject<?> dvmObject = cSignUtil.callStaticJniMethodObject(emulator, "drift(Landroid/content/Context;Ljava/lang/String;)Ljava/lang/String;", cNative, aa);
        System.out.println(dvmObject);
//        }
    }
        @Override
    public int getStaticIntField(BaseVM vm, DvmClass dvmClass, String signature) {
        if ("android/content/Context->MODE_PRIVATE:I".equals(signature)) {
            return 0;
        }
        return super.getStaticIntField(vm, dvmClass, signature);
    }
 
        @Override
    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature) {
            case "java/lang/String->getBytes(Ljava/lang/String;)[B": {
                String str = (String) dvmObject.getValue();
                StringObject charsetName = vaList.getObjectArg(0);
                try {
                    return new ByteArray(vm, str.getBytes(charsetName.getValue()));
                } catch (UnsupportedEncodingException e) {
                    throw new IllegalStateException(e);
                }
            }
            case "com/pupumall/customer/global/AppTinker->getPackageName()Ljava/lang/String;":{
                return new StringObject(vm, "com.pupumall.customer");
            }
        }
        throw new UnsupportedOperationException(signature);
    }
 
        @Override
    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature) {
            case "com/pupumall/tinystack/utils/P->a(Landroid/content/Context;)Ljava/lang/String;":
            case "com/pupumall/tinystack/utils/S->e(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":
            case "com/pupumall/tinystack/utils/S->q()Ljava/lang/String;":
                return new StringObject(vm, "Ljava/lang/String;");
        }
        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }
 
 
}
package com.pp;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.virtualmodule.android.AndroidModule;
import com.github.unidbg.virtualmodule.android.JniGraphics;
import java.io.File;
import java.io.UnsupportedEncodingException;
 
 
public class pp_seal extends AbstractJni {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    public pp_seal() {
        // 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验
        emulator = AndroidEmulatorBuilder.for64Bit()
                .addBackendFactory(new Unicorn2Factory(true))
                .setProcessName("com.pupumall.customer")
                .build();
        // 获取模拟器的内存操作接口
        final Memory memory = emulator.getMemory();
        emulator.getSyscallHandler().setEnableThreadDispatcher(false);    //  如果报错 [main]W/libc: pthread_create failed: clone failed: Out of memory 采用改代码
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
        vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/pp/pp4.8.8.apk"));
        // 如果提示缺失依赖so
        new AndroidModule(emulator,vm).register(memory);
        new JniGraphics(emulator,vm).register(memory);
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/pp/libwindcharger.so"), false);
        module = dm.getModule();
        vm.setJni(this); // 设置JNI
        vm.setVerbose(true); // 打印日志
        dm.callJNI_OnLoad(emulator); // 调用JNI OnLoad
 
    }
 
    public static void main(String[] args){

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2024-12-4 17:05 被wx_我想吃橘子味的橙子々编辑 ,原因:
收藏
免费 24
支持
分享
最新回复 (19)
雪    币: 1429
活跃值: (1560)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
牛逼 的大佬
2024-11-29 16:55
0
雪    币: 192
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
最新版本的能过吗
2024-12-5 04:06
0
雪    币: 226
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
牛逼
2024-12-5 10:20
0
雪    币: 1333
活跃值: (2765)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
666
2024-12-5 10:38
0
雪    币: 261
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
看看
2024-12-5 10:56
0
雪    币: 231
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
7
11
2024-12-5 13:22
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
66
2024-12-5 13:33
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
nb 大佬
2024-12-5 13:44
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
1
2024-12-6 06:29
0
雪    币: 206
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
11
1
2024-12-6 10:40
0
雪    币: 260
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
1
2024-12-6 17:22
0
雪    币: 735
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
6666666666
2024-12-6 19:48
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
666
2024-12-6 20:57
0
雪    币: 1000
活跃值: (1042)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
666
2024-12-7 11:42
0
雪    币: 206
活跃值: (1175)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
学习一下
2024-12-7 11:48
0
雪    币: 47
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
17
学习学习
2024-12-7 13:35
0
雪    币: 43
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
11
2024-12-7 19:42
0
雪    币: 205
活跃值: (102)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
学习学习
4天前
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
666
21小时前
0
游客
登录 | 注册 方可回帖
返回
//