前言
最近在宿舍搞了个路由器,之前一直用的是路由器默认的SSID (Xiaomi_xxxx),为了更好地辨别自己的Wifi,决定更改一个更有辨识度的名字。正在想取什么名字好的时候,正好在B站刷到了“Ciallo~(∠・ω< )⌒☆” (虽然我不知道这是什么意思),看起来很适合用于WiFi名,所以决定就这样修改。
修改遇阻
然而在小米WiFi app里尝试修改时,遇到了困难。
APP中提示“WiFi名称包含非法字符”,看来APP强制不能包含特殊字符,不能进行下一步修改。
尝试删除“☆”之后仍提示特殊字符,最后删到只有Ciallo~才允许继续修改。
实际上现在大多设备都支持特殊字符了,并不像以前的老设备上会乱码甚至崩溃,所以
正好最近学习了一些简单的安卓逆向,所以想尝试逆向看看能不能绕过这个限制。
分析安装包
先通过MT管理器提取 小米WiFi.apk
其中,classes.dex是java编译后的字节码(也就是源码编译后的产物),resources.arsc是记录所有字符串及其对应id的文件。
先反编译dex,可以看到源码结构只有abcd这样的名字,因此小米对源代码进行了一定程度的混淆,直接搜索方法名就不太合适了。
所以需要在.arsc中搜索对应的字符串,找到字符串对应的id,再回到dex中搜索id,才能开始分析代码逻辑。
搜索ARSC
在arsc中尝试搜索“非法字符”(因为刚刚报的错是“WiFi名称包含非法字符”)。
查找资源ID
顺利找到了字符串以及String name,接着搜索string name对应值(common_illegal_input_tips_ssid),找到对应的资源id.
得到了资源id(0x7f11037c),不过,也同时记录一下上一个id(0x7f11037b)意思是密码包含非法字符,等会说不定用得上。
有了id之后就可以开始分析代码了。
分析源码
“classes.dex是Android应用程序中的一个文件,它包含了Java编译后的字节码,用于在Dalvik虚拟机上执行。与Java中的class文件对应,Dex文件可以大大缩小体积,减少数据冗余,有利于在移动端中运行”
由于dex是java编译后的文件,所以查看的代码并不是java,而是反编译后得到的smail反汇编代码。
搜索ID
在smail代码中搜索0x7f11037c,发现有好几处地方涉及到了“WiFi名称含有非法字符”,查看方法名可以排除几个(guest访客WiFi什么的,因为我修改的并不是访客WiFi)。在可疑的方法名中,将id修改为刚刚记录的“密码包含非法字符”的id(0x7f11037b),逐个排除。
修改完之后保存工程,并回编译,安装apk,再次进入修改WiFi名称界面。
发现原本的WiFi名称包含非法字符 已经变成了 WiFi密码包含非法字符
通过修改id,这样就找到了要分析的代码所在的方法(method)里
位于“com.xiaomi.router.setting”下的“WiFiitemview”里,进入并分析。
源码解读
定位到代码位置,分析代码。
以下为节选的核心代码,已添加必要注释。
:goto_50
const/4 v5, 0x0
invoke-static {v0, v5}, Lcom/xiaomi/router/common/util/w0;->d(Ljava/lang/String;Ljava/lang/String;)Z #判断某个布尔值的真假
move-result v6 #将结果储存到变量名“v6”里,值只有0或1
const v7, 0x7f11037c #将字符串“WiFi名称含有非法字符”储存到变量v7中
if-eqz v6, :cond_6a #如果v6 == 0(equal zero)就跳转到cond_6a,否则继续下面的代码,即v6为0就是没有非法字符,v6为1就接着下面的代码进行报错。
invoke-virtual {p0}, Landroid/view/View;->getContext()Landroid/content/Context;
move-result-object v2
invoke-virtual {v2, v7}, Landroid/content/Context;->getString(I)Ljava/lang/String;
move-result-object v2 #使用到了v7
invoke-virtual {p2, v2}, Landroid/widget/TextView;->setError(Ljava/lang/CharSequence;)V
invoke-virtual {p2}, Landroid/view/View;->requestFocus()Z #这里就是控制报错的代码
const/4 v2, 0x0
:cond_6a #cond_6a开始
invoke-static {v1, v5}, Lcom/xiaomi/router/common/util/w0;->d(Ljava/lang/String;Ljava/lang/String;)Z #判断一个布尔值
move-result v5
const v6, 0x7f11037b #将“密码含有非法字符串”保存到v6变量中
if-eqz v5, :cond_82 #如果v5==0,转跳,否则继续
invoke-virtual {p0}, Landroid/view/View;->getContext()Landroid/content/Context;
move-result-object v2
invoke-virtual {v2, v6}, Landroid/content/Context;->getString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {p3, v2}, Landroid/widget/TextView;->setError(Ljava/lang/CharSequence;)V
invoke-virtual {p2}, Landroid/view/View;->requestFocus()Z
#报错提示密码含有非法字符
const/4 v2, 0x0
#################################################################################
实际上,看到这里,已经初步了解了控制报错的代码逻辑,只需要让v6永远等于0,if-eqz v6, :cond_6a无论如何都会运行cond_6a,不会运行报错的相关代码。
要让v6==0,只需要在if-eqz v6, :cond_6a的前一行加一句“const/4 v6, 0x0”就好,意思是将v6的值设置为4位的(dex中的数字用4或16位储存),这样无论v6之前的值是什么,在if判断之前都被重新赋值为0。
添加完之后,保存、回编译、安装应用。
然而事情并不是想象的那么容易,将v6固定为0之后,更改WiFi名仍与先前报错一致。
实际上,cond_6a下面的报错代码确实没有运行,而是if-eqz v5, :cond_82判断密码是否有非法字符时,cond_82中还存在冗余代码,重复判断了名称是否含有非法字符,因此还需要继续分析cond_82
##########################################################################
#接上井号处代码
:cond_82
invoke-static {v0}, Lcom/xiaomi/router/common/util/w0;->a(Ljava/lang/String;)Z
#此处又获取了某个布尔值,但与前两次不同,这次只带了一个参数
move-result v5
#将结果储存到v5,虽然不清楚这里判断了什么,但可以肯定如果v5==0,下面的if就不会跳转到cond_98
if-eqz v5, :cond_98 #下面又是报错的代码
invoke-virtual {p0}, Landroid/view/View;->getContext()Landroid/content/Context;
move-result-object v2
invoke-virtual {v2, v7}, Landroid/content/Context;->getString(I)Ljava/lang/String;
#这里又用到了v7,“名称含有非法字符”,所以肯定要让v5等于0
move-result-object v2
invoke-virtual {p2, v2}, Landroid/widget/TextView;->setError(Ljava/lang/CharSequence;)V
invoke-virtual {p2}, Landroid/view/View;->requestFocus()Z
const/4 v2, 0x0
##########################################################################
可以在”if-eqz v5, :cond_98“的前一行添加 “const/4 v5, 0x0”
添加、保存、回编译、安装测试。
##########################################################################
#接上井号处代码
:cond_98
invoke-static {v1}, Lcom/xiaomi/router/common/util/w0;->a(Ljava/lang/String;)Z
move-result v5
#其实刚刚修改完已经成功绕过了,可以修改成特殊字符了,
#但是cond_98又双叒叕获取了一个布尔值,下面的报错代码是判断密码是否有特殊字符的冗余代码,
#所以不需要再改了,密码就没必要那么多特殊符号。
if-eqz v5, :cond_ad
invoke-virtual {p0}, Landroid/view/View;->getContext()Landroid/content/Context;
#悄悄的说,其实根本没办学校的宽带{doge}(60一个月又贵又慢),53号端口有新大陆
move-result-object v2
invoke-virtual {v2, v6}, Landroid/content/Context;->getString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {p3, v2}, Landroid/widget/TextView;->setError(Ljava/lang/CharSequence;)V
invoke-virtual {p3}, Landroid/view/View;->requestFocus()Z
const/4 v2, 0x0
:cond_ad #下面就是和路由器通信的代码,告诉路由器要修改成的名字。
invoke-static {}, Lcom/xiaomi/router/common/application/RouterBridge;->E()Lcom/xiaomi/router/common/application/RouterBridge;
move-result-object v5
invoke-virtual {v5}, Lcom/xiaomi/router/common/application/RouterBridge;->x()Lcom/xiaomi/router/common/api/model/CoreResponseData$RouterInfo;
move-result-object v5
invoke-virtual {v5}, Lcom/xiaomi/router/common/api/model/CoreResponseData$RouterInfo;->isSupportTridBandRouter()Z
move-result v5
修改结果
可以看到不再报错,进入到了下一步。
在点击刚刚的确认后,又弹出了一个提示。
鸡贼的小米,在重启WiFi的代码里还判断了一次特殊字符,看来至少他们曾经 允许或想过支持修改特殊字符,但因为某些原因,强制不允许特殊字符了。
成功连接到含有特殊字符的WiFi
雷军!金凡!
干完小米WiFi app,想看看网页版后台上怎么显示的,才发现网页版可以直接修改含有特殊字符的ssid,我TM!
附录:
需要特殊版本的MT管理器请在评论区留言,我会分享到网盘里
初学逆向,如有不当之处,还请予以指正。
Comments NOTHING