QQ表情-脏话bug漏洞

最近洗心革面,好像新学期伊始就能给人很大的力量,希望可以坚持~
今天看到一篇分析QQ表情bug的博客,记录一下学习过程,原博戳这里

1. bug

Android 7.6.0-7.6.3版本的QQ发送[菜刀]+数字+[表情]就会转换成脏话发出去.

2. 分析

(1)下载三个版本中任意一个版本,这里下载的是7.6.0。测试一下,[菜刀]+”1”+[心] 被转换为死胖子, [菜刀]+” “+[心] 被转换为 [跳舞]AmN you
(2)通过字符串搜索定位到com.tencent.mobilqq.lovelanguage.LoveLanguageConfig.class
title
(3)f9982a脏话的引用处:
a. public static String a(String str),将前6个char改变大小写,这也是为什么”damn you”被转为了”[跳舞]AmN you” 的一个原因。这个暂时没理清。
b. public static boolean m1991a(char c) ,看是否下标越界
c. public static String a(String str)中if (str4.equals(substring.toLowerCase())) 判断是否收到骂人的话,是的话就换成友好的表情
d. public int a(EditText editText) 似乎是判断是否发出骂人的话,是的话就换成友好的表情
e. public void m1994a(EditText editText) 判断是否输入0x11,a,b,c,是的话就替换为脏话
(4)LoveLanguageConfig中有两个对 char 的运算
title
分析一下, [菜刀]+”1”+[心] 被转换为死胖子, [菜刀]+” “+[心] 被转换为 [跳舞]AmN you 。而 “1”的ASCII码为49,” “的ASCII码是32,两者的差是 17,在数组中,死胖子和 damn you 的间隔也是 17。而 “ “与(char)30的差是2,2在数组中是”damn you”。所以这个运算就是将char和数组对应起来。
(5)LoveLanguageManager中的public int a(EditText editText)判断发出的话是否是脏话。
title
如果输入框内容发现有 ‘\x11’ + charA + charB + charC 这种格式的,调用 LoveLanguageConfig.a函数,进行转化后替换掉原来的文本,之后发出去。
绝大部分情况下,用户肯定不会输入 \x11 这个字符,所以猜测是[菜刀]表情编码中带有 \x11,然后拼接了后面的几个任意的 char,就会被替换成脏话。【后来发现菜刀确实是 \x14\x11组成的】
(6)LoveLanguageManager中的public void a(EditText editText)判断收到的话是否是脏话。验证一下猜想,输入 [菜刀]+”111” ,触发;输入 [菜刀]+1234567 ,发现123消失了。
(7)这里顺便贴一下原作者的xposed实验

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
ClassLoader loader = loadPackageParam.classLoader;
Log.d(TAG, "start hook");
XposedHelpers.findAndHookMethod("com.tencent.qphone.base.util.QLog", loader, "d", String.class, int.class, String.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
Log.d(TAG, param.args[0] + "\t" + param.args[2]);
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
}
});
XposedHelpers.findAndHookMethod("com.tencent.qphone.base.util.QLog", loader, "isColorLevel", new XC_MethodReplacement() {

@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
return true;
}
});

XposedHelpers.findAndHookMethod("com.tencent.mobileqq.lovelanguage.LoveLanguageManager", loader, "a", EditText.class, new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
return 0;
}
});


XposedHelpers.findAndHookMethod("com.tencent.mobileqq.lovelanguage.LoveLanguageManager", loader, "a", EditText.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);

Object obj = param.thisObject;
Method[] methods = obj.getClass().getDeclaredMethods();
for (Method m : methods) {
Log.e(TAG, m.toGenericString() + "===" + printHexString(m.getName()));
}

EditText editText = (EditText) param.args[0];
String s = editText.getText().toString();
Log.d(TAG, "input=" + s);
Log.d(TAG, "input=" + printHexString(s));
}

@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
EditText editText = (EditText) param.args[0];
String s = editText.getText().toString();
Log.d(TAG, "after=" + s);
Log.d(TAG, "after=" + printHexString(s));
}
});


Log.d(TAG, "end hook");

我们输入:[菜刀]1[心]的时候
输入输出的Log:

1
2
3
4
5
05-28 04:24:03.716 1511-1511/com.tencent.mobileqq D/LDB: input=1J
05-28 04:24:03.716 1511-1511/com.tencent.mobileqq D/LDB: input=141131144a
05-28 04:24:03.866 1511-1511/com.tencent.mobileqq D/LDB: LoveLanguageManager love language report 0X8009167
05-28 04:24:03.866 1511-1511/com.tencent.mobileqq D/LDB: after=死胖子
05-28 04:24:03.866 1511-1511/com.tencent.mobileqq D/LDB: after=14e6adbbe88396e5ad90

我们输入:[菜刀]123的时候

1
2
3
4
05-28 05:04:28.338 1511-1511/com.tencent.mobileqq D/LDB: input=123
05-28 05:04:28.338 1511-1511/com.tencent.mobileqq D/LDB: input=1411313233
05-28 05:04:28.347 1511-1511/com.tencent.mobileqq D/LDB: after=死胖子
05-28 05:04:28.347 1511-1511/com.tencent.mobileqq D/LDB: after=14e6adbbe88396e5ad90

我们输入:[菜刀]空格[心]的时候

1
2
3
4
05-28 05:11:06.107 1511-1511/com.tencent.mobileqq D/LDB: input= J
05-28 05:11:06.107 1511-1511/com.tencent.mobileqq D/LDB: input=141120144a
05-28 05:11:06.120 1511-1511/com.tencent.mobileqq D/LDB: after=dAmN you
05-28 05:11:06.120 1511-1511/com.tencent.mobileqq D/LDB: after=1464416d4e20796f75

(8)[菜刀]表情包含2个 char,是 \x14\x11 ,既然如此,这里又有一个细节,其实转化为脏话以后,第一个 char 还是保留着的,当它与字母拼接时,是可以组合成 QQ 快捷表情发出去的,比如[菜刀]+”9”+“gh”发出去就是[加油拳头]dIot。