当前位置: 首页 > news >正文

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

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了个对象传了进去,很快出现了报错:

对应汇编

 此处判断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.lryc.cn/news/188849.html

相关文章:

  • Linux 安全 - LSM机制
  • uni-app:实现简易自定义下拉列表
  • 排序算法——直接插入排序
  • 手动抄表和自动抄表优缺点对比
  • HiSilicon352 android9.0 emmc添加新分区
  • networkX-04-查找k短路
  • Linux虚拟机搭建RabbitMQ集群
  • C之fopen/fclose/fread/fwrite/flseek
  • 3D机器视觉:解锁未来的立体视野
  • 大端字节序存储 | 小端字节序存储介绍
  • ASP.Core3.1 WebAPI 发布到IIS
  • MyBatisPlus属性自动填充和乐观锁插件+查询删除操作+整合SpringBoot出现问题解决
  • 软件测试/测试开发丨App自动化—CSS 定位与原生定位
  • c语言:通讯录管理系统(文件版本)
  • Android Studio 配置Git SVN忽略文件
  • 独享IP地址的层级划分和管理:打造稳定高效的网络架构
  • js中async的作用
  • 什么是信创测试?信创测试工具有哪些?
  • 健康医疗类APP在高需求快速发展背景下,商业化如何快速破局增收?
  • java开源商城免费搭建 VR全景商城 saas商城 b2b2c商城 o2o商城 积分商城 秒杀商城 拼团商城 分销商城 短视频商城
  • k8spod就绪检查失败
  • 【数据结构】链表详解
  • STM32使用HAL库驱动DS18B20
  • echarts折线图设置背景颜色
  • spring boot+ vue+ mysql开发的一套厘米级高精度定位系统源码
  • 【初试396分】西北工业大学827学长经验分享
  • 【Qt之信号和槽】对象多层嵌套后,高效使用信号和槽
  • 搬砖日记:vue2 用require引入图片项目编译失败
  • 国内外都可以使用的【免费AI工具】,实用性满满
  • 银河麒麟服务器x86安装ntp客户端,并配置成功可以同步时间