某线上超市纯算分析完整篇
本文仅作为学习交流,禁止用于商业使用。
通过分析抓包请求,可以确定加密参数为 “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:d92cef65a435b35cd235883f4c65c5e1md5处理的字节必须是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_我想吃橘子味的橙子々编辑
,原因: