书接上回;
单词表
Line是使用两个 URL 来检索单词列表。如果使用非中文区域安装 LINE,则这些 URL 显然不会输入到设置数据库中,但可以在 LINE .apk 文件根部的 app-config.properties 文件中找到。这些 URL 自 v3.4.2 以来一直存在。
URL 及其内部描述是:
URL_CHINA_BAD_WORDS_INFO = http://line.naver.jp/app/resources/bwi
URL_CHINA_BAD_WORDS = https://line.naver.jp/app/resources/bwraw
文件 bwi 包含有关坏词文件版本的信息,其中包含一个如下所示的字符串:21,4320,v21,需要注意的事情是,如果没有上述 URL 中引用的内容,则无法通过 HTTP 直接访问该文件。用户代理字符串设置为“Android Mobile LA/xx”,其中 xx 是位置代码。但是,可以通过 HTTPS 访问它,无需 UA 字符串:
$ curl http://line.naver.jp/app/resources/bwi
<!DOCTYPE HTML PUBLIC “-//IETF//DTD HTML 2.0//EN”>
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href=”http://line.naver.jp/en”>here</a>.</p>
</body></html>$ curl -A ‘Android Mobile LA/UK’ http://line.naver.jp/app/resources/bwi
21,4320,v21,$ curl https://line.naver.jp/app/resources/bwi
21,4320,v21,
原始文件实际上并未托管在上述 URL 上;上面的文件名附加了版本号。例如,v21 文件托管在 https://line.naver.jp/app/resources/bwraw.v21。截至 2013 年 10 月 31 日,v21 和 v20 的文件可用。该文件可以在没有上述用户代理字符串的情况下通过 HTTPS 访问,也可以在有用户代理字符串的情况下通过 HTTP 访问。
坏词文件采用 Base64 编码,并使用 AES 在密码块链接 (CBC) 模式下使用 PCKS#7 填充进行加密。解密使用存储在二进制文件中的静态密钥:
private static final byte[] key = {
76, -86, -111, 47, -128, -21, 62, -44, 4, -91, 44, 60, 72, -46, 91, -42, -9, 46, -127, -110, -37, 85, -98, 73, -86, 27, -103, 103, -25, 81, 117, -89
}; public static String decrypt(String encryptedFile) { try { byte[] encryptedBytes = Base64encoder.decode(encryptedFile); SecretKeySpec secretKey = new SecretKeySpec(key, “AES”);
Cipher c = Cipher.getInstance(“AES/CBC/PKCS7Padding”);
c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[16])); String decryptedWords = new String(c.doFinal(encryptedBytes), “UTF-8”); return decryptedWords; }
作为参考,256 位 AES 密钥为:
4c aa 91 2f 80 eb 3e d4 04 a5 2c 3c 48 d2 5b d6
f7 2e 81 92 db 55 9e 49 aa 1b 99 67 e7 51 75 a7
坏词文件将以 cbw.dat 的形式存储在应用程序的缓存目录中。如果此列表不可用,LINE 将默认使用较小的内部列表:
private static Pattern g()
{
File localFile = new File(n.b().getApplicationContext().getCacheDir(), “cbw.dat”);
if (!localFile.exists())
try
{
Pattern localPattern2 = getInternalBadWords()1;
return localPattern2; } catch (bwd localbwd2) { a(“failed getDefaultWords”, localbwd2); return null; }
该应用程序还在下载的单词列表上设置偏好信息。10800000毫秒的延迟时间相当于3小时;
static void setWordListPreferences()
{
long l = System.currentTimeMillis();
SharedPreferences.Editor localEditor = bgb.a(bga.h).edit();
localEditor.putLong(“word_list_update_delay”, 10800000L); localEditor.putLong(“word_list_update_date”, l); localEditor.putLong(“word_list_version”, 0L);
localEditor.commit(); }
内部审查单词列表也使用相同的密钥进行 Base64 编码和加密,并且自 v3.4.2 引入以来一直保持不变:
5mxphvUu6sGOrG+Qw8EsqlMmx+kNh11mTfMLXZgNmxLfH4grWErsAEsqw+j34zUbdxDUiitSMr77CBwBdEojckjIHvdBPtRFduMb5TgvBjbtzmlXHN+UmUsDVmto7rMdCwP6+/AE zLmKB6GsAEs+3Q8xEtejCqdMnuU262feg4m5OrNxlgX3wpifO/+9Q9lm4KzHAhs7ZSGCOZbE2j6wPOTTMA6TXh9G1gA560ZjGNu+tLPJStUd08Kkw+AQvLl3ZSC3CexDT83D+FK1MYAUmfc 6BIGh/AalsSszJcLyatT7hRUpeNl0/3i+0z2vtEZxEO6SU4mempEnR9ErjGWLpUIbNdWxFVf32Le1UaLE000+fl0y06lopoFyGIjELHg+dbtmGFRMpxhmZauEFmkIeElCVctonsX1866+c3qXVf DnXZg30BXb9Octrytti5C81/P9M0yDrbtDod2IKX1k39IDrsdqTPUC3+TYyuAOACGnAN/FNkRQmeBbhzpY7Du2+F2fLm8QlFhm2MczaHyj9aDjMfUAEukNDtYi+Jj3MS+h8/F9FW3gMHjn eviLWBBe0fRJBbrxRvUKDtvS6vrMO/J2 +nxiz/3dBgkG2kXFR6Y9PfV7X0fmBW/ZZLM3MMUk8LMmAJIuhcaiKhaHg4721pXqT7v7U2FmHLLiKJIev4a0lG+bxg9nM2m9IcDRSq7Uca08JefErOSSUOWUoeWhNTtr1dhu07HgbhBaHx dHvurl9Ld+FHiKrJZNbZEnuNK5+xOrmBVemDc8untuB5IhotpDU3yAnZNmvZSDJ00/PH05jOCbf4SgW+rkVOjsgodSpljGar7OBSfGR+hMujN4gay3hHm9Ygg5zN8LlME31CCADlFRCixo0p3b3VxMlAvBHSRITE/B/QwxKsG/IY7y2LCu6wJrctgfPYW/px2ItSOnd4LtztEpCBhQT3/CZbO6c0OLWaDPufjnZYuyEXyA6677+aMCIAA0RpInRMmzw Yg7eG4PnuygTgDWhm6mc5C8Raz2teUysHhsIP26WAjdBQ+IPWgRvKLDzgpKaOI+moYqXarkTRBBdtMEOp4d4+sU953rE4i8sWtVHSzpV9sprJ5FgdayGOleKnZoy9GX1l38ey983hX8+LnM syVKpjw8I9NWCFdknigP9QvAAYaDAqE0g4Y0oD3G1YAikkHCV0Foc8lUww++9XpECxlED7znaF9USMeXV+ZyzRjztUk/kg==
仅当 LINE 设置中存储的区域为“CN”时,才会执行异常检查;
public static final boolean c()
{
add.a();
if (add.c());
String str;
do
{
return true;
add.a();
if (jl.d(add.a(cya.a)))
return false;
af localaf = b();
if (localaf == null)
break;
str = localaf.c();
}
while ((jl.d(str)) && (
Locale.CHINA.getCountry().equalsIgnoreCase(str)
)); return false; }
未完待续。。。。。