几乎99%的软件都有登陆功能,而登陆这一个动做真的将咱们的用户名和密码上传到了服务器吗,会不会有我的隐私呢。根据咱们这个问题,咱们用FaceU这个软件,逆向来看看他的登陆功能到底都传了什么数据。php
首先下载faceu的APK,具体下载地址你们能够去各大应用市场,我下载的版本是v2.2.6。java
须要的工具下载地址:github.com/hanhan12312…android
首先,咱们利用apktool拆包apk,执行命令git
apktool d faceu.apk
复制代码
这样在当前文件夹就获得了一个faceu的文件夹。程序员
咱们打开Faceu软件,点击下面的已有帐号在此登陆,而后弹出来登陆界面,如图所示
咱们利用字符串搜索法,这个页面的注册的EditText的hint字为"Faceu号/手机号",咱们搜索res文件夹内全部文件的内容,搜索此关键字找到两处,位置都在res/values/strings.xml文件内github
strings.xmlshell
<string name="str_account_hint">Faceu号 / 手机号</string>
<string name="str_search_user">Faceu号/手机号</string>
复制代码
根据name咱们也能知道,account_hint是帐号的输入框,而另外一个是用于搜索的。 咱们知道一个布局文件确定有用到过这个值。因此咱们在工程内搜索"str_account_hint",但是结果却发现只有两处引用到,如图
json
<public type="string" name="str_account_hint" id="0x7f070047" />
复制代码
由此咱们能够看出在java代码内对应的是0x7f070047。所以咱们再次在代码里面搜索0x7f070047试试。 找到了引用到这个常量的地方。api
在文件com/lemon/faceu/login/b内bash
const v2, 0x7f070047
invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
move-result-object v1
invoke-virtual {v0, v1}, Lcom/lemon/faceu/uimodule/view/AccountEditText->setHintText(Ljava/lang/String;)V
复制代码
熟悉smali语法的话,咱们可以读懂,这个翻译成Java代码其实就是
String v1 = context.getString(0x7f070047);
editText.setHintText(v1);
复制代码
目的是找到到这个字符串。
到此为止咱们分析一下当前的类是个什么类,是个Activity?Fragment?仍是自定义View。
咱们找到当前页面网上翻几行,看看还有没有用到什么别的资源id,找到了以下代码
const v0, 0x7f0e026e
invoke-virtual {p1, v0}, Landroid/view/View;->findViewById(I)Landroid/view/View;
move-result-object v0
check-cast v0, Lcom/lemon/faceu/uimodule/view/PasswordEditText;
iput-object v0, p0, Lcom/lemon/faceu/login/b;->bpP:Lcom/lemon/faceu/uimodule/view/PasswordEditText;
复制代码
很明显,这个凭借PasswordEditText名称咱们也能发现他就是密码输入的EditText
翻译成java代码
PasswordEditText v0 = (PasswordEditText)this.findViewById(0x7f0e026e);
this.bpP = v0;
复制代码
根据这一句话咱们在public.xml里面找到对应的xml
<public type="id" name="cet_login_password" id="0x7f0e026e" />
复制代码
而后咱们再看看有没有布局文件引用到了cet_login_password,因而找到了4处
咱们进入fragment_login.xml发现他只有登陆页面的上半部分。却没有下面的取消和确认按钮。能够猜想他并非Activity,Fragment,由于没有标志性的onCreate方法,父类最终也没有找到Activity,Fragment等。极可能是一个负责处理业务的类。
可是咱们知道了当前的成员变量bpP就是对应的密码的EditText了,那么看看都哪里调用这个bpP了。
经过对当前类分析,我最终找到了Lu方法里面对应到了登陆按钮的。
通过一番努力总算找到了登陆界面,登陆代码,如今咱们进行分析,而且加入一段咱们本身的代码,进行二次打包。
下面是分析详解
Lcom/lemon/faceu/login/b;
.method Lu()V
.locals 4
.prologue
.line 216
invoke-virtual {p0}, Lcom/lemon/faceu/login/b;->Ls()Z
#检测用户名是否合法
move-result v0
#若是不合法就返回
if-eqz v0, :cond_0
invoke-virtual {p0}, Lcom/lemon/faceu/login/b;->Lt()Z
#检测密码是否合法
move-result v0
#若是不合法就返回
if-nez v0, :cond_1
.line 241
:cond_0
:goto_0
return-void
.line 220
:cond_1
invoke-virtual {p0}, Lcom/lemon/faceu/login/b;->Uv()V
.line 222
const-string v0, "LoginFragment"
const-string v1, "startLogin"
invoke-static {v0, v1}, Lcom/lemon/faceu/sdk/utils/c;->i(Ljava/lang/String;Ljava/lang/String;)V
#调用Faceu本身的统计打点方法
.line 223
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpO:Lcom/lemon/faceu/uimodule/view/AccountEditText;
invoke-virtual {v0}, Lcom/lemon/faceu/uimodule/view/AccountEditText;->getAccount()Ljava/lang/String;
move-result-object v0
#调用AccountEditText的getAccount方法,并将用户户名存入v0
iput-object v0, p0, Lcom/lemon/faceu/login/b;->aAS:Ljava/lang/String;
#将aAs赋值为用户名
.line 224
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpP:Lcom/lemon/faceu/uimodule/view/PasswordEditText;
invoke-virtual {v0}, Lcom/lemon/faceu/uimodule/view/PasswordEditText;->getEditText()Landroid/widget/EditText;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
#将密码从bpP取出来,并取出String类型的密码复制给v0
.line 227
invoke-static {}, Lcom/lemon/faceu/common/e/a;->xJ()Lcom/lemon/faceu/common/e/a;
move-result-object v1
iget-object v2, p0, Lcom/lemon/faceu/login/b;->aAS:Ljava/lang/String;
invoke-virtual {v1, v2}, Lcom/lemon/faceu/common/e/a;->setAccount(Ljava/lang/String;)V
#将如今的用户名存入sharedprefence,以便于记住用户名下次直接显示
.line 229
new-instance v1, Ljava/util/HashMap;
#new一个HashMap存储进v1
invoke-direct {v1}, Ljava/util/HashMap;-><init>()V
#初始化v1
.line 230
const-string v2, "account"
iget-object v3, p0, Lcom/lemon/faceu/login/b;->aAS:Ljava/lang/String;
invoke-interface {v1, v2, v3}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#将用户名存入HashMap
.line 231
const-string v2, "pwd"
invoke-static {v0}, Lcom/lemon/faceu/common/i/g;->bS(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
invoke-interface {v1, v2, v0}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#将密码调用bS方法加密而且存入map
.line 232
const-string v0, "councode"
const-string v2, "86"
invoke-interface {v1, v0, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#国家编号86,存入map
.line 233
const-string v0, "manufacture"
sget-object v2, Landroid/os/Build;->MANUFACTURER:Ljava/lang/String;
invoke-interface {v1, v0, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#将厂商信息存入map
.line 234
const-string v0, "model"
sget-object v2, Landroid/os/Build;->MODEL:Ljava/lang/String;
invoke-interface {v1, v0, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#将model信息存入map
.line 235
const-string v0, "version"
sget v2, Lcom/lemon/faceu/common/d/b;->aAL:I
invoke-static {v2}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v2
invoke-interface {v1, v0, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#将软件版本信息存入map
.line 236
const-string v0, "deviceinfo"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xt()Lorg/json/JSONObject;
move-result-object v2
#将调用com.lemon.faceu.common.b.a->xt()方法,取回JsonObject而且赋值给v2
invoke-interface {v1, v0, v2}, Ljava/util/Map;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#将JSONObject存入map
.line 238
new-instance v0, Lcom/lemon/faceu/common/t/a;
sget-object v2, Lcom/lemon/faceu/common/d/a;->azO:Ljava/lang/String;
invoke-static {}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper;
move-result-object v3
invoke-direct {v0, v2, v1, v3}, Lcom/lemon/faceu/common/t/a;-><init>(Ljava/lang/String;Ljava/util/Map;Landroid/os/Looper;)V
.line 239
iget-object v1, p0, Lcom/lemon/faceu/login/b;->aKe:Lcom/lemon/faceu/common/t/a$a;
invoke-virtual {v0, v1}, Lcom/lemon/faceu/common/t/a;->a(Lcom/lemon/faceu/common/t/a$a;)V
.line 240
const-string v1, "login"
invoke-static {v0, v1}, Lcom/lemon/faceu/sdk/i/b;->a(Ljava/lang/Runnable;Ljava/lang/String;)V
goto :goto_0 .end method
#此方法主要校验用户名是否合法,错误的话输出错误信息,返回值为boolean
.method Ls()Z
.locals 5
.prologue
const/4 v1, 0x0
#使v0寄存器为0
.line 177
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpO:Lcom/lemon/faceu/uimodule/view/AccountEditText;
#将成员变量bpO赋值给v0,此时v0就是用户名
invoke-virtual {v0}, Lcom/lemon/faceu/uimodule/view/AccountEditText;->getAccount()Ljava/lang/String;
move-result-object v2
#调用AccountEditText的getAccount方法,并将返回值存入v2
.line 178
invoke-virtual {v2}, Ljava/lang/String;->length()I
#取出用户名长度
move-result v0
#v0 = 用户名长度
if-lez v0, :cond_0
invoke-virtual {v2, v1}, Ljava/lang/String;->charAt(I)C
move-result v0
invoke-static {v0}, Ljava/lang/Character;->isDigit(C)Z
move-result v0
if-eqz v0, :cond_0
.line 180
invoke-static {v2}, Lcom/lemon/faceu/common/u/t;->dz(Ljava/lang/String;)Z
move-result v0
if-nez v0, :cond_4
.line 181
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpO:Lcom/lemon/faceu/uimodule/view/AccountEditText;
const v2, 0x7f0700ae
invoke-virtual {p0, v2}, Lcom/lemon/faceu/login/b;->getString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v0, v2}, Lcom/lemon/faceu/uimodule/view/AccountEditText;->setTips(Ljava/lang/String;)V
.line 202
:goto_0
return v1
.line 185
:cond_0
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v0
const/16 v3, 0x14
if-le v0, v3, :cond_1
.line 186
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpO:Lcom/lemon/faceu/uimodule/view/AccountEditText;
const v2, 0x7f070087
invoke-virtual {p0, v2}, Lcom/lemon/faceu/login/b;->getString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v0, v2}, Lcom/lemon/faceu/uimodule/view/AccountEditText;->setTips(Ljava/lang/String;)V
goto :goto_0
.line 188
:cond_1
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v0
if-lez v0, :cond_2
invoke-virtual {v2, v1}, Ljava/lang/String;->charAt(I)C
move-result v0
invoke-static {v0}, Lcom/lemon/faceu/sdk/utils/h;->u(C)Z
move-result v0
if-nez v0, :cond_2
.line 189
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpO:Lcom/lemon/faceu/uimodule/view/AccountEditText;
const v2, 0x7f070086
invoke-virtual {p0, v2}, Lcom/lemon/faceu/login/b;->getString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v0, v2}, Lcom/lemon/faceu/uimodule/view/AccountEditText;->setTips(Ljava/lang/String;)V
goto :goto_0
:cond_2
move v0, v1
.line 192
:goto_1
invoke-virtual {v2}, Ljava/lang/String;->length()I
move-result v3
if-ge v0, v3, :cond_4
.line 193
invoke-virtual {v2, v0}, Ljava/lang/String;->charAt(I)C
move-result v3
.line 194
const/16 v4, 0x5f
if-eq v3, v4, :cond_3
invoke-static {v3}, Ljava/lang/Character;->isDigit(C)Z
move-result v4
if-nez v4, :cond_3
invoke-static {v3}, Lcom/lemon/faceu/sdk/utils/h;->u(C)Z
move-result v3
if-nez v3, :cond_3
.line 195
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpO:Lcom/lemon/faceu/uimodule/view/AccountEditText;
const v2, 0x7f070085
invoke-virtual {p0, v2}, Lcom/lemon/faceu/login/b;->getString(I)Ljava/lang/String;
move-result-object v2
invoke-virtual {v0, v2}, Lcom/lemon/faceu/uimodule/view/AccountEditText;->setTips(Ljava/lang/String;)V
goto :goto_0
.line 192
:cond_3
add-int/lit8 v0, v0, 0x1
goto :goto_1
.line 202
:cond_4
const/4 v1, 0x1
goto :goto_0 .end method
#此方法主要校验密码是否合法,错误的话输出错误信息,作一些动画之类,正确返回true
.method Lt()Z
.locals 2
.prologue
.line 206
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpP:Lcom/lemon/faceu/uimodule/view/PasswordEditText;
invoke-virtual {v0}, Lcom/lemon/faceu/uimodule/view/PasswordEditText;->getEditText()Landroid/widget/EditText;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/String;->length()I
move-result v0
.line 207
const/4 v1, 0x6
if-lt v0, v1, :cond_0
const/16 v1, 0x10
if-le v0, v1, :cond_1
.line 208
:cond_0
iget-object v0, p0, Lcom/lemon/faceu/login/b;->bpP:Lcom/lemon/faceu/uimodule/view/PasswordEditText;
const v1, 0x7f0700b5
invoke-virtual {p0, v1}, Lcom/lemon/faceu/login/b;->getString(I)Ljava/lang/String;
move-result-object v1
invoke-virtual {v0, v1}, Lcom/lemon/faceu/uimodule/view/PasswordEditText;->setTips(Ljava/lang/String;)V
.line 209
const/4 v0, 0x0
.line 211
:goto_0
return v0
:cond_1
const/4 v0, 0x1
goto :goto_0 .end method
复制代码
咱们主要看Lu方法里面的如下几行,他调用了com.lemon.faceu.common.b.a->xt()方法,这个主要是用于窃取咱们的手机型号,系统,厂商等信息,咱们进入方法看看
const-string v0, "deviceinfo"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xt()Lorg/json/JSONObject;
move-result-object v2
#将调用com.lemon.faceu.common.b.a->xt()方法,取回JsonObject而且赋值给v2
复制代码
咱们进入方法看看
.method public static xt()Lorg/json/JSONObject;
.locals 5
.prologue
.line 34
new-instance v1, Lorg/json/JSONObject;
invoke-direct {v1}, Lorg/json/JSONObject;-><init>()V
.line 36
:try_start_0
const-string v0, "cpu"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xv()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
#取出你的cpu信息放入json
.line 37
const-string v0, "radio"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xx()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
#机型的RADIO信息存入json
.line 38
const-string v0, "os_version"
sget v2, Landroid/os/Build$VERSION;->SDK_INT:I
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;I)Lorg/json/JSONObject;
#取出你系统版本
.line 39
const-string v0, "imei"
invoke-static {}, Lcom/lemon/faceu/common/e/a;->xJ()Lcom/lemon/faceu/common/e/a;
move-result-object v2
#取出IMEI号
invoke-virtual {v2}, Lcom/lemon/faceu/common/e/a;->getContext()Landroid/content/Context;
move-result-object v2
invoke-static {v2}, Lcom/lemon/faceu/common/b/a;->bd(Landroid/content/Context;)Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
.line 40
const-string v0, "imsi"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xy()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
.line 41
const-string v0, "iccid"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xz()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
.line 42
const-string v0, "android_id"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xw()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
.line 43
const-string v0, "model"
sget-object v2, Landroid/os/Build;->MODEL:Ljava/lang/String;
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
.line 44
const-string v0, "core_count"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xA()I
move-result v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;I)Lorg/json/JSONObject;
.line 45
const-string v0, "wifi"
invoke-static {}, Lcom/lemon/faceu/common/b/a;->xu()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v0, v2}, Lorg/json/JSONObject;->put(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
:try_end_0
.catch Lorg/json/JSONException; {:try_start_0 .. :try_end_0} :catch_0
.line 49
:goto_0
return-object v1
.line 46
:catch_0
move-exception v0
.line 47
const-string v2, "DeviceInfo"
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const-string v4, "jsonexception, "
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v3
invoke-virtual {v0}, Lorg/json/JSONException;->getMessage()Ljava/lang/String;
move-result-object v0
invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
invoke-static {v2, v0}, Lcom/lemon/faceu/sdk/utils/c;->e(Ljava/lang/String;Ljava/lang/String;)V
goto :goto_0 .end method
复制代码
咱们能看到他获取了咱们的cpu,radio,os_version(系统版本),imei,MODEL,cpu_count,mac地址。 看了半天代码,咱们加入一些咱们的代码,让程序本身把提交的信息打印出来吧。
const-string v0, "MartinHan--map"
invoke-virtual {v1}, Ljava/util/HashMap;->toString()Ljava/lang/String;
move-result-object v3
invoke-static {v0, v3}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
const-string v3, "MartinHan---url"
invoke-static {v3, v2}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
复制代码
而后咱们执行代码
apktool d faceu
cd faceu/disk
#签名 生成文件明为_signed.apk
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore "MartinHan.jks" -signedjar "_signed.apk" "faceu.apk" "111111" << EOF
111111
adb install _signed.apk
复制代码
这样的流程走下来,咱们的二次打包apk就安装到手机上啦,看看咱们输入咱们账号,点击登陆。会打印出log信息。
以下所示
03-13 14:17:15.269 10240-10240/com.lemon.faceu V/MartinHan--map: {account=159xxxxxxxx, deviceinfo={"android_id":"62fjdhu42d070400","wifi":"08:33:61:cc:b9:fc","model":"HUAWEI G630-U00","imei":"81338398767854654","iccid":"","cpu":"ARMv7 Processor rev 3 (v7l) ","radio":"203040,203040","imsi":"","core_count":4,"os_version":18}, model=HUAWEI G630-U00, pwd=4d259481d57ffc1c6b4b68cd73dbd301, councode=86, manufacture=HUAWEI, version=270540806}
03-13 14:17:15.269 10240-10240/com.lemon.faceu V/MartinHan---url: https://api2.faceu.mobi/faceu/v3/login.php
复制代码
如上诉代码所示,咱们在faceu登陆一次,faceu会上传咱们的不少我的信息
mac地址,手机型号,imei,cpu信息,radio,系统版本,国家代码, 而且找到了faceu登陆的地址是https://api2.faceu.mobi/faceu/v3/login.php
以上就是个人全部思路,从问题开始,一直找代码,最后动态的打log实如今https加密前就让app本身吐出数据。
其实我想不只faceu,像是其余的厂商也会收集咱们的我的信息,完成统计。而且经过大数据分析使用软件的人群,手机型号。
但愿全部喜欢逆向的朋友们一块儿探讨,多多交流。
注:若有侵权,请联系我
我的博客:MartinHan的小站
博客网站:hanhan12312的专栏
知乎:MartinHan01