7138 字
36 分钟
逆向解析 ColorOS 离线号码库 (一):12-Bit 极限压缩的归属地查询算法

逆向解析 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 编码)。例如:010020021(分别对应北京、广州、上海),以及成百上千个地级市的区号。

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");
}

通过上述代码,我们可以清晰地得出尾部字典的结构:

  1. bArr2:存放了 400 个区号,每个固定占 5 个字节(需执行 .trim() 去除空格)。
  2. bArr3:存放了 400 个城市名称,每个固定占 20 个字节(需使用 GBK 解码)。
  3. 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.aHashMap。这个 Map 存放的是手机号前三位(基础号段)对应的内存基础偏移量

代码通过循环,为 130-139150-159 以及 188189 等基础号段分配了递增的偏移值。例如:

  • 130 对应偏移量 0
  • 131 对应偏移量 10000
  • 132 对应偏移量 20000

随后,它还会从尾部的扩展区中读取诸如 170199 等较新的号段,并将它们同样补充进该 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() 方法的剥离与寻址逻辑如下:

  1. 提取核心:截取前 7 位,得到 1381234
  2. 拆分前后缀:前缀 Prefix = 138,后缀 Suffix = 1234
  3. 计算绝对索引: 去 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,揭开运营商识别的底层多级指针寻址机制,敬请期待!

逆向解析 ColorOS 离线号码库 (一):12-Bit 极限压缩的归属地查询算法
https://006lp.de/posts/reverse-coloros-offline-number-lookup/12bit-phone-number-compression-1/
作者
Hotaru
发布于
2026-02-21
许可协议
CC BY-NC-ND 4.0