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();
|
解决方法就是如此简单,基础,却让我绕了一大圈弯路,不得不感叹,基础真重要啊!
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关键函数,很快的。
结合ida伪代码和sha256的伪代码,还原
sub_2636c
编排地址:
sub_2BD20
sub_25938
sub_120C4
至此,明文输入字符串的加密结果拿到
更多【某手新版本sig3参数算法还原】相关视频教程:www.yxfzedu.com