AppUpdateHack

前几天收获了一个Android木马,各种拍照,微信数据库也打包了,网友说是在App点击检测更新就安装了这么个东西。 1. 从检测更新开始,检测更新跑了一段如下代码

if (Utils.isNetConnect(SettingFragment.this.mContext)) {
           final Utils utils = new Utils();
           new Thread() {
               public void run() {
                   utils.requestADModel(true, SettingFragment.this.mContext);
               }
           }.start();
       } else {
           Toast.makeText(SettingFragment.this.mContext, "", 0).show();
       }   
  1. 更新请求 这部分做了两部分其实 http请求,加了一个弱爆了的请求校验,看第二段代码

    
    
    public void requestADModel(boolean isCheck, Context main) {
            new ParserADModel(isCheck, main).parseRssByUrl(getUrl(main).toString());
    
    
    }
    
public StringBuffer getUrl(Context main) {
    StringBuffer sb = new StringBuffer();
    String mod = "update";
    sb.append("http://xxx/service.php?mod=");
    sb.append(mod);
    sb.append("&act=");
    String act = "androidUpdate";
    sb.append(act);
    sb.append("&uid=");
    String uid = generateClientUID(XXX, main);
    sb.append(uid);
    sb.append("&cks=");
    sb.append(MD5Calculator.calculateMD5(mod + act + uid + "xx"));
    return sb;
}
  1. 处理请求后的数据,解析,xml

返回结果

key value
versionCode versionCode
updateNote 更新描述
packageUrl 包的URL
packageSize 包大小
public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
            if ("versionCode".equals(localName)) {
                Utils.this.versionCode = Integer.valueOf(this.value).intValue();
            } else if ("showAd".equals(localName)) {
                Utils.this.showAd = Integer.valueOf(this.value).intValue();
            } else if ("showBaidu".equals(localName)) {
                Utils.this.showBaidu = Integer.valueOf(this.value).intValue();
            } else if ("updateNote".equals(localName)) {
                Utils.this.updateNote += this.value;
            } else if ("packageUrl".equals(localName)) {
                Utils.this.packageUrl = this.value;
            } else if (GameAppOperation.QQFAV_DATALINE_VERSION.equals(localName)) {
                Utils.this.version = this.value;
            } else if ("packageSize".equals(localName)) {
                Utils.this.packageSize = this.value;
            }
            }
  1. 提示用户下载更新

    private void showUpdateDialog(Context main, boolean isChecked, int versionCode) {
        try {
            final AlertDialog DialogChange = new AlertDialog.Builder(main).create();
            DialogChange.show();
//省略部分
            DialogChange.getWindow().findViewById(R.id.upadte_btn).setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    Utils.this.downloadTheFile(Utils.this.packageUrl, context);//用户点击下载就去下载了
                    DialogChange.dismiss();

                }
            });

        } catch (Exception ex) {

        }
    }

downloadTheFile(final String strPath, final Context main)调用了doDownloadTheFile(String strPath, Context main)

//下载文件的主要代码,下载完了openFile
while (true) {
    int numread = is.read(buf);
    if (numread <= 0) {
        String str = main.getString(R.string.update_finish);
        isDownloading = $assertionsDisabled;
        openFile(myTempFile, main);
        try {
            is.close();
            return;
        } catch (Exception ex) {
            ex.printStackTrace();
            return;
        }
    }
  //openFile就一行代码  
    public void openFile(File f, Context main) {
    installApk(f, main);
}
//installApk 然后就。。。

    private void installApk(File file, Context context) {
        Intent intent = new Intent("android.intent.action.VIEW");
        intent.setFlags(268435456);
        intent.setAction("android.intent.action.VIEW");
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

回过头看下这个问题 用户手动检测更新,客户端根据客户端uid做了一个key,通过http请求服务器然后一个xml的更新数据(https都有中间人攻击,那个http不用说了), 其中有包的路径和大小,然后客户端拿到URL下载,下载完了就去调用安装了(如果校验下包名和签名),至于那一部分被拦截了我就不知道,没法复现, 如果xml数据没有被劫持那就是下载的包被劫持了。 这个漏洞其实应该是挺广泛的。通知一下厂商。