首先我们发现京东的 sign
是 32
位的,猜测其可能是 md5
之类的 hash
算法,既然是 hash
算法,那么就大概率会用到 getBytes
方法,我们首先 hook
一下 java.lang.String
的 getBytes
方法,代码如下:
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
z
=
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
这个函数吧,因为这个函数是没有返回值的,所以我们尝试输出一下调用前与调用后的 httpSetting
的 url
不就知道他有没有给 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
函数 (其实从名字就能看出来),所以 sign
的 jni
入口为: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
的时候不知道为什么会报这样一个错误,并且也没有堆栈,因为还是小白,暂时不知道如何解决
目前会导致获取到的结果拿不到,以后有思路了再来完善这一块!希望有大佬能指导一下,万分感谢!!