逆向解析 ColorOS 离线号码库 (一):12-Bit 极限压缩的归属地查询算法
0. 前言
最近在开发一个项目时,需要用到中国大陆电话号码归属地以及运营商查询的 API。在调研了网络上现有的 API 后,我发现它们要么存在严格的并发限制和 API Key 双重校验,要么底层的数据库不够完整和准确。
但我们平时使用的智能手机,在没有网络的情况下依然能在来电几毫秒内准确显示号码归属地,它们是如何做到的?与其依赖受限的网络 API,不如直接从手机系统自带的拨号软件中提取离线数据库。
1. 理论依据与通用架构
在原生的 Android 系统中,来电归属地等本土化功能其实比较薄弱。但国内的手机厂商(如 OPPO、小米、vivo 等)都基于此构建了一套非常成熟的 “本地离线查询 + 云端辅助” 机制。
这类系统实现“归属地与运营商”查找的通用技术架构一般如下:
a. 核心原理:基于“号段”的离线映射
中国大陆的手机号码分配有着严格的规律。通常,前 3 位决定了基础运营商,而前 7 位决定了具体的地级市归属地和运营商细分。厂商会在系统级的核心应用(如 ContactsProvider.apk 或独立的 Telephony 服务)中内置一个高度压缩的离线数据库(通常是 .db、.dat 格式或自定义的二进制文件)。
| 号段示例 (前7位) | 运营商 | 归属地 |
|---|---|---|
| 138 0010 | 中国移动 | 北京 |
| 186 0210 | 中国联通 | 上海 |
| 189 0200 | 中国电信 | 天津 |
b. 代码层面的查询流程
当我们在拨号盘输入号码,或者收到来电时,系统的跨进程查询流程通常如下:
- 提取特征:系统前端首先清洗输入的号码(去除
+86、空格、破折号等格式字符),然后截取前 7 位核心号段。 - IPC 跨进程通信:UI 层不会直接去读取底层离线文件,而是通过构建特定的
Uri,向系统的底层内容提供者(ContentProvider)发起查询请求。 - 底层解析返回:底层的服务应用接收到请求后,通过查表或特定算法解析二进制数据文件,将计算出的“归属地”和“运营商”字段打包,原路返回给 UI 层进行渲染显示。
2. 寻找并定位离线数据库
以我所使用的设备 OPPO Find X6(ColorOS 16.0 系统) 为例。
通过在系统中进行关键词检索,我很快定位到了专门负责处理归属地逻辑的系统应用——号码归属地 (com.oplus.phonenoareainquire)。幸运的是,作为系统内建的基础服务,该应用并未进行深度的加固或高强度混淆,这为我们的静态分析提供了极大的便利。
提取并解压该应用的 APK 文件后,在 /assets 目录下,我如愿以偿地找到了两个核心数据文件:
PhoneNumberData_3_1_0.dat(归属地数据库)CarrierData_1_0.dat(运营商数据库)
本节我们先将目光聚焦在归属地文件 PhoneNumberData_3_1_0.dat 上。
不出所料,使用普通的文本编辑器打开它后是一堆乱码。为了让系统在极短的时间内完成检索,厂商并没有使用纯文本或标准的 SQLite 格式,而是采用了一种自定义的高强度压缩二进制数据结构。
不过,通过分析文件底层的字节流,我们依然能窥探到一些明文线索:
- 文件头 (Header):文件最开头明文存储了一串数字
817820250424。在大多数安卓号段库中,这通常代表着数据库的版本号或最后更新的编译时间戳。 - 数据字典区 (Tail):在文件靠后的尾部数据区,清晰地暴露出了中国大陆的城市长途区号及地名(采用 GBK 编码)。例如:
010、020、021(分别对应北京、广州、上海),以及成百上千个地级市的区号。
3. 提取读取规则与字典表
既然无法直接阅读,那没招了,试试 Jadx 逆向吧。
在 Jadx 中全局搜索字符串 "PhoneNumberData_3_1_0.dat",很快定位到了负责初始化的 PhoneNoInquireDatabaseHelper.java 类。在它的 c() 方法中,揭示了文件头部的读取规则:
public void c(SQLiteDatabase sQLiteDatabase, String str) throws Throwable {17 collapsed lines
File fileA = b.a(PhoneNoInquireProvider.f300w); InputStream inputStreamOpen = this.f740d.getResources().getAssets().open("PhoneNumberData_3_1_0.dat"); FileOutputStream fileOutputStream = new FileOutputStream(fileA); byte[] bArr = new byte[102400]; Log.i("PhoneNoDbHelper", "copy PhoneNumberData.dat to /data/data/"); while (true) { int i3 = inputStreamOpen.read(bArr); if (i3 == -1) { break; } else { fileOutputStream.write(bArr, 0, i3); } } inputStreamOpen.close(); fileOutputStream.close(); FileInputStream fileInputStream = new FileInputStream(fileA); DataInputStream dataInputStream = new DataInputStream(a(fileInputStream)); byte[] bArr2 = new byte[12]; // 读取前 12 个字节作为版本号 int i4 = dataInputStream.read(bArr2, 0, 12); String str2 = new String(bArr2, "UTF-8"); // 对应我们看到的 817820250424 Log.i("PhoneNoDbHelper", "version =" + str2 + ", versionLength = " + i4);53 collapsed lines
try { ContentValues contentValues = new ContentValues(); contentValues.put("ver", str2); sQLiteDatabase.insert("version", null, contentValues); } catch (Exception e3) { Log.e("PhoneNoDbHelper", BuildConfig.FLAVOR + e3); } File fileA2 = b.a(PhoneNoInquireProvider.f301x); InputStream inputStreamOpen2 = this.f740d.getResources().getAssets().open("ExtendNumber.dat"); FileOutputStream fileOutputStream2 = new FileOutputStream(fileA2); while (true) { int i5 = inputStreamOpen2.read(bArr); if (i5 == -1) { break; } else { fileOutputStream2.write(bArr, 0, i5); } } inputStreamOpen2.close(); fileOutputStream2.close(); f(dataInputStream, sQLiteDatabase); File fileA3 = b.a(PhoneNoInquireProvider.f302y); InputStream inputStreamOpen3 = this.f740d.getResources().getAssets().open("city_name_table.txt"); FileOutputStream fileOutputStream3 = new FileOutputStream(fileA3); while (true) { int i6 = inputStreamOpen3.read(bArr); if (i6 == -1) { break; } else { fileOutputStream3.write(bArr, 0, i6); } } inputStreamOpen3.close(); fileOutputStream3.close(); d(sQLiteDatabase); try { h(sQLiteDatabase); } catch (Exception e4) { Log.e("PhoneNoDbHelper", "updateCityCode fail " + e4); } try { b.b(new File(PhoneNoInquireProvider.f303z)); OplusLocaleChangeJobIntentService.n(PhoneNumberAreaApplication.b("Multi_Language_Table.txt", PhoneNoInquireProvider.f303z), this.f740d, sQLiteDatabase, str); } catch (Exception e5) { try { OplusLocaleChangeJobIntentService.n(null, this.f740d, sQLiteDatabase, str + "-Exception"); } catch (Exception e6) { Log.e("PhoneNoDbHelper", "e = " + e6); } Log.e("PhoneNoDbHelper", "e = " + e5); } fileInputStream.close();}更关键的是用于解析字典表的 f() 方法。代码展示了它是如何通过跳过核心数据区,直接读取尾部的城市字典的:
private void f(DataInputStream dataInputStream, SQLiteDatabase sQLiteDatabase) throws IOException { byte[] bArr = new byte[2]; byte[] bArr2 = new byte[2000]; byte[] bArr3 = new byte[8000]; byte[] bArr4 = new byte[2000]; dataInputStream.skip(dataInputStream.available() - 12002); // 直接跳到文件末尾的倒数 12002 字节处 dataInputStream.read(bArr); // 数量标识 dataInputStream.read(bArr2); // 区号区 dataInputStream.read(bArr3); // 城市名区 dataInputStream.read(bArr4); // 扩展标记区4 collapsed lines
if (f738e) { Log.d("PhoneNoDbHelper", "cityNum:" + ((bArr[1] & 255) | (bArr[0] << 8))); } Log.d("PhoneNoDbHelper", "start insert areano_and_citynames table"); for (int i3 = 0; i3 < 400; i3++) { try { String strTrim = new String(bArr2, i3 * 5, 5).trim(); String strTrim2 = new String(bArr3, i3 * 20, 20, "gbk").trim();24 collapsed lines
if (strTrim.equals(BuildConfig.FLAVOR) && strTrim2.equals(BuildConfig.FLAVOR)) { break; } sQLiteDatabase.execSQL("insert into areano_and_citynames(areano,cityname) values ('" + strTrim + "','" + strTrim2 + "');"); } catch (Exception unused) { Log.e("PhoneNoDbHelper", "init database failed"); return; } } SharedPreferences.Editor editorEdit = this.f740d.getSharedPreferences("expand", 0).edit(); editorEdit.clear(); for (int i4 = 0; i4 < 1000; i4++) { int i5 = i4 * 2; int i6 = (bArr4[i5] & 255) << 8; int i7 = bArr4[i5 + 1] & 255; if (i6 == 0 && i7 == 0) { break; } editorEdit.putString(Integer.toString(i4), Integer.toString(i6 + i7)); } editorEdit.commit(); dataInputStream.close(); Log.d("PhoneNoDbHelper", "init database sucess"); }通过上述代码,我们可以清晰地得出尾部字典的结构:
bArr2:存放了 400 个区号,每个固定占 5 个字节(需执行.trim()去除空格)。bArr3:存放了 400 个城市名称,每个固定占 20 个字节(需使用GBK解码)。bArr4:1000 个 16 位的扩展号段标记。
遗憾的是,当试图查看最核心的查询方法 l() 和初始化号码树的方法 F() 时,Jadx 提示 Method dump skipped。由于方法体过长或逻辑过于复杂,反编译引擎放弃了转换。无奈之下,只能硬着头皮去阅读底层的 Smali 汇编指令。
4. 还原真正的核心号码映射
4.1 内存字典库初始化 (F() 方法)
.method public F()V .registers 20
move-object/from16 v1, p0
1303 collapsed lines
const-string v2, "expand"
const-string v3, " bytes"
const-string v4, "PhoneNumberData_3_1_0.dat"
const-string v5, "skip fail"
const-string v6, "Exception when close resfile "
const-string v7, "PhoneNoProvider"
.line 1 iget-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
if-nez v0, :cond_1a
.line 2 new-instance v0, Ljava/util/HashMap;
invoke-direct {v0}, Ljava/util/HashMap;-><init>()V
iput-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
goto :goto_1d
.line 3 :cond_1a invoke-virtual {v0}, Ljava/util/HashMap;->clear()V
:goto_1d const/4 v8, 0x0
const/16 v0, 0x82
move v9, v8
move v10, v9
:goto_22 const/16 v11, 0xa
if-ge v9, v11, :cond_3a
.line 4 iget-object v11, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
invoke-static {v0}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v12
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v13
invoke-virtual {v11, v12, v13}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
add-int/lit16 v10, v10, 0x2710
add-int/lit8 v9, v9, 0x1
add-int/lit8 v0, v0, 0x1
goto :goto_22
:cond_3a const/16 v0, 0x96
move v9, v8
:goto_3d if-ge v9, v11, :cond_53
.line 5 iget-object v12, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
invoke-static {v0}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v13
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v14
invoke-virtual {v12, v13, v14}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
add-int/lit16 v10, v10, 0x2710
add-int/lit8 v9, v9, 0x1
add-int/lit8 v0, v0, 0x1
goto :goto_3d
.line 6 :cond_53 iget-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
const-string v9, "188"
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v11
invoke-virtual {v0, v9, v11}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
add-int/lit16 v10, v10, 0x2710
.line 7 iget-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
const-string v9, "189"
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v11
invoke-virtual {v0, v9, v11}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
add-int/lit16 v10, v10, 0x2710
const/4 v9, -0x1
const v11, 0x19000
.line 8 :try_start_71 new-instance v12, Ljava/io/FileInputStream;
sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->w:Ljava/lang/String;
invoke-direct {v12, v0}, Ljava/io/FileInputStream;-><init>(Ljava/lang/String;)V :try_end_78 .catch Ljava/io/IOException; {:try_start_71 .. :try_end_78} :catch_20b .catch Ljava/lang/Exception; {:try_start_71 .. :try_end_78} :catch_1d4 .catchall {:try_start_71 .. :try_end_78} :catchall_1cf
.line 9 :try_start_78 invoke-virtual {v12}, Ljava/io/FileInputStream;->available()I
move-result v0 :try_end_7c .catch Ljava/io/IOException; {:try_start_78 .. :try_end_7c} :catch_1ca .catch Ljava/lang/Exception; {:try_start_78 .. :try_end_7c} :catch_115 .catchall {:try_start_78 .. :try_end_7c} :catchall_217
if-nez v0, :cond_11f
.line 10 :try_start_7e invoke-static {}, Landroid/os/SystemClock;->elapsedRealtime()J
move-result-wide v17
.line 11 new-instance v0, Ljava/io/File;
sget-object v13, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->w:Ljava/lang/String;
invoke-direct {v0, v13}, Ljava/io/File;-><init>(Ljava/lang/String;)V
.line 12 invoke-virtual {v0}, Ljava/io/File;->delete()Z
.line 13 invoke-virtual {v0}, Ljava/io/File;->createNewFile()Z
.line 14 new-instance v13, Ljava/io/FileOutputStream;
invoke-direct {v13, v0}, Ljava/io/FileOutputStream;-><init>(Ljava/io/File;)V :try_end_94 .catch Ljava/io/IOException; {:try_start_7e .. :try_end_94} :catch_119 .catch Ljava/lang/Exception; {:try_start_7e .. :try_end_94} :catch_115 .catchall {:try_start_7e .. :try_end_94} :catchall_217
:try_start_94 const-string v0, "copy PhoneNumberData.dat to /data/data/ again"
.line 15 invoke-static {v7, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
new-array v0, v11, [B
.line 16 invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;->getContext()Landroid/content/Context;
move-result-object v16
invoke-virtual/range {v16 .. v16}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;
move-result-object v16
invoke-virtual/range {v16 .. v16}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;
move-result-object v11
invoke-virtual {v11, v4}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
move-result-object v11 :try_end_ab .catch Ljava/io/IOException; {:try_start_94 .. :try_end_ab} :catch_111 .catch Ljava/lang/Exception; {:try_start_94 .. :try_end_ab} :catch_115 .catchall {:try_start_94 .. :try_end_ab} :catchall_217
.line 17 :goto_ab :try_start_ab invoke-virtual {v11, v0}, Ljava/io/InputStream;->read([B)I
move-result v14
if-eq v14, v9, :cond_b5
.line 18 invoke-virtual {v13, v0, v8, v14}, Ljava/io/FileOutputStream;->write([BII)V
goto :goto_ab
.line 19 :cond_b5 invoke-virtual {v13}, Ljava/io/OutputStream;->flush()V
.line 20 invoke-virtual {v13}, Ljava/io/FileOutputStream;->close()V :try_end_bb .catchall {:try_start_ab .. :try_end_bb} :catchall_103
.line 21 :try_start_bb invoke-virtual {v12}, Ljava/io/FileInputStream;->close()V :try_end_be .catch Ljava/lang/Exception; {:try_start_bb .. :try_end_be} :catch_bf .catchall {:try_start_bb .. :try_end_be} :catchall_103
goto :goto_d5
:catch_bf move-exception v0
move-object v14, v0
.line 22 :try_start_c1 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v15, "exception when close resFile "
invoke-virtual {v0, v15}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v14}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_d5 .catchall {:try_start_c1 .. :try_end_d5} :catchall_103
.line 23 :goto_d5 :try_start_d5 invoke-virtual {v11}, Ljava/io/InputStream;->close()V
.line 24 new-instance v14, Ljava/io/FileInputStream;
sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->w:Ljava/lang/String;
invoke-direct {v14, v0}, Ljava/io/FileInputStream;-><init>(Ljava/lang/String;)V :try_end_df .catch Ljava/io/IOException; {:try_start_d5 .. :try_end_df} :catch_111 .catch Ljava/lang/Exception; {:try_start_d5 .. :try_end_df} :catch_115 .catchall {:try_start_d5 .. :try_end_df} :catchall_217
.line 25 :try_start_df new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v11, "copySourceFile time = "
invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-static {}, Landroid/os/SystemClock;->elapsedRealtime()J
move-result-wide v11
sub-long v11, v11, v17
invoke-virtual {v0, v11, v12}, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I :try_end_f9 .catch Ljava/io/IOException; {:try_start_df .. :try_end_f9} :catch_fc .catch Ljava/lang/Exception; {:try_start_df .. :try_end_f9} :catch_1c0 .catchall {:try_start_df .. :try_end_f9} :catchall_207
move-object/from16 v16, v13
goto :goto_122
:catch_fc move-exception v0
move-object v9, v1
move-object v12, v14
move-object v1, v0
move-object v14, v13
goto/16 :goto_211
:catchall_103 move-exception v0
move-object v14, v0
if-eqz v11, :cond_110
.line 26 :try_start_107 invoke-virtual {v11}, Ljava/io/InputStream;->close()V :try_end_10a .catchall {:try_start_107 .. :try_end_10a} :catchall_10b
goto :goto_110
:catchall_10b move-exception v0
move-object v11, v0
:try_start_10d invoke-virtual {v14, v11}, Ljava/lang/Throwable;->addSuppressed(Ljava/lang/Throwable;)V
:cond_110 :goto_110 throw v14 :try_end_111 .catch Ljava/io/IOException; {:try_start_10d .. :try_end_111} :catch_111 .catch Ljava/lang/Exception; {:try_start_10d .. :try_end_111} :catch_115 .catchall {:try_start_10d .. :try_end_111} :catchall_217
:catch_111 move-exception v0
move-object v9, v1
move-object v14, v13
goto :goto_11c
:catch_115 move-exception v0
move-object v14, v12
goto/16 :goto_1d6
:catch_119 move-exception v0
move-object v9, v1
const/4 v14, 0x0
:goto_11c move-object v1, v0
goto/16 :goto_211
:cond_11f move-object v14, v12
const/16 v16, 0x0
.line 27 :goto_122 :try_start_122 new-instance v0, Ljava/io/DataInputStream;
invoke-direct {v1, v14}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->d(Ljava/io/InputStream;)Ljava/io/InputStream;
move-result-object v11
invoke-direct {v0, v11}, Ljava/io/DataInputStream;-><init>(Ljava/io/InputStream;)V
invoke-virtual {v1, v0}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->K(Ljava/io/DataInputStream;)V
.line 28 invoke-virtual {v14}, Ljava/io/FileInputStream;->getChannel()Ljava/nio/channels/FileChannel;
move-result-object v0
const-wide/16 v11, 0x0
invoke-virtual {v0, v11, v12}, Ljava/nio/channels/FileChannel;->position(J)Ljava/nio/channels/FileChannel; :try_end_137 .catch Ljava/io/IOException; {:try_start_122 .. :try_end_137} :catch_1c2 .catch Ljava/lang/Exception; {:try_start_122 .. :try_end_137} :catch_1c0 .catchall {:try_start_122 .. :try_end_137} :catchall_207
move v13, v10
const-wide/16 v9, 0x10
.line 29 :try_start_13a invoke-virtual {v14, v9, v10}, Ljava/io/FileInputStream;->skip(J)J
move-result-wide v0
cmp-long v9, v0, v11
if-lez v9, :cond_15a
.line 30 new-instance v9, Ljava/lang/StringBuilder;
invoke-direct {v9}, Ljava/lang/StringBuilder;-><init>()V
const-string v10, "skip "
invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v9, v0, v1}, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;
invoke-virtual {v9, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v9}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_15d
.line 31 :cond_15a invoke-static {v7, v5}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 32 :goto_15d invoke-virtual {v14}, Ljava/io/FileInputStream;->available()I
move-result v0
.line 33 invoke-virtual {v14}, Ljava/io/FileInputStream;->available()I
move-result v1
new-array v1, v1, [B :try_end_167 .catch Ljava/io/IOException; {:try_start_13a .. :try_end_167} :catch_1ba .catch Ljava/lang/Exception; {:try_start_13a .. :try_end_167} :catch_1c0 .catchall {:try_start_13a .. :try_end_167} :catchall_207
move-object/from16 v9, p0
:try_start_169 iput-object v1, v9, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->b:[B
move v1, v8
:goto_16c if-ge v1, v0, :cond_178
.line 34 iget-object v10, v9, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->b:[B
sub-int v11, v0, v1
invoke-virtual {v14, v10, v1, v11}, Ljava/io/FileInputStream;->read([BII)I
move-result v10
add-int/2addr v1, v10
goto :goto_16c
.line 35 :cond_178 invoke-virtual {v14}, Ljava/io/FileInputStream;->close()V
.line 36 invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;->getContext()Landroid/content/Context;
move-result-object v0
invoke-virtual {v0, v2, v8}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
move-result-object v0
.line 37 invoke-interface {v0}, Landroid/content/SharedPreferences;->getAll()Ljava/util/Map;
move-result-object v0
check-cast v0, Ljava/util/HashMap; :try_end_189 .catch Ljava/io/IOException; {:try_start_169 .. :try_end_189} :catch_1b8 .catch Ljava/lang/Exception; {:try_start_169 .. :try_end_189} :catch_1c0 .catchall {:try_start_169 .. :try_end_189} :catchall_207
move v1, v8
move v10, v13
.line 38 :goto_18b :try_start_18b invoke-virtual {v0}, Ljava/util/HashMap;->size()I
move-result v11
if-ge v1, v11, :cond_1a9
.line 39 invoke-static {v1}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v11
invoke-virtual {v0, v11}, Ljava/util/HashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
move-result-object v11
check-cast v11, Ljava/lang/String;
.line 40 iget-object v12, v9, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v13
invoke-virtual {v12, v11, v13}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; :try_end_1a4 .catch Ljava/io/IOException; {:try_start_18b .. :try_end_1a4} :catch_1b6 .catch Ljava/lang/Exception; {:try_start_18b .. :try_end_1a4} :catch_1c0 .catchall {:try_start_18b .. :try_end_1a4} :catchall_207
add-int/lit16 v10, v10, 0x2710
add-int/lit8 v1, v1, 0x1
goto :goto_18b
.line 41 :cond_1a9 :try_start_1a9 invoke-virtual {v14}, Ljava/io/FileInputStream;->close()V :try_end_1ac .catch Ljava/lang/Exception; {:try_start_1a9 .. :try_end_1ac} :catch_1ae
goto/16 :goto_393
:catch_1ae move-exception v0
move-object v1, v0
.line 42 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
goto :goto_1f8
:catch_1b6 move-exception v0
goto :goto_1c5
:catch_1b8 move-exception v0
goto :goto_1bd
:catch_1ba move-exception v0
move-object/from16 v9, p0
:goto_1bd move-object v1, v0
move v10, v13
goto :goto_1c6
:catch_1c0 move-exception v0
goto :goto_1d6
:catch_1c2 move-exception v0
move-object v9, v1
move v13, v10
:goto_1c5 move-object v1, v0
:goto_1c6 move-object v12, v14
move-object/from16 v14, v16
goto :goto_211
:catch_1ca move-exception v0
move-object v9, v1
move v13, v10
move-object v1, v0
goto :goto_210
:catchall_1cf move-exception v0
move-object v1, v0
const/4 v14, 0x0
goto/16 :goto_3af
:catch_1d4 move-exception v0
const/4 v14, 0x0
.line 43 :goto_1d6 :try_start_1d6 new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "Exception when load number data to cache "
invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_1ea .catchall {:try_start_1d6 .. :try_end_1ea} :catchall_207
if-eqz v14, :cond_393
.line 44 :try_start_1ec invoke-virtual {v14}, Ljava/io/FileInputStream;->close()V :try_end_1ef .catch Ljava/lang/Exception; {:try_start_1ec .. :try_end_1ef} :catch_1f1
goto/16 :goto_393
:catch_1f1 move-exception v0
move-object v1, v0
.line 45 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
:goto_1f8 invoke-virtual {v0, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
goto/16 :goto_393
:catchall_207 move-exception v0
move-object v1, v0
goto/16 :goto_3af
:catch_20b move-exception v0
move-object v9, v1
move v13, v10
move-object v1, v0
const/4 v12, 0x0
:goto_210 const/4 v14, 0x0
:goto_211 if-eqz v14, :cond_232
.line 46 :try_start_213 invoke-virtual {v14}, Ljava/io/FileOutputStream;->close()V :try_end_216 .catch Ljava/lang/Exception; {:try_start_213 .. :try_end_216} :catch_21c .catchall {:try_start_213 .. :try_end_216} :catchall_217
goto :goto_232
:catchall_217 move-exception v0
move-object v1, v0
move-object v14, v12
goto/16 :goto_3af
:catch_21c move-exception v0
move-object v11, v0
.line 47 :try_start_21e new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v13, "Exception when close tarFile in Exception "
invoke-virtual {v0, v13}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_232 .catchall {:try_start_21e .. :try_end_232} :catchall_217
:cond_232 :goto_232 const-string v11, "Exception when close tarFile "
if-eqz v12, :cond_254
.line 48 :try_start_236 invoke-virtual {v12}, Ljava/io/FileInputStream;->close()V :try_end_239 .catch Ljava/lang/Exception; {:try_start_236 .. :try_end_239} :catch_23e .catchall {:try_start_236 .. :try_end_239} :catchall_23a
goto :goto_254
:catchall_23a move-exception v0
move-object v1, v0
goto/16 :goto_394
:catch_23e move-exception v0
move-object v13, v0
.line 49 :try_start_240 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v15, "Exception when close resFile "
invoke-virtual {v0, v15}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v13}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
:cond_254 :goto_254 const-string v0, "IOException copySourceFile again"
.line 50 invoke-static {v7, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 51 new-instance v0, Ljava/io/File;
sget-object v13, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->w:Ljava/lang/String;
invoke-direct {v0, v13}, Ljava/io/File;-><init>(Ljava/lang/String;)V
.line 52 invoke-virtual {v0}, Ljava/io/File;->delete()Z
.line 53 invoke-virtual {v0}, Ljava/io/File;->createNewFile()Z
const-string v13, "IOException copy PhoneNumberData.dat to /data/data/ again"
.line 54 invoke-static {v7, v13}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 55 new-instance v13, Ljava/io/FileOutputStream;
invoke-direct {v13, v0}, Ljava/io/FileOutputStream;-><init>(Ljava/io/File;)V :try_end_270 .catch Ljava/lang/Exception; {:try_start_240 .. :try_end_270} :catch_340 .catchall {:try_start_240 .. :try_end_270} :catchall_23a
const v14, 0x19000
:try_start_273 new-array v0, v14, [B
.line 56 invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;->getContext()Landroid/content/Context;
move-result-object v14
invoke-virtual {v14}, Landroid/content/Context;->getResources()Landroid/content/res/Resources;
move-result-object v14
invoke-virtual {v14}, Landroid/content/res/Resources;->getAssets()Landroid/content/res/AssetManager;
move-result-object v14
invoke-virtual {v14, v4}, Landroid/content/res/AssetManager;->open(Ljava/lang/String;)Ljava/io/InputStream;
move-result-object v4
.line 57 :goto_285 invoke-virtual {v4, v0}, Ljava/io/InputStream;->read([B)I
move-result v14
const/4 v15, -0x1
if-eq v14, v15, :cond_290
.line 58 invoke-virtual {v13, v0, v8, v14}, Ljava/io/FileOutputStream;->write([BII)V
goto :goto_285
.line 59 :cond_290 invoke-virtual {v13}, Ljava/io/OutputStream;->flush()V
.line 60 invoke-virtual {v13}, Ljava/io/FileOutputStream;->close()V
.line 61 new-instance v14, Ljava/io/FileInputStream;
sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->w:Ljava/lang/String;
invoke-direct {v14, v0}, Ljava/io/FileInputStream;-><init>(Ljava/lang/String;)V :try_end_29d .catch Ljava/lang/Exception; {:try_start_273 .. :try_end_29d} :catch_33d .catchall {:try_start_273 .. :try_end_29d} :catchall_339
.line 62 :try_start_29d invoke-virtual {v14}, Ljava/io/FileInputStream;->getChannel()Ljava/nio/channels/FileChannel;
move-result-object v0
const-wide/16 v8, 0x0
invoke-virtual {v0, v8, v9}, Ljava/nio/channels/FileChannel;->position(J)Ljava/nio/channels/FileChannel;
move-object v15, v5
const-wide/16 v4, 0x10
.line 63 invoke-virtual {v14, v4, v5}, Ljava/io/FileInputStream;->skip(J)J
move-result-wide v4
cmp-long v0, v4, v8
if-lez v0, :cond_2c9
.line 64 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v8, " has skiped "
invoke-virtual {v0, v8}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v4, v5}, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;
invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_2cd
:cond_2c9 move-object v3, v15
.line 65 invoke-static {v7, v3}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 66 :goto_2cd invoke-virtual {v14}, Ljava/io/FileInputStream;->available()I
move-result v0
.line 67 invoke-virtual {v14}, Ljava/io/FileInputStream;->available()I
move-result v3
new-array v3, v3, [B
move-object/from16 v4, p0
iput-object v3, v4, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->b:[B
const/4 v3, 0x0
:goto_2dc if-ge v3, v0, :cond_2e8
.line 68 iget-object v5, v4, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->b:[B
sub-int v8, v0, v3
invoke-virtual {v14, v5, v3, v8}, Ljava/io/FileInputStream;->read([BII)I
move-result v5
add-int/2addr v3, v5
goto :goto_2dc
.line 69 :cond_2e8 invoke-virtual {v14}, Ljava/io/FileInputStream;->close()V
.line 70 invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;->getContext()Landroid/content/Context;
move-result-object v0
const/4 v3, 0x0
invoke-virtual {v0, v2, v3}, Landroid/content/Context;->getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;
move-result-object v0
.line 71 invoke-interface {v0}, Landroid/content/SharedPreferences;->getAll()Ljava/util/Map;
move-result-object v0
check-cast v0, Ljava/util/HashMap;
move v8, v3
.line 72 :goto_2fb invoke-virtual {v0}, Ljava/util/HashMap;->size()I
move-result v2
if-ge v8, v2, :cond_319
.line 73 invoke-static {v8}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v0, v2}, Ljava/util/HashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
move-result-object v2
check-cast v2, Ljava/lang/String;
.line 74 iget-object v3, v4, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v5
invoke-virtual {v3, v2, v5}, Ljava/util/HashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; :try_end_314 .catch Ljava/lang/Exception; {:try_start_29d .. :try_end_314} :catch_336 .catchall {:try_start_29d .. :try_end_314} :catchall_332
add-int/lit16 v10, v10, 0x2710
add-int/lit8 v8, v8, 0x1
goto :goto_2fb
.line 75 :cond_319 :try_start_319 invoke-virtual {v13}, Ljava/io/FileOutputStream;->close()V :try_end_31c .catch Ljava/lang/Exception; {:try_start_319 .. :try_end_31c} :catch_31d .catchall {:try_start_319 .. :try_end_31c} :catchall_207
goto :goto_370
:catch_31d move-exception v0
move-object v2, v0
.line 76 :try_start_31f new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_331 .catchall {:try_start_31f .. :try_end_331} :catchall_207
goto :goto_370
:catchall_332 move-exception v0
move-object v1, v0
move-object v12, v14
goto :goto_33b
:catch_336 move-exception v0
move-object v12, v14
goto :goto_33e
:catchall_339 move-exception v0
move-object v1, v0
:goto_33b move-object v14, v13
goto :goto_394
:catch_33d move-exception v0
:goto_33e move-object v14, v13
goto :goto_341
:catch_340 move-exception v0
.line 77 :goto_341 :try_start_341 new-instance v2, Ljava/lang/StringBuilder;
invoke-direct {v2}, Ljava/lang/StringBuilder;-><init>()V
const-string v3, "Exception again:"
invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_355 .catchall {:try_start_341 .. :try_end_355} :catchall_23a
if-eqz v14, :cond_36f
.line 78 :try_start_357 invoke-virtual {v14}, Ljava/io/FileOutputStream;->close()V :try_end_35a .catch Ljava/lang/Exception; {:try_start_357 .. :try_end_35a} :catch_35b .catchall {:try_start_357 .. :try_end_35a} :catchall_217
goto :goto_36f
:catch_35b move-exception v0
move-object v2, v0
.line 79 :try_start_35d new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_36f .catchall {:try_start_35d .. :try_end_36f} :catchall_217
:cond_36f :goto_36f move-object v14, v12
.line 80 :goto_370 :try_start_370 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v2, "IOException: "
invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I :try_end_384 .catchall {:try_start_370 .. :try_end_384} :catchall_207
if-eqz v14, :cond_393
.line 81 :try_start_386 invoke-virtual {v14}, Ljava/io/FileInputStream;->close()V :try_end_389 .catch Ljava/lang/Exception; {:try_start_386 .. :try_end_389} :catch_38a
goto :goto_393
:catch_38a move-exception v0
move-object v1, v0
.line 82 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
goto/16 :goto_1f8
:cond_393 :goto_393 return-void
:goto_394 if-eqz v14, :cond_3ae
.line 83 :try_start_396 invoke-virtual {v14}, Ljava/io/FileOutputStream;->close()V :try_end_399 .catch Ljava/lang/Exception; {:try_start_396 .. :try_end_399} :catch_39a .catchall {:try_start_396 .. :try_end_399} :catchall_217
goto :goto_3ae
:catch_39a move-exception v0
move-object v2, v0
.line 84 :try_start_39c new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
.line 85 :cond_3ae :goto_3ae throw v1 :try_end_3af .catchall {:try_start_39c .. :try_end_3af} :catchall_217
:goto_3af if-eqz v14, :cond_3c9
.line 86 :try_start_3b1 invoke-virtual {v14}, Ljava/io/FileInputStream;->close()V :try_end_3b4 .catch Ljava/lang/Exception; {:try_start_3b1 .. :try_end_3b4} :catch_3b5
goto :goto_3c9
:catch_3b5 move-exception v0
move-object v2, v0
.line 87 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v0, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v7, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
.line 88 :cond_3c9 :goto_3c9 throw v1.end method阅读 Smali 代码后发现,在 F() 方法中,系统构建了一个名为 this.a 的 HashMap。这个 Map 存放的是手机号前三位(基础号段)对应的内存基础偏移量。
代码通过循环,为 130-139、150-159 以及 188、189 等基础号段分配了递增的偏移值。例如:
130对应偏移量0131对应偏移量10000132对应偏移量20000
随后,它还会从尾部的扩展区中读取诸如 170、199 等较新的号段,并将它们同样补充进该 HashMap 中。
4.2 号段的数学映射模型 (l() 方法)
.method public l(Ljava/lang/String;)Landroid/database/Cursor; .registers 15
const-string v0, "10"
1009 collapsed lines
.line 1 invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v1
const-string v2, "PhoneNoProvider"
const/4 v3, 0x0
if-eqz v1, :cond_11
const-string p0, "phoneNo is empty return null "
.line 2 invoke-static {v2, p0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
return-object v3
:cond_11 const-string v1, "-"
const-string v4, ""
.line 3 invoke-virtual {p1, v1, v4}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object p1
const-string v5, " "
invoke-virtual {p1, v5, v4}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object p1
.line 4 invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v5
if-eqz v5, :cond_26
return-object v3
.line 5 :cond_26 iget-object v5, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->l:Ljava/util/ArrayList;
if-nez v5, :cond_30
.line 6 invoke-static {}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->i()Ljava/util/ArrayList;
move-result-object v5
iput-object v5, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->l:Ljava/util/ArrayList;
:cond_30 const/4 v5, 0x0
move v6, v5
.line 7 :goto_32 iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->l:Ljava/util/ArrayList;
invoke-virtual {v7}, Ljava/util/ArrayList;->size()I
move-result v7
if-ge v6, v7, :cond_6c
.line 8 iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->l:Ljava/util/ArrayList;
invoke-virtual {v7, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v7
check-cast v7, Ljava/lang/String;
invoke-virtual {p1, v7}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v7
if-eqz v7, :cond_69
.line 9 new-instance v7, Ljava/lang/StringBuilder;
invoke-direct {v7}, Ljava/lang/StringBuilder;-><init>()V
const-string v8, "+"
invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
iget-object v8, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->l:Ljava/util/ArrayList;
invoke-virtual {v8, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v8
check-cast v8, Ljava/lang/String;
invoke-virtual {v8}, Ljava/lang/String;->length()I
move-result v8
invoke-virtual {p1, v8}, Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object p1
invoke-virtual {v7, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v7}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p1
:cond_69 add-int/lit8 v6, v6, 0x1
goto :goto_32
.line 10 :cond_6c iget-object v6, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
if-nez v6, :cond_7a
.line 11 invoke-virtual {p0}, Landroid/content/ContentProvider;->getContext()Landroid/content/Context;
move-result-object v6
invoke-static {v6}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->x(Landroid/content/Context;)Ljava/util/ArrayList;
move-result-object v6
iput-object v6, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
:cond_7a move v6, v5
.line 12 :goto_7b iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
invoke-virtual {v7}, Ljava/util/ArrayList;->size()I
move-result v7
const/4 v8, 0x1
if-ge v6, v7, :cond_13f
.line 13 iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
invoke-virtual {v7, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v7
check-cast v7, Ljava/lang/String;
invoke-virtual {p1, v7}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v7
if-eqz v7, :cond_13b
.line 14 iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
invoke-virtual {v7, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v7
check-cast v7, Ljava/lang/String;
invoke-virtual {v7}, Ljava/lang/String;->length()I
move-result v7
invoke-virtual {p1, v7}, Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object p1
.line 15 invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v7
if-nez v7, :cond_13f
iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
.line 16 invoke-virtual {v7, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v7
check-cast v7, Ljava/lang/String;
const-string v9, "+86"
invoke-virtual {v7, v9}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v7
if-nez v7, :cond_c8
iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->k:Ljava/util/ArrayList;
invoke-virtual {v7, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v6
check-cast v6, Ljava/lang/String;
const-string v7, "0086"
invoke-virtual {v6, v7}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v6
if-eqz v6, :cond_13f
:cond_c8 invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v6
const/4 v7, 0x6
if-lt v6, v7, :cond_13f
move v6, v5
.line 17 :goto_d0 :try_start_d0 iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->i:Ljava/util/ArrayList;
invoke-virtual {v7}, Ljava/util/ArrayList;->size()I
move-result v7
if-ge v6, v7, :cond_112
.line 18 iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->i:Ljava/util/ArrayList;
invoke-virtual {v7, v6}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v7
check-cast v7, Ljava/lang/String;
.line 19 invoke-static {v7}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v9
if-nez v9, :cond_fc
invoke-virtual {v7, v0}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v9
if-eqz v9, :cond_fc
.line 20 invoke-virtual {p1, v7}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v7
if-eqz v7, :cond_fc
invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v7 :try_end_f6 .catch Ljava/lang/Exception; {:try_start_d0 .. :try_end_f6} :catch_ff
const/16 v9, 0xa
if-eq v7, v9, :cond_fc
move v6, v5
goto :goto_113
:cond_fc add-int/lit8 v6, v6, 0x1
goto :goto_d0
:catch_ff move-exception v6
.line 21 new-instance v7, Ljava/lang/StringBuilder;
invoke-direct {v7}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v7, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v7, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v7}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v6
invoke-static {v2, v6}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
:cond_112 move v6, v8
:goto_113 const-string v7, "0"
if-eqz v6, :cond_11d
.line 22 invoke-virtual {p1, v0}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v0
if-nez v0, :cond_12b
.line 23 :cond_11d invoke-virtual {p1, v7}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v0
if-nez v0, :cond_13f
const-string v0, "1"
invoke-virtual {p1, v0}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v0
if-nez v0, :cond_13f
.line 24 :cond_12b new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v0, v7}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p1
goto :goto_13f
:cond_13b add-int/lit8 v6, v6, 0x1
goto/16 :goto_7b
.line 25 :cond_13f :goto_13f invoke-static {p1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v0
const/16 v6, 0x30
const/4 v7, 0x2
const/4 v9, 0x3
if-nez v0, :cond_161
invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
if-le v0, v9, :cond_161
const-string v0, "01"
.line 26 invoke-virtual {p1, v0}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v0
if-eqz v0, :cond_161
invoke-virtual {p1, v7}, Ljava/lang/String;->charAt(I)C
move-result v0
if-eq v0, v6, :cond_161
.line 27 invoke-virtual {p1, v8}, Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object p1
:cond_161 if-eqz p1, :cond_32e
.line 28 invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
if-nez v0, :cond_16b
goto/16 :goto_32e
.line 29 :cond_16b :try_start_16b invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
move v10, v5
:goto_170 const/4 v11, 0x7
if-ge v10, v0, :cond_186
if-ge v10, v11, :cond_186
const-string v11, "0123456789-"
.line 30 invoke-virtual {p1, v10}, Ljava/lang/String;->charAt(I)C
move-result v12
invoke-virtual {v11, v12}, Ljava/lang/String;->indexOf(I)I
move-result v11
const/4 v12, -0x1
if-ne v11, v12, :cond_183
return-object v3
:cond_183 add-int/lit8 v10, v10, 0x1
goto :goto_170
.line 31 :cond_186 invoke-virtual {p1, v1, v4}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object p1
.line 32 invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
if-nez v0, :cond_196
const-string p0, "Regular telephone number\'s length is 0 return"
.line 33 invoke-static {v2, p0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
return-object v3
.line 34 :cond_196 invoke-virtual {p1, v5}, Ljava/lang/String;->charAt(I)C
move-result v0
const/16 v1, 0x31
const/4 v10, 0x4
if-ne v0, v6, :cond_1d5
.line 35 invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
if-ge v0, v9, :cond_1a6
return-object v3
.line 36 :cond_1a6 invoke-virtual {p1, v8}, Ljava/lang/String;->charAt(I)C
move-result v0
if-eq v0, v1, :cond_1c1
invoke-virtual {p1, v8}, Ljava/lang/String;->charAt(I)C
move-result v0
const/16 v1, 0x32
if-ne v0, v1, :cond_1b5
goto :goto_1c1
.line 37 :cond_1b5 invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0
if-ge v0, v10, :cond_1bc
return-object v3
.line 38 :cond_1bc invoke-virtual {p1, v5, v10}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object p1
goto :goto_1c5
.line 39 :cond_1c1 :goto_1c1 invoke-virtual {p1, v5, v9}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object p1
.line 40 :goto_1c5 sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->s:Landroid/net/Uri;
invoke-static {v0, p1}, Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;
move-result-object v5
const/4 v6, 0x0
const/4 v7, 0x0
const/4 v8, 0x0
const/4 v9, 0x0
move-object v4, p0
.line 41 invoke-virtual/range {v4 .. v9}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
move-result-object p0
return-object p0
.line 42 :cond_1d5 invoke-virtual {p1, v5}, Ljava/lang/String;->charAt(I)C
move-result v0
if-ne v0, v1, :cond_317
.line 43 invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v0 :try_end_1df .catch Ljava/lang/Exception; {:try_start_16b .. :try_end_1df} :catch_318
if-ge v0, v11, :cond_1e2
return-object v3
:cond_1e2 move v0, v5
.line 44 :goto_1e3 :try_start_1e3 iget-object v1, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->i:Ljava/util/ArrayList;
invoke-virtual {v1}, Ljava/util/ArrayList;->size()I
move-result v1
if-ge v0, v1, :cond_233
.line 45 iget-object v1, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->i:Ljava/util/ArrayList;
invoke-virtual {v1, v0}, Ljava/util/ArrayList;->get(I)Ljava/lang/Object;
move-result-object v1
check-cast v1, Ljava/lang/String;
.line 46 invoke-static {v1}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v6
if-nez v6, :cond_230
invoke-virtual {p1, v1}, Ljava/lang/String;->startsWith(Ljava/lang/String;)Z
move-result v6
if-eqz v6, :cond_230
.line 47 iget-object v0, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->c:Ljava/util/HashMap;
invoke-virtual {v0, v1}, Ljava/util/HashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Ljava/lang/Integer;
if-nez v0, :cond_20a
return-object v3
.line 48 :cond_20a invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v6
invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
move-result v12
if-ge v6, v12, :cond_215
return-object v3
.line 49 :cond_215 invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
move-result v0
invoke-virtual {p1, v5, v0}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v0
.line 50 invoke-virtual {v1}, Ljava/lang/String;->length()I
move-result v6
invoke-virtual {v0, v5, v6}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v6 :try_end_225 .catch Ljava/lang/Exception; {:try_start_1e3 .. :try_end_225} :catch_237
.line 51 :try_start_225 invoke-virtual {v1}, Ljava/lang/String;->length()I
move-result v1
invoke-virtual {v0, v1}, Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object v1 :try_end_22d .catch Ljava/lang/Exception; {:try_start_225 .. :try_end_22d} :catch_22e
goto :goto_24d
:catch_22e move-exception v0
goto :goto_239
:cond_230 add-int/lit8 v0, v0, 0x1
goto :goto_1e3
:cond_233 move-object v0, v3
move-object v1, v0
move-object v6, v1
goto :goto_24d
:catch_237 move-exception v0
move-object v6, v3
.line 52 :goto_239 :try_start_239 new-instance v1, Ljava/lang/StringBuilder;
invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v2, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
move-object v0, v3
move-object v1, v0
:goto_24d if-nez v0, :cond_25b
.line 53 invoke-virtual {p1, v5, v11}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v0
.line 54 invoke-virtual {v0, v5, v9}, Ljava/lang/String;->substring(II)Ljava/lang/String;
move-result-object v6
.line 55 invoke-virtual {v0, v9}, Ljava/lang/String;->substring(I)Ljava/lang/String;
move-result-object v1
.line 56 :cond_25b iget-object v0, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->a:Ljava/util/HashMap;
invoke-virtual {v0, v6}, Ljava/util/HashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Ljava/lang/Integer;
if-nez v0, :cond_27e
.line 57 new-instance v0, Ljava/lang/StringBuilder;
invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
const-string v1, "prefix == null return number = "
invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-direct {p0, p1}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->G(Ljava/lang/String;)Ljava/lang/String;
move-result-object p0
invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p0
invoke-static {v2, p0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
return-object v3
.line 58 :cond_27e invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
move-result p1
invoke-static {v1}, Ljava/lang/Integer;->parseInt(Ljava/lang/String;)I
move-result v0
add-int/2addr p1, v0
.line 59 rem-int/lit8 v0, p1, 0x2
if-eqz v0, :cond_292
add-int/lit8 p1, p1, -0x1
if-gez p1, :cond_290
move p1, v5
:cond_290 move v0, v8
goto :goto_293
:cond_292 move v0, v5
:goto_293 shr-int/2addr p1, v8
mul-int/2addr p1, v9
.line 60 iget-object v1, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->b:[B
aget-byte v4, v1, p1
and-int/lit16 v4, v4, 0xff
add-int/lit8 v6, p1, 0x1
.line 61 aget-byte v6, v1, v6
and-int/lit16 v6, v6, 0xff
add-int/2addr p1, v7
.line 62 aget-byte p1, v1, p1
and-int/lit16 p1, p1, 0xff
shl-int/lit8 v1, v4, 0x4
shr-int/lit8 v4, v6, 0x4
or-int/2addr v1, v4
and-int/lit8 v4, v6, 0xf
shl-int/lit8 v4, v4, 0x8
or-int/2addr p1, v4
if-eqz v0, :cond_2b3
move v1, p1
:cond_2b3 add-int/2addr v1, v8
if-ne v1, v8, :cond_2b7
return-object v3
.line 63 :cond_2b7 invoke-static {v1}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object p1
.line 64 iget-object v0, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->j:Lcom/oplus/phonenoareainquire/a;
if-eqz v0, :cond_300
.line 65 invoke-virtual {v0, p1}, Lcom/oplus/phonenoareainquire/a;->b(Ljava/lang/String;)Lcom/oplus/phonenoareainquire/a$a;
move-result-object v0
if-eqz v0, :cond_300
.line 66 invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;->a()Ljava/lang/String;
move-result-object v4
invoke-static {v4}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v4
if-nez v4, :cond_300
invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;->b()Ljava/lang/String;
move-result-object v4
invoke-static {v4}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v4
if-nez v4, :cond_300
.line 67 new-instance p0, Landroid/database/MatrixCursor;
new-array v1, v9, [Ljava/lang/String;
const-string v4, "_id"
aput-object v4, v1, v5
const-string v4, "areano"
aput-object v4, v1, v8
const-string v4, "cityname"
aput-object v4, v1, v7
invoke-direct {p0, v1, v8}, Landroid/database/MatrixCursor;-><init>([Ljava/lang/String;I)V
new-array v1, v9, [Ljava/lang/String;
aput-object p1, v1, v5
.line 68 invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;->a()Ljava/lang/String;
move-result-object p1
aput-object p1, v1, v8
invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;->b()Ljava/lang/String;
move-result-object p1
aput-object p1, v1, v7
invoke-virtual {p0, v1}, Landroid/database/MatrixCursor;->addRow([Ljava/lang/Object;)V
return-object p0
.line 69 :cond_300 sget-object p1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->s:Landroid/net/Uri;
.line 70 invoke-static {v1}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v0
.line 71 invoke-static {p1, v0}, Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;
move-result-object v5
const/4 v6, 0x0
.line 72 invoke-static {v1}, Ljava/lang/Integer;->toString(I)Ljava/lang/String;
move-result-object v7
const/4 v8, 0x0
const/4 v9, 0x0
move-object v4, p0
invoke-virtual/range {v4 .. v9}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;->query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
move-result-object p0 :try_end_316 .catch Ljava/lang/Exception; {:try_start_239 .. :try_end_316} :catch_318
return-object p0
:cond_317 return-object v3
:catch_318 move-exception p0
.line 73 new-instance p1, Ljava/lang/StringBuilder;
invoke-direct {p1}, Ljava/lang/StringBuilder;-><init>()V
const-string v0, "e = "
invoke-virtual {p1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {p1, p0}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {p1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p0
invoke-static {v2, p0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
return-object v3
:cond_32e :goto_32e const-string p0, "num is null or length is 0 return null "
.line 74 invoke-static {v2, p0}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
return-object v3.end method当系统需要查询一个具体的号码(例如 13812345678)时,l() 方法的剥离与寻址逻辑如下:
- 提取核心:截取前 7 位,得到
1381234。 - 拆分前后缀:前缀 Prefix =
138,后缀 Suffix =1234。 - 计算绝对索引:
去
HashMap中查到138的基础偏移量(假设为80000)。 将其与后缀转换为的整数相加:绝对索引 = 80000 + 1234 = 81234。
4.3 精妙的 12-Bit 极限压缩算法
拿到绝对索引后,如何去庞大的二进制流中取出归属地 ID?
通常,表示一个城市的 ID 至少需要一个 short (16位/2字节)。但为了将千万级号段的数据体积压缩到极致,工程师为每个城市 ID 仅分配了 12 个 Bit (1.5 字节)。因为全国地级市不到 400 个,最大 ID 只需要 12 位二进制(最大可表示 4095)便绰绰有余。
为了将两个 12-Bit 的数据严丝合缝地塞进 3 个字节(24 bits)里,底层进行了绝妙的位移运算(Bitwise Shift)。将 Smali 代码还原为 Java 逻辑如下:
int remainder = index % 2;int baseIndex = (index / 2) * 3; // 因为每 2 个数据共占 3 个字节
// 连续读取 3 个字节int b1 = this.b[baseIndex] & 0xFF;16 collapsed lines
int b2 = this.b[baseIndex + 1] & 0xFF;int b3 = this.b[baseIndex + 2] & 0xFF;
int cityId;if (remainder == 0) { // 偶数索引:取第1个字节的全部 + 第2个字节的前4位 cityId = (b1 << 4) | (b2 >> 4);} else { // 奇数索引:取第2个字节的后4位 + 第3个字节的全部 cityId = ((b2 & 0x0F) << 8) | b3;}
// cityId 为 0 时表示未知归属地if (cityId == 0) { return null;}拿到解密后的 cityId 后,直接将其作为索引,去步骤 3 中提取出的城市字典列表中查找,即可完美获得该号码的对应城市与区号。
5. Python 算法重构
基于以上的逆向分析,我们完全脱离了 Android 环境,使用纯 Python 实现了对该二进制数据文件的脱机解析与查询。完整代码如下:
import os
def load_database(file_path): print("⏳ 正在加载并解析底层数据库...") with open(file_path, 'rb') as f:117 collapsed lines
data = f.read()
# 1. 解析城市字典 (尾部 12002 字节) tail_data = data[-12002:] area_codes_raw = tail_data[2:2002] city_names_raw = tail_data[2002:10002] extend_prefix_raw = tail_data[10002:12002]
cities = [] for i in range(400): # 解析区号 area = area_codes_raw[i*5 : i*5+5].decode('ascii', errors='ignore').strip() # 解析城市名 (GBK编码,遇 \x00 截断) name_bytes = city_names_raw[i*20 : i*20+20].split(b'\x00')[0] name = name_bytes.decode('gbk', errors='ignore').strip() cities.append((area, name))
# 2. 构建号段偏移映射表 prefix_map = {} base_idx = 0
# 基础号段 130-139, 150-159 for p in range(130, 140): prefix_map[str(p)] = base_idx; base_idx += 10000 for p in range(150, 160): prefix_map[str(p)] = base_idx; base_idx += 10000
# 特殊基础号段 188, 189 prefix_map["188"] = base_idx; base_idx += 10000 prefix_map["189"] = base_idx; base_idx += 10000
# 扩展号段 for i in range(1000): b1 = extend_prefix_raw[i*2] b2 = extend_prefix_raw[i*2 + 1] prefix_val = (b1 << 8) | b2 if prefix_val == 0: break prefix_map[str(prefix_val)] = base_idx base_idx += 10000
# 3. 提取核心二进制映射区 (跳过头部16字节,去掉尾部12002字节) binary_array = data[16 : -12002] print(f"✅ 数据库加载成功!共解析出 {len(prefix_map)} 个号段。") return prefix_map, cities, binary_array
def query_phone(phone_7, prefix_map, cities, binary_array): if len(phone_7) != 7 or not phone_7.isdigit(): return "❌ 格式错误:请输入纯数字的 7 位号码前缀!"
prefix = phone_7[:3] suffix = phone_7[3:]
if prefix not in prefix_map: return f"❓ 未知号段:数据库中不存在 {prefix} 号段"
# 计算绝对索引 base_index = prefix_map[prefix] absolute_index = base_index + int(suffix)
# 1.5 字节对齐读取算法:每 2 个索引占用 3 个字节 byte_offset = (absolute_index // 2) * 3
if byte_offset + 2 >= len(binary_array): return "⚠️ 数据越界:该号码超出了数据库核心区范围"
b1 = binary_array[byte_offset] b2 = binary_array[byte_offset + 1] b3 = binary_array[byte_offset + 2]
# 解码 12-Bit 城市 ID if absolute_index % 2 == 0: city_id = (b1 << 4) | (b2 >> 4) else: city_id = ((b2 & 0x0F) << 8) | b3
if city_id == 0: return "📍 归属地未知 (系统中无此记录)"
list_index = city_id if list_index >= len(cities) or list_index < 0: return f"⚠️ 数据异常:解析出未知的城市 ID ({city_id})"
area_code, city_name = cities[list_index] if not city_name: return "📍 归属地未知 (城市字段为空)"
return f"📍 归属地: 【{city_name}】 (长途区号: {area_code})"
def main(): file_name = "PhoneNumberData_3_1_0.dat" if not os.path.exists(file_name): print(f"❌ 找不到文件:{file_name}") return
prefix_map, cities, binary_array = load_database(file_name)
print("\n" + "="*40) print("📞 ColorOS 离线号码归属地查询系统") print("="*40)
while True: try: user_input = input("\n👉 请输入 7 位手机号码前缀 (输入 q 退出): ").strip() if user_input.lower() == 'q': break
if len(user_input) >= 7: user_input = user_input[:7]
result = query_phone(user_input, prefix_map, cities, binary_array) print(result)
except KeyboardInterrupt: break except Exception as e: print(f"发生错误: {e}")6. 阶段总结与预告
至此,我们已经成功解决了字典的内存偏移规则、精妙的 12-Bit 压缩解密算法,以及尾部城市的解析方式,完成了号码归属地的逆向重构。
不过,你可能会发现,这套方案目前只能查到归属城市,还缺少至关重要的“运营商”信息。在下一节中,我们将继续深挖同目录下的 CarrierData_1_0.dat,揭开运营商识别的底层多级指针寻址机制,敬请期待!