以下的内容实验环境中通过,代码并未开源,只聊聊思路

#反编译带来的困扰

对于一个开发给自己组织内部用的程序,我们是不怎么需要考虑程序被反编译的事情的,但是对于商业软件来说,这又显得有必要,毕竟国内软件行业的竞争还是非常的激烈,大家可以把竞争对手的程序搞过来反编译一下(至于怎么拿别人的程序我相信大家都已经很老手了),轻易的知道对手基于什么软件来做,或者能够比较容易知道实现原理,然后。。抄抄抄,换个名字,完事,一个全新的产品就出来了。对于Java来说这个问题就更加明显了。虽然有类似ZKM这样的商业软件来进行混码,但是混码后只要你有耐心,还是有很大机会能读懂的

在这里不得不吐槽一下,ZKM实在太难用了

#尝试用Go来保护我们的Jar文件

这里我们只讨论胖胖的Jar包(就是那种全部都打在一起直接java -jar就能跑的包,例如Spring Boot打出来的,这个叫法是不是有点萌(○’ω’○) )。

对于防止反编译来说,Golang这类打包出来就是二进制的方式其实就非常适合,打包成二进制之后的程序反编译难度比起一个普通的Jar来说难度会高很多。

对于新写的程序来说,Go其实是个挺好的选择,可以省去反编译带来的问题

那是不是把Jar包放到Go里面打包就可以了呢?恩,是的。不过go build的时候只会对go文件进行编译打包,静态文件是不会被包括进去的。所以就需要通过Golang的一些静态资源库来进行操作。把Jar包作为静态文件来处理。然后把各种静态文件打包成go文件,binary-go就是其中一个合适的选择

go get -u github.com/samuelngs/binary-go

安装完之后,我们执行

binary -dir ./[静态文件位置] -out binary

就会产生出许多的go文件,默认它是以20M为一个进行分拆的。

输入图片说明

分拆后,我们可以通过binary提供的方法帮我们把这个包重新还原回来。

#怎么从二进制流启动Jar

打包好程序后,接下来就是启动的问题了。虽然能把Jar从二进制还原回来,不过java没法从二进制流启动啊。或者在外面再放一个壳,然后动态加载反射调用。但是换个角度来看,其实也可以通过一些小技巧来实现的。每次启动的时候把我们的jar包随机放到一个目录,每次启动的时候这个jar包的名字也随机给。

让Jar随机出现在不同的位置主要目的是减少被蹲点的几率

然后用Golang来执行命令行启动,完成启动之后就把这个随机生成的jar包干掉。这样一系列操作之后,一个伪装成Go的胖胖的Jar也就出来了。

#方案的优缺点

##优点

  • 简单,省事:比起ZKM这种麻烦而且收费的混淆器,这个方法简单多了
  • 多了一层壳,更安全一些:比起普通的Jar,这个方法多了一层壳,能够把一些水平比较一般的小伙伴拒之门外,ps一下发现有个jar,但是又不知道这个jar在什么位置。想反编译一下发现是个二进制文件反编译难度有点大。或者干脆一看是个二进制就放弃了。。。

##缺点

  • 还是有机会被蹲点,然后把Jar拿出来继续反编译
  • 对于保密性要求很高的场景这种方案显得不太合适,还是需要内部继续混淆,当然再多一层壳反射调用应该会更好一些
  • ....欢迎补充