<em id="pzl9c"></em>
      <dl id="pzl9c"><ins id="pzl9c"></ins></dl>
      <dfn id="pzl9c"></dfn>

        <progress id="pzl9c"></progress>
        <div id="pzl9c"><ol id="pzl9c"></ol></div>
          <div id="pzl9c"><tr id="pzl9c"></tr></div>

          <em id="pzl9c"></em>

            <em id="pzl9c"><ins id="pzl9c"><mark id="pzl9c"></mark></ins></em>
            <dl id="pzl9c"></dl>

            <dl id="pzl9c"></dl>

              <div id="pzl9c"></div>
              <dl id="pzl9c"><ins id="pzl9c"></ins></dl>

              <dfn id="pzl9c"></dfn>
              <sup id="pzl9c"><ins id="pzl9c"></ins></sup>

                <dl id="pzl9c"></dl>

                飄云閣(PYG官方論壇)

                 找回密碼
                 加入論壇

                QQ登錄

                只需一步,快速開始

                掃一掃,訪問微社區

                查看: 2289|回復: 31
                打印 上一主題 下一主題

                [Android] 戀戀APK之登錄時DES加密分析

                [復制鏈接]
              1. TA的每日心情
                慵懶
                2018-9-30 10:36
              2. 簽到天數: 101 天

                [LV.6]常住居民II

                跳轉到指定樓層
                樓主
                發表于 2018-4-6 22:27:20 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
                本帖最后由 Bu棄 于 2018-4-6 22:27 編輯

                大家好呀,好久都沒在論壇發帖了(好像我一共也沒發幾個帖,尷尬)。因為最近對Android的逆向有興趣,所以去網上找了下教程。好像論壇也有。叫《無名Android逆向》,感興趣的可以去看看。
                此次發帖算是筆記吧。記錄自己怎么跟著視頻一步一步的分析,也算是一個作業。畢竟 看懂了 !=  你會了!
                教程第一課是分析一款戀戀的交友APK。具體是分析它登錄時是如何把信息加密,然后發送到服務器的。廢話不多說,開搞吧。我盡量寫詳細點,以下有些思路和內容是視頻里面的,我借鑒下,希望不會被噴。另外有些詞把握得不是很準。有些地方或許說法有些錯誤,希望大家多多指正。畢竟我也是個小白,正在學習ing。。。。
                   一、需要的工具
                       JEB、IDA(分析so文件)、Fiddler(抓包)、任意一款Android模擬器/手機
                   二、開整吧
                       1.首先使用抓包工具Fiddler,抓下此APK登錄時發送的數據包。設置如下。
                                             

                         
                                    2. 設置模擬器網絡
                                          
                                  3.登錄后的封包(用戶名為123456789  密碼為[email protected]#$%^)
                                        
                                  4.從上面的封包中,我們看到了請求的url(POST后面跟著的那串),還有加密后的用戶名和密碼。下面我們就使用url字符串(http://mob.imlianai.com/call.do?cmd=mobileUser.login )搜索,定位到關鍵點。
                                  5.打開JEB,把APK拖入,然后切換到字符串。搜索上面抓到的url(http://mob.imlianai.com/call.do?cmd=mobileUser.login )其實我們這里只需要搜索mobileUser.login 就行了。
                                  6.雙擊找到的字符串,來到匯編界面。
                                     
                                7.點擊任意一行,按TAB鍵,到java代碼界面
                                  
                               8.這里是switch語句。主要應該是根據參數來選擇操作的連接地址。我們往下找找。看看有沒有什么我們需要的。
                               9.在下面很多地方,我們都發現了類似這樣的代碼:
                [Java] 純文本查看 復制代碼
                           JSONObject v1_1 = new JSONObject();   //創建一個構建JSON字符串的對象
                            v1_1.put("xxxx", xxxx);   //往里面加入key/value形式的鍵值對
                            v1_1.put("xxxx", xxxx);
                            v0 = com.a.a.a.f.a.a(v1_1.toString()).getBytes(); //com.a.a.a.f.a.a(v1_1.toString()) 就是具體的加密邏輯了
                

                               10.com.a.a.a.f.a.a()這個方法就是具體的加密邏輯了。接下來我們著重分析下。我們雙擊這個方法,進入到方法實現位置,具體代碼如下:
                [Java] 純文本查看 復制代碼
                public class a {
                    private static final byte[] a;
                    private static final IvParameterSpec b;
                    private static String c;
                    private static Key d;
                
                    static {
                        a.a = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
                        a.b = new IvParameterSpec(a.a);
                        a.c = "hqi/FjjcBxA=";
                        a.d = null;
                    }
                
                    public static String a(String arg1) { //這就是加密的方法體
                        return Jni.getInstance().encryptString(arg1);
                    }
                }
                
                                                 
                                11.觀察上面的代碼,發現其又調用了Jni中的encryptString方法。把Json字符串傳遞過去。我們照樣雙擊這個方法。得到如下代碼
                [Java] 純文本查看 復制代碼
                    public String encryptString(String arg9) {
                        String v0_1;
                        if(arg9 == null || arg9.length() == 0) { // 如果什么都沒輸入的話,就把v0_1置為空串,返回。否則則進行加密操作
                            v0_1 = "";
                        }
                        else {
                            String v2 = this.encode(arg9);  //調用本類中的encode方法。這個方法主要是把字符串的每個字符的字節碼轉換成16進制形式。例如 ‘a’ 的ASCII是[color=#333333]97,經過這個方法后,就變成了61[/color]
                            int v3 = v2.length();
                            StringBuffer v4 = new StringBuffer();
                            if(v3 < 500) {    //如果v2的長度小于500.則執行下面的邏輯。否則執行else中的。我們現在就只看下面的邏輯,先不看else中的邏輯
                                v4.append(this.getEncryptString(v2, true)); //調用this.getEncryptString(v2, true)加密。具體細節我們后面說
                            }
                            else {
                                int v0;
                                for(v0 = 1; v0 < v3 / 500 + 1; ++v0) {
                                    if(v3 % 500 == 0 && v0 == v3 / 500) {
                                        v4.append(this.getEncryptString(v2.substring((v0 - 1) * 500, v0 * 500), true));
                                        break;
                                    }
                
                                    v4.append(this.getEncryptString(v2.substring((v0 - 1) * 500, v0 * 500), false));
                                }
                
                                if(v3 % 500 == 0) {
                                    goto label_15;
                                }
                
                                v4.append(this.getEncryptString(v2.substring((v0 - 1) * 500, v3), true));
                            }
                
                        label_15:
                            v0_1 = DESencryption.getEncString(v4.toString(), this.getEncryptString("a", true).substring(0, 8));  //使用DES對加密后的數據再進行加密。DES的key是一個固定的值。因為用到了getEncryptString()方法,所以等分析完這個方法我們再提
                        }
                        return v0_1;
                    }
                
                

                            三、分析this.getEncryptString(v2, true)                  

                                   1.getEncryptString代碼如下:
                [Java] 純文本查看 復制代碼
                private native String getEncryptString(String arg1, boolean arg2) {}  //native為原生態方法,一般是調用C++、C語言代碼
                

                                   2.上面代碼是通過JNI調用C++或者C語言代碼。有關于這方面的知識。我也是小白,所以也不怎么懂。大家可以去百度下。既然這里是通過JNI調用,那么我們怎么知道他調用的是哪個so文件呢?在這個類上面的static靜態代碼塊中聲明出來了。如下:
                [Java] 純文本查看 復制代碼
                    static {
                        Jni.hexString = "0123456789ABCDEF";  //這個先不管。這個是用于上面說的encode方法把字符串的每個字符的字節碼轉換成16進制形式的。
                        System.loadLibrary("jni"); //這個就是加載so的庫了。so的名字是libjni.so。字符串jni前面再加上lib。
                    }
                
                

                                    3.在APK中的\lib\armeabi下有個libjni.so文件。我們現在把它拖入ida中。
                                    4.在IDA載入完成后,進入Exports中。如果沒有Exports視圖,則需要進行如下操作就行了。Exports中會顯示所有的導出函數

                                        
                                                 
                                    5.因為供Java調用的API有個明顯的特征:Java_包名_方法名。我們Ctrl+F搜索下Java開頭的。很幸運,這個里面只有一個。而且發現方法名也是和Java中聲明的native方法名是一樣的。
                                              
                                     6.雙擊進去吧。就進入了匯編頁面。匯編代碼頁面我就不貼了。直接按F5變成C代碼,我們再分析吧。總體分析如下。
                [C++] 純文本查看 復制代碼
                int __fastcall Java_com_jni_Jni_getEncryptString(_JNIEnv *a1, JNIInvokeInterface *a2, int inputStr, int inputBool) //你們一點進去可能方法定義不是這樣的。你只需要導入下jni.h就行。具體操作,在第7點中給出
                {
                  _JNIEnv *v4; // [email protected]
                  int str; // [email protected]
                  int v6; // [email protected]
                  const char *v7; // [email protected]
                  size_t v8; // [email protected]
                  _JNIEnv *v9; // [email protected]
                  char *v10; // [email protected]
                  jstring (__cdecl *v11)(JNIEnv *, const char *); // [email protected]
                  int result; // [email protected]
                  char *s; // [sp+0h] [bp-828h]@1
                  int v14; // [sp+4h] [bp-824h]@1
                  char dest; // [sp+Ch] [bp-81Ch]@3
                  int v16; // [sp+80Ch] [bp-1Ch]@1
                
                  v4 = a1;
                  str = inputStr;
                  v14 = inputBool;
                  v16 = _stack_chk_guard;
                  g_env = a1;
                  s = (char *)initAddStr();                     // 初始化一個字符串。待會我們再分析
                  v7 = (const char *)jstringTostring((int)v4, str, v6);// 調用JNI的方法,把Java中的String變成C中的char *
                  v8 = strlen(s);                               // 求出初始化字符串的長度
                  if ( strlen(v7) + v8 <= 0x7FF )               // 轉成C的inputStr的長度和s的長度<0x7ff(2047)如果小于則拼上s.否則不拼
                  {
                    memset(&dest, 0, 0x7FFu);                   // 往dest這個地址填充0x7FF個0
                    strcat(&dest, v7);                          // 這里是把v7的值,也就是inputStr轉成Char的值賦給dest
                    if ( v14 )                                  // 第2個傳參也就是inputBool為true的時候,就在后面跟上初始值s。否則不跟
                      strcat(&dest, s);
                    v9 = v4;                                    // v9 = JNIEnv
                    v10 = &dest;
                    v11 = v4->functions->NewStringUTF;          // v11 =  NewStringUTF:把C的char* 轉換成Java中的String
                  }
                  else
                  {
                    v9 = v4;
                    v10 = (char *)v7;
                    v11 = v4->functions->NewStringUTF;          // v11 =  NewStringUTF:把C的char* 轉換成Java中的String
                  }
                  result = ((int (__fastcall *)(_JNIEnv *, char *))v11)(v9, v10);// 調用NewStringUTF方法,把v10轉換成String
                  if ( v16 != _stack_chk_guard )
                    _stack_chk_fail(result);
                  return result;
                }
                

                                   7.導入jni.h文件。此文件在java_home/jdk/lib下。當然你直接導會報錯。我們需要修改一下。具體修改方法百度下吧。我待會會提供個。導入操作如下:
                                     
                                 8.現在我們逐步來分析下。首先看方法聲明中的參數。int __fastcall Java_com_jni_Jni_getEncryptString(_JNIEnv *a1, JNIInvokeInterface *a2, int inputStr, int inputBool)。參數列表函數如下:                              1)_JNIEnv * :這個參數是固定的。傳入的是Dalvik虛擬的函數表。具體可參考   https://www.cnblogs.com/gavanwanggw/p/6907893.html
                                              2)JNInvokeInterface * :這個參數也是固定的。傳入的是正在調用這個方法的類。
                                              3)int :這個是函數的參數,也就是java傳遞過來的參數,因為在Java中第一個參數傳的是String,而C中沒有String。所以這個應該是char*指針。
                                              4)int:這個同樣是Java傳遞過來的參數。在Java中傳的是boolean。C中沒有。所以用int代替。
                                9.分析 s = (char *)initAddStr(); 。我們點開這個函數。他內部如下
                [C++] 純文本查看 復制代碼
                int initAddStr()
                {
                  int v0; // [email protected]
                  int v1; // [email protected]
                
                  if ( !isInit ) //這里是如果初始化一次了,就不需要再執行了。也就是這里只會執行一次。
                  {
                    v0 = initInflect((int)jniStr);  //在第10點中分析
                    key = jstringTostring((int)g_env, v0, v1); //調用方法,把java的String變成C語言中的char*
                    isInit = 1;
                  }
                  return key;
                }
                
                

                                 10.分析initInflect((int)jniStr)。蠶食為jniStr。那么jniStr是什么呢?我們雙擊下jniStr。發現如下:
                                     
                                       那么,jniStr = “/key=i im lianai” 。接下來我們看看initInflect方法的內部吧
                [C++] 純文本查看 復制代碼
                int __fastcall initInflect(int a1)
                {
                  int *v1; // [email protected]
                  int v2; // [email protected]
                  bool v3; // [email protected]
                  int v4; // [email protected]
                  int v5; // [email protected]
                  int (__fastcall *v6)(int *, const char *); // [email protected]
                  const char *v7; // [email protected]
                  int v8; // [email protected]
                  int v9; // [email protected]
                  int v10; // [email protected]
                  int v12; // [sp+Ch] [bp-1Ch]@1
                
                  v12 = a1;
                  v1 = g_env;
                  v2 = (*(int (__fastcall **)(_DWORD *, const char *))(*g_env + 24))(g_env, "com/Reflect");
                  v4 = v2;
                  v3 = v2 == 0;
                  v5 = *v1;
                  if ( v3 )
                  {
                    v6 = *(int (__fastcall **)(int *, const char *))(v5 + 668);
                    v7 = "jclass";
                    return v6(v1, v7);
                  }
                  v8 = (*(int (__fastcall **)(int *, int, const char *, const char *))(v5 + 452))(
                         v1,
                         v4,
                         "func",
                         "(ILjava/lang/String;)Ljava/lang/String;");
                  v9 = *v1;
                  v10 = v8;
                  if ( !v8 )
                  {
                    v6 = *(int (__fastcall **)(int *, const char *))(v9 + 668);
                    v7 = "method";
                    return v6(v1, v7);
                  }
                  (*(void (__fastcall **)(int *, int))(v9 + 668))(v1, v12);
                  return _JNIEnv::CallStaticObjectMethod(v1, v4, v10, 10);
                }
                
                

                                      好吧。這里我就不一行一行分析了,因為我也不會。但是大致意思是看懂了。意識是調用com.Reflect類中的func方法。參數就是“/key=i im lianai”我們接下來回到JEB看吧。
                                 11. 代碼如下:
                [Java] 純文本查看 復制代碼
                package com;
                
                public class Reflect {
                    private static String hexString;
                    public static String tmp;
                
                    static {
                        Reflect.tmp = " alien";
                        Reflect.hexString = "0123456789ABCDEF";
                    }
                
                    public Reflect() {
                        super();
                    }
                
                    private static String encode(String arg5) {//arg5 = “/key=i im lianai alien”   這里就是上面的把字符串中的字母變為16進制的代碼了。我就不一行一行讀了
                        byte[] v1 = arg5.getBytes();
                        StringBuilder v2 = new StringBuilder(v1.length * 2);
                        int v0;
                        for(v0 = 0; v0 < v1.length; ++v0) {
                            v2.append(Reflect.hexString.charAt((v1[v0] & 240) >> 4));
                            v2.append(Reflect.hexString.charAt((v1[v0] & 15) >> 0));
                        }
                
                        return v2.toString();
                    }
                
                    public static String func(int arg2, String arg3) {//這個就是IDA中調用的方法
                        return Reflect.encode(String.valueOf(arg3) + Reflect.tmp);  //這里調用了此類中的encode方法,傳入的是我們傳遞過來的參數“/key=i im lianai” 加上此類提供的一個靜態字符串" alien"<注意前面有個空格>,綜合起來也就是“/key=i im lianai alien”
                    }
                }
                
                

                                     12.總結下initInflect((int)jniStr)的作用:傳入“/key=i im lianai alien”把其中的每個字母轉成16進制字符串。最后的結果是“2F6B65793D6920696D206C69616E616920616C69656E” 這個是固定的。
                                     13.其他的都分析完了。現在我們總結下getEncryptString()這個方法.這個方法說的就是把傳入的字符串,如果長度小于0x7FF的就在后面拼上“2F6B65793D6920696D206C69616E616920616C69656E”。
                                     14.so部分到此結束,這個so挺容易。做的事也容易。就是拼下字符串。然后我們回到JEB中的java代碼中。看類Jni的encryptString的最后。
                [Java] 純文本查看 復制代碼
                 v0_1 = DESencryption.getEncString(v4.toString(), this.getEncryptString("a", true).substring0, 8));   //這個就是最終的結果了。v4就是經過so處理過的字符串,第二個參數是“a”去讓so處理,在截取他的0~8位作為DES加密的key。加密后就是結果了。
                
                

                                    15.DES算法我不懂。所以里面的就不看了。我們可以直接把這些代碼拷出來到Eclipse中。然后使用Java代碼驗證我們的分析是否正確。Java代碼如下:
                [Java] 純文本查看 復制代碼
                public class Test01 {
                    public static void main(String[] args) throws Exception {
                       String jsonHex = getHexString("{\"pwd\":\"[email protected]#$%^\",\"number\":\"1234567890\"}"); //登錄時的JSON字符串
                       String initStringHex = getHexString("/key=i im lianai alien");//固定的字符串
                       String soString = jsonHex+initStringHex;
                       String ret = DESencryption.getEncString(soString, "a2F6B657");
                       System.out.println(ret);
                    }
                
                    /**
                     * 這里是復制JEB中的把字符串中每個字符轉換成16進制字符串
                     * @param str
                     * @return
                     * @throws Exception
                     */
                    public static String getHexString(String str) throws Exception {
                        byte[] v1 = str.getBytes("UTF-8");
                        String hexString = "0123456789ABCDEF";   
                        StringBuilder v2 = new StringBuilder(v1.length * 2);
                        int v0;
                        for(v0 = 0; v0 < v1.length; ++v0) {
                            v2.append(hexString.charAt((v1[v0] & 240) >> 4));
                            v2.append(hexString.charAt((v1[v0] & 15) >> 0));
                        }
                       return v2.toString();
                    }
                }
                
                

                                 16.最后結果如下:
                            
                                 
                                17.總結下流程:
                                        1)用戶輸入用戶名和密碼。把他么封裝成JSON字符串
                                        2)把JSON字符串的每個字符,變成16進制形式
                                        3)調用so庫。拼接固定字符串"2F6B65793D6920696D206C69616E616920616C69656E"
                                        4)調用DES加密。密碼是固定的"a2F6B6579",要加密的數據就是第3)步拼接出來的。
                                        5)我也是小白,各位親噴。有地方說錯的,歡迎批評指正。
                                        6)這個能吐槽下論壇的這個帖子的富文本編輯器么?為嘛不支持TAB鍵。。。。還有排版好蛋疼。。。。
                                        6)收工,洗澡睡覺。謝謝大家。
                               考慮到有些小伙伴需要《無名Android逆向》所以這里就直接給出了。按道理不會違規吧。如果有違規,麻煩版主大人@下我,我改正。
                                《無名Android逆向》鏈接: https://pan.baidu.com/s/1yb-1OJWJPkDFjJQZ5Fh-4w 密碼: 39y5


                               第一課的課件里面也有。有的不需要這個課程,我也直接給下課件的分享吧。
                                課件 鏈接: https://pan.baidu.com/s/1N-GYBBS4x9hZeKu_T3pjPg 密碼: phgi






                評分

                參與人數 4威望 +14 飄云幣 +18 收起 理由
                losers + 2 很給力!
                Rooking + 8 很給力!
                gfjykldd + 2 PYG有你更精彩!
                wai1216 + 10 + 10 贊一個!

                查看全部評分

                本帖被以下淘專輯推薦:

                分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友 微信微信
                收藏收藏9 轉播轉播 分享分享 分享淘帖1 頂 踩 友情贊助 微信分享
              3. TA的每日心情
                慵懶
                2018-9-30 10:36
              4. 簽到天數: 101 天

                [LV.6]常住居民II

                沙發
                 樓主| 發表于 2018-4-6 22:29:34 | 只看該作者
                沙發自己來
                回復 支持 反對

                使用道具 舉報

              5. TA的每日心情
                開心
                2016-6-16 14:07
              6. 簽到天數: 10 天

                [LV.3]偶爾看看II

                藤椅
                發表于 2018-4-6 23:26:33 | 只看該作者
                666 就喜歡看協議分析 精了!
                回復 支持 反對

                使用道具 舉報

              7. TA的每日心情
                開心
                昨天 13:47
              8. 簽到天數: 1078 天

                [LV.10]以壇為家III

                板凳
                發表于 2018-4-7 13:55:34 | 只看該作者
                小白前來學習了
                回復 支持 反對

                使用道具 舉報

              9. TA的每日心情
                開心
                昨天 21:21
              10. 簽到天數: 1009 天

                [LV.10]以壇為家III

                報紙
                發表于 2018-4-7 16:56:39 | 只看該作者
                謝謝大神提供這么好的學習資料好好學習天天向上
                回復 支持 反對

                使用道具 舉報

              11. TA的每日心情
                奮斗
                4 天前
              12. 簽到天數: 188 天

                [LV.7]常住居民III

                地板
                發表于 2018-4-7 19:59:36 | 只看該作者

                厲害啊樓主,謝謝樓主分享
                回復 支持 反對

                使用道具 舉報

              13. TA的每日心情
                奮斗
                4 天前
              14. 簽到天數: 188 天

                [LV.7]常住居民III

                7#
                發表于 2018-4-7 20:00:46 | 只看該作者

                謝謝大神提供這么好的學習資料
                回復 支持 反對

                使用道具 舉報

              15. TA的每日心情
                奮斗
                2018-9-28 09:44
              16. 簽到天數: 276 天

                [LV.8]以壇為家I

                8#
                發表于 2018-4-7 22:51:21 | 只看該作者
                圍觀大神 受益匪淺
                回復 支持 反對

                使用道具 舉報

              17. TA的每日心情

                5 天前
              18. 簽到天數: 68 天

                [LV.6]常住居民II

                9#
                發表于 2018-4-9 17:02:49 | 只看該作者
                Bu棄師傅厲害呀,研究加密算法了。

                點評

                我是一渣渣,算法部分都跳過了  詳情 回復 發表于 2018-4-9 22:40
                回復 支持 反對

                使用道具 舉報

              19. TA的每日心情
                慵懶
                2018-9-30 10:36
              20. 簽到天數: 101 天

                [LV.6]常住居民II

                10#
                 樓主| 發表于 2018-4-9 22:40:07 | 只看該作者
                666888tzq 發表于 2018-4-9 17:02
                Bu棄師傅厲害呀,研究加密算法了。

                我是一渣渣,算法部分都跳過了
                回復 支持 反對

                使用道具 舉報

                您需要登錄后才可以回帖 登錄 | 加入論壇

                本版積分規則

                關閉

                站長推薦上一條 /1 下一條

                快速回復 返回頂部 返回列表
                11选5中奖报道