您现在的位置是:首页 > 文章详情

反编译Android App问题攻克

日期:2017-06-01点击:195

在这里讲述的其实是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]; } } 

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

image

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

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

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

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

javap -c -private xohome.class 

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

image

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

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

image

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

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

image

编程,无非就是对各种参数的各种加减乘除运算,在了解了变量表之后,在基于堆栈的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,逻辑基本理清完整,放入工程,一切正常,目前还需要做测试,看看运算结果是否和原包结果一致。 这阶段就到这里,眼睛痛。

原文链接:https://yq.aliyun.com/articles/113911
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章