=Start=
缘由:
学习了解一下Electron是什么,能做什么,代码该怎么写,方便以后参考。
正文:
参考解答:
1、Electron是什么?
Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库。Electron通过将Chromium和Node.js合并到同一个运行时环境中,并将其打包为Mac,Windows和Linux系统下的应用来实现这一目的。
2、Electron能做什么?
Electron 可以让你使用纯 JavaScript 调用丰富的原生(操作系统) APIs 来创造桌面应用。你可以把它看作一个 Node. js 的变体,它专注于桌面应用而不是 Web 服务器端。
这不意味着 Electron 是某个图形用户界面(GUI)库的 JavaScript 版本。 相反,Electron 使用 web 页面作为它的 GUI,所以你能把它看作成一个被 JavaScript 控制的,精简版的 Chromium 浏览器。
3、Electron应用的开发
①开发环境准备
# 下面这行的命令会打印出Node.js的版本信息
node -v
# 下面这行的命令会打印出npm的版本信息
npm -v
# 全局安装 electron 然后查看其版本
npm install electron@latest -g
electron --version
②代码目录结构
从开发的角度来看, Electron application 本质上是一个 Node. js 应用程序。 与 Node.js 模块相同,应用的入口是 package.json
文件。一个最基本的 Electron 应用一般来说会有如下的目录结构:
your-app/
├── package.json
├── main.js
└── index.html
③Demo应用开发
为你的新Electron应用创建一个新的空文件夹。 打开你的命令行工具,然后在该文件夹下运行npm init
命令:
npm init
该 npm init 命令会帮助你创建一个基本的 package.json
文件。其中的 main
字段所表示的脚本为应用的启动脚本,它将会在主进程中执行。 如下片段是一个 package.json
的示例:
{
"name": "your-app",
"version": "0.1.0",
"main": "main.js"
}
下面是一个简单的main.js
文件,它将在应用程序准备就绪后打开一个窗口,同时打开开发者工具,并添加上处理窗口关闭事件、在macOS用户点击dock上图标时重建窗口的逻辑:
const { app, BrowserWindow } = require('electron')
// 保持对window对象的全局引用,如果不这么做的话,当JavaScript对象被
// 垃圾回收的时候,window对象将会自动的关闭
let win
function createWindow () {
// 创建浏览器窗口。
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 加载index.html文件
win.loadFile('index.html')
// 打开开发者工具
win.webContents.openDevTools()
// 当 window 被关闭,这个事件会被触发。
win.on('closed', () => {
// 取消引用 window 对象,如果你的应用支持多窗口的话,
// 通常会把多个 window 对象存放在一个数组里面,
// 与此同时,你应该删除相应的元素。
win = null
})
}
// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)
// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
// 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
// 否则绝大部分应用及其菜单栏会保持激活。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
// 通常在应用程序中重新创建一个窗口。
if (win === null) {
createWindow()
}
})
// 在这个文件中,你可以续写应用剩下主进程代码。
// 也可以拆分成几个文件,然后用 require 导入。
然后,创建你想展示的 index.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</body>
</html>
在创建并初始化完成 main.js
、 index.html
和package.json
之后,您就可以在当前工程的根目录执行 npm start
命令来启动刚刚编写好的Electron程序了。
一些简单的知识点和注意事项:
主进程&渲染进程
- 在 Electron 里,运行
package.json
里main
脚本的进程被称为主进程。 - 由于 Electron 使用 Chromium 来展示页面,所以 Chromium 的多进程结构也被充分利用。每个 Electron 的页面都在运行着自己的进程,这样的进程我们称之为渲染进程。在一般浏览器中,网页通常会在沙盒环境下运行,并且不允许访问原生资源。然而,Electron 用户拥有在网页中调用 io.js 的 APIs 的能力,可以与底层操作系统直接交互。
主进程和渲染进程的区别
主进程使用 BrowserWindow 实例创建网页。每个 BrowserWindow 实例都在自己的渲染进程里运行着一个网页。当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。
主进程管理所有页面和与之对应的渲染进程。每个渲染进程都是相互独立的,并且只关心他们自己的网页。
由于在网页里管理原生 GUI 资源是非常危险而且容易造成资源泄露,所以在网页面调用 GUI 相关的 APIs 是不被允许的。如果你想在网页里使用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。
在 Electron,我们提供用于在主进程与渲染进程之间通讯的 ipc 模块。并且也有一个远程进程调用风格的通讯模块 remote。
低版本Electron
不支持loadFile
在1.x
和2.x
的electron
中,如果要使用loadFile
函数,就会报错unknown function
。所以如果想用这个函数的话,需要更新到 3.x 及以后版本的 Electron 。
参考链接:
- Electron macOS 开发环境配置
https://nodejs.org/en/download/ - 打造你的第一个 Electron 应用
https://electronjs.org/docs/tutorial/first-app - Electron入门教程
- electron 3.x 系统新增加的页面加载函数 loadFile
- Electron 中文文档
=END=
《 “Electron 快速入门” 》 有 12 条评论
用Nodejs开发桌面应用。NW.js 和 Electron 各有什么优缺点,你选择哪个?
https://www.zhihu.com/question/38854224
`
我们最近有个项目需要使用Node桌面版技术,正如大多数人一样,我的初次选型是NW,那么出乎意料,大坑来了!!!
倘若你的桌面版应用没有跟底层(C++模块)挂钩,也就是没有使用到消息推送、版本升级、打印功能之类的东西,但是bug还是挺多的。并且一旦使用到这些功能,你就彻底调到坑里了,nw有个致命的缺陷在于所有的非javascript编写的模块都需要重新用nw-gyp重新编译一下,这个编译的过程会出现各种各样的问题。而Electron几乎可以使用所有的node模块,只需要node-gyp编译的即可。主要深坑就在这!!!还有,NW不像Electron自带版本升级。
nw唯一的好处是啥?兼容window XP呗。
`
http://tangiblejs.com/posts/nw-js-electron-compared
https://github.com/nwjs/nw.js/
https://github.com/electron/electron
维护一个大型开源项目是怎样的体验?
https://www.zhihu.com/question/36292298/answer/102418523
怎么去阅读Chromium的源码?
https://www.zhihu.com/question/306408034/answer/565791530
`
从初学者角度的话,如果是刚开始研究chromium,建议找个老版本chromium来看。新版太大太复杂了。我建议从github搜下 chromium.bb 这个项目,是个chromium49的删减版。之所以推荐这个,有几个原因:
0,工程环境比原版chromium好搭多了,不用翻墙,不用改一些系统设置。90%的初学者我估计卡在搭chromium环境这了,尤其是国内。。
1,代码量相对较小,所以直接可以生成vs工程后配合vax的代码着色和智能跳转阅读。有VAX辅助,对于查找函数具体位置有很大帮助。
2,同样由于代码量小,你可以用vs直接编译跑起来。阅读chromium代码你一定要调试,否则很难理清某个流程。
搭好环境后,建议你疯狂搜下网上讲解chromium架构的文章预热一下。否则你会不知所云。先把chromium的进程架构了解下,大概每个进程是做什么的,然后开始研究content层,这是chromium最主要的层,负责连接所有其他组件。
其他具体架构细节以后想到再写……
`
Chromium
https://www.zhihu.com/topic/19557071/top-answers
Chromium source code and modifications
https://github.com/bloomberg/chromium.bb
http://bloomberg.github.io/chromium.bb/
`
This repository contains the version of Chromium used by Bloomberg, along with all the modifications made by Bloomberg in order to use it in our environment.
`
Chromium 编译增加 音频/视频 支持(chromium add wav support compile options)
https://stackoverflow.com/questions/50971187/can-i-build-chromium-with-ffmpeg-to-support-all-video-formats
https://www.chromium.org/developers/how-tos/get-the-code
https://chromium.googlesource.com/chromium/src/+/master/docs/windows_build_instructions.md
https://chromium.googlesource.com/chromium/src/+/master/docs/mac_build_instructions.md
https://www.chromium.org/audio-video
https://superuser.com/questions/1111994/how-to-compile-chromium-with-mp3-aac-and-h264-support
https://github.com/henrypp/chromium
`
enable_ac3_eac3_audio_demuxing = true
enable_mse_mpeg2ts_stream_parser = true
proprietary_codecs = true
`
History of Node.js on a Timeline
https://blog.risingstack.com/history-of-node-js/
你需要了解的Node.js 发展史
https://www.jianshu.com/p/4e45641123dc
https://zh.wikipedia.org/wiki/Node.js
向Typora学习electron安全攻防
https://mp.weixin.qq.com/s/Ggx34AqhzsbBLkecv5RNJw
`
越来越多的应用开始使用 electron 来构建跨平台桌面应用。从实现方式上来说,其本质还是基于chrome内核的html、js、css构成的应用,基于浏览器,代码必定会暴露在用户侧,任何加密手段只是增加破解门槛跟时间成本而已。
# 认识electron项目文件目录特征
electron打包的项目,最常见的就是 asar 格式的私有编码文件,里面包含文件名、大小、内容偏移量等数据,按文件头部的 json内容 解析即可提取出所有文件。
# electron asar解包
目前来说,官方的版本并没有提供保护源码的方法。在github开源的找到个大神提供的解决方案(https://github.com/toyobayashi/electron-asar-encrypt-demo) ,该方案可以把启动文件编译为node二进制文件,作为启动入口,来保护薄弱的js代码。在项目启动时,将加密后的代码进行解密,交回electron流程进行执行,从而避免上述步骤直接解包拿到源代码的可能。
经过分析对比,typora用的恰好是这个demo提供的思路。
找到上述步骤解压成功的 package.json 文件,main属性就是 electron 项目启动的主入口。把 main.node 拖到ida中, 分析执行流程。
结合 electron-asar-encrypt-demo 跟 IDA伪代码, 可以定位到两个关键函数 napi_create_string_utf8 跟 napi_call_function。
# 万能js提取方案
已知经过编译后的node文件, 在执行前,都会调用 napi_create_string_utf8 创建js字符串,所以在调用该函数的时候,基于electron没有自带加密的特性,想要运行js流程,必定会传递明文,所以在加载流程上截断,就可以导出解密后的数据。
解包项目中的所有 asar文件,就能拿到所有的源代码,并且把解压的文件夹,改成对应的 asar 文件名即可正常运行项目,无需重打包即可调试。
# 无限试用思路
删除注册表键,让程序认为是第一次安装。
# 去除授权功能实现单机版本思路
将所有的网络验证给他删掉/注释掉, 也可以直接把 “是否授权” 的变量,改成true即可。
# 注册机思路
由于该示例使用了rsa解密,所以要基于官方版本编写注册机就不太行了。一定要出注册机的话,需要先替换截图部分的rsa公钥即可。
# 自建授权网关实现注册机思路
自建网关的话,可以把应用自带的域名,替换成自己的,然后按接口需要的返回值,给他返回响应的数据格式即可。这个实例仅需要修改两处即可。
# 重打包发版思路
把解压的文件夹打包回 asar格式的文件即可, 这个网上一大把资料。
# 对于electron加密方式的思考
相对于原生开发来说,js安全做客户端毕竟薄弱,UI交互是没问题的,关键代码可以放到dll、so层去做,但是也没办法避免从js层面去剥离dll层函数的调用。所以目前来说并没有很好的解决方案,本文只是起到抛砖引玉的作用。期待electron有更好、更安全的解决方案。
`
又是 Electron!Element 桌面版被发现远程代码执行
https://mp.weixin.qq.com/s/bcgtMXmx_yRvSR2olvOKhA
`
Remote Code Execution on Element Desktop Application using Node Integration in Sub Frames Bypass – CVE-2022-23597
Element 是一款基于 Matrix 协议的即时通讯软件,支持多个桌面和移动平台,允许端到端加密、拉群、语音视频通话和自建服务器等功能。
Element 的桌面端主要还是用 Electron。一个有趣的现象是,只要一款 App 而且足够流行,而且选择使用 Electron,那么一定会被人搞出 XSS 甚至 RCE 漏洞来。
2018 年 5 月,Signal 桌面端很短的时间内连续发现两个 XSS
2020 年 8 月,另一款以安全为卖点的跨平台即时通信软件 Wire 桌面端被发现没有对打开文件的参数做检查,可以远程运行可执行文件。
2020 年 10 月,知名的即时聊天和社群工具 Discord 被发现 XSS 和远程代码执行。
2021 年 7 月,还是 Discord。
Electron 大大方便了桌面应用的开发,可是两大黑点广受诟病——大多数 Electron 应用都没几个功能,却要带上一整个 Chrome 引擎来浪费存储空间和性能;而用 js 做桌面应用极大降低了漏洞利用成本,经常栽在 XSS 之类问题上。
哪怕是公认性能架构好性能高,同时还是 Electron 亲兄弟的 VSCode,也时不时出过安全问题。怎么说呢?虽然因噎废食不好,可是 Electron 的生态确实该领几张反思券。其他的应用,能用网页版尽量用网页版吧……
`
TAURI
https://tauri.app/
`
Build an optimized, secure, and frontend-independent application for multi-platform deployment.
Electron 的替代品,用来制作跨平台的桌面应用,使用 Rust 语言开发。它采用各平台自带的 WebView,缺点是支持的 Web API 会比较少,优点是打包产物体积小。
`
文件桥
https://github.com/ppz-pro/file-bridge
`
网页里的文件服务器
一个简单的 JS 脚本,用来架设静态文件服务器。A 电脑在网页上打开一个本地文件目录,B 电脑就能下载里面的文件,两者不必在同一局域网。
# 需要
* 一个公网可访问的服务器
* Node.js
* https
git clone https://github.com/ppz-pro/file-bridge.git
cd file-bridge
node file_bridge.js
# 原理
两个“客户端”之间没法直接“传递数据”,因为没有公网地址,于是就需要一个“桥”,连接两个“客户端”。提供文件供人下载的,我在这里叫它“提供端”,另一个叫“下载端”。
1. “桥”为每一个“提供端”生成一个 id(以下称为“提供端 id”)
2. “提供端”使用 File System API 读取用户指定的目录,把目录结构发给“桥”
3. “下载端”根据“提供端 id”从“桥”那里获取目录结构
4. “下载端”要下载文件时,向“桥”发送“下载请求”并指定“提供端 id”及文件路径,桥会把这个请求存起来
5. 用户在“提供端”指定“允许下载的目录”后,“提供端”程序就开始每隔 1 秒向“桥”发请求:问一问“有没有谁想下载我的文件”
6. 上两个步骤,一个想下载别人的文件,一个想让人下载,一拍即合,而传文件只需一行代码 http.IncomingMessage.pipe(http.ServerResponse)
其实第 5 步的“每隔 1 秒”很膈应,但原生 Node.js 对 Websocket 支持度比较低,而专门封装一个 Websocket 可能需要几十甚至上百行代码,于是作罢。反正,,,,这只是个有趣的项目,我是说,,,一开始就没以实用为目的。当然,适当地改造一下,也可以很实用,但谁能拒绝“仅使用原生模块”的诱惑呢。
这个项目更加深我那个刻板印象:编程的难点不在于“让人使用”,而是“不让人使用”,比如“非法用户”和“未付费用户”。其实“未付费用户”就是“非法用户
`
Electron 安全与你我息息相关
https://mp.weixin.qq.com/s/xEvkvvfA89xeHFKQUqRmEw
`
0x00 简介
大家好,今天向大家介绍一些关于 Electron 程序以及其安全相关一些内容。
采用Electron 构建的桌面程序在日常使用过程中非常常见。
它的应用面如此之广,以至于我们很难忽略它的存在。这篇文章的目的在于介绍当前 Electron 安全发展态势,更关键的是,最近 XZ 后门事件直接导致了供应链安全的担忧,虽然很多应用程序并不一定开源,但是这篇文章会给大家介绍一些通用的切实可行的检测措施,找出 Electron 程序可能存在的 XSS To RCE 和有危害的供应链威胁
如果你之前没有接触过相关内容,仅仅是想了解一下我使用的 Electron 开发的程序安全性怎么样,那你可以直接跳转到 0x04 如何评估 Electron 程序的安全性 章节
没想到文章越写越长,为保证观感,我们在文末放了 PDF 版本的链接
==
0x00 简介
0x01 Electron 简介
1. Electron 架构
2. 主进程
3. 渲染进程
4. 预加载脚本
5. 实用进程
0x02 Electron 漏洞史
CVE-2016-10534
CVE-2016-1202
CVE-2017-1000424
CVE-2017-12581
CVE-2017-16151
CVE-2018-1000006
CVE-2018-1000118
CVE-2018-1000136
CVE-2018-15685
CVE-2020-15096
CVE-2020-15174
CVE-2020-15215
CVE-2020-26272
CVE-2020-4075
CVE-2020-4076
CVE-2020-4077
CVE-2021-39184
CVE-2022-21718
CVE-2022-29247
CVE-2022-29257
CVE-2022-36077
CVE-2023-23623
CVE-2023-29198
CVE-2023-39956
CVE-2023-44402
`embeddedAsarIntegrityValidation`
`onlyLoadAppFromAsar`
CVE-2024-1648
CVE-2024-27303
CVE-2024-29900
0x03 Electron 应用漏洞案例
1. Goby
2. 蚁剑
3. Typora
4. Discord
5. Others
0x04 如何评估 Electron 程序的安全性
1. 解包 asar 文件
2. 供应链安全评估
3. Electron 版本
4. nodeIntegration
5. contextIsolation
6. sandbox
8. webSecurity
7. fuse
8. Preload 预加载脚本
9. CSP
10. 自定义协议
小结
0x05 Electron 测试技巧
1. nodeIntegrationInSubframes
2. 开发者工具
3. 抓包
4. 导航
5. 自定义协议
6. 本地文件读取
7. 本地代码注入
0x06 实测电脑上的APP
1. Goby
2. Yakit
3. Discord
4. VSCode
5. xmind
6. signal
7. bilibili
8. Docker Desktop
9. 百度网盘
10. 夸克网盘
11. 优酷
12 小结
0x07 小感慨
0x08 PDF 版本下载地址
往期文章
==
0x01 Electron 简介
Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发经验。
1. Electron 架构
Chromium 具备网页渲染能力, Nodejs 具备操作系统API的能力
因此从架构上,Electron 分为两个部分:主进程和渲染进程
2. 主进程
每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。
Chrome的多进程架构
3. 渲染进程
每个 Electron 应用都会为每个打开的 BrowserWindow ( 与每个网页嵌入 ) 生成一个单独的渲染器进程。 洽如其名,渲染器负责渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的 (至少就目前使用的 Chromium 而言是如此) 。
4. 预加载脚本
主进程可以与操作系统交互,渲染进程只能渲染网页,那么当功能需要操作系统支持的时候,渲染进程如何将需求传递给主进程,主进程如何将结果传递给渲染进程就是个问题,Electron 设计了一系列的 IPC 功能,方便主进程和渲染进程间通信,渲染进程的通信通常在 preload 脚本中发生
预加载(preload)脚本包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码 。 这些脚本虽运行于渲染器的环境中,却因能访问 Node.js API 而拥有了更多的权限,当然,为了安全考虑,它的 API 是受限的,主要就是发起 IPC 请求或监听,将自定义的API和变量等传递给渲染进程使用
5. 实用进程
在 Electron 22.0.0 中开始引入 utility process,每个Electron应用程序都可以使用主进程生成多个子进程UtilityProcess API,实用进程(官方翻译叫效率进程)可用于托管,例如:不受信任的服务, CPU 密集型任务或以前容易崩溃的组件托管在主进程或使用Node.jschild_process.fork API 生成的进程中。
`
预加载脚本 | Electron 安全
https://mp.weixin.qq.com/s/EKVlnqE6I3Zt-HWR8_8clQ
`
0x00 提醒
之前的一篇Electron 安全与你我息息相关文章非常的长,虽然提供了 PDF 版本,但还是导致很多人仅仅是点开看了一下,完读率大概 7.95% 左右,但上一篇真的是我觉得很重要的一篇,对大家了解 Electron 开发的应用程序安全有帮助,与每个人切实相关
但是上一篇文章内容太多,导致很多内容粒度比较粗,可能会给大家造成误解,因此我们打算再写一些文章,一来是将细节补充清楚,二来是再次来呼吁大家注意Electron 安全这件事,如果大家不做出反应,应用程序的开发者是不会有所行动的,这无异于在电脑中埋了一些地雷
0x01 简介
相信看了前面的文章,大家对于预加载脚本已经非常了解了,对于之前篇章中已经测试并解释清楚的部分,不会再次详细解释
预加载脚本 (Preload) 是一个比较让我意外的内容,可能因为学习 Electron 时就使用了官网推荐的安全开发案例,所以一直以为预加载脚本的 Node.js 就是被限制过的,但是随着最近的几篇文章的实验发现并不是
在 sandbox 没有被设置为 true 时(Electron 20.0 版本开始默认值为 true) ,预加载脚本是拥有完整 Node.js 环境的,如果在 Preload 中如果定义并暴露了不安全的方法,而开发者对于预加载脚本的能力并不了解可能会带来危害
0x02 预加载脚本中的Node.js
预加载脚本的意义在于完成主进程和渲染进程之间的联络,因此重要逻辑不应该在预加载脚本中进行,也不应该赋予其过于繁重的责任,完成主进程与渲染进程之间的通信,将通信结果传递给另一方才是它实际的意义,通过暴露方法使这种固定的逻辑可以被渲染进程调用
因此预加载脚本在渲染器加载网页之前注入,也就是说预加载脚本中的内容会先一步定义好,以供网页中的 JavaScript 正确调用
0x03 风险点
Preload 可以说是平衡风险和便捷的一种措施,本身已经做得不错了,风险点也都是开发者不安全编码造成的
* 未开启上下文隔离及 sandbox
* 不安全的实现
* 接口过度暴露
第一点就不多说了,前面的文章已经说清楚了,主要说后面两点,在后面两点中,我们的前提是开启了上下文隔离,开启了 sandbox
0x04 总结
预加载脚本的风险主要来源于不安全的编码习惯,但是有些泄漏可能是不容易发现的,例如有几个函数只是给 Preload 自己使用的,但是不小心暴露给了渲染进程;函数是给自己写的渲染进程使用的,结果同时暴露给了 iframe 这种嵌入内容等
预加载脚本是一个很好的代码审计的切入点,如果安全配置较为完善,则安全漏洞的利用基本都要通过预加载脚本传递数据,也就是掌握了咽喉位置,详细分析每一个 IPC 通信,就能找到几乎所有渲染进程攻击主进程的攻击面
`
https://github.com/Just-Hack-For-Fun/Electron-Security