ELECTRON程序源码保护

发布于 2024-02-29  653 次阅读


泄露原理

  • electron的实现相当于用一个自定义的浏览器(用的chromium内核)指定访问了某个远程地址(loadURL方法)或者某个本地静态的前端资源(loadFile方法),当然也可以加上nodejs本身的后端加点api或者路由
  • 其中loadFile方法从本地加载的资源文件来源于项目打包后的resource文件夹下面的app.asar包,项目打包成二进制文件后asar文件得一起发给用户
asar 是一种文件归档方式,类似于 tar 包,把多个目录和文件合并在一起,但是并不进行压缩

为什么要用 asar 文件呢?主要有三点原因:

避免 Windows 系统下文件路径过长(Windows 限制最长路径为 260 个字符)
加快 require 函数的加载文件的速度
避免向用户直接暴露代码文件
  • 这个文件本身没有任何加密,可以被node的asar模块轻松解出来,所以后端和本地前端的所有代码都是向程序持有者公开的,即使使用所谓的"打包成单个exe",这也只是创建了一个自解压程序,本质上是一个压缩文件,改一下后缀即可解压得到二进制文件与有关依赖,然后解一下asar的包就行了
  • 因为是自解压程序,加壳保护是没有用的,并且对asar文件的任何操作都会导致electron无法解包(除非重写electron对于这个包的处理逻辑)
  • 这里简单演示一下asar归档文件的解包,先安装asar模块
npm i -g asar
  • 终端测试一下是否已经全局安装好了,没安好就是node的环境有问题喽,网络不好可以考虑换源(阿里源据说要停止支持了🥺)或者使用cnpm

  • 创建一个electron的项目,随便丢几个文件进去,然后打包成exe(之前写过相关的教程),在dist的resource文件夹里面找到asar文件

  • 当前目录打开终端,使用asar解包,e参数表示extract,app.asar是待解包的文件名,app是解包后的文件夹名字
asar e app.asar app

  • 打开app目录得到了之前构建dist时的所有资源

现有方案

  • 大概有下面这样一些方案:

  • 通过对 JS 代码进行丑化和混淆,尽可能降低其可读性。简单来说就是混淆

  • 通过 XOR 或 AES 对构建产物进行加密,封装到 Node Addon 中,并在运行时由 JS 解密。相当于弄了个自解密的程序喽,问了一下他们逆向的,这样做的安全性不是很高

  • 将 Electron ASAR 文件进行加密,并修改 Electron 源代码,在读取 ASAR 文件之前对其解密后再运行。electron的源码泄露来自于asar文件,但是这样就得重写electron的底层逻辑,个人不是很好弄

  • 通过 Node 标准库里的 vm 模块,可以从 script 对象中生成其缓存数据。该缓存数据可以理解为 v8 的字节码,该方案通过分发字节码的形式来达到源代码保护的目的。

  • 有一些第三方的虚拟机提供接入加密js的功能,但是重写了几乎所有方法,从头改很难受

方案比较:

- Obfuscator 混淆 Native 加密 ASAR 加密 V8 字节码
解包 容易
篡改 容易 容易 中等
可读性 容易 容易 容易
二次打包 容易 容易 容易 容易
接入成本 中等
保护强度 中等 中等

我的方案

  • 上面提到了v8字节码,它类似于二进制文件,我们可以用bytenode库将需要保护的js编译成v8字节码(一个jsc文件),然后想要使用时直接require("xxx.jsc")即可
V8 是 Google Chrome 浏览器和 Node.js 运行时的 JavaScript 引擎。V8 引擎在执行 JavaScript 代码时,会将 
JavaScript 代码转换为机器码执行,但在某些情况下,V8 会将 JavaScript 代码编译成字节码,然后再解释执行。这个字
节码被称为 V8 字节码。
  • 先安装bytenode模块
npm install --save bytenode

或者
cnpm install --save bytenodec
  • 然后新建一个buildjsc.js写入,这可以将同目录下的index.js编译成字节码,如果需要编译其它文件直接改名字即可
  • 如果需要编译更多的文件可以使用一些文件操作的库来读取某个文件夹下面所有js文件,或者写个循环然后对一个文件名列表依次转换,这里就不再展示
require('bytenode').compileFile({
    filename: 'index.js'
});
  • 执行buildjsc.js即可,可以把electron的入口js(我是main.js)的内容暂时剪切出来,把上面的内容写进去,启动electron
  • 或者直接node buildjsc.js来执行这个js,但是我在网上看到说执行环境的整个工程目录不能有packge.json文件,可以考虑临时把packge.json文件移走,或者新建一个目录来执行buildjsc.js文件(不知道是不是真的)
  • 注意新建的目录如果不在之前的项目文件夹里面,就得在新目录里面再安一次bytenode,因为上面的安装是仅安装到当前项目(没试过全局安装bytenode,不知道会不会出错)

  • 这样就成功得到了index.js的字节码文件,然后我们将它导入即可
require('bytenode');
require('./index.jsc');
  • 比如我们可以原本main.js的内容全部移入index.js,然后生成index.jsc,在main.js只写入上面的语句,就能保护入口js的源码了,其它的也是类似

  • 注意,这种方式只能用于属于node的js的保护,或者说后端js的保护,比如这里用来electron,就只能保护electron的js文件,不能应用于前端的js文件,在某个html文件里面<script>引入一个jsc或者require一个jsc都是不行的,还得是老老实实的混淆

  • 那么就不能保证前端的安全了吗?当然可以,我们只需要将资源文件托管到服务器,使用loadURL来远程加载,然后给静态文件的路由和本地的electron的js之间加一些访问控制参数(甚至可以直接来一段jwt)就可以了,即使抓包发现了远程资源的位置别人也无法访问(因为不知道程序生成控制参数的逻辑)

届ける言葉を今は育ててる
最后更新于 2024-03-09