qu头条qdata字段unidbg逆向
Java层
com.jifen.qukan.lib.report.ReportEncryptManager.encryptBodyMap
com.jifen.qukan.lib.report.ReportEncryptManager.encodeToString
com.inno.innosecure.InnoSecureMain.innoSecureEncodeV2
com.inno.innosecure.InnoSecureMain.secure
可以看到最后是在libInnoSecure.so
里。
hook看看数据
android hooking watch class_method com.inno.innosecure.InnoSecureUtils.secure --dump-args --dump-return
入参1是json数据,入参2是uuid,入参3,4是固定的(本机固定,不同设备未测试)。输出做个base64就是qdata
再用frida进行主动调用
function call_secure() {
var Inno = Java.use("com.inno.innosecure.InnoSecureUtils");
var p0 = "{\"name\":\"everhu\",\"version\":\"31061000\",\"OSVersion\":\"7.1.2\",\"dtu\":\"003\",\"network\":\"wifi\",\"versionName\":\"3.10.61.000.0927.1727\"}";
var p1 = "9ba5e613-ab5d-4835-b7fa-84582f19c46e";
var p2 = "3082021b30820184a0030201020204574beab6300d06092a864886f70d01010505003052310c300a06035504061303303231310b3009060355040813025348310b3009060355040713025348310b3009060355040a13025a48310b3009060355040b1302434e310e300c0603550403130551754b616e301e170d3136303533303037323433385a170d3431303532343037323433385a3052310c300a06035504061303303231310b3009060355040813025348310b3009060355040713025348310b3009060355040a13025a48310b3009060355040b1302434e310e300c0603550403130551754b616e30819f300d06092a864886f70d010101050003818d0030818902818100aa5bae49b771380e692444437b82b375cabdefb3f23307c29510653776b8e4115f776bea5eb6690285f97d4e6e8d0469e49f79ecba31e4b7fb85dd612ee6b27ef38502aa38d055ddad2aa7b52d19fb8d2aeeb59a830b91c341f1b467655e7313e9ff65feb6539bf1655f35a37e17faa94e506a08219df196730f45d9c1cd94d30203010001300d06092a864886f70d0101050500038181000e6cc9fb74aef11dd33d6603869a9db61b8dcedae77bc815433026693fe59fd4b75a3284170f8872737e55595c1fd40da3dfbe5ad8a4e96802f53637977f0eb6e9b0dc35161cbaed398b41ecd73c4009a1dae7bcb00b75c3f8d5792405bcc5e4602d9dff6a0dc4739240a3b42626f5efce4d7baea0fced2b13361cb4ded8ed0b";
var p3 = [-119,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,10,0,0,0,10,8,2,0,0,0,2,80,88,-22,0,0,1,110,73,68,65,84,120,1,0,31,0,-32,-1,0,120,-62,101,-43,-19,-94,64,70,-80,-72,-87,-101,-104,-27,-46,84,-80,13,-16,29,-96,95,67,-46,-26,122,-63,82,104,-114,0,31,0,-32,-1,0,106,99,-21,15,-31,94,-30,-51,-90,-62,118,-49,-8,-97,-22,36,-60,86,-51,0,0,29,-62,101,-43,-6,-94,64,70,49,0,31,0,-32,-1,0,-22,-87,-101,-104,-19,-46,84,-80,7,-54,29,-96,95,115,-46,-26,122,33,-81,104,-114,106,-23,-21,15,-31,-127,76,-51,-90,0,31,0,-32,-1,0,-62,32,-49,-8,-97,100,-88,-60,86,-51,0,0,90,0,-122,-109,-127,27,51,18,-122,-41,-35,-27,40,23,-20,-42,-40,98,0,31,0,-32,-1,0,-52,83,121,-87,97,21,37,-10,-17,63,110,19,86,114,-52,93,84,34,-24,-43,-29,50,23,-13,-29,11,30,-17,64,-65,0,31,0,-32,-1,0,-51,-109,-103,-45,-112,37,-105,102,-87,85,-13,50,22,92,-63,92,121,-27,-22,-37,101,-76,40,-112,49,-88,49,-11,-106,90,0,31,0,-32,-1,0,-114,-34,-72,118,-14,-42,118,-98,-10,-127,-24,120,46,11,78,-5,127,27,-25,-124,-66,-34,-17,-47,123,-90,96,113,-122,-67,0,31,0,-32,-1,0,70,46,92,-79,-108,-62,78,-86,38,10,-4,-3,-50,-34,-70,0,-73,59,82,-79,54,120,114,-105,-33,27,30,-9,-11,-48,0,31,0,-32,-1,0,124,48,-27,113,-51,-97,70,92,-35,39,98,25,30,-47,-43,29,-62,-73,105,-15,96,71,92,4,-54,39,-122,-88,48,-117,1,31,0,-32,-1,0,-103,-32,67,-62,-95,95,-106,-31,5,-44,-28,-7,25,41,112,-92,-59,-11,105,-127,-34,115,-87,-121,-88,118,-74,76,-22,27,-17,-86,-94,53,-55,-88,5,74,0,0,0,0,73,69,78,68,-82,66,96,-126];
var p4 = null;
var p5 = 0;
var ret = Inno.secure(p0, p1, p2, p3, p4, p5);
}
主动调用了2次,结果不一样,说明可能有时间戳或随机数参与计算。
unidbg实现
public class Qutoutiao extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
public static String pkgName = "com.jifen.qukan";
public static String apkPath = "unidbg-android/src/test/java/com/qutoutiao/qutoutiao31061.apk";
public static String soName = "InnoSecure";
public Qutoutiao() {
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName(pkgName).build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM(new File(apkPath));
vm.setJni(this);
vm.setVerbose(true);
DalvikModule dm = vm.loadLibrary(soName, true);
module = dm.getModule();
dm.callJNI_OnLoad(emulator);
}
public void call_secure() {
String p0 = "{\"name\":\"everhu\",\"version\":\"31061000\",\"OSVersion\":\"7.1.2\",\"dtu\":\"003\",\"network\":\"wifi\",\"versionName\":\"3.10.61.000.0927.1727\"}";
String p1 = "9ba5e613-ab5d-4835-b7fa-84582f19c46e";
String p2 = "3082021b30820184a0030201020204574beab6300d06092a864886f70d01010505003052310c300a06035504061303303231310b3009060355040813025348310b3009060355040713025348310b3009060355040a13025a48310b3009060355040b1302434e310e300c0603550403130551754b616e301e170d3136303533303037323433385a170d3431303532343037323433385a3052310c300a06035504061303303231310b3009060355040813025348310b3009060355040713025348310b3009060355040a13025a48310b3009060355040b1302434e310e300c0603550403130551754b616e30819f300d06092a864886f70d010101050003818d0030818902818100aa5bae49b771380e692444437b82b375cabdefb3f23307c29510653776b8e4115f776bea5eb6690285f97d4e6e8d0469e49f79ecba31e4b7fb85dd612ee6b27ef38502aa38d055ddad2aa7b52d19fb8d2aeeb59a830b91c341f1b467655e7313e9ff65feb6539bf1655f35a37e17faa94e506a08219df196730f45d9c1cd94d30203010001300d06092a864886f70d0101050500038181000e6cc9fb74aef11dd33d6603869a9db61b8dcedae77bc815433026693fe59fd4b75a3284170f8872737e55595c1fd40da3dfbe5ad8a4e96802f53637977f0eb6e9b0dc35161cbaed398b41ecd73c4009a1dae7bcb00b75c3f8d5792405bcc5e4602d9dff6a0dc4739240a3b42626f5efce4d7baea0fced2b13361cb4ded8ed0b";
byte[] barr = new byte[] {-119,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,10,0,0,0,10,8,2,0,0,0,2,80,88,-22,0,0,1,110,73,68,65,84,120,1,0,31,0,-32,-1,0,120,-62,101,-43,-19,-94,64,70,-80,-72,-87,-101,-104,-27,-46,84,-80,13,-16,29,-96,95,67,-46,-26,122,-63,82,104,-114,0,31,0,-32,-1,0,106,99,-21,15,-31,94,-30,-51,-90,-62,118,-49,-8,-97,-22,36,-60,86,-51,0,0,29,-62,101,-43,-6,-94,64,70,49,0,31,0,-32,-1,0,-22,-87,-101,-104,-19,-46,84,-80,7,-54,29,-96,95,115,-46,-26,122,33,-81,104,-114,106,-23,-21,15,-31,-127,76,-51,-90,0,31,0,-32,-1,0,-62,32,-49,-8,-97,100,-88,-60,86,-51,0,0,90,0,-122,-109,-127,27,51,18,-122,-41,-35,-27,40,23,-20,-42,-40,98,0,31,0,-32,-1,0,-52,83,121,-87,97,21,37,-10,-17,63,110,19,86,114,-52,93,84,34,-24,-43,-29,50,23,-13,-29,11,30,-17,64,-65,0,31,0,-32,-1,0,-51,-109,-103,-45,-112,37,-105,102,-87,85,-13,50,22,92,-63,92,121,-27,-22,-37,101,-76,40,-112,49,-88,49,-11,-106,90,0,31,0,-32,-1,0,-114,-34,-72,118,-14,-42,118,-98,-10,-127,-24,120,46,11,78,-5,127,27,-25,-124,-66,-34,-17,-47,123,-90,96,113,-122,-67,0,31,0,-32,-1,0,70,46,92,-79,-108,-62,78,-86,38,10,-4,-3,-50,-34,-70,0,-73,59,82,-79,54,120,114,-105,-33,27,30,-9,-11,-48,0,31,0,-32,-1,0,124,48,-27,113,-51,-97,70,92,-35,39,98,25,30,-47,-43,29,-62,-73,105,-15,96,71,92,4,-54,39,-122,-88,48,-117,1,31,0,-32,-1,0,-103,-32,67,-62,-95,95,-106,-31,5,-44,-28,-7,25,41,112,-92,-59,-11,105,-127,-34,115,-87,-121,-88,118,-74,76,-22,27,-17,-86,-94,53,-55,-88,5,74,0,0,0,0,73,69,78,68,-82,66,96,-126};
DvmClass clz = vm.resolveClass("com/inno/innosecure/InnoSecureUtils");
String methodSign = "secure(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;I)[B";
ByteArray ret = clz.callStaticJniMethodObject(emulator, methodSign,
new StringObject(vm, p0),
new StringObject(vm, p1),
new StringObject(vm, p2),
new ByteArray(vm, barr),
null,
null);
byte[] barr2 = ret.getValue();
byte[] barr3 = Base64.encodeBase64(barr2);
System.out.println(new String(barr3));
System.out.println(Arrays.toString(barr2));
}
public static void main(String[] args) {
Qutoutiao test = new Qutoutiao();
test.call_secure();
}
}
运行多次后,发现结果不变,和frida调用表现不一致。这是因为unidbg的种子是固定的,导致生成的随机数序列是固定的,进而导致结果是固定的。
固定随机数
ida跳转到0x5ead
innoSecure
innoSecure
函数有900行左右,把很多东西都塞到这里实现了,看起来又臭又长。
其中有个arc4random
函数,一看就是用于生成随机数的,hook它将随机数固定。
// fail
public void hook_libc() {
IHookZz hookZz = HookZz.getInstance(emulator);
hookZz.wrap(module.findSymbolByName("arc4random"), new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
ctx.setR0(1);
}
});
}
public static void main(String[] args) {
Qutoutiao test = new Qutoutiao();
test.hook_libc();
test.call_secure();
}
然后就报错了,跳转过去看看。
这个函数没有实现,这我也不会啊。。
换个思路,直接patch调用arc4random函数这条指令,将r0
设为1,相当于每次随机数函数的返回值为1。
public void patch() {
// mov r0,1
emulator.getMemory().pointer(module.base + 0x77e8).setInt(0, 0x0001f04f);
}
public static void main(String[] args) {
Qutoutiao test = new Qutoutiao();
test.patch();
test.call_secure();
}
结果出来了,之后的逆向将基于此结果。
固定随机数的好处就是每次输出都不会变,方便分析。而且我们能一眼看出哪个是随机数,做到心中有数。
分析输出
真正开始逆向之前看看输出的组成方式,base64解码看看输出。
可以大致看出输出由3部分组成,各部分用.
连接,第1部分是32位字符串,应该是个MD5;第2部分是base64之后的字符串,第3部分是乱码,应该是加密后的数据。
base64解码第2部分看看
比较容易构造。
第3部分的长度是147,比较奇怪,因为json数据的长度是125。AES,DES,RC4加密后都和这个长度搭不上边,可能还拼接了其他东西。
逆向
一个比较容易看出来的就是MD5,x22
对应update方法,x23
对应final方法。hook看看
public void hook_MD5() {
IHookZz hookZz = HookZz.getInstance(emulator);
hookZz.enable_arm_arm64_b_branch();
hookZz.wrap(module.base + 0x35EC + 1, new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer input = ctx.getPointerArg(1);
byte[] inputHex = input.getByteArray(0, ctx.getR2Int());
Inspector.inspect(inputHex, "Input(x22)");
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
}
});
hookZz.wrap(module.base + 0x3E10 + 1, new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer output = ctx.getR1Pointer();
ctx.push(output);
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer output = ctx.pop();
byte[] outputHex = output.getByteArray(0, 16);
Inspector.inspect(outputHex, "Output(x23)");
}
});
hookZz.disable_arm_arm64_b_branch();
}
public static void main(String[] args) {
Qutoutiao test = new Qutoutiao();
test.patch();
test.hook_MD5();
test.call_secure();
}
进行了两轮MD5,每轮的第1个调用是真实数据,其他是算法填充。cyberchef验证是标准MD5。
可以看到第二轮的MD5结果就是最后输出的第1部分。而第二次MD5输入的前面部分则是最后输出的第3部分的后面部分。
再看看第二轮MD5输入的后面32字节。可以看出偶数位拼接起来就是第一次MD5的输出,而奇数位反向拼接起来则是原始输入的第二个参数(去掉-
符号)。
至此,第1部分的计算方式已经出来了。
接下来先看看第3部分的后面部分的计算方式。
这个是AES的常量,从代码可以看出是CBC,进行了13+1=14
轮操作,所以应该是AES-CBC-256加密,key的长度位32。
由于实现的时候把大部分代码都写在一起了,没有一个函数入口来hook,得到输入,key,iv。因此只能分析代码,下断点看看对应的变量。
由于v112初始值为0,所以先进入else
语句
这里是输入与iv进行异或操作的地方,下断点看看。
emulator.attach().addBreakPoint(module.base+0x7F84);
由于之前固定了随机数,一眼就看出它是随机数,不需要继续往下分析了
从代码也能看出。
然后是key
同样下断点
emulator.attach().addBreakPoint(module.base+0x7F9C);
有了输出,key,iv,尝试解密看看
说明找的是对的。
固定住uuid和iv,更换输入的第一个参数,其他部分不变。此时有个取巧的方案,固定uuid和iv,这样剩下的就不用分析了。
继续分析key的来源
其中要关注的变量有v206, v191
,还有个常量innoSecureParityTable256
下断点看看
v206
之前讲过它的构成了。
v191
更换输入后发现它是不变的。
然后根据代码实现一下即可。
table = [
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1,
0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0,
0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1,
0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1,
0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1,
0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0,
0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1,
0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1,
0,
]
def make_key(v206):
# v206 = bytes.fromhex('70 6E C6 C4 3D 19 5C 2F DC 58 3F 84 A7 FA 97 B768 35 C9 48 6A 5D 1A AB 51 13 66 E6 24 A5 E7 9B')
v191 = bytes.fromhex('C2 65 D5 A2 40 46 A9 9B 98 D2 54 B0 1D A0 5F D2E6 7A 68 8E 6A EB 0F E1 CD A6 C2 CF F8 9F C4 56')
bucket = []
for j in range(32):
v67 = v206[j]
if table[v67] == 1:
v68 = 0
v69 = 8
while 1:
v70 = v67 >> v69
v69 -= 1
v68 = v68 | (((v70 ^ (v67 >> v69)) & 1) << v69)
if not v69:
break
# v68 = v67 ^ (v67 >> 1)
v71 = v191[j] ^ v68
else:
v72 = 0
v73 = 7
v74 = 0
for v72 in range(8):
v75 = ((v191[j] ^ 0xff) >> v73) & 1
v73 -= 1
v76 = v75 << v72
v72 += 1
v74 |= v76
# x = f'{v191[j] ^ 0xff:08b}'
# v74 = int(x[::-1], 2)
v71 = v67 ^ v74
bucket.append(v71)
print(bytes(bucket))
print(bytes(bucket).hex())
return bytes(bucket)
接下来是找输出的第3部分的前面部分,共19个字节。
先分析后16字节
v205
是iv
v208
是第一次MD5的结果。
然后实现一下即可
v201 = bytes(map(lambda x, y: ~(x ^ y) & 0xff, s0, iv))
接着分析前3个字节。
先看第1,第3个字节。
v201
正是后面的16字节,然后实现一下即可。
def calc_var(v201):
v43 = 15
v42 = 0
for v43 in range(15, -1, -1):
v45 = v201[15-v43]
v42 |= (((v45 >> 3) & 1) << v43)
print(v42)
print(hex(v42))
v47 = 16
v49 = 0
v46 = 0
v48 = 0
while 1:
v50 = v47 - 1
v51 = ((v42 >> v47) ^ (v42 >> (v47 - 1))) & 1
if v49 > 7:
v48 |= (v51 << v50)
else:
v46 |= (v51 << (v47 - 9))
v49 += 1
v47 -= 1
if not v50:
break
print(v46, hex(v46))
print(v48, hex(v48))
return v46, v48
最后分析第2个字节。
同样根据代码实现即可
n2 = -sum(v201) & 0xff
全部分析完了,最后把代码整合一下即可
unidbg代码
public class Qutoutiao extends AbstractJni {
private final AndroidEmulator emulator;
private final VM vm;
private final Module module;
public static String pkgName = "com.jifen.qukan";
public static String apkPath = "unidbg-android/src/test/java/com/qutoutiao/qutoutiao31061.apk";
public static String soName = "InnoSecure";
public Qutoutiao() {
emulator = AndroidEmulatorBuilder.for32Bit().setProcessName(pkgName).build();
Memory memory = emulator.getMemory();
memory.setLibraryResolver(new AndroidResolver(23));
vm = emulator.createDalvikVM(new File(apkPath));
vm.setJni(this);
vm.setVerbose(true);
DalvikModule dm = vm.loadLibrary(soName, true);
module = dm.getModule();
dm.callJNI_OnLoad(emulator);
}
public void patch() {
// mov r0,1
emulator.getMemory().pointer(module.base + 0x77e8).setInt(0, 0x0001f04f);
}
public void hook_libc() {
IHookZz hookZz = HookZz.getInstance(emulator);
hookZz.wrap(module.findSymbolByName("arc4random"), new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
ctx.setR0(1);
}
});
}
public void hook_MD5() {
IHookZz hookZz = HookZz.getInstance(emulator);
hookZz.enable_arm_arm64_b_branch();
hookZz.wrap(module.base + 0x35EC + 1, new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer input = ctx.getPointerArg(1);
byte[] inputHex = input.getByteArray(0, ctx.getR2Int());
Inspector.inspect(inputHex, "Input(x22)");
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
}
});
hookZz.wrap(module.base + 0x3E10 + 1, new WrapCallback<HookZzArm32RegisterContext>() {
@Override
public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer output = ctx.getR1Pointer();
ctx.push(output);
}
@Override
public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
Pointer output = ctx.pop();
byte[] outputHex = output.getByteArray(0, 16);
Inspector.inspect(outputHex, "Output(x23)");
}
});
hookZz.disable_arm_arm64_b_branch();
}
public void call_secure() {
String p0 = "{\"name\":\"everhu\",\"version\":\"31061000\",\"OSVersion\":\"7.1.2\",\"dtu\":\"003\",\"network\":\"wifi\",\"versionName\":\"3.10.61.000.0927.1727\"}";
String p1 = "9ba5e613-ab5d-4835-b7fa-84582f19c46e";
String p2 = "3082021b30820184a0030201020204574beab6300d06092a864886f70d01010505003052310c300a06035504061303303231310b3009060355040813025348310b3009060355040713025348310b3009060355040a13025a48310b3009060355040b1302434e310e300c0603550403130551754b616e301e170d3136303533303037323433385a170d3431303532343037323433385a3052310c300a06035504061303303231310b3009060355040813025348310b3009060355040713025348310b3009060355040a13025a48310b3009060355040b1302434e310e300c0603550403130551754b616e30819f300d06092a864886f70d010101050003818d0030818902818100aa5bae49b771380e692444437b82b375cabdefb3f23307c29510653776b8e4115f776bea5eb6690285f97d4e6e8d0469e49f79ecba31e4b7fb85dd612ee6b27ef38502aa38d055ddad2aa7b52d19fb8d2aeeb59a830b91c341f1b467655e7313e9ff65feb6539bf1655f35a37e17faa94e506a08219df196730f45d9c1cd94d30203010001300d06092a864886f70d0101050500038181000e6cc9fb74aef11dd33d6603869a9db61b8dcedae77bc815433026693fe59fd4b75a3284170f8872737e55595c1fd40da3dfbe5ad8a4e96802f53637977f0eb6e9b0dc35161cbaed398b41ecd73c4009a1dae7bcb00b75c3f8d5792405bcc5e4602d9dff6a0dc4739240a3b42626f5efce4d7baea0fced2b13361cb4ded8ed0b";
byte[] barr = new byte[] {-119,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,10,0,0,0,10,8,2,0,0,0,2,80,88,-22,0,0,1,110,73,68,65,84,120,1,0,31,0,-32,-1,0,120,-62,101,-43,-19,-94,64,70,-80,-72,-87,-101,-104,-27,-46,84,-80,13,-16,29,-96,95,67,-46,-26,122,-63,82,104,-114,0,31,0,-32,-1,0,106,99,-21,15,-31,94,-30,-51,-90,-62,118,-49,-8,-97,-22,36,-60,86,-51,0,0,29,-62,101,-43,-6,-94,64,70,49,0,31,0,-32,-1,0,-22,-87,-101,-104,-19,-46,84,-80,7,-54,29,-96,95,115,-46,-26,122,33,-81,104,-114,106,-23,-21,15,-31,-127,76,-51,-90,0,31,0,-32,-1,0,-62,32,-49,-8,-97,100,-88,-60,86,-51,0,0,90,0,-122,-109,-127,27,51,18,-122,-41,-35,-27,40,23,-20,-42,-40,98,0,31,0,-32,-1,0,-52,83,121,-87,97,21,37,-10,-17,63,110,19,86,114,-52,93,84,34,-24,-43,-29,50,23,-13,-29,11,30,-17,64,-65,0,31,0,-32,-1,0,-51,-109,-103,-45,-112,37,-105,102,-87,85,-13,50,22,92,-63,92,121,-27,-22,-37,101,-76,40,-112,49,-88,49,-11,-106,90,0,31,0,-32,-1,0,-114,-34,-72,118,-14,-42,118,-98,-10,-127,-24,120,46,11,78,-5,127,27,-25,-124,-66,-34,-17,-47,123,-90,96,113,-122,-67,0,31,0,-32,-1,0,70,46,92,-79,-108,-62,78,-86,38,10,-4,-3,-50,-34,-70,0,-73,59,82,-79,54,120,114,-105,-33,27,30,-9,-11,-48,0,31,0,-32,-1,0,124,48,-27,113,-51,-97,70,92,-35,39,98,25,30,-47,-43,29,-62,-73,105,-15,96,71,92,4,-54,39,-122,-88,48,-117,1,31,0,-32,-1,0,-103,-32,67,-62,-95,95,-106,-31,5,-44,-28,-7,25,41,112,-92,-59,-11,105,-127,-34,115,-87,-121,-88,118,-74,76,-22,27,-17,-86,-94,53,-55,-88,5,74,0,0,0,0,73,69,78,68,-82,66,96,-126};
DvmClass clz = vm.resolveClass("com/inno/innosecure/InnoSecureUtils");
String methodSign = "secure(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[BLjava/lang/String;I)[B";
ByteArray ret = clz.callStaticJniMethodObject(emulator, methodSign,
new StringObject(vm, p0),
new StringObject(vm, p1),
new StringObject(vm, p2),
new ByteArray(vm, barr),
null,
null);
byte[] barr2 = ret.getValue();
byte[] barr3 = Base64.encodeBase64(barr2);
System.out.println(new String(barr3));
System.out.println(Arrays.toString(barr2));
}
public static void main(String[] args) {
Qutoutiao test = new Qutoutiao();
test.patch();
test.hook_MD5();
test.call_secure();
}
}