反编译Android App问题攻克

在这里讲述的其实是java反编译,主要是因为我是反编译人家的app源码入手的,就自然的挂起了羊头。

众所周知,通过dex2jar能将android app的dex解析为class文件jar包,然后通过jd等反编译工具查看源代码,貌似很容易就能对别人的劳动成果拿来主义,可果真如此理想么? 本着实事求是的原则,自己亲手试了下,结果自然是杯具的。

以下是反编译出的结果,我们简单的以一个方法为例:

public double getCORRLN(double[] paramArrayOfDouble)
  {
    double d1 = 0.0D;
    double d2 = 0.0D;
    double d3 = 0.0D;
    double d4 = 0.0D;
    double[] arrayOfDouble1 = new double[this.grayLevel];
    double[] arrayOfDouble2 = new double[this.grayLevel];
    int i = 0;
    int k;
    label42: int m;
    if (i >= this.grayLevel)
    {
      k = 0;
      if (k < 32)
        break label171;
      m = 0;
      if (m < 32)
        break label201;
    }
    for (int i1 = 0; ; i1++)
    {
      if (i1 >= 32)
      {
        if ((d3 != 0.0D) && (d4 != 0.0D))
          this.CORRLN = ((this.CORRLN - d1 * d2) / Math.sqrt(d3 * d4));
        return this.CORRLN;
        for (int j = 0; ; j++)
        {
          if (j >= this.grayLevel)
          {
            d1 += (i + 1) * arrayOfDouble1[i];
            i++;
            break;
          }
          arrayOfDouble1[i] += paramArrayOfDouble[(j + i * this.grayLevel)];
        }
        label171: d3 += Math.pow(k + 1 - d1, 2.0D) * arrayOfDouble1[k];
        k++;
        break label42;
        label201: for (int n = 0; ; n++)
        {
          if (n >= 32)
          {
            d2 += (m + 1) * arrayOfDouble2[m];
            m++;
            break;
          }
          arrayOfDouble2[m] += paramArrayOfDouble[(m + n * this.grayLevel)];
        }
      }
      d4 += Math.pow(i1 + 1 - d2, 2.0D) * arrayOfDouble2[i1];
    }
  }



是不是感觉狗屁不通?这还是例举的一个相对简单的方法,看看这个

基本每个方法都有错误,基本每个错误都是逻辑混乱,基本没一个方法能用,简单来说,这个文件就是废的。

第一次看到这情况,心里很纳闷,不知道是dex2jar这个过程除了问题还是jd的问题,后来百度了一下(谷歌打不开,懒得折腾,别鄙视,人家度娘一样很敬业),发现这种问题很多,通过jad为核心的反编译工具(jd就是如此)都这副尿性,偏偏jad在java反编译工具中又算最好的,不知道是不是因为太久没更新的缘故,反正就是不给力。

那如何是好呢,嘿 用java开发,就没有不能破解的,工具不给力,那就人工来呗,果断搞起。

首先,找出该类的.class文件,javap隆重登场,在这里 比如该类为xohome.class, 在终端中,切入该文件所在目录,执行命令:

javap -c -private xohome.class



简单扫盲:javap是jdk自带的反编译工具,能简单解析class字节码文件的内容,参数 -c为显示字节码 -private为反编译级别,可开发过程中可见级别一样,一下是上头例举方法的字节码:

反编译Android App问题攻克

相信学过汇编的对这些都不陌生,如果你看得头晕,那就没辙了,因为这只是窗口大小的代码,一个中等方法大概有这样的代码500行。。。

我们开好工作窗口,将jd反编译的代码、字节码、空白文档(用作写反编译的代码用)依次列开:

反编译Android App问题攻克

这就是简单的工作台了,我本来想截大点的,可oc上传图片200K让人忧伤。。。

OK,开始正式工作,首先 我们得了解下java字节码中方法的构成,在这里,需要明白的是方法内的局部变量表,一个java方法,包含一个局部变量表,里头存储着包含参数在内的变量信息,一个java方法默认有一个参数,则是隐性参数this,也就说该表下标为0的变量为this,其次,根据你参数的数量和顺序,一次对于参数1、参数2、参数3....等等; 其次,是Exception的异常表,该表在反编译过程中不太重要:

反编译Android App问题攻克

编程,无非就是对各种参数的各种加减乘除运算,在了解了变量表之后,在基于堆栈的Java虚拟机,就剩下很简单的重复劳动了,以java字节码指令表为参考,用上述例举的方法为例:

0  > this					// 参数0为this
1  > paramArrayOfDouble		// 参数1为方法参数,标记为paramArrayOfDouble 
2  > d1						// double d1  该变量是通过字节码信息来确定的,下述变量都是如此, 因为double变量占2字节,下一个变量下标就为4
4  > d2
6  > d3
8  > d4
10 > arrayOfDouble1  double[]
11 > arrayOfDouble2  double[]
12 > i
13 > j
public double getDouble(double[]);
    Code:
       0: dconst_0			// 取常数0入栈
       1: dstore_2			// d1 = 0 dstore_2指令为为double类型变量赋值,可得出参数1为double类型,这里命名为d1
       2: dconst_0      
       3: dstore        4		// d2 = 0 同d1
       5: dconst_0      
       6: dstore        6		// d3 = 0 同d2
       8: dconst_0      
       9: dstore        8		// d4 = 0 同d3
      11: aload_0			// aload_0指令为加载局部变量0的引用,0为this
      12: getfield      #48                 // Field grayLevel:I   // 获取当前类成员变量grayLevel	
      15: newarray       double
      17: astore        10	// 上面指令为创建数组 附带信息未double  当前指令为赋值 》array1 = new double[this.grayLevel]
      19: aload_0       
      20: getfield      #48                 // Field grayLevel:I
      23: newarray       double
      25: astore        11	// 同array1 array2 = new double[this.grayLevel]

      27: iconst_0      
      28: istore        12	// int i = 0 istore指令为int类型赋值

// if i < this.grayLevel goto 110
      30: iload         12
      32: aload_0       
      33: getfield      #48                 // Field grayLevel:I
      36: if_icmplt     110		// if_icmplt指令为分支指令,对比当前栈的值value1是否小于value2  
// else
      39: iconst_0      
      40: istore        14		// int k = 0
	// loop
      42: iload         14
      44: bipush        32		// byte 32入栈
// if k < 32 goto 171
      46: if_icmplt     171		
// else
      49: iconst_0      
      50: istore        15		// int m = 0

      52: iload         15
      54: bipush        32
// if m < 32 goto 201
      56: if_icmplt     201
// else 
      59: iconst_0      
      60: istore        17		// int i1
      62: iload         17
      64: bipush        32
// if i1 < 32 goto 262
      66: if_icmplt     262
// else
      69: dload         6			// 载入d3
      71: dconst_0				// 载入0
      72: dcmpl         
      73: ifeq          105		// d3!=0
      76: dload         8	
      78: dconst_0      
      79: dcmpl         
      80: ifeq          105		// d4!=0
      83: aload_0       
      84: aload_0       
      85: getfield      #84                 // Field CORRLN:D
      88: dload_2       
      89: dload         4
      91: dmul          
      92: dsub          
      93: dload         6
      95: dload         8
      97: dmul          
      98: invokestatic  #147                // Method java/lang/Math.sqrt:(D)D
     101: ddiv          
     102: putfield      #84                 // Field CORRLN:D

     105: aload_0       
     106: getfield      #84                 // Field CORRLN:D
     109: dreturn    

// if i < this.grayLevel
     110: iconst_0      
     111: istore        13		// int j=0

     113: iload         13
     115: aload_0       
     116: getfield      #48                 // Field grayLevel:I
// if j < this.grayLevel goto 142
     119: if_icmplt     142
// else
     122: dload_2			// 载入d2  
     123: iload         12	// 载入i
     125: iconst_1			// 载入1
     126: iadd				// d2 + 1      
     127: i2d				// int to double
     128: aload         10	// arrayOfDouble1
     130: iload         12	// 载入i
     132: daload				// arrayOfDouble1[i]  
     133: dmul
     134: dadd          
     135: dstore_2			// d1 += (i + 1) * arrayOfDouble1[i];
     136: iinc          12, 1	// i++
     139: goto          30

// j < this.grayLevel
     142: aload         10	// 载入arrayOfDouble1
     144: iload         12	// 载入i
     146: aload         10
     148: iload         12
     150: daload				// arrayOfDouble1[i]
     151: aload_1			// paramArrayOfDouble       
     152: iload         13	// j
     154: iload         12	// i
     156: aload_0       
     157: getfield      #48                 // Field grayLevel:I
     160: imul          
     161: iadd          
     162: daload				// paramArrayOfDouble[j + i*this.grayLevel]
     163: dadd          
     164: dastore			
		// arrayOfDouble1[i] += paramArrayOfDouble[(j + i * this.grayLevel)];       
     165: iinc          13, 1
     168: goto          113

// if k < 32 goto
     171: dload         6
     173: iload         14
     175: iconst_1      
     176: iadd          
     177: i2d           
     178: dload_2       
     179: dsub          
     180: ldc2_w        #148                // double 2.0d
     183: invokestatic  #153                // Method java/lang/Math.pow:(DD)D
     186: aload         10
     188: iload         14
     190: daload        
     191: dmul          
     192: dadd          
     193: dstore        6
	// d3 += Math.pow(k + 1 - d1, 2.0D) * arrayOfDouble1[k];
     195: iinc          14, 1
     198: goto          42

// if m < 32
     201: iconst_0      
     202: istore        16	// n = 0
     204: iload         16
     206: bipush        32	// 32
// if n < 32  goto 233
     208: if_icmplt     233
// else
     211: dload         4		// d2
     213: iload         15	// m
     215: iconst_1			// 1
     216: iadd				// m + 1
     217: i2d           
     218: aload         11
     220: iload         15
     222: daload        
     223: dmul          
     224: dadd          
     225: dstore        4		// d2 += (m + 1) * arrayOfDouble2[m];
     227: iinc          15, 1
     230: goto          52

if n<32
     233: aload         11
     235: iload         15
     237: aload         11
     239: iload         15
     241: daload        
     242: aload_1					// paramArrayOfDouble
     243: iload         15
     245: iload         16
     247: aload_0       
     248: getfield      #48                 // Field grayLevel:I
     251: imul          
     252: iadd          
     253: daload        
     254: dadd          
     255: dastore       
     256: iinc          16, 1
     259: goto          204

// i1 < 32
     262: dload         8
     264: iload         17
     266: iconst_1      
     267: iadd          
     268: i2d           
     269: dload         4
     271: dsub          
     272: ldc2_w        #148                // double 2.0d
     275: invokestatic  #153                // Method java/lang/Math.pow:(DD)D
     278: aload         11
     280: iload         17
     282: daload        
     283: dmul          
     284: dadd          
     285: dstore        8
     287: iinc          17, 1
     290: goto          62



花了大概接近一个小时,将该方法逻辑理清楚,顺便去洗了下眼睛。还好jd对运算的解析还算到位,只是逻辑不清楚,否则难度还会上升N大截。  根据上面标注的信息,源码撰写如下:

0  > this
1  > paramArrayOfDouble
2  > d1
4  > d2
6  > d3
8  > d4
10 > arrayOfDouble1  double[]
11 > arrayOfDouble2  double[]
12 > i
13 > j
14 > k
15 > m
16 > n
17 > i1
code:
double d1 = 0.0D;
double d2 = 0.0D;
double d3 = 0.0D;
double d4 = 0.0D;
double[] arrayOfDouble1 = new double[this.grayLevel];
double[] arrayOfDouble2 = new double[this.grayLevel];

	
	for(int i=0;
30			i < this.grayLevel; i++) {
110		for(int j=0;
113				j < this.grayLevel; j++) {
142			arrayOfDouble1[i] += paramArrayOfDouble[(j + i * this.grayLevel)];
		}
122		d1 += (i + 1) * arrayOfDouble1[i];
	}
39	for(int k=0;
42			k < 32;k++) {
171		d3 += Math.pow(k + 1 - d1, 2.0D) * arrayOfDouble1[k];
	}
49	for(int m=0;
52			m < 32;m++) {
201		for(int n=0; n<32; n++) {
233			arrayOfDouble2[m] += paramArrayOfDouble[(m + n * this.grayLevel)];
		}
		d2 += (m + 1) * arrayOfDouble2[m];
	}
59	for(int i1=0; 
62			i1 < 32; i1++) {
262		d4 += Math.pow(i1 + 1 - d2, 2.0D) * arrayOfDouble2[i1];
	}
69	if(d3 != 0 && d4 != 0) {
		this.CORRLN = ((this.CORRLN - d1 * d2) / Math.sqrt(d3 * d4));
	}
	return this.CORRLN;



OK,逻辑基本理清完整,放入工程,一切正常,目前还需要做测试,看看运算结果是否和原包结果一致。 这阶段就到这里,眼睛痛。

你可能感兴趣的:(反编译Android App问题攻克)