这章主要介绍java层的hook,首先需要找到qq加密的函数在哪里,这里采用最简单的monitor的录制方法。
monitor是android sdk里面的一个小工具,就是之前的ddms,里面的录制调用的功能可以快速定位。
这里有一个疑问:为什么搜不到onClick的操作呢,没有的话他是通过什么实现的呢?有知道的评论一下呀,谢谢
定位之后发现了一个函数:com.tencent.qphone.base.util.CodecWarpper.nativeEncodeRequest
猜测这个函数就是最终的加密函数,通过jadx反编译qq的dex,找到该函数,是一个多态函数,有3中参数的可能。
这里不知道最终调用哪一种,所以3个都写了Hook,打印输出,判断出哪个被最终调用。
得到第二个是最常见的调用。故我们最终hook第二个。
这里然后打印即可得到加密前后的数据:可以看到最终发送的数据应该是携带版本号,qq号,以及该行为的类型的:第7和第15个参数是个数组,应该包含加密前明文,这里看介绍是使用了类似google的probuf的序列化操作,腾讯这里是jcestruct,过年前研究完了加上。
01-25 03:50:26.614 I/Xposed ( 6657): param1 = class java.lang.Integer data = 50538
01-25 03:50:26.617 I/Xposed ( 6657): param2 = class java.lang.String data = 312576676479927
01-25 03:50:26.617 I/Xposed ( 6657): param3 = class java.lang.String data =
01-25 03:50:26.617 I/Xposed ( 6657): param4 = class java.lang.String data = 7.9.7.390008
01-25 03:50:26.617 I/Xposed ( 6657): param5 = class java.lang.String data =
01-25 03:50:26.617 I/Xposed ( 6657): param6 before = class java.lang.String data = StatSvc.GetOnlineStatus
01-25 03:50:26.617 I/Xposed ( 6657): param7 before = class [B data = [B@b9790c9
01-25 03:50:26.617 I/Xposed ( 6657): param7 now= [-84, -19, 0, 5, 117, 114, 0, 2, 91, 66, -84, -13, 23, -8, 6, 8, 84, -32, 2, 0, 0, 120, 112, 0, 0, 0, 4, -52, 73, 124, -95]
01-25 03:50:26.617 I/Xposed ( 6657): param7 = ACED0005757200025B42ACF317F8060854E0020000787000000004CC497CA1
01-25 03:50:26.617 I/Xposed ( 6657): param8 = class java.lang.Integer data = 537060431
01-25 03:50:26.617 I/Xposed ( 6657): param9 = class java.lang.Integer data = 537060431
01-25 03:50:26.617 I/Xposed ( 6657): param10 = class java.lang.String data = 2100327022
01-25 03:50:26.617 I/Xposed ( 6657): param11 = class java.lang.Byte data = 0
01-25 03:50:26.617 I/Xposed ( 6657): param12 = class java.lang.Byte data = 1
01-25 03:50:26.617 I/Xposed ( 6657): param13 = class java.lang.Byte data = 1
01-25 03:50:26.617 I/Xposed ( 6657): param15 type = class [B
01-25 03:50:26.617 I/Xposed ( 6657): param15 before = [-84, -19, 0, 5, 117, 114, 0, 2, 91, 66, -84, -13, 23, -8, 6, 8, 84, -32, 2, 0, 0, 120, 112, 0, 0, 0, 12, 0, 0, 0, 12, 8, -18, -28, -63, -23, 7, 16, 0]
01-25 03:50:26.617 I/Xposed ( 6657): data = [B@21c13ce
01-25 03:50:26.617 I/Xposed ( 6657): param15 = [-84, -19, 0, 5, 117, 114, 0, 2, 91, 66, -84, -13, 23, -8, 6, 8, 84, -32, 2, 0, 0, 120, 112, 0, 0, 0, 12, 0, 0, 0, 12, 8, -18, -28, -63, -23, 7, 16, 0]
01-25 03:50:26.617 I/Xposed ( 6657): param14 before = null
01-25 03:50:26.617 I/Xposed ( 6657): param14 be error : java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference
01-25 03:50:26.618 I/Xposed ( 6657): hook nativeEncodeRequest afterok???
01-25 03:50:26.618 I/Xposed ( 6657): return now is : class [B[-84, -19, 0, 5, 117, 114, 0, 2, 91, 66, -84, -13, 23, -8, 6, 8, 84, -32, 2, 0, 0, 120, 112, 0, 0, 1, 60, 0, 0, 1, 60, 0, 0, 0, 10, 1, 0, 0, 0, 68, -99, 68, 46, -66, -78, 95, 57, -24, -40, -54, 78, -89, -110, -72, -77, -28, 11, 26, -68, -60, -58, -20, 75, -103, -32, -36, 0, 49, -68, 92, 118, 18, -2, -57, 92, -127, -109, 17, 78, 35, -6, 55, -82, -13, 123, -55, 104, -59, 61, 110, 82, -20, 15, -60, 35, 51, -52, -119, -78, -63, -107, -33, 16, 46, 0, 0, 0, 0, 14, 50, 49, 48, 48, 51, 50, 55, 48, 50, 50, -12, -116, 109, 94, 39, 10, 31, 13, -59, 110, -85, 84, -109, 98, -105, 26, -51, 73, 12, -117, 118, 77, 78, 74, 92, 57, 49, -61, 64, -18, 56, 100, 7, -66, 45, -128, 37, 76, -99, 118, -113, 102, 94, 117, -11, 45, 3, 106, -72, 19, 37, 52, -58, -116, 60, -2, -95, 92, 57, 13, 42, -128, 37, -99, 32, -11, -16, 28, 80, 51, 70, -28, 56, -61, -34, 18, -61, -10, -57, 83, 61, -29, -86, 116, 112, 34, 6, -94, 57, -57, 55, -79, 38, -53, 78, -58, 98, -18, 52, -58, -15, -98, -49, 73, 47, 23, -29, -74, -118, -16, -8, -103, 34, 9, -45, 87, 93, -105, -80, 103, 4, 82, -111, -128, 25, 68, 63, -101, 116, 113, 124, -122, 103, 92, 69, 111, 23, -98, 3, 0, 49, -98, 17, -7, -127, -63, 0, 55, 37, 90, 126, -125, 105, 115, 8, 32, -70, 64, -74, -89, -44, -67, 1, 5, -116, 32, 88, 42, 110, 5, -80, 120, 4, 15, 111, 9, 124, -80, 38, 57, 7, -23, 110, 124, 15, 57, -118, -76, 27, 48, 24, -114, -4, -12, -98, 44, -50, 47, -116, 124, -59, -47, 5, -110, 76, 68, -7, -27, -79, -38, 13, 81, -120, 13, 19, 63, 73, -77, 117, 76, -107, 10, 110, -120]
01-25 03:50:26.618 I/Xposed ( 6657): return is : ACED0005757200025B42ACF317F8060854E002000078700000013C0000013C0000000A01000000449D442EBEB25F39E8D8CA4EA792B8B3E40B1ABCC4C6EC4B99E0DC0031BC5C7612FEC75C8193114E23FA37AEF37BC968C53D6E52EC0FC42333CC89B2C195DF102E000000000E32313030333237303232F48C6D5E270A1F0DC56EAB549362971ACD490C8B764D4E4A5C3931C340EE386407BE2D80254C9D768F665E75F52D036AB8132534C68C3CFEA15C390D2A80259D20F5F01C503346E438C3DE12C3F6C7533DE3AA74702206A239C737B126CB4EC662EE34C6F19ECF492F17E3B68AF0F8992209D3575D97B0670452918019443F9B74717C86675C456F179E0300319E11F981C10037255A7E8369730820BA40B6A7D4BD01058C20582A6E05B078040F6F097CB0263907E96E7C0F398AB41B30188EFCF49E2CCE2F8C7CC5D105924C44F9E5B1DA0D51880D133F49B3754C950A6E88
这里不知道为什么第14个参数,jadx显示是个byte[]类型的入参,但是不管怎么打印都打印不出来,显示是个空指针。猜测是不是这个地方传递密钥,但是只有第一次有,后面没有了,真的就是只传递一个空指针了。但是这里加密函数应该是传密钥的呀。。
所以这两天还会接着分析一下so层的。
代码如下:
package com.example.liuti.hooksport;
import android.app.Application;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.util.Log;
import android.util.SparseArray;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
import static de.robv.android.xposed.XposedBridge.log;
import static de.robv.android.xposed.XposedHelpers.findClass;
public class HookSport implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
// filter
if (!loadPackageParam.packageName.equals("com.tencent.mobileqq")) {
return;
}
//
// XposedHelpers.findAndHookMethod("com.tencent.qphone.base.util.QLog",loadPackageParam.classLoader, "setManualLogLevel",int.class,new XC_MethodHook(){
// //进行hook操作
// protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
// param.setResult(true);
// log("hook setManualLogLevel ok");
//
// };
//
// });
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ClassLoader cl = ((Context)param.args[0]).getClassLoader();
Class> hookclass = null;
try {
hookclass = cl.loadClass("com.tencent.qphone.base.util.CodecWarpper");
log("hook CodecWarpper ok");
} catch (Exception e) {
return;
}
// XposedHelpers.findAndHookMethod(hookclass, "nativeOnReceData",byte[].class,new XC_MethodHook(){
// //进行hook操作
// protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// //param.setResult(true);
// log("hook nativeEncodeRequest ok");
//
// };
//
// });
XposedHelpers.findAndHookMethod(hookclass, "nativeEncodeRequest",int.class,String.class,String.class,String.class,String.class,String.class,byte[].class,int.class,int.class,String.class,byte.class,byte.class,byte[].class,byte[].class,boolean.class,new XC_MethodHook(){
//进行hook操作
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//param.setResult(true);
log("hook nativeEncodeRequest 1ok???");
//log("1" + param.args[2].toString());
};
});
XposedHelpers.findAndHookMethod(hookclass, "nativeEncodeRequest",int.class,String.class,String.class,String.class,String.class,String.class,byte[].class,int.class,int.class,String.class,byte.class,byte.class,byte.class,byte[].class,byte[].class,boolean.class,new XC_MethodHook(){
//进行hook操作
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//param.setResult(true);
log("hook nativeEncodeRequest 2ok???");
//log("param count = " + param.)
log("param1 = " + param.args[0].getClass() + " data = " + param.args[0].toString());
log("param2 = " + param.args[1].getClass() + " data = " + param.args[1].toString());
log("param3 = " + param.args[2].getClass() + " data = " + param.args[2].toString());
log("param4 = " + param.args[3].getClass() + " data = " + param.args[3].toString());
log("param5 = " + param.args[4].getClass() + " data = " + param.args[4].toString());
log("param6 before = " + param.args[5].getClass() + " data = " + param.args[5].toString());
//String param6 = ByteArrayToHexString(objectToByteArray(param.args[5]));
//log("param6 = " + param6);
try {
log("param7 before = " + param.args[6].getClass() + " data = " + param.args[6].toString());
} catch (Exception e) {
log("param7 be error : " + e.toString());
return;
}
try {
log("param7 now= " + Arrays.toString(objectToByteArray(param.args[6])));
String param7 = ByteArrayToHexString(objectToByteArray(param.args[6]));
log("param7 = " + param7);
} catch (Exception e) {
log("param7 error : " + e.toString());
return;
}
log("param8 = " + param.args[7].getClass() + " data = " + param.args[7].toString());
log("param9 = " + param.args[8].getClass() + " data = " + param.args[8].toString());
log("param10 = " + param.args[9].getClass() + " data = " + param.args[9].toString());
log("param11 = " + param.args[10].getClass() + " data = " + param.args[10].toString());
log("param12 = " + param.args[11].getClass() + " data = " + param.args[11].toString());
log("param13 = " + param.args[12].getClass() + " data = " + param.args[12].toString());
//String param13 = ByteArrayToHexString(objectToByteArray(param.args[12]));
//log("param13 = " + param13);
// try {
// log("param14 before = " + param.args[13].getClass());
// log(" data = " + param.args[13].toString());
// } catch (Exception e) {
// log("param14 be error : " + e.toString());
// return;
// }
// try {
// String param14 = Arrays.toString(objectToByteArray(param.args[13]));
// log("param14 = " + param14);
// } catch (Exception e) {
// log("param14 error : " + e.toString());
// return;
// }
try {
log("param15 type = " + param.args[14].getClass());
log("param15 before = " + Arrays.toString(objectToByteArray(param.args[14])));
log( " data = " + param.args[14].toString());
} catch (Exception e) {
log("param15 be error : " + e.toString());
return;
}
try {
String param15 = Arrays.toString(objectToByteArray(param.args[14]));
log("param15 = " + param15);
} catch (Exception e) {
log("param15 error : " + e.toString());
return;
}
try {
log("param14 before = " + param.args[13]);
log(param.args[13].toString());
log(" data = " + param.args[13].toString());
} catch (Exception e) {
log("param14 be error : " + e.toString());
return;
}
try {
String param14 = Arrays.toString(objectToByteArray(param.args[13]));
log("param14 = " + param14);
} catch (Exception e) {
log("param14 error : " + e.toString());
return;
}
};
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
//param.setResult(true);
log("hook nativeEncodeRequest afterok???");
String res = ByteArrayToHexString(objectToByteArray(param.getResult()));
log("return now is : " + param.getResult().getClass() + Arrays.toString(objectToByteArray(param.getResult())));
log("return is : " + res);
};
});
XposedHelpers.findAndHookMethod(hookclass, "nativeEncodeRequest",int.class,String.class,String.class,String.class,String.class,String.class,byte[].class,int.class,int.class,String.class,byte.class,byte.class,byte[].class,boolean.class,new XC_MethodHook(){
//进行hook操作
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
//param.setResult(true);
log("hook nativeEncodeRequest 3ok???");
//log("1" + param.args[2].toString());
};
});
}
});
}
private static String ByteArrayToHexString(byte[] bytes) {
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static byte[] objectToByteArray(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}
}
这个输出byte[]的方式,因为没学过java。。都是百度的,后面有时间还是要多补补基础知识呀。。关于byte[]打印有想法的欢迎留言呀。