1. 内部类
内部类反编出来会出现如下结果:
1 2 3 4 5 6 7
| public final class -$$Lambda$ExtNetworkTracker$InterfaceObserver$6h5H0nN5nrJkfCZwlwJqwAaVTc0 implements Runnable { public final void run() { InterfaceObserver.lambda$interfaceRemoved$1(this.f$0, this.f$1); } }
|
2. 给外部类参数赋值
如果在反编译文件中出现access$xxx等标识,基本都是对外部类变量赋值,找到外部类对应变量进行复制即可即可。
1 2 3
| mLinkStateIfaceName = ifaceName; mNetworkLinkState = state;
|
3. Log日志
日常中打的log,在反编译之后,会使用StringBuilder来包装一句log日志。
1 2
| Log.d(TAG, "interfaceLinkStateChanged:" + ifaceName + " up: " + state);
|
4.for循环的解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| for (;;){ bool1 = bool2; if ((i >= 3) || (paramBoolean)) {} try{ } catch (Exception localException){ for (;;) {} } str.printStackTrace(); i += 1; }
while (true) { if (i >= 3) { break; } try { break; } catch (Exception e) { e.printStackTrace(); i++; } }
|
5.同步代码块
5.1 类锁
如果遇到try-finally组合,且finally是空的,考虑是synchronized代码同步块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| private void updateInterface(String paramString, boolean paramBoolean) { try { Object localObject = TAG; StringBuilder localStringBuilder = new StringBuilder(); localStringBuilder.append("updateInterface(iface:"); localStringBuilder.append(paramString); localStringBuilder.append(", status:"); localStringBuilder.append(paramBoolean); localStringBuilder.append(")"); Log.d((String)localObject, localStringBuilder.toString()); return; } finally { } }
private void updateInterface(String paramString, boolean paramBoolean) { synchronized (this) { Object localObject = TAG; StringBuilder localStringBuilder = new StringBuilder(); localStringBuilder.append("updateInterface(iface:"); localStringBuilder.append(paramString); localStringBuilder.append(", status:"); localStringBuilder.append(paramBoolean); localStringBuilder.append(")"); Log.d((String)localObject, localStringBuilder.toString()); } }
|
5.2 对象锁
1 2 3 4
| synchronized (CarlibTimeoutUtil.this.mLock){ }
|
6.编译器对象擦除机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| private void updateInterface(String paramString, boolean paramBoolean) { try { Object localObject = TAG; StringBuilder localStringBuilder = new StringBuilder(); localStringBuilder.append("updateInterface(iface:"); localStringBuilder.append(paramString); localStringBuilder.append(", status:"); localStringBuilder.append(paramBoolean); localStringBuilder.append(")"); Log.d((String) localObject, localStringBuilder.toString()); localObject = (ExtNetworkSet) this.mExtNetworkSets.方法; if (localObject == null) { localObject = TAG; localStringBuilder = new StringBuilder(); localStringBuilder.append("ExtNetworkSet of "); localStringBuilder.append(paramString); localStringBuilder.append(" not found"); Log.e((String) localObject, localStringBuilder.toString()); return; } ((ExtNetworkSet) localObject).mNetworkFactory.方法; (((ExtNetworkSet) localObject).mIpConfig.方法; ((ExtNetworkSet) localObject).mNetworkFactory.方法; ((ExtNetworkSet) localObject).mNetworkFactory.方法; return; } finally { } }
|
从代码中可以看到localObject这个对象从方法进入到方法结束都一直使用的这个变量。这就是java在编译之后进行对象擦拭机制。进入方法之后,编译器会把所有对象擦拭成Object对象,然后在适合的位置强转成真实的对象。
例如:在方法进入,编译器先创建了一个Object对象,接收TAG参数,在Log.d方法中将它转化成String对象;
然后接收从mExtNetworkSets集合中获得的ExtNetworkSet对象,在方法最后强转成ExtNetworkSet对象来使用它。
7.关于资源文件的解析
在代码中有关于资源文件的应用如下
解析方法:
- 首先将十进制“2130837504”转化成十六进制为“0x7f020000”
- 将apk文件直接拖入Android Studio,找到resources.arsc索引文件,然后根据要查看的内容类型找到具体的内容。
8.超高难度解析–内部类调用外部类方法
该文件是内部类中的一个实现,实现了Runnable接口。
然后看InterfaceObserver.lambda$interfaceRemoved$1(this.f$0, this.f$1); 这个是interfaceRemoved接口方法中会调用$1(this.f$0, this.f$1)方法。
以上方法的破解有两个方案:
- 一般是内部的实现方法,根据接口的名字interfaceRemoved猜测外部类private的哪个方法比较靠近这个实现,然后用这个方法去试逻辑是否吻合
- 用排除法,先将其他方法都处理完成之后,看那几个方法没有被调用过,然后结合传入参数,实现内容就可以初步断定调用哪个方法。最后在编译出来上机验证是否符合猜测。
9.超高难度解析–解析协议
如果遇到以上这种情况,反编译代码中会有奇形怪状的数字(hash值),这个情况一般是编译器为了找到运行时的对象,算了一个hash值,所以我们不必关心这个hash值,我们就看判断的内容即可。
根据截图以上的代码上下文,可以判断localObject2是协议的key值,localObject3是协议的value值,然后判断key值是否与对应的key值相等,然后处理对应的value值。
根据上面分析,解析结果可以判断为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| String key = pair[0]; String value = pair[1]; switch (key) { case "ip": ipConfig.ipAddress = new LinkAddress(value); break; case "domains": ipConfig.domains = value; break; case "gateway": ipConfig.gateway = InetAddress.parseNumericAddress(value); break; case "dns": { ArrayList<InetAddress> dnsAddresses = new ArrayList<>(); for (String address : value.split(",")) { dnsAddresses.add(InetAddress.parseNumericAddress(address)); } ipConfig.dnsServers.addAll(dnsAddresses); break; } default: { throw new IllegalArgumentException("Unexpected key: " + key + " in " + configs); } }
|
版权声明: 此文章版权归Jack Ou所有,如有转载,请註明来自原作者