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).
如以下反编译后的代码:

 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),恢复原代码结构就变的简单,这里就再敖叙了

时间: 2024-10-10 16:21:59

JD-GUI反编译后代码逻辑分析的相关文章

实现android apk反编译后代码混淆

通常情况下我们需要对我们开发的android代码进行混淆,以免代码在反编译时暴露敏感信息及相关技术代码: 反编译测试工具:onekey-decompile-apk-1.0.1. 在高级版本的adt创建完都会有project.properties文件:开启混淆的话,需要在文件中这样做如图: 注意:混淆代码的生效时刻是在:apk签名之后. 然后在用onekey-decompile-apk-1.0.1反编译后效果如下:

浅析Class文件反编译后的文件与源码文件大小关系

1.  编辑java文件后(有注释的情况下) 使用eclipse编译后成为.class文件后 2. 使用反编译工具编译后使用自带(Ctrl+S)的保存源码方式保存 3. 仅复制java翻译后的信息 其大小目前为149字节. 后续处理 a.      现在删除掉[第一步]源码文件中无关注释行,其大小变为118字节,但是其功能仍能实现. b.      现在将[第二步]中反编译工具保存的源码删除了无关部分,再看其大小.发现只有通过删除无关代码和空行后,才能使得其大小与第三步得到为java文件大小一致

反编译后的数组使用解析

上午在一个群里见到有人在问反编译后的数组问题,不知道如何计算数据,想起来自己以前有写过小记录,这里再次贴上吧,供人参考一下. 对于一些简单的游戏来说,商店物品和人物血量之类的都是用数组来定义的.拿到一个游戏反编译后,经过分析寻找,发现所使用人物初始化数值为数组定义,以下为人物血量值,从第一级血量到满级都存放在下面这个数组. 这个图看不懂,没问题,我放上下图的的java代码你就明白了: 关于这个数组,我们需要分析的是其中数值的计算,经过查询资料,这里面的数据是低级的数据存储,每一行代表着数组中一个

C#中修改Dll文件 (反编译后重新编译)

Dll文件生成后,如没有源代码,又要修改其中内容 可以用微软自带的ildasm和ilasm程序 先用ildasm将dll文件反编译成il文件 ildasm Test.dll /out=Test.il 会生成Test.res和Test.il两个文件 il文件可以用文本编辑器修改,要注意其中的语法 改完后再用ilasm将il文件重新编译成dll文件 ilasm /dll /res:Test.res Test.il /out:Test.dll 本人测试时因为ildasm和ilasm程序都是从网上下载来

Android - 使用JD-GUI反编译Android代码

使用JD-GUI反编译Android代码 本文地址: http://blog.csdn.net/caroline_wendy Android程序出现Bug时,需要根据Bug寻找问题出错的地方; 需要使用工具dex2jar.sh和JD-GUI,并把dex2jar.sh添加进系统路径; 把需要反编译的apk包修改为zip文件, 解压, 找到".dex"文件, "classes.dex"; 使用命令: sh dex2jar.sh ~/Desktop/ChunyuDocto

APK反编译jd-gui代码分析(草稿记录)

1. 连续for循环 反编译代码: 1 private void removeHideLines() 2 { 3 int i = 0; 4 if (i >= this.lines.size()) {} 5 for (int j = 0;; j++) 6 { 7 if (j >= this.recordLines.size()) 8 { 9 return; 10 if (((MusicTrackLine)this.lines.get(i)).getX() + ((MusicTrackLine)t

apk应用的反编译和源代码的生成

对于反编译一直持有无所谓有或无的态度.经过昨天一下午的尝试,也有了点心得和体会: 先给大家看看编译的过程和我们反编译的过程概图吧: 例如以下是反编译工具的根文件夹结构: 三个目录也实际上是下面三个步骤的体现: (不知道大家发现没,我把三个文件夹名字都改了一下,apktool即为处理apk的工具:dex2jar即就是将dex文件处理为jar包的工具.jar2gui即就是我们将jar包内的class转换为源代码的gui界面以供大家參考的工具) setp 1: 在apktool里: 打开dos框(cm

(转)unity3D 如何提取游戏资源 (反编译)+代码反编译

原帖:http://bbs.9ria.com/thread-401140-1-1.html 首先感谢 雨松MOMO 的一篇帖子 教我们怎么提取 .ipa 中的游戏资源.教我们初步的破解unity3d资源的基本方法附上原帖的链接:http://www.xuanyusong.com/archives/2584 下面我会从头介绍一下提取的全过程: 步骤一:首先从 https://github.com/ata4/disunity/releases 下载 DisUnity v0.3.1也可以直接用工具下载

Android反编译后重新打包

apk中包含的内容 使用apktool直接反编译apk 好吧,不管怎样,反正是报异常了.有人说是apktool的版本不是最新导致的,我也难得去查找原因了,以前这样直接反编译也就是那样而已. 使用dex2jar将从apk中解压得到的dex文件转成jar包 使用jd-gui来查看jar包内容 将要需改的类更改代码后复制到jar内,完成覆盖替换 把jar包重新转成dex文件 将修改完成后的dex文件复制到原来的apk文件中 直接覆盖原来的dex文件 然后就兴冲冲地直接去安装了,然而- 看来果然没这么简