某手新版本sig3参数算法还原

news/2024/12/23 4:17:29/

Frida Native层主动调用

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

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

export function callDoCommandNative(){ // jni方法复习

    Java.perform(function() {

        var base_addr = Module.findBaseAddress("libkwsgmain.so") || ptr(0x0);

        var real_addr = base_addr.add(0x41680)

        var docommand = new NativeFunction(real_addr, "pointer", ["pointer""pointer""int""pointer"]);

        var JNIEnv = Java.vm.getEnv();

        var Intger = Java.use("java.lang.Integer");

        var jstring = Java.use("java.lang.String");

        var Boolean = Java.use("java.lang.Boolean");

        var cla = JNIEnv.findClass("java/lang/Object");

        // args1:,d7b7d042-d4f2-4012-be60-d97ff2429c17,,,com.yxcorp.gifshow.App@27101bb,,'} data: None

        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();

        var context = currentApplication.getApplicationContext();

        log("context"+context)

        var input_1 = JNIEnv.newStringUtf('d7b7d042-d4f2-4012-be60-d97ff2429c17');

        var argList_0 = JNIEnv.newObjectArray(7, cla, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList_0, 0, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList_0, 1, input_1);

        JNIEnv.setObjectArrayElement(argList_0, 2, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList_0, 3, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList_0, 4, context.$h);

        JNIEnv.setObjectArrayElement(argList_0, 5, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList_0, 6, ptr(0x0));

        var point_0 = docommand(JNIEnv, ptr(0x0), 10412, argList_0); // 返回的是指针,通过cast转成java对象,从而读出来

        console.log("point_0: " + point_0);

        var s_0 = Java.cast(point_0, Java.use("java.lang.Object"));

        console.log("result: " + s_0);

        var argList = JNIEnv.newObjectArray(8, cla, ptr(0x0));

        var argList_1 = JNIEnv.newObjectArray(1, cla, ptr(0x0));

        var input0 = JNIEnv.newStringUtf('/rest/n/feed/selectionbb9caf23ee1fda57a6c167198aba919f');

        var input1 = JNIEnv.newStringUtf('d7b7d042-d4f2-4012-be60-d97ff2429c17');

        var input2 = Boolean.$new(false);

        var input2_2 = Boolean.$new(false);

        var input3 = Intger.$new(-1);

        var input5 = JNIEnv.newStringUtf("010a11c6-f2cb-4016-887d-0d958aef1534");

         

        JNIEnv.setObjectArrayElement(argList_1, 0, input0);

        JNIEnv.setObjectArrayElement(argList, 0, argList_1);

        JNIEnv.setObjectArrayElement(argList, 1, input1);

        JNIEnv.setObjectArrayElement(argList, 2, input3.$h);

        JNIEnv.setObjectArrayElement(argList, 3, input2.$h);

        JNIEnv.setObjectArrayElement(argList, 4, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList, 5, ptr(0x0));

        JNIEnv.setObjectArrayElement(argList, 6, input2_2.$h);

        JNIEnv.setObjectArrayElement(argList, 7, input5);

        var point = docommand(JNIEnv, ptr(0x0), 10418, argList); // 返回的是指针,通过cast转成java对象,从而读出来

        var s = Java.cast(point, Java.use("java.lang.Object")); // $className : java.lang.String

        console.log("result: " + s);

        console.log("result: " + Java.vm.tryGetEnv().getStringUtfChars(point).readCString());

    })

}

     

export function jniOnload(){

    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");

    if (android_dlopen_ext != null) {

        Interceptor.attach(android_dlopen_ext, {

            onEnter: function (args) {

                this.hook = false;

                var soName = args[0].readCString() || '';

                if (soName.indexOf("libkwsgmain.so") !== -1) {

                    this.hook = true;

                }

            },

            onLeave: function (retval) {

                if (this.hook) {

                    var jniOnload = Module.findExportByName("libkwsgmain.so""JNI_OnLoad") || ptr(0x0);

                    Interceptor.attach(jniOnload, {

                        onEnter: function (args) {

                            console.log("Enter Mtguard JNI OnLoad");

                        },

                        onLeave: function (retval) {

                            console.log("After Mtguard JNI OnLoad");

                            callDoCommandNative();

                            // hook_ks();

                        }

                    });

                }

            }

        });

    }

}

这里踩了一个坑,传入的对象数组里有个元素是context类型,打印出来是com.yxcorp.gifshow.App@b97f2c,所以想当然的就按这个类直接new了个对象传了进去,很快出现了报错:


这个报错让我百思不得其解,压根就没往context这块想,以为哪怕填个空指针都没问题的。

最后,用笨法frida hooknative层地址,打印定位,找到了如此地方:

此处判断X23的值是否为0,正常打印出来是/data/app/com.smile.gifmaker-q14Fo0PSb77vTIOM1-iEqQ==/base.apk,调用了getPackageCodePath 方法。 

这是一个context方法,那必须传入有效的context:

1

2

var currentApplication = Java.use("android.app.ActivityThread").currentApplication();

var context = currentApplication.getApplicationContext();

解决方法就是如此简单,基础,却让我绕了一大圈弯路,不得不感叹,基础真重要啊!

IDA静态分析

  • 花指令
    • 这块看龙哥的分析就好了,非常清晰

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

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

package com.smile.gifmaker3;

import com.github.unidbg.*;

import com.github.unidbg.Module;

import com.github.unidbg.arm.backend.Backend;

import com.github.unidbg.arm.backend.CodeHook;

import com.github.unidbg.arm.backend.UnHook;

import com.github.unidbg.arm.backend.UnicornBackend;

import com.github.unidbg.arm.context.Arm32RegisterContext;

import com.github.unidbg.arm.context.Arm64RegisterContext;

import com.github.unidbg.file.FileResult;

import com.github.unidbg.file.IOResolver;

import com.github.unidbg.file.linux.AndroidFileIO;

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.api.AssetManager;

import com.github.unidbg.linux.android.dvm.array.ArrayObject;

import com.github.unidbg.linux.android.dvm.wrapper.DvmBoolean;

import com.github.unidbg.linux.android.dvm.wrapper.DvmInteger;

import com.github.unidbg.memory.Memory;

import com.github.unidbg.pointer.UnidbgPointer;

import com.github.unidbg.spi.SyscallHandler;

import com.github.unidbg.utils.Inspector;

import com.github.unidbg.virtualmodule.android.AndroidModule;

import com.github.unidbg.virtualmodule.android.JniGraphics;

import com.sun.jna.Pointer;

import king.trace.GlobalData;

import king.trace.KingTrace;

import unicorn.Unicorn;

import unicorn.UnicornConst;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.PrintStream;

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.util.ArrayList;

import java.util.List;

public class kswgmain11420 extends AbstractJni implements IOResolver {

    private final AndroidEmulator emulator;

    private final VM vm;

    private final Module module;

    kswgmain11420() throws FileNotFoundException {

        // 创建模拟器实例,要模拟32位或者64位,在这里区分

        EmulatorBuilder<AndroidEmulator> builder = AndroidEmulatorBuilder.for64Bit().setProcessName("com.smile.gifmaker");

        emulator = builder.build();

        emulator.getSyscallHandler().setEnableThreadDispatcher(true);

        // 模拟器的内存操作接口

        final Memory memory = emulator.getMemory();

        // 设置系统类库解析

        memory.setLibraryResolver(new AndroidResolver(23));

        // 创建Android虚拟机

        // vm = emulator.createDalvikVM();

        vm = emulator.createDalvikVM(new File("unidbg-android\\src\\test\\java\\com\\smile\\gifmaker3\\1142064wei.apk"));

        // 设置是否打印Jni调用细节

        vm.setVerbose(true);

        new JniGraphics(emulator, vm).register(memory);

        new AndroidModule(emulator, vm).register(memory);

        vm.setJni(this);

        SyscallHandler<AndroidFileIO> handler = emulator.getSyscallHandler();

        handler.addIOResolver(this);

        // 加载libttEncrypt.so到unicorn虚拟内存,加载成功以后会默认调用init_array等函数

        DalvikModule dm = vm.loadLibrary(new File("unidbg-android\\src\\test\\java\\com\\smile\\gifmaker3\\libkwsgmain.so"), true);

        // 加载好的libttEncrypt.so对应为一个模块

        module = dm.getModule();

        // trace code

//        String traceFile = "unidbg-android\\src\\test\\java\\com\\smile\\gifmaker3\\sig3_jniOnload.trc";

//        GlobalData.ignoreModuleList.add("libc.so");

//        GlobalData.ignoreModuleList.add("libhookzz.so");

//        GlobalData.ignoreModuleList.add("libc++_shared.so");

//        emulator.traceCode(module.base, module.base+module.size).setRedirect(new PrintStream(new FileOutputStream(traceFile), true));

        dm.callJNI_OnLoad(emulator);

    }

    public static void main(String[] args) throws FileNotFoundException {

        kswgmain11420 kk = new kswgmain11420();

        kk.init_native();

        kk.get_NS_sig3();

    }

    public void init_native() throws FileNotFoundException {

        // trace code

//        String traceFile = "unidbg-android\\src\\test\\java\\com\\smile\\gifmaker3\\sig3_init_native.trc";

//        GlobalData.ignoreModuleList.add("libc.so");

//        GlobalData.ignoreModuleList.add("libhookzz.so");

//        GlobalData.ignoreModuleList.add("libc++_shared.so");

//        emulator.traceCode(module.base, module.base+module.size).setRedirect(new PrintStream(new FileOutputStream(traceFile), true));

        List<Object> list = new ArrayList<>(10);

        list.add(vm.getJNIEnv()); // 第一个参数是env

        DvmObject<?> thiz = vm.resolveClass("com/kuaishou/android/security/internal/dispatch/JNICLibrary").newObject(null);

        list.add(vm.addLocalObject(thiz)); // 第二个参数,实例方法是jobject,静态方法是jclass,直接填0,一般用不到。

        DvmObject<?> context = vm.resolveClass("com/yxcorp/gifshow/App").newObject(null); // context

        vm.addLocalObject(context);

        list.add(10412); //参数1

        StringObject appkey = new StringObject(vm,"d7b7d042-d4f2-4012-be60-d97ff2429c17"); // SO文件有校验

        vm.addLocalObject(appkey);

        DvmInteger intergetobj = DvmInteger.valueOf(vm, 0);

        vm.addLocalObject(intergetobj);

        list.add(vm.addLocalObject(new ArrayObject(intergetobj,appkey,intergetobj,intergetobj,context,intergetobj,intergetobj)));

        // 直接通过地址调用

        Number numbers = module.callFunction(emulator, 0x41680, list.toArray());

        System.out.println("numbers:"+numbers);

        DvmObject<?> object = vm.getObject(numbers.intValue());

        String result = (String) object.getValue();

        System.out.println("result:"+result);

    }

    @Override

    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {

        switch (signature) {

            case "com/yxcorp/gifshow/App->getPackageCodePath()Ljava/lang/String;": {

                return new StringObject(vm, "/data/app/com.smile.gifmaker-q14Fo0PSb77vTIOM1-iEqQ==/base.apk");

            }

            case "com/yxcorp/gifshow/App->getAssets()Landroid/content/res/AssetManager;": {

//                return new Long(vm, "3817726272");

                return new AssetManager(vm, signature);

            }

            case "com/yxcorp/gifshow/App->getPackageName()Ljava/lang/String;": {

                return new StringObject(vm, "com.smile.gifmaker");

            }

            case "com/yxcorp/gifshow/App->getPackageManager()Landroid/content/pm/PackageManager;": {

                DvmClass clazz = vm.resolveClass("android/content/pm/PackageManager");

                return clazz.newObject(signature);

            }

        }

        return super.callObjectMethodV(vm, dvmObject, signature, vaList);

    }

    @Override

    public boolean callBooleanMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {

        switch (signature) {

            case "java/lang/Boolean->booleanValue()Z":

                DvmBoolean dvmBoolean = (DvmBoolean) dvmObject;

                return dvmBoolean.getValue();

        }

        return super.callBooleanMethodV(vm, dvmObject, signature, vaList);

    }

    public String get_NS_sig3() throws FileNotFoundException {

        // trace code

//        String traceFile = "unidbg-android\\src\\test\\java\\com\\smile\\gifmaker3\\sig3_new.trc";

//        GlobalData.ignoreModuleList.add("libc.so");

//        GlobalData.ignoreModuleList.add("libhookzz.so");

//        GlobalData.ignoreModuleList.add("libc++_shared.so");

//        emulator.traceCode(module.base, module.base+module.size).setRedirect(new PrintStream(new FileOutputStream(traceFile), true));

        System.out.println("_NS_sig3 start");

        List<Object> list = new ArrayList<>(10);

        list.add(vm.getJNIEnv()); // 第一个参数是env

        DvmObject<?> thiz = vm.resolveClass("com/kuaishou/android/security/internal/dispatch/JNICLibrary").newObject(null);

        list.add(vm.addLocalObject(thiz)); // 第二个参数,实例方法是jobject,静态方法是jclass,直接填0,一般用不到。

        DvmObject<?> context = vm.resolveClass("com/yxcorp/gifshow/App").newObject(null); // context

        vm.addLocalObject(context);

        list.add(10418); //参数1

        StringObject urlObj = new StringObject(vm, "/rest/app/eshop/ks/live/item/byGuest6bcab0543b7433b6d0771892528ef686");

        vm.addLocalObject(urlObj);

        ArrayObject arrayObject = new ArrayObject(urlObj);

        StringObject appkey = new StringObject(vm,"d7b7d042-d4f2-4012-be60-d97ff2429c17");

        vm.addLocalObject(appkey);

        DvmInteger intergetobj = DvmInteger.valueOf(vm, -1);

        vm.addLocalObject(intergetobj);

        DvmBoolean boolobj = DvmBoolean.valueOf(vm, false);

        vm.addLocalObject(boolobj);

        StringObject appkey2 = new StringObject(vm,"7e46b28a-8c93-4940-8238-4c60e64e3c81");

        vm.addLocalObject(appkey2);

        list.add(vm.addLocalObject(new ArrayObject(arrayObject,appkey,intergetobj,boolobj,context,null,boolobj,appkey2)));

        // 直接通过地址调用

        Number numbers = module.callFunction(emulator, 0x41680, list.toArray());

        System.out.println("numbers:"+numbers);

        DvmObject<?> object = vm.getObject(numbers.intValue());

        String result = (String) object.getValue();

        System.out.println("result:"+result);

        return result;

    }

    @Override

    public FileResult resolve(Emulator emulator, String pathname, int oflags) {

        System.out.println("fuck:"+pathname);

        return null;

    }

    public String readStdString(Pointer strptr){

        Boolean isTiny = (strptr.getByte(0) & 1) == 0;

        if(isTiny){

            return strptr.getString(1);

        }

        return strptr.getPointer(emulator.getPointerSize()* 2L).getString(0);

    }

    @Override

    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {

        switch (signature) {

            case "com/kuaishou/android/security/internal/common/ExceptionProxy->getProcessName(Landroid/content/Context;)Ljava/lang/String;":

                return new StringObject(vm, "com.smile.gifmaker");

            case "com/meituan/android/common/mtguard/NBridge->getSecName()Ljava/lang/String;":

                return new StringObject(vm, "ppd_com.sankuai.meituan.xbt");

            case "com/meituan/android/common/mtguard/NBridge->getAppContext()Landroid/content/Context;":

                return vm.resolveClass("android/content/Context").newObject(null);

            case "com/meituan/android/common/mtguard/NBridge->getMtgVN()Ljava/lang/String;":

                return new StringObject(vm, "4.4.7.3");

            case "com/meituan/android/common/mtguard/NBridge->getDfpId()Ljava/lang/String;":

                return new StringObject(vm, "");

        }

        return super.callStaticObjectMethodV(vm, dvmClass, signature,vaList);

    }

}

这里也有一个小tips,让unidbg加载指定SO文件,如果这个SO有依赖其他的SO库,那么很有可能会加载失败。这个情况不同于直接加载apk文件里的so文件,那种情况下unidbg会帮我们自动去寻找需要的SO文件。这个情况下,我们只要把需要的SO文件提取出来,放在同一目录下即可。

  • trace code

    用去花后的so文件,trace关键函数,很快的。

SHA256还原

结合ida伪代码和sha256的伪代码,还原

  • 思路:先看iv和table,然后看明文编排,最后比对具体运算 ———— 龙哥语录
  • sha256算法基础

确定调用栈

  • [确定调用堆栈]
  • 找到sig3最先出现的地方
  • sub_2636c 编排地址:

 

  • sub_2BD20
  • sub_25938
  • sub_120C4

至此,明文输入字符串的加密结果拿到

拼接过程

  • 固定字符串
  • 随机字符串
    • 猜测是随机,进一步验证,追踪,在JNI_OnLoad里:
  • 明文字符加密结果
  • 时间戳
  • 固定字符串

 


http://www.ppmy.cn/news/1120575.html

相关文章

C语言-扫雷游戏的实现

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

基于若依ruoyi-nbcio增加flowable流程待办消息的提醒,并提供右上角的红字数字提醒(三)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 1、上一节说到RedisReceiver &#xff0c;这里有调用了NbcioRedisListener自定义业务监听&#xff0c;如下…

APP应用在Google Play上架/更新被拒的原因及解决方法汇总

Google Play商店作为全球发布Android应用的领先平台之一&#xff0c;吸引了数百万开发人员的关注。 然而&#xff0c;要在Google Play商店上架和更新应用并不容易。商店有严格的规定和审核政策&#xff0c;需要开发者遵守。 一、谷歌上架方式 1、NewUpdate 正式发布后最主流…

【MySQL】 MySQL的增删改查(进阶)--贰

文章目录 &#x1f6eb;新增&#x1f6ec;查询&#x1f334;聚合查询&#x1f6a9;聚合函数&#x1f388;GROUP BY子句&#x1f4cc;HAVING &#x1f38b;联合查询⚾内连接⚽外连接&#x1f9ed;自连接&#x1f3c0;子查询&#x1f3a1;合并查询 &#x1f3a8;MySQL的增删改查(…

Spring Security的使用

Spring Security是一个强大且灵活的安全框架&#xff0c;它为Spring应用程序提供身份验证、授权和安全性。Spring Security可以在Web和非Web应用程序中提供安全性。 以下是使用Spring Security的步骤&#xff1a; 在项目的pom.xml文件中添加Spring Security的依赖。 <dep…

Java零拷贝(一):从硬件到内核再到源码分析

&#xff08;笔记整理自b站小刘说源码课程&#xff09; 一、DMA 在没有DMA时&#xff1a;CPA首先将内存数据读到缓存&#xff0c;再写到网卡。这样做会降低CPU的速度至网卡层面。 当出现DMA时&#xff1a;首先进行一次CPU复制&#xff0c;将内存数据读到socket内核缓冲区&am…

基于PyTorch搭建FasterRCNN实现目标检测

基于PyTorch搭建FasterRCNN实现目标检测 1. 图像分类 vs. 目标检测 图像分类是一个我们为输入图像分配类标签的问题。例如&#xff0c;给定猫的输入图像&#xff0c;图像分类算法的输出是标签“猫”。 在目标检测中&#xff0c;我们不仅对输入图像中存在的对象感兴趣。我们还…

文件操作(1)

1. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失 了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久…