APP登陸協議的分析

1、前言

最近暴雨不斷,只能宅在家裏,閒來無事,寫寫文章

2、整體分析

通過抓包工具,簡單看看登陸封包內容,如下:
其中密碼爲123456
這裏寫圖片描述

登陸,封包如下:
這裏寫圖片描述

居然是明文傳輸密碼和賬號,不止如此,傳輸居然採用http,看到這,這款企業級的app安全性,可以想象,根本毫無安全可言。另外,可以看到封包最後有個簽名sign,如果我們把sign算法搞定,那豈不是,可以寫自動註冊機了。

3、登陸簽名算法分析

搜索”註冊成功”,來到關鍵的處理登陸信息的代碼,如下:

public static HashMap<String, String> a(final HashMap<String, String> hashMap) {
        hashMap.put("appkey", "android2009");
        hashMap.put("timestamp", ps.a());
        hashMap.put("v", "1.0");
        hashMap.put("format", "xml");
        hashMap.put("appSource", ot.v);
        hashMap.put("osType", "ANDROID");
        hashMap.put("osVersion", Build$VERSION.RELEASE);
        if (!hashMap.containsKey("appVersion")) {
            hashMap.put("appVersion", pj.a);
        }
        if (!hashMap.containsKey("apptype")) {
            hashMap.put("apptype", "cinema");
        }
        if (!hashMap.containsKey("version")) {
            hashMap.put("version", "1.0");
        }
        if (!hashMap.containsKey("memberEncode")) {
            final String a = px.a();
            if (pq.i(a)) {
                hashMap.put("memberEncode", a);
            }
        }
        if (!hashMap.containsKey(ot.p)) {
            hashMap.put("deviceId", ot.f);
        }
        if (!hashMap.containsKey(ot.o)) {
            hashMap.put("mobileType", ot.d);
        }
        if (!hashMap.containsKey(ot.q)) {
            hashMap.put("imei", ot.e);
        }
        if (!hashMap.containsKey(ot.n)) {
            hashMap.put("mprovider", ot.h);
        }
        if (!hashMap.containsKey(ot.m)) {
            hashMap.put("mnet", ot.g);
        }
        if (!hashMap.containsKey(ot.r)) {
            hashMap.put("citycode", ot.i);
        }
        if (!hashMap.containsKey(ot.t)) {
            hashMap.put("pointx", ot.k);
        }
        if (!hashMap.containsKey(ot.u)) {
            hashMap.put("pointy", ot.l);
        }
        final ArrayList<Comparable> list = new ArrayList<Comparable>();
        final ArrayList<String> list2 = new ArrayList<String>();
        for (final Map.Entry<String, String> entry : hashMap.entrySet()) {
            if (entry.getValue() == null) {
                list2.add(entry.getKey());
            }
            list.add(entry.getKey());
        }
        for (int size = list2.size(), i = 0; i < size; ++i) {
            hashMap.remove(list2.get(i));
            list.remove(list2.get(i));
        }
        Collections.sort(list);
        final int size2 = list.size();
        final TreeMap<String, String> treeMap = new TreeMap<String, String>();
        for (int j = 0; j < size2; ++j) {
            treeMap.put(list.get(j), hashMap.get(list.get(j)));
        }
        String a2 = "";
        while (true) {
            try {
                a2 = om.a(treeMap, "prikey-android");
                hashMap.put("sign", a2);
                hashMap.put("signmethod", "MD5");
                return hashMap;
            }
            catch (Exception ex) {
                continue;
            }
            break;
        }
    }

可以非常清晰的看到,通過獲取一系列的信息放到map中,然後通過 a2 = om.a(treeMap, “prikey-android”) 進行簽名。最後,作者居然把簽名算法提示出來類,無語。。。。。。

我們再來詳細可看,簽名算法

public static String a(final Map<String, String> map, final String s) throws IOException {
        final TreeMap<String, Object> treeMap = new TreeMap<String, Object>(map);
        final StringBuilder sb = new StringBuilder();
        for (final Map.Entry<String, V> entry : treeMap.entrySet()) {
            sb.append(entry.getKey()).append("=").append((String)entry.getValue()).append("&");
        }
        final byte[] digest = a().digest((pp.a(sb.toString(), "&") + s).getBytes("UTF-8"));
        final StringBuilder sb2 = new StringBuilder();
        for (int i = 0; i < digest.length; ++i) {
            final String hexString = Integer.toHexString(digest[i] & 0xFF);
            if (hexString.length() == 1) {
                sb2.append("0");
            }
            sb2.append(hexString.toUpperCase());
        }
        return sb2.toString().toUpperCase();
    }

代碼比較清晰,獲取map中的key 和value,重新組合,調用pp.a(String, String)方法,返回值加上傳遞進來的參數s轉換成byte數組,傳遞給a().digest。再說明a()之前,首先說下pp.a(String, String)的作用,該函數對傳入的字符串進行非空和空白字符判斷,並去掉第一個參數末尾的標識,其中標識由第二個參數指定。處理後的字符串如下:

appSource=AS134&appVersion=6.0.1&appkey=android2009&apptype=cinema&citycode=330100&deviceId=68F72842A46E&deviceid=dS8h6JIFtlBBBbsPCKfwPTdpvftV1cOyrzOXFtVQrtg=&format=xml&imei=864394106824727&method=xxxxxx.login&mnet=WIFI&mobileType=HTC M8t&mprovider=46000&osType=ANDROID&osVersion=4.4.2&password=123456&pointx=&pointy=&pushstatus=1&timestamp=2016-07-03 12:36:41&username=666666@qq.com&v=1.0&version=1.0prikey-android

下面,來看下a()方法,比較簡單返回MD5數字簽名實例,如下:

private static MessageDigest a() throws IOException {
        try {
            return MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException ex) {
            throw new IOException(ex.getMessage());
        }
    }

繼續分析,代碼的後半部分,作用就是轉換成大寫十六進制格式的md5.

最後,附上md5加密算法模板

/* 
    * MD5加密 
    */  
     public String getMD5Str(String str) {       
         MessageDigest messageDigest = null;  
         String result = null;

         try {       
             messageDigest = MessageDigest.getInstance("MD5");       

             messageDigest.reset();       

             messageDigest.update(str.getBytes("UTF-8"));  

             byte[] byteArray = messageDigest.digest();       

             StringBuffer md5StrBuff = new StringBuffer();       

             for (int i = 0; i < byteArray.length; i++) {                   
                 if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)       
                     md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));       
                 else       
                     md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));       
             }       
            //16位加密,從第9位到25位  
             result = md5StrBuff.substring(8, 24).toString().toUpperCase(); 

         } catch (NoSuchAlgorithmException e) {       
             System.out.println("NoSuchAlgorithmException caught!");       
             result = null;      
         } catch (UnsupportedEncodingException e) {       
             result = null;     
         }       

         return  result;    
      }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章