反編譯之JD-GUI程式碼邏輯分析

lvxiangan發表於2018-10-24
反編譯後程式碼:
public static void notify(Context context, String type, final String no, String money, String mark, String time) {
    if ((TextUtils.isEmpty(str2)) || (TextUtils.isEmpty(str4))) {
        sendmsg(context, "異常");
        return;
    }
    String str1 = "";
    String str3 = AbSharedUtil.getString(context, type + "balance");
    if (type.equals("ccc")) {
        str1 = AbSharedUtil.getString(context, "ccc");
    }
    for (; ; ) {
        HttpUtils httpUtils = new HttpUtils(15000);
        str4 = MD5.md5(time + mark + money + no + type + str4);
        RequestParams requestParams = new RequestParams();
        requestParams.addBodyParameter("balance", str3);
        if (!TextUtils.isEmpty(str1)) {
            requestParams.addBodyParameter("account", str1);
        }
        requestParams.addBodyParameter("sign", str4);
        httpUtils.send(HttpRequest.HttpMethod.POST, str2, requestParams, new RequestCallBack() {

            public void onFailure(HttpException paramAnonymousHttpException, String paramAnonymousString) {
                update(no, paramAnonymousString);
            }

            public void onSuccess(ResponseInfo<String> responseInfo) {
                responseInfo = (String) responseInfo.result;
                for (; ; ) {
                    update(no, responseInfo);
                    return;
                }
            }
        });
        return;
        if (type.equals("aaa")) {
            str1 = AbSharedUtil.getString(context, "aaa");
        } else if (type.equals("bbb")) {
            str1 = AbSharedUtil.getString(context, "bbb");
        }
    }
}

原始碼:
public static void notify(final Context context, String type, final String no, String money, String mark, String time) {
    if (!TextUtils.isEmpty(notifyurl) && !TextUtils.isEmpty(signkey)) {
        String account = "";
        String balance = AbSharedUtil.getString(context, type + "balance");
        if (type.equals("ccc")) {
            account = AbSharedUtil.getString(context, "ccc");
        } else if (type.equals("aaa")) {
            account = AbSharedUtil.getString(context, "aaa");
        } else if (type.equals("bbb")) {
            account = AbSharedUtil.getString(context, "bbb");
        }

        HttpUtils httpUtils = new HttpUtils(15000);
        signkey = MD5.md5(time + mark + money + no + type + signkey);
        RequestParams params = new RequestParams();
        params.addBodyParameter("balance", balance);
        if (!TextUtils.isEmpty(account)) {
            params.addBodyParameter("account", account);
        }

        params.addBodyParameter("sign", signkey);
        httpUtils.send(HttpMethod.POST, notifyurl, params, new RequestCallBack<String>() {

            public void onFailure(HttpException e, String msg) {
                update(no, msg);
            }

            public void onSuccess(ResponseInfo<String> resp) {
                String result = (String)resp.result;
                update(no, result);
            }
        });
    } else {
        sendmsg(context, "異常");
    }
}

 

for迴圈前後對比:

public static boolean isServiceRunning(Context context, String serviceName) {
    if (("".equals(serviceName)) || (serviceName == null)) {
        return false;
    }
    context = (ArrayList) ((ActivityManager) context.getSystemService("activity")).getRunningServices(30);
    int i = 0;
    for (; ; ) {
        if (i >= context.size()) {
            return false;
        }
        if ((context.get(i)).service.getClassName().toString().equals(serviceName)) {
            return true;
        }
        i += 1;
    }
}


public static boolean isServiceRunning(Context context, String serviceName) {
    if (!"".equals(serviceName) && serviceName != null) {
        
        ArrayList list = (ArrayList)((ActivityManager)context.getSystemService("activity")).getRunningServices(30);
        for(int i = 0; i < list.size(); ++i) {
            if (list.get(i).service.getClassName().toString().equals(serviceName)) {
                return true;
            }
        }
        return false;
    } else {
        return false;
    }
}



while迴圈前後對比:

public static int isActivityTop(Context context) {
    try {
        Iterator iterator = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(100).iterator();
        ActivityManager.RunningTaskInfo taskInfo;
        do {
            if (!iterator.hasNext()) {
                return 0;
            }
            taskInfo = (ActivityManager.RunningTaskInfo) iterator.next();
        }
        while (!taskInfo.topActivity.getClassName().equals("xxxyActivity"));
        int i = taskInfo.numActivities;
        return i;
    } catch (SecurityException e) {
        sendmsg(context, e.getMessage());
    }
    return 0;
}

public static int isActivityTop(Context context) {
    try {
        Iterator iterator = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).getRunningTasks(100).iterator();

        while(iterator.hasNext()) {
            RunningTaskInfo taskInfo = (RunningTaskInfo)iterator.next();
            if (taskInfo.topActivity.getClassName().equals("xxxyActivity"));
                int num = taskInfo.numActivities;
                return num;
            }
        }

        return 0;
    } catch (SecurityException e) {
        sendmsg(context, e.getMessage());
        return 0;
    }
}

 

 

用混淆器打亂的程式碼,反編譯後,要想看懂也不是一件容易的事。因為大部人都會用免費的混淆器來混淆原始碼,大部份反編譯過來的程式碼就有一定的規則可尋:

反編譯後的程式碼一般會產生以下結構的程式碼,(程式碼結構是個人總結的,如有雷同,純屬巧合)比較難看懂,本文章根據實現情況對這幾種結構做個簡單說明。

1,反編譯後的程式碼:if while結構

if (BTActivity.access$2300(this.this$0))
    {
      int i = BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
      BTActivity.access$2500(this.this$0).notifyDataSetChanged();
    }
    while (true)
    {
      return;
      Bluetooth localBt = BTActivity.access$700(this.this$0);
      int k = BTActivity.access$600(this.this$0);
      int l = localBt.sendCommand(1026, paramInt, k);
     }

 (1)只分析邏輯
這裡應該有一個if else的邏輯。從上面的程式碼分析,return下的程式碼應該是永遠不會被執行,但這是不可能的。所以上面的程式碼邏輯(我們先不看語句)應該是這樣的,  去掉while和return,加上else,修改後如下:

 if (BTActivity.access$2300(this.this$0))
    {
       int i = BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
       BTActivity.access$2500(this.this$0).notifyDataSetChanged();
    }
  else
  {
      Bluetooth localBt = BTActivity.access$700(this.this$0);
      int k = BTActivity.access$600(this.this$0);
      int l = localBt.sendCommand(1026, paramInt, k);
    }

  (2)邏輯分析完了,繼續分析語句.
      A)像:int i = BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
            這個是引用外部的一個類中的一個方法。然後返回整型,但這個返回值用不到,所以去掉int i 
      還原應該這樣:
      BTActivity.access$700(this.this$0).sendCommand(1028, 4, paramInt);
      
      B)access$700是什麼意思呢?這是BTActivity類中的一個物件,物件有sendCommand方法。這樣就可以查BTActivity類定義的哪個物件有這樣一個方法了,這好理解。不好理解的是:int k = BTActivity.access$600(this.this$0);  中的access$600,它對應的是BTActivity中的哪個方法呢?這很難確定,所以只能猜:
      1,看這個類中有多少個方法,如果只有一個,那指定就是它了。
      2,如果有多個,那就要看引數。如果只有一個方法的引數與之相對應,那一定是它。
      3,如果引數一樣的也有多個。那看邏輯。如果看不出來,只有猜或新增自己的邏輯。
   
   (3)為什麼會有access$700這樣的方法/屬性名稱?原因是,呼叫者和被調者不在同一個類中。如果兩者在同一個類(包括內部類),反編譯後方法/屬性名稱不會有數字。
   
   (4) 再舉一個更簡單的if else例

if (paramBoolean)
        paramTextView.setTextColor(-16727809);
       while (true)
       {
         return;
         paramTextView.setTextColor(-1315861);
       }

            還原成真正的原始程式碼:

 if (paramBoolean)
         {
           paramTextView.setTextColor(-16727809);
         }
         else
         {
            paramTextView.setTextColor(-1315861);
         }  

2, 反編譯後的程式碼:switch case while結構   

switch (this.mBand)
    {
     default:
     case 0:
     case 1:
     case 2:
    }
    while (true)
    {
      return;
      this.mBand.setText("FM1");
      continue;
      this.mBand.setText("FM2");
      continue;
      this.mBand.setText("AM");
    }

   (1)分析邏輯:根據mBand的不同值,設定文字的顯示內容。還原成原始程式碼:  

  switch (mBand)
    {

     case 0:
      mBand.setText("FM1");
      break;
     case 1:
       mBand.setText("FM2");
       break;
     case 2:
       mBand.setText("AM");
       break;
     default:
    }

   (2)關鍵:一個continue對你應著一個case的結束;。

 

3,反編譯後程式碼如下:if for while結構 

   int i15 = this.freq;
      int i16 = this.rmin;
      if (i15 < i16)
        i17 = this.min;
      int i29;
      for (this.freq = i17; ; this.freq = i29)
      {
        int i27;
        int i28;
        do
        {
          this.x = getWidth();
          this.y = -1;
          break label32:
          i27 = this.freq;
          i28 = this.max;
        }
        while (i27 <= i28);
        i29 = this.max;
      }
      this.y = 0;
      invalidate();

  (1)程式碼邏輯分析:保證freq的值在min和max之間。分析後得到的原始原始碼:

  if (freq < min)
      {
       freq = min;
      }
      
      if (freq <= max)
      {
         x = getWidth();
         y = -1;  
      }
      else
      {
       freq  = max;
       y = 0;
       invalidate();
      }

 4, 解析switch for while結構程式碼

   PowerManager localPowerManager = (PowerManager)getSystemService("power");
    switch (paramInt)
    {
    default:
    case 0:
    case 1:
    }
    for (String str = "on"; ; str = "other")
      while (true)
      {
        PowerManager.WakeLock localWakeLock = localPowerManager.newWakeLock(6, str);
        localWakeLock.acquire();
        localWakeLock.release();
        return;
        str = "off";
      }

還原原始碼:    

 PowerManager localPowerManager = (PowerManager)getSystemService("power");
     String str = null;
     switch (paramInt)
     {
      case 0:
       str = "on";
       break;
      case 1:
       str = "off";
       break;
      default:
       str = "other";
       break;
     }

     PowerManager.WakeLock localWakeLock = localPowerManager.newWakeLock(6, str);
        localWakeLock.acquire();
        localWakeLock.release();

5, 分析返編譯後的程式碼(if while結構)

 例1:  

 if (paramInt1 == 0)
      this.mMessage.setText("");
    while (true)
    {
      this.mAdditionalMessage.setVisibility(8);
      int i = this.mLevel.getMax();
      if (paramInt2 != i)
        this.mLevel.setMax(paramInt2);
      Toast localToast = this.mToast;
      ...... 

      return;
      TextView localTextView = this.mMessage;
      String str = "" + paramInt1;
      localTextView.setText(str);
    }

  分析:1,先去掉“this"

              2,看返編譯後的按順序邏輯走一遍。可以看出while到return這段程式碼,不管怎麼樣都會執行的。所以原始程式碼應該是這樣的:    

setSmallIcon(paramInt1);
     paramInt1 &= 2147483647;
     if (paramInt1 == 0)
     {
       mMessage.setText("");
     }
     else
     {
       String str = "" + paramInt1;
       mMessage.setText(str);
     }
     mAdditionalMessage.setVisibility(8);
     if (paramInt2 != mLevel.getMax())
     {
       mLevel.setMax(paramInt2);
     }
     mToast.setView(mView);

      ......

 

 6,一個continue對應一個back原則(switch while結構)
在這種形式中,一個contiune一定是對應一個back,但一個case不一定只對應一個contiune,也有一個case對應兩個或多個contiune(即back).
如以下反編譯後的程式碼:


    分析程式碼:

1),上遍已對這種形式有講過,一個continue對應一個case,但是你數一數會發現,對不上號,明顯case多於contiune,原因是什麼呢?其實switch裡的default對應的是while中的return,在switch中default以上的case是用不著,是沒有用的。

2),如果default上面的case沒有用,聰明的你可以可能會問兩個問題?
A,default上面的case沒有用,為什麼還會有呢?原因很簡單,因為反編譯器也不是全智慧的總會有不對的(但是執行邏輯是不會有錯),呵呵真正的原因當然不會是這樣,你可以自己去分析一下,從整個程式分析就可以得出結論來。
B,那按一個continue對應一個back的原則不是有錯嗎? 當然沒有。一個continue還是對應一個back, 聰明的你一定看懂了,每兩個continue中間還有一個if語句,對,沒錯,你理解是對的,就是在這中間滿足條件時就會back,所以就會有一個continue與之相對應。
  所這裡每個if + continue + continue的形式對應一個case。









 

二 錯誤程式碼還原規則

if…else 語句:

反編譯程式碼

if (paramBoolean)
        paramTextView.setTextColor(-16727809);
       while (true)
       {
         return;
         paramTextView.setTextColor(-1315861);
       } 還原後if (paramBoolean)
         {
           paramTextView.setTextColor(-16727809);
         }
         else
         {
            paramTextView.setTextColor(-1315861);
         }  



例子2:
if (responseInfo.contains("success")) {
    sendmsg(this, "傳送成功" + responseInfo);
}
for (; ; ) {
    update(no, responseInfo);
    return;
    sendmsg(this, "傳送失敗" + responseInfo);   // 紅色部分對應下方else分支
}

還原後變成
if (result.contains("success")) {
    sendmsg(context, "傳送成功" + result);
} else {
    sendmsg(context, "傳送失敗" + result);
}
update(no, result);

 

 

if ..esle 反編譯成 if …while(true)結構.

反編譯程式碼
if (paramInt1 != 1)
        break label185;
      if (this.countChild_1 == null)  {
        this.countChild_1 = new PokerCountChild(this.mContext);
        this.countChild_1.setCount(paramInt2);
        addOneChild(this.countChild_1);
        if (paramInt2 == 0)
          this.countChild_1.setAlpha(0);
      }
      this.countChild_1.setCount(paramInt2);
    }
    label185:
    do
      return;
    while (paramInt1 != 2);
    if (this.countChild_2 == null)  {
      this.countChild_2 = new PokerCountChild(this.mContext);
      this.countChild_2.setCount(paramInt2);
      addOneChild(this.countChild_2);
      if (paramInt2 == 0)
        this.countChild_2.setAlpha(0);
    }
    this.countChild_2.setCount(paramInt2);

還原
if(i == 1)  {
                if(countChild_1 == null)  {
                    countChild_1 = new PokerCountChild(mContext);
                    countChild_1.setCount(j);
                    addOneChild(countChild_1);
                    if(j == 0)
                        countChild_1.setAlpha(0);
                }
                countChild_1.setCount(j);
            } else  if(i == 2)  {
                if(countChild_2 == null) {
                    countChild_2 = new PokerCountChild(mContext);                    
                    countChild_2.setCount(j);
                    addOneChild(countChild_2);
                    if(j == 0)
                        countChild_2.setAlpha(0);
                }
                countChild_2.setCount(j);
                return;
            }
會將語句倒序,出現break label結構

 

 

label1:{
    label2: {
        if () {
            break label2; //是要跳出label2,也就是label2 end的下一句
        }
    }//label2 end
}

 

 

 

 


 
另外,jd-gui有時會將while語句翻譯成if,要將if改成while

 

switch語句

反編譯程式碼

switch (this.mBand)
    {
     default:
     case 0:
     case 1:
     case 2:
    }
    while (true)
    {
      return;
      this.mBand.setText("FM1");
      continue;
      this.mBand.setText("FM2");
      continue;
      this.mBand.setText("AM");
    }
還原
switch (mBand)
    {
     case 0:
      mBand.setText("FM1");
      break;
     case 1:
       mBand.setText("FM2");
       break;
     case 2:
       mBand.setText("AM");
       break;
     default:
    }
switch規則就是一個continue對應一個case.要注意是是要外層的continue才算數,在if裡的continue不算

相關文章