[原创]某东 APP 逆向分析+ Unidbg 算法模拟
2023-3-11 13:22:56 Author: bbs.pediy.com(查看原文) 阅读量:222 收藏

首先我们发现京东的 sign32 位的,猜测其可能是 md5 之类的 hash 算法,既然是 hash 算法,那么就大概率会用到 getBytes 方法,我们首先 hook 一下 java.lang.StringgetBytes 方法,代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

uri = https://api.m.jd.com/client.action?functionId=getLegoWareDetailComment&lmt=0&clientVersion=11.6.4&build=98704&client=android&partner=tencent&oaid=1B4220DEA49487D7AF8DE6AF4C0F1F60F05819E2ADCC3CD2ACDF3C07D81BEDC6&eid=eidAf5088122acsfbxEYf1ulTs2pUn38cGRLh28RGgYgyPwz80gu9s7yfbXAvbZ1R70WQm1PENZaDGd6EF/munBEHRDWPW5sYgYPelPhS+vYueanoeJv&sdkVersion=29&lang=zh_CN&harmonyOs=0&networkType=wifi&uemps=2-2-2&ext=%7B%22prstate%22%3A%220%22%2C%22pvcStu%22%3A%221%22%2C%22cfgExt%22%3A%22%7B%5C%22privacyOffline%5C%22%3A%5C%220%5C%22%7D%22%7D&ef=1&ep=%7B%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22ts%22%3A1678345151525%2C%22ridx%22%3A-1%2C%22cipher%22%3A%7B%22area%22%3A%22CV83Cv8yDzu5XzK%3D%22%2C%22d_model%22%3A%22J05PUOnVU0O2CNKm%22%2C%22wifiBssid%22%3A%22dW5hbw93bq%3D%3D%22%2C%22osVersion%22%3A%22CJK%3D%22%2C%22d_brand%22%3A%22J25vUQn1cm%3D%3D%22%2C%22screen%22%3A%22CtO1EIenCNqm%22%2C%22uuid%22%3A%22ZtvwDNKnDzVsZtHtDtcnCK%3D%3D%22%2C%22aid%22%3A%22ZtvwDNKnDzVsZtHtDtcnCK%3D%3D%22%2C%22openudid%22%3A%22ZtvwDNKnDzVsZtHtDtcnCK%3D%3D%22%7D%2C%22ciphertype%22%3A5%2C%22version%22%3A%221.2.0%22%2C%22appname%22%3A%22com.jingdong.app.mall%22%7D&st=1678346289851&sign=4bcf4d55a72e4023eebcf2d80c0bac2c&sv=111

bArr string = {"category":"12218;12221;13554","commentNum":3,"isNew":"0","newTitle":null,"shadowMainSku":"0","shieldCurrentComment":"1","shopId":null,"shopType":"0","sku":"10064651465940","venderId":"12715063","wareType":"0"}

str  = application/x-www-form-urlencoded; charset=UTF-8

str2  = Post

= true

mapStr  = {"jdgs":"{\"b1\":\"a4574221-958f-4752-ba5b-40e53bed1c17\",\"b2\":\"3.1.4-grey_0\",\"b3\":\"2.0\",\"b4\":\"eDIaHBTaPBKuc86zzA+aq9kltjVpsfYK9uL9uBZTn64tmAtrIPjdnnSaRU5oYnqGZrpwAfVY8PxsVG6T0BM07qPisYg5ffIXkrDYnM9W1bnZyY9uOnXSCSgwMt369HcipuC56Bh3OoP2\/8dGTfb1IJTRCj8s5o12Js+W4id6RKGen4q52iF74F+bl3fA5Zsl2Z3fg96JTVf7nAAIDvXiJBacMEMzWVBblzJMwjNENwZs2SvOB\/b6XSr5lrdlAtHgSytyL7ME5ftn+flvL2nJwH3CQ7AanNGaKFCaZPzjV0sU3+Q29NONh1SBjFDMGX\/PgA9QZmrQj14raPf7w7t\/QsdjjBPix+jbGr5KuPGOVaVBWSKhzh0s3Wkqhe5PqkjkYOUM3DAFGb7d1fNTXlZJUsI8Dsqin8a\/iXLb4RU=\",\"b5\":\"a49356adf69f2937aa764b661c2982d202ec6003\",\"b7\":\"1678346289856\",\"b6\":\"3e5485b2ee5c1e3a55e6ab35606728264d787a0f\"}"}

使用 firda 重新加载 js 脚本后发现其返回值居然是请求头里面的 jdgs,并不是我们需要的 sign,并且里面的参数,也就是 uri 里面包含了我们需要的 sign 参数,所以 sign 应该是在获取 jdgs 之前就生成了!
图片描述

那么我们尝试定位上一级堆栈,也就是 com.jingdong.jdsdk.network.toolbox.HttpSettingTool.doSignUsingJdGuard ,源码如下:

我们可以发现此时的 uri 里面就有的 sign ,因此我们继续定位上层 com.jingdong.jdsdk.network.toolbox.ParamBuilderForJDMall.setupParams ,源码如下:

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

public static void setupParams(HttpRequest httpRequest) {

        String str;

        HttpSetting httpSetting = HttpSettingTool.setupBaseParams(httpRequest);

        HttpSettingTool.addGuardVerifyLmtCode(httpSetting);

        if (httpSetting.getCustomMapParam() == null || !httpSetting.getCustomMapParam().containsKey("uuid")) {

            str = "";

        } else {

            str = httpSetting.getCustomMapParam().get("uuid");

            httpSetting.getCustomMapParam().remove("uuid");

        }

        if (TextUtils.isEmpty(str) && httpSetting.getCustomEncryptMapParam() != null && httpSetting.getCustomEncryptMapParam().containsKey("uuid")) {

            str = httpSetting.getCustomEncryptMapParam().get("uuid");

            httpSetting.getCustomEncryptMapParam().remove("uuid");

        }

        if (TextUtils.isEmpty(str)) {

            str = JDHttpTookit.getEngine().getStatInfoConfigImpl().getDeviceUUID(httpSetting.getFunctionId(), httpSetting.isEnableEncryptTransmission());

        }

        if (TextUtils.isEmpty(str)) {

            str = "unknow";

        }

        if (OKLog.D) {

            String str2 = TAG;

            OKLog.d(str2, "id:" + httpSetting.getId() + "- uuid -->> " + str);

        }

        String bodyParam = HttpSettingTool.getBodyParam(httpSetting);

        if (httpSetting.getType() == 6000) {

            if (RuntimeConfigHelper.advertiseStatDataEnable()) {

                HttpSettingTool.addStatQueryParam(httpSetting, bodyParam, str);

            }

        } else {

            HttpSettingTool.addStatQueryParam(httpSetting, bodyParam, str);

        }

        HttpSettingTool.addCustomQueryParam(httpSetting);

        if (JDHttpTookit.getEngine().isNeedVerifySignature()) {

            JDHttpTookit.getEngine().getSignatureHandlerImpl().networkSettingsPreSignature();

            signature(httpSetting, bodyParam, str);

        }

        HttpSettingTool.doSignUsingJdGuard(httpSetting, bodyParam);

        JDHttpTookit.getEngine().getExternalDebugConfigImpl().addMockerIdName(httpSetting);

    }

发现这个函数是设置 httpSetting 的 参数的,貌似就是我们需要的!我们看一下有没有关键的代码!发现了这么一行代码:signature(httpSetting, bodyParam, str); ,很可疑,我们先来尝试 hook 验证加密入口是否正确,先尝试 hook 一下 com.jingdong.jdsdk.network.toolbox.ParamBuilderForJDMall.signature 这个函数吧,因为这个函数是没有返回值的,所以我们尝试输出一下调用前与调用后的 httpSettingurl 不就知道他有没有给 url 加上 sign 了吗?代码如下:

果然发现这就是关键入口,因为之前的 uri 里面是没有 sign 这个参数的,但是后面却有了,因此我们就追进去看看,发现了这么一行代码:String signature = JDHttpTookit.getEngine().getSignatureHandlerImpl().signature(JDHttpTookit.getEngine().getApplicationContext(), functionId, str, str2, property, versionName); ,继续跟进到 signature 里面去发现他只是一个接口,所以肯定有实现或者重载的地方!(这种情况,我们一般 hook 不到,因为位置不正确,实际调用的是其实现类的那个函数,不信你可以试试!)

那么我们应该如何找这个接口的实现呢?这边提供一个思路,因为实现的话肯定要使用同样的函数名,返回值以及参数,所以可以尝试直接搜索,例如当前函数定义为 String signature(Context context, String str, String str2, String str3, String str4, String str5);,那么我们就直接将这个作为关键字进行搜索(当然你也可以尝试查找用例,不过应该找不到)

再继续跟进去就能发现这个是一个 native 函数 (其实从名字就能看出来),所以 signjni 入口为:com.jingdong.common.utils.BitmapkitUtils.getSignFromJni

使用通用的办法找到 so 文件和函数签名:so 文件 libjdbitmapkit.so, 函数签名:getSignFromJni(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;hook 一下分析一下参数吧!

使用通用的办法找到 so 文件和函数签名:so 文件 libjdg.so, 函数签名:main(I[Ljava/lang/Object;)[Ljava/lang/Object;hook 一下分析一下参数吧!

发现报错了,是因为缺少环境问题,可以看到最底层的报错堆栈在 com.github.unidbg.linux.android.dvm.AbstractJni.getStaticObjectField,大概意思就是要找com/jingdong/common/utils/BitmapkitUtils这个类的 a 字段,但是找不到,所以报了上述的错误,那么我们就需要重写 getStaticObjectField 这个方法,将环境补充完毕,步骤如下:

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

@Override

public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {

    switch (signature) {

        case "android/content/Context->TELEPHONY_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.TELEPHONY_SERVICE);

        case "android/content/Context->WIFI_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.WIFI_SERVICE);

        case "android/content/Context->CONNECTIVITY_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.CONNECTIVITY_SERVICE);

        case "android/content/Context->ACCESSIBILITY_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.ACCESSIBILITY_SERVICE);

        case "android/content/Context->KEYGUARD_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.KEYGUARD_SERVICE);

        case "android/content/Context->ACTIVITY_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.ACTIVITY_SERVICE);

        case "android/content/Context->LOCATION_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.LOCATION_SERVICE);

        case "android/content/Context->WINDOW_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.WINDOW_SERVICE);

        case "android/content/Context->SENSOR_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.SENSOR_SERVICE);

        case "android/content/Context->UI_MODE_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.UI_MODE_SERVICE);

        case "android/content/Context->DISPLAY_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.DISPLAY_SERVICE);

        case "android/content/Context->AUDIO_SERVICE:Ljava/lang/String;":

            return new StringObject(vm, SystemService.AUDIO_SERVICE);

        case "java/lang/Void->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Void");

        case "java/lang/Boolean->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Boolean");

        case "java/lang/Byte->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Byte");

        case "java/lang/Character->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Character");

        case "java/lang/Short->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Short");

        case "java/lang/Integer->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Integer");

        case "java/lang/Long->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Long");

        case "java/lang/Float->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Float");

        case "java/lang/Double->TYPE:Ljava/lang/Class;":

            return vm.resolveClass("java/lang/Double");

    }

    throw new UnsupportedOperationException(signature);

}

重写这个方法,补充实现,我们查看 jadx 发现 a 这个字段是一个 android.app.Application (你也可以通过签名看出来),所以我们需要在 unidbg 里面构造出来。

拿目前需要补充的 android.app.Application 为例,通过搜索资料可知,Application 继承与 ContextWrapper, 而 ContextWrapper 又继承与 Context,所以在 unidbg 里面需要实现一个 Application,那么可以使用以下嵌套代码:

所以他找的好像是 apk 里面 META-INF 文件夹里面的 xxx.RSA , 我们只要使用压缩文件打开 apk 就可以看到一个叫做 JINGDONG.RSA 的文件,补全一下即可!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public void getSign() {

    DvmObject<?> context = vm.resolveClass("android/content/Context").newObject(null);

    String arg1 = "getLegoWareDetailComment";

    String arg2 = "{\"category\":\"12473;12480;12515\",\"commentNum\":3,\"isNew\":\"0\",\"newTitle\":null,\"shadowMainSku\":\"0\",\"shieldCurrentComment\":\"1\",\"shopId\":null,\"shopType\":\"0\",\"sku\":\"11653586880\",\"venderId\":\"644185\",\"wareType\":\"0\"}";

    String arg3 = "f9f40175bf4c6710";

    String arg4 = "android";

    String arg5 = "11.6.4";

    DvmObject<?> ret = module.callStaticJniMethodObject(emulator, "getSignFromJni(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", vm.addLocalObject(context), arg1, arg2, arg3, arg4, arg5

    );

    System.out.println("================================================");

    System.out.println(ret.getValue());

    System.out.println("================================================");

}

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

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

package com.jingdong.app.mall;

import com.github.unidbg.AndroidEmulator;

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

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.linux.android.dvm.jni.ProxyDvmObject;

import com.github.unidbg.memory.Memory;

import sun.security.pkcs.PKCS7;

import sun.security.pkcs.ParsingException;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.IOException;

import java.io.ObjectOutputStream;

import java.security.cert.X509Certificate;

public class signUtils extends AbstractJni {

    private final AndroidEmulator emulator;

    private final VM vm;

    // 包名

    private final String packageName = "com.com.jingdong.app.mall";

    // apk 地址

    private final String packagePath = "unidbg-android/src/test/resources/jd.apk";

    // so 名称, 要去掉 lib 和  .so

    private final String libraryName = "jdbitmapkit";

    // jni 类名

    private final String jniClassName = "com.jingdong.common.utils.BitmapkitUtils";

    // 调试信息

    private final Boolean verbose = true;

    // jni 模块

    private final DvmClass module;

    public signUtils() {

        // 实例化一个模拟器

        emulator = AndroidEmulatorBuilder

                .for32Bit()

                .addBackendFactory(new Unicorn2Factory(true))

                .setProcessName(packageName)

                .build();

        Memory memory = emulator.getMemory();

        memory.setLibraryResolver(new AndroidResolver(23));

        vm = emulator.createDalvikVM(new File(packagePath));

        vm.setJni(this);

        vm.setVerbose(verbose);

        DalvikModule dm = vm.loadLibrary(libraryName, true);

        module = vm.resolveClass(jniClassName);

        dm.callJNI_OnLoad(emulator);

    }

    public void getSign() {

        DvmObject<?> context = vm.resolveClass("android/content/Context").newObject(null);

        String arg1 = "getLegoWareDetailComment";

        String arg2 = "{\"category\":\"12473;12480;12515\",\"commentNum\":3,\"isNew\":\"0\",\"newTitle\":null,\"shadowMainSku\":\"0\",\"shieldCurrentComment\":\"1\",\"shopId\":null,\"shopType\":\"0\",\"sku\":\"11653586880\",\"venderId\":\"644185\",\"wareType\":\"0\"}";

        String arg3 = "f9f40175bf4c6710";

        String arg4 = "android";

        String arg5 = "11.6.4";

        DvmObject<?> ret = module.callStaticJniMethodObject(emulator, "getSignFromJni(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", vm.addLocalObject(context), arg1, arg2, arg3, arg4, arg5

        );

        System.out.println("================================================");

        System.out.println(ret.getValue());

        System.out.println("================================================");

    }

    public static void main(String[] args) {

        signUtils ins = new signUtils();

        ins.getSign();

    }

    @Override

    public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {

        switch (signature) {

            case "com/jingdong/common/utils/BitmapkitUtils->a:Landroid/app/Application;": {

                DvmClass Context = vm.resolveClass("android/content/Context");

                DvmClass ContextWrapper = vm.resolveClass("android/content/ContextWrapper", Context);

                // 使用 android/app/Application 发现会报错: com.github.unidbg.arm.backend.BackendException

                // 百度了一下发现这个错误是找不到 methodID

                // 因此可以使用 android/app/Activity 代替, 因为它也可以获取 Application 对象

                DvmClass Application = vm.resolveClass("android/app/Activity", ContextWrapper);

                return Application.newObject(signature);

            }

        }

        return super.getStaticObjectField(vm, dvmClass, signature);

    }

    @Override

    public DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {

        switch (signature) {

            case "android/content/pm/ApplicationInfo->sourceDir:Ljava/lang/String;": {

                return new StringObject(vm, "/data/app/com.jingdong.app.mall-Icn20e0xHLzrVHPBwOirRA==/bask.apk");

            }

        }

        return super.getObjectField(vm, dvmObject, signature);

    }

    @Override

    public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {

        switch (signature) {

            case "com/jingdong/common/utils/BitmapkitZip->unZip(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)[B": {

                StringObject apkPath = varArg.getObjectArg(0);

                StringObject directory = varArg.getObjectArg(1);

                StringObject filename = varArg.getObjectArg(2);

                if (

                        "/data/app/com.jingdong.app.mall-Icn20e0xHLzrVHPBwOirRA==/bask.apk".equals(apkPath.getValue())

                                && "META-INF/".equals(directory.getValue())

                                && ".RSA".equals(filename.getValue())

                ) {

                    byte[] data = vm.unzip("META-INF/JINGDONG.RSA");

                    return new ByteArray(vm, data);

                }

            }

            case "com/jingdong/common/utils/BitmapkitZip->objectToBytes(Ljava/lang/Object;)[B": {

                return new ByteArray(vm, objectToBytes(varArg.getObjectArg(0).getValue()));

            }

        }

        return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);

    }

    @Override

    public DvmObject<?> newObject(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {

        switch (signature) {

            case "sun/security/pkcs/PKCS7-><init>([B)V": {

                PKCS7 pkcs7 = null;

                try {

                    byte[] bArray = (byte[]) varArg.getObjectArg(0).getValue();

                    pkcs7 = new PKCS7(bArray);

                } catch (ParsingException e) {

                    e.printStackTrace();

                }

                DvmClass pkcs7Class = vm.resolveClass("sun/security/pkcs/PKCS7");

                return pkcs7Class.newObject(pkcs7);

            }

        }

        return super.newObject(vm, dvmClass, signature, varArg);

    }

    @Override

    public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {

        switch (signature) {

            case "sun/security/pkcs/PKCS7->getCertificates()[Ljava/security/cert/X509Certificate;": {

                PKCS7 pkcs7 = (PKCS7) dvmObject.getValue();

                X509Certificate[] x509Certificates = pkcs7.getCertificates();

                return ProxyDvmObject.createObject(vm, x509Certificates);

            }

        }

        return super.callObjectMethod(vm, dvmObject, signature, varArg);

    }

    public static byte[] objectToBytes(Object obj) {

        try {

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);

            objectOutputStream.writeObject(obj);

            objectOutputStream.flush();

            byte[] byteArray = byteArrayOutputStream.toByteArray();

            objectOutputStream.close();

            byteArrayOutputStream.close();

            return byteArray;

        } catch (IOException e2) {

            return null;

        }

    }

    @Override

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

        switch (signature) {

            case "java/lang/StringBuffer-><init>()V": {

                StringBuffer stringBuffer = new StringBuffer();

                return vm.resolveClass("java/lang/StringBuffer").newObject(stringBuffer);

            }

        }

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

    }

    @Override

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

        switch (signature) {

            case "java/lang/StringBuffer->append(Ljava/lang/String;)Ljava/lang/StringBuffer;": {

                StringBuffer stringBuffer = (java.lang.StringBuffer) dvmObject.getValue();

                DvmClass StringBuffer = vm.resolveClass("java/lang/StringBuffer");

                return StringBuffer.newObject(stringBuffer.append(vaList.getObjectArg(0).getValue()));

            }

            case "java/lang/Integer->toString()Ljava/lang/String;": {

                Integer value = (Integer) dvmObject.getValue();

                return vm.resolveClass("java/lang/String").newObject(value.toString());

            }

            case "java/lang/StringBuffer->toString()Ljava/lang/String;": {

                StringBuffer value = (StringBuffer) dvmObject.getValue();

                return vm.resolveClass("java/lang/String").newObject(value.toString());

            }

        }

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

    }

}

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

package com.jingdong.app.mall;

import com.github.unidbg.AndroidEmulator;

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

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.jni.ProxyDvmObject;

import com.github.unidbg.memory.Memory;

import java.io.File;

public class jdgs extends AbstractJni {

    private final AndroidEmulator emulator;

    private final VM vm;

    // 包名

    private final String packageName = "com.com.jingdong.app.mall";

    // apk 地址

    private final String packagePath = "unidbg-android/src/test/resources/jd.apk";

    // so 名称, 要去掉 lib 和  .so

    private final String libraryName = "jdg";

    // jni 类名

    private final String jniClassName = "com.jd.security.jdguard.core.Bridge";

    // 调试信息

    private final Boolean verbose = true;

    // jni 模块

    private final DvmClass module;

    public jdgs() {

        // 实例化一个模拟器

        emulator = AndroidEmulatorBuilder

                .for32Bit()

                .addBackendFactory(new Unicorn2Factory(true))

                .setProcessName(packageName)

                .build();

        Memory memory = emulator.getMemory();

        memory.setLibraryResolver(new AndroidResolver(23));

        vm = emulator.createDalvikVM(new File(packagePath));

        vm.setJni(this);

        vm.setVerbose(verbose);

        DalvikModule dm = vm.loadLibrary(libraryName, true);

        module = vm.resolveClass(jniClassName);

        dm.callJNI_OnLoad(emulator);

    }

    public static void main(String[] args) {

        jdgs ins = new jdgs();

        ins.getJdgs();

    }

    public void getJdgs() {

        Integer i2 = 101;

        String arr1 = "/client.action bef=1&bfa06501b64b4672e3b8645fd0ad54401e4786bd9efebc784fa483cf99bec2fd=&build=98704&client=android&clientVersion=11.6.4&ef=1&eid=eidAf5088122acsfbxEYf1ulTs2pUn38cGRLh28RGgYgyPwz80gu9s7yfbXAvbZ1R70WQm1PENZaDGd6EF%2FmunBEHRDWPW5sYgYPelPhS+vYueanoeJv&ep=%7B%22hdid%22%3A%22JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw%3D%22%2C%22ts%22%3A1678345151525%2C%22ridx%22%3A-1%2C%22cipher%22%3A%7B%22area%22%3A%22CV83Cv8yDzu5XzK%3D%22%2C%22d_model%22%3A%22J05PUOnVU0O2CNKm%22%2C%22wifiBssid%22%3A%22dW5hbw93bq%3D%3D%22%2C%22osVersion%22%3A%22CJK%3D%22%2C%22d_brand%22%3A%22J25vUQn1cm%3D%3D%22%2C%22screen%22%3A%22CtO1EIenCNqm%22%2C%22uuid%22%3A%22ZtvwDNKnDzVsZtHtDtcnCK%3D%3D%22%2C%22aid%22%3A%22ZtvwDNKnDzVsZtHtDtcnCK%3D%3D%22%2C%22openudid%22%3A%22ZtvwDNKnDzVsZtHtDtcnCK%3D%3D%22%7D%2C%22ciphertype%22%3A5%2C%22version%22%3A%221.2.0%22%2C%22appname%22%3A%22com.jingdong.app.mall%22%7D&ext=%7B%22prstate%22%3A%220%22%2C%22pvcStu%22%3A%221%22%2C%22cfgExt%22%3A%22%7B%5C%22privacyOffline%5C%22%3A%5C%220%5C%22%7D%22%7D&functionId=wareBusiness&harmonyOs=0&lang=zh_CN&lmt=0&networkType=wifi&oaid=1B4220DEA49487D7AF8DE6AF4C0F1F60F05819E2ADCC3CD2ACDF3C07D81BEDC6&partner=tencent&scval=10062561918391&sdkVersion=29&sign=68049b09fa2cb6111f9ab0209ea9412e&st=1678348533650&sv=100&uemps=2-2-2";

        String arr2 = "sdm845|-|OnePlus6|-|-|-|-|-|-|-|-|-|-|-|-|-|-§§0|1§§-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-§§-|115717931008§§-|-|1.0|-§§0|1|-|-|-|-|-|-|-|-|-§§OnePlus/OnePlus6/OnePlus6:10/QKQ1.190716.003/2107162030:user/release-keys/|-|-|1678344292938|-§§-|-|-|-|-|-|-";

        String arr3 = "eidAf5088122acsfbxEYf1ulTs2pUn38cGRLh28RGgYgyPwz80gu9s7yfbXAvbZ1R70WQm1PENZaDGd6EF/munBEHRDWPW5sYgYPelPhS+vYueanoeJv";

        String arr4 = "1.0";

        String arr5 = "83";

        Object[] arr = new Object[]{arr1.getBytes(), arr2, arr3, arr4, arr5};

        DvmObject<?> ret = module.callStaticJniMethodObject(emulator, "main(I[Ljava/lang/Object;)[Ljava/lang/Object;", i2, ProxyDvmObject.createObject(vm, arr));

        System.out.println("================================================");

        System.out.println(ret.getValue());

        System.out.println("================================================");

    }

}

模拟 jdgs 的时候不知道为什么会报这样一个错误,并且也没有堆栈,因为还是小白,暂时不知道如何解决
目前会导致获取到的结果拿不到,以后有思路了再来完善这一块!希望有大佬能指导一下,万分感谢!!
图片描述


文章来源: https://bbs.pediy.com/thread-276430.htm
如有侵权请联系:admin#unsafe.sh