天天看點

JD-GUI反編譯後代碼邏輯分析

一,用jd-gui.exe等工具檢視源代碼。如何你不會,可以參看此文章:

http://blog.csdn.net/hp_2008/article/details/8207879

 可以到以下連接配接下載下傳可視化反編譯工具:

http://download.csdn.net/detail/hp_2008/5099046

二,反編譯後的源代碼,是亂的,看不太懂。這是因為開發者在釋出APK時,一般都會用代碼混淆器将原始的源代碼打亂,

這也是防盜的一種方法。但是再怎樣防,道高一尺,魔高一丈,用反編譯工具很輕松的就可反編譯成源碼。要想做到反編譯成一點也看不懂的代碼,這很難,

在Android Java開源的世界裡就更難做到了。當然你可以把核心的放到中間層,用C/C++封裝成庫,通過JNI調用,這樣要想反編譯庫就有難度了。

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

(本人水準有限,如有什麼不對的地方,還請指教,非常感謝)

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

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); 這句初步還原就是去掉int k。

      然後是這個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);

         }   

         以後碰到這樣的if while還原就應該是上面的樣子。

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();

      }

     (2)得到上面的源代碼關鍵在于,按反編譯後的代碼走一遍。 

 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).

如以下反編譯後的代碼:

[java]  view plain copy

  1. switch (getId())  
  2.  {  
  3.  case 2131034119:  
  4.  case 2131034120:  
  5.  case 2131034121:  
  6.  case 2131034122:  
  7.  case 2131034123:  
  8.  case 2131034124:  
  9.  case 2131034125:  
  10.  case 2131034126:  
  11.  case 2131034127:  
  12.  case 2131034128:  
  13.  default:  
  14.  case 2131034129:  
  15.  case 2131034130:  
  16.  case 2131034131:  
  17.  case 2131034132:  
  18.  case 2131034133:  
  19.  case 2131034134:  
  20.  case 2131034117:  
  21.  case 2131034118:  
  22.  }  
  23.  while (true)  
  24.  {  
  25.    return;  
  26.    int i = paramVerticalSeekBar.getProgress() * 14;  
  27.    int j = paramVerticalSeekBar.getMax();  
  28.    int k = i / j;  
  29.    if (APPActivity.access$200(this.this$0) == k)  
  30.      continue;  
  31.    int l = APPActivity.access$202(this.this$0, k);  
  32.    int i1 = APPActivity.access$200(this.this$0);  
  33.     continue;  
  34.    int i3 = paramVerticalSeekBar.getProgress() * 14;  
  35.    int i4 = paramVerticalSeekBar.getMax();  
  36.    k = i3 / i4;  
  37.    if (APPActivity.access$400(this.this$0) == k)  
  38.      continue;  
  39.    int i5 = APPActivity.access$402(this.this$0, k);  
  40.    EQ localEQ2 = APPActivity.access$1400(this.this$0);  
  41.    int i6 = APPActivity.access$400(this.this$0);  
  42.    int i7 = localEQ2.sendCommand(257, 2, i6);  
  43.    continue;  
  44.    int i8 = paramVerticalSeekBar.getProgress() * 14;  
  45.    int i9 = paramVerticalSeekBar.getMax();  
  46.    k = i8 / i9;  
  47.    if (APPActivity.access$500(this.this$0) == k)  
  48.      continue;  
  49.    int i10 = APPActivity.access$502(this.this$0, k);  
  50.    int i11 = APPActivity.access$500(this.this$0);  
  51.    continue;  
  52.    int i13 = paramVerticalSeekBar.getProgress() * 3;  
  53.    int i14 = paramVerticalSeekBar.getMax();  
  54.    k = i13 / i14;  
  55.    if (APPActivity.access$600(this.this$0) == k)  
  56.      continue;  
  57.    int i15 = APPActivity.access$602(this.this$0, k);  
  58.    EQ localEQ4 = APPActivity.access$1400(this.this$0);  
  59.    int i16 = APPActivity.access$600(this.this$0);  
  60.    int i17 = localEQ4.sendCommand(257, 8, i16);  
  61.    continue;  
  62.    int i18 = paramVerticalSeekBar.getProgress() * 3;  
  63.    int i19 = paramVerticalSeekBar.getMax();  
  64.    k = i18 / i19;  
  65.    if (EQActivity.access$700(this.this$0) == k)  
  66.      continue;  
  67.    int i20 = APPActivity.access$702(this.this$0, k);  
  68.    EQ localEQ5 = APPActivity.access$1400(this.this$0);  
  69.    int i21 = APPActivity.access$700(this.this$0);  
  70.    continue;  
  71.    int i23 = paramVerticalSeekBar.getProgress() * 3;  
  72.    int i24 = paramVerticalSeekBar.getMax();  
  73.    k = i23 / i24;  
  74.    if (APPActivity.access$800(this.this$0) == k)  
  75.      continue;  
  76.    int i25 = APPActivity.access$802(this.this$0, k);  
  77.    EQ localEQ6 = APPActivity.access$1400(this.this$0);  
  78.    int i26 = APPActivity.access$800(this.this$0);  
  79.    continue;  
  80.    int i28 = paramVerticalSeekBar.getProgress() * 14;  
  81.    int i29 = paramVerticalSeekBar.getMax();  
  82.    k = i28 / i29;  
  83.    if (APPActivity.access$900(this.this$0) == k)  
  84.      continue;  
  85.    int i30 = APPActivity.access$902(this.this$0, k);  
  86.    EQ localEQ7 = APPActivity.access$1400(this.this$0);  
  87.    int i31 = APPActivityvity.access$900(this.this$0);  
  88.    continue;  
  89.    int i33 = paramVerticalSeekBar.getProgress() * 3;  
  90.    int i34 = paramVerticalSeekBar.getMax();  
  91.    k = i33 / i34;  
  92.    if (APPActivity.access$1000(this.this$0) == k)  
  93.      continue;  
  94.    int i35 = APPActivity.access$1002(this.this$0, k);  
  95.    EQ localEQ8 = APPActivity.access$1400(this.this$0);  
  96.    int i36 = APPActivity.access$1000(this.this$0);  
  97.  }  

    分析代碼:

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。

3),恢複原代碼結構就變的簡單,這裡就再敖叙了。

轉自:http://blog.csdn.net/ordinaryjoe/article/details/8626010