动机

其实很久之前就有逆向Typora的打算了,但是苦于当时找到的网上的教程不是非常细致,很多地方都看不懂是在干嘛,所以一直没有进度。虽然这学期还是有各种长线的大作业吊着,近期也有编译原理和英语听说两个临近deadline的作业,但我还是忍不住干了,尤其是已经看了新找到的一些教程后。趁记忆消退前,成功后先记下来。

在新电脑上通过修改注册表得到的(实际只记得移动了安装的位置)Typora的无限试用期重置了,今天(2024年11月17日)刚好只剩1天,也是折腾这个的理由。本来想用Typora作为英语听说present的准备的编辑器,也是理由。

过程

背景知识

  • Typora采用的框架是Electron。

  • 调试它的可执行文件还是得用上反汇编软件,例如IDA。

  • asar是一种打包方式,可以直接用nodejs的asar提取出来,没有加密。

  • AES是一种块加密,也就是把明文划分成相同大小的块再进行加密,加密用的密钥叫key。AES-128、192、256用到的key长度分别是16byte、24byte、32byte。这里Typora用到的是AES-256,所以key的长度是32byte12

    aes_detials
    aes_enc_dec
  • AES加密和解密会分别用到两个256byte的矩阵,叫SBox和InvBox。它们的值是固定的,所以可以通过IDA的FindCrypt插件找出来。

  • 块加密有不同的模式,有CBC、ECB、CFB等等。其中ECB是每个明文块分别加密;CBC和CFB是把上一块的密文和当前块的明文做异或后再加密,区别是它们俩明文与密文做异或的时机不一样。在这里Typora用的是CBC模式。3

    BlockCipherModesofOperation
  • CBC这种加密方式需要在第一个加密的周期前面再加一个初始的“与明文做异或”的块,就叫iv(initial vector)。因为AES的块是一个4x4的格子,长度为16byte,所以iv的长度就是16byte

整体介绍

Typora通过app.asar里的main.node模块(实际为dll动态链接库文件)加载atom.js中关于验证license的代码,atom.js通过AES-256加密后用base64编码,以密文的形式存储。解密的过程就发生在main.node中。45

破解的思路是找到AES加密的key和iv,修改解密出来的验证license的代码,再将修改过的代码加密,替换掉原来的atom.js,再重新打包。所以整个过程大概可以分成两个部分:AES解密和patch JavaScript代码。因为不太熟悉后面这部分,估计还得花点时间搞,所以我打算下次再写。

听说还有一种更方便的方法是hook,不过我还没怎么搞明白。

文件结构

在Typora的安装路径下,有Typora.exe可执行文件,它会使用resources/app.asar.unpacked中的main.node来动态加载app.asar,再解密里面的atom.js。我们自己打开app.asar后里面会3个文件,其他两个都不用管,重点关注这个atom.js就好了。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Typora
➜ tree -L 3
.
├── chrome_100_percent.pak
├── chrome_200_percent.pak
├── d3dcompiler_47.dll
├── DO NOT ADD FILES HERE
├── ffmpeg.dll
├── icudtl.dat
├── libEGL.dll
├── libGLESv2.dll
├── LICENSE
├── LICENSES.chromium.html
├── locales
│   ├── uk.pak
| ...
│   ├── zh-CN.pak
│   └── zh-TW.pak
├── resources
│   ├── app.asar
│   ├── app.asar.unpacked
| | └── main.node
│   ├── appsrc
│   ├── assets
│   ├── conf.default.json
│   ├── Docs
│   ├── DO NOT ADD FILES HERE
│   ├── html
│   ├── lib.asar
│   ├── locales
│   ├── node_modules
│   ├── node_modules.asar
│   ├── package.json
│   ├── page-dist
│   ├── style
│   ├── updater
│   └── window.html
├── resources.pak
├── snapshot_blob.bin
├── Typora.exe
├── Typora.VisualElementsManifest.xml
├── unins000.dat
├── unins000.exe
├── v8_context_snapshot.bin
├── version
├── vk_swiftshader.dll
├── vk_swiftshader_icd.json
└── vulkan-1.dll

听说这个“chrome_100_percent.pak”“chrome_200_percent.pak”是Electron框架的一个特征。6

简单提取一下:npx asar extract app.asar app.asar.manual

1
2
3
4
5
6
Typora/resources/app.asar.manual
➜ tree
.
├── atom.js
├── main.node
└── package.json

步骤

  1. 通过IDA打开main.node。IDA会自动识别文件类型,然后自动勾选一些选项。

    ida_open
  2. Shift+F12打开字符串搜索,找到“./atom.js”,双击点进去,F5自动生成伪代码,估计就是用这个函数加载的密文。把函数名“sub_xxxx”改成“load_atomjs”这种方便理解的名字。点击函数名,按N即可修改,后面分析伪代码修改变量名也是这样。

    ida_strings
    ida_load_atomjs
    ida_load_atomjs_asm
  3. Ctrl+Alt+F使用FindCrypt插件,或者在工具栏Edit/Plugins/下点开,可以找到两个RijinDaelSBox和InvBox。第二个IDA的识别有一点错误,把后面的不相干的数据也划成InvBox的了,小键盘*修改Array的大小为256byte。我们要找解密的过程,所以要找用了InvBox的函数。双击InvBox进去,可以把函数重命名为“load_invbox”。右边分号后面的是汇编代码的注释,可以看到“DATA XREF: sub_xxxx”,这是IDA自动生成的,代表IDA找到的引用了这个数据的函数,可以双击点进去。

    ida_findcrypt
    ida_invbox
  4. 在汇编代码窗口按X查看当前函数的交叉引用,工具栏View/Graphs可以查看调用当前函数和当前函数调用的关系图。可以看到重命名后IDA自动把单纯调用“load_invbox”的函数命名为了“j_load_invbox”。

    ida_xref
  5. “load_invbox”函数的伪代码的结构很像AES解密的流程7,我们把其中的循环结构标记出来后就更清晰了。将伪代码中无意义的v1v2的变量名重命名为有实际意义的变量名,以及通过/添加注释,可以降低理解代码的难度。

    ida_load_invbox
  6. 找到表示密文的变量并重命名,下断点,动态调试,双击变量名。右键调试窗口的hex子窗口,synchronized with汇编窗口,再取消同步,多走几步可以看到数据一行一行地变为“require…”开头的明文。因为AES-256的key在做key expansion的时候,头两轮的key分别是原key的前后两段;而在解密中这两段key会用在最后两次AddRoundKey中。因为第一次找的时候我没找到key具体存放在哪里,所以我们可以异或密文和明文得到key来曲线救国。

    ida_debug
  7. 在旧版的Typora中,iv就是密文的前16byte,在1.9.5中已经不是了。奈何我实在没看懂iv到底是在哪里,所以我就求助于比较新的教程8910,把教程中标注为iv的变量标注为iv,动态调试得到它的值。

  8. 在CyberChef中选择cbc模式解密失败,选择cbc/no padding模式成功了,但是明文的末尾有一串非ascii字符串。我猜测是CyberChef自动去除padding时不能判断哪里是padding。

其他

  • IDA的颜色

    1,2两篇教程的ida的theme都设置成了护眼的黑色,而非默认的米黄色,第2篇米黄色背景的软件是x64dbg

  • CyberChef

    第1篇教程保存按钮的软件是notepad++,两篇都用到了CyberChef(BAKE!)

参考链接


  1. 高级加密标准Wiki↩︎

  2. CTF Wiki AES↩︎

  3. Block cipher mode of operation Wiki↩︎

  4. [原创] Typora 授权解密与剖析↩︎

  5. [原创] Typora 1.0.4版本破解复现↩︎

  6. Electron程序逆向(asar归档解包)↩︎

  7. 从零实现 AES 加密算法↩︎

  8. [原创]Typora 破解 之 逆向分析(上)↩︎

  9. Typora破解复现↩︎

  10. [原创]【最新】Typora最新版的逆向过程分析↩︎

背景

想用VMware里的Kali跑一下数图的一篇论文的项目EAGLE, 因为在WSL上尝试配了一下环境, 但是conda env create -f environment.yml的报错里有一个windows_support.py, 所以我 怀疑是什么东西把WSL当成了Windows. (现在在VMware里搞完了, 报错跟之前的一摸一样, 首先都是一个找不到libffi.so.6, 但是symlink到libffi.so.8.1.2在跑 download_dataset.py时又会报IOT的什么错)

但是虚拟机里没装代理, conda的速度非常慢, create env的时候直接结束了, 没有成功创 建. 代理软件更新后, 我没有打开允许局域网连接. 浏览器可以通过代理上网, 但我没有 找到配置系统代理的设置界面(像Ubuntu那种).

proxychains

在网上随便找一篇proxychains的教程都可以, 过程就是在/etc/proxychains.conf中把 strict_chain禁用, 把dynamic_chain启用, 再在最后加入形如"socks5 xxxx xxxx"的一句 . 使用proxychains firefox确实有效果. 但是proxychains ping xxx没有用.

还有比较麻烦的一点是设置的代理ip要到宿主机上面看一眼, 再手动修改.

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

版本管理

在 WSL 上,我用 n 管理 node 版本;在 Win 上,我用 nvm 管理 node。如果用 nvm 要重新给全局的 node_module 设置环境变量,因为 nvm 会把它删掉😵

sudo n latest 会很慢,下载到 40% 左右就会断掉,因为它不会走代理

sudo -E n latest 就很快,像喝水一样

目前我的 WSL 可以正常走 Win 的代理,git 一般没问题。不过配置的过程断断续续的,我没有记下来,可能只是在 %USERPROFILE%\.wslconfig 里加了 networkingMode=mirrored 和 autoProxy=true

build 内存溢出

build Open-WebUI 的时候,出现了如下报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
rendering chunks (179)...
<--- Last few GCs --->

[34877:0x76335a0] 48848 ms: Scavenge 2020.6 (2076.4) -> 2019.7 (2086.2) MB, 14.60 / 0.00 ms (average mu = 0.663, current mu = 0.876) allocation failure;
[34877:0x76335a0] 48892 ms: Scavenge 2027.0 (2086.6) -> 2024.4 (2087.2) MB, 15.86 / 0.00 ms (average mu = 0.663, current mu = 0.876) allocation failure;
[34877:0x76335a0] 48952 ms: Scavenge 2028.3 (2087.6) -> 2026.5 (2106.6) MB, 42.90 / 0.00 ms (average mu = 0.663, current mu = 0.876) allocation failure;


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

1: 0xcc08f6 node::OOMErrorHandler(char const*, v8::OOMDetails const&) [node]
2: 0x1054130 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
3: 0x1054417 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, v8::OOMDetails const&) [node]
4: 0x1273655 [node]
5: 0x128a178 [node]
6: 0x126167e v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
7: 0x1262964 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [node]
8: 0x1240625 v8::internal::Factory::NewFillerObject(int, v8::internal::AllocationAlignment, v8::internal::AllocationType, v8::internal::AllocationOrigin) [node]
9: 0x1670bec v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [node]
10: 0x7f20326653f6
Aborted

这是 ChatGPT 的回答

试了前两种方法,似乎只有第一种 NODE_OPTIONS="--max-old-space-size=4096" npm run build 有用

开头

事情的起因是我想玩玩一个 魔改的pvz ,但是卡巴斯基报毒说有木马。为了安全起见,我想试一试用前段时间装的 Sandboxie 来运行一下。因为不会设置隔离的沙盒,搞到一般就放弃了。(后面的问题可能是这里修改了注册表的什么地方吧)

中间

然后我想看一看数据库实验的手册,结果 Microsoft 365 报 0x426-0x0 的错误码。我看了 帖子,装了个 Microsoft Support and Recovery Assistant (没有什么用),打算卸载了重新安装。结果这个 Assistant 卸载了老半天还没卸载完,我就中途取消了。

而后我把沙盒的设置修改回去了,启用了 MS ClickToRun 的服务,还有 Windows Module Installer 服务。然后把 Office 365 卸载了,又在微软商店装了回来。尝试打开文档,还是失败了。

然后我看到了 这个 教程,想试一下 msconfig 里面的“诊断启动”,导致了今天最惊险的情况😇。电脑启动后唯二的两种登录方式都不可用了:人脸和 PIN 码(选择 PIN 会弹出一个弹窗问你是否从商店里安装一个什么,有点太幽默了点)。电脑险些直接变成薄薄的板砖。

结果

多次物理重启后,我根据 教程 进入恢复环境,把 Utilman.exe 换成 cmd.exe,重启后点右下角的小人就打开了 cmd,再打开 msconfig 改成正常启动,再重启就恢复正常了。

最后 Office 是根据 教程官网 重新安装好了。Office 已卸载的时候搜索 WINWORD 可以找到在 C:\Program Files\Microsoft Office\root\Office16 的疑似本体的文件。

因为想把电脑上的一些图片转成 ASCII 图片, 在复制 Windows 的文件地址到 WSL 上时, 没有找到像 cygpath 这样的工具, 所以我在 .zshrc 里加了下面的内容:

1
2
3
4
5
# cygpath-like func
w2nix()
{
echo "$1" | sed -e 's/\\/\//g' -e 's/E:/\/mnt\/e/g'
}

在我想把这件事写进 blog 时, 我又发现我的 hexo 命令找不到了。

一番排查后发现是 nvm 修改系统变量的时候连着 node_global 也给改掉了。蒸 🦐 头

参考链接

Linux技巧:sed命令替换、删除、同时匹配多个模式的方法

zsh自定义命令并传递参数

问题

尝试在 Hexo 中显示公式,采用了 pandoc + mathjax 的方法。 但是在下标中仍然不能有 # 或 \# ,现在也没有找到解决办法

详细信息

安装的 node_modules :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ npm ls
hexo-site@0.0.0 E:\Document\Blog
├── hexo-deployer-git@4.0.0
├── hexo-filter-flowchart@1.0.4
├── hexo-filter-mathjax@0.9.0
├── hexo-generator-archive@2.0.0
├── hexo-generator-category@2.0.0
├── hexo-generator-index@3.0.0
├── hexo-generator-tag@2.0.0
├── hexo-renderer-ejs@2.0.0
├── hexo-renderer-pandoc@0.4.0
├── hexo-renderer-stylus@3.0.1
├── hexo-server@3.0.0
├── hexo-theme-next@8.19.2
└── hexo@7.1.1

在 _config.yml 中添加:

1
2
3
4
5
6
7
8
9
10
11
12
# Mathjax
mathjax:
tags: none # or 'ams' or 'all'
single_dollars: true # enable single dollar signs as in-line math delimiters
cjk_width: 0.9 # relative CJK char width
normal_width: 0.6 # relative normal (monospace) width
append_css: true # add CSS to pages rendered by MathJax
every_page: false # if true, every page will be rendered by MathJax regardless the `mathjax` setting in Front-matter
packages: # extra packages to load
extension_options: {}
# you can put your extension options here
# see http://docs.mathjax.org/en/latest/options/input/tex.html#tex-extension-options for more detail

通过 winget 安装了 pandoc 3.1.12.2

如果开启代理时打开 WSL ,会提示 “wsl: 检测到 localhost 代理配置,但未镜像到 WSL。NAT 模式下的 WSL 不支持 localhost 代理。”

参考链接

%USERHOME%/.wslconfig 中添加如下内容

1
2
3
4
5
6
[experimental]
autoMemoryReclaim=gradual | dropcache | disabled
networkingMode=mirrored
dnsTunneling=true
firewall=true
autoProxy=true

例题

有三个表

学生

课程

选课

  1. 检索不学 C2 课的学生姓名,年龄
  2. 检索学习全部课程的学生学号

笔记

  1. 错误的做法是

    这意味着检索出“选了不是 C2 的课程”的学生姓名、年龄,而非所有学生中“没有选 C2 课程”的学生

    正确的做法是

  2. 错误的做法是

    这意味着检索出“学习全部课程且成绩相同”的学生学号,因为 S 和 Grade 共同作为除法“ ”中的

    正确的做法是

VMware 版本:16.2.4 Pro

Kali pre-built 版本:Kali Rolling (2023.4) x64

因为之前配 Ubuntu 的网络的时候就有点抓瞎,所以这次打算把配置过程稍微记录下来,免得再把头搞大。之前我是用 iso 安装了 kali ,因为当时没想到还有直接下载虚拟机的,后来感觉 pre-built 的启动更快一点,键盘鼠标输入也更流畅,就把之前的删掉了。

基本配置

Kali可以手动配置网络,也可以让NetworkManager(命令有 nmclinmtui )自动配置。默认的配置文件是 /etc/network/interfaces ,nm的配置文件是 /etc/NetworkManger/NetworkManager.conf

据我观察kali应该就只有 networking.serviceNetworkManager.service 两个服务是跟网络相关的,不过前者是 actived(exited) 状态,后者是 actived(running) 状态。我猜 networking 应该就是管那个 interfaces 的服务。

/etc/network/interfaces默认配置:

1
2
3
4
5
auto lo
iface lo inet loopback

# auto eth0
# iface eth0 inet dhcp

/etc/NetworkManager/NetworkManager.conf 默认配置:

1
2
3
4
5
[main]
plugins=ifupdown,keyfile

[ifupdown]
managed=false

因为 managed 默认为 false ,nm 不会接管 interfaces 中已经配置的接口,所以 interfaces 中只需要写 loopback 的内容。如果把 interfaces 中 eth0 的配置取消注释,右上角的网络小图标会显示没有网络,但是此时是可以上网的。

我的虚拟机的网卡名字叫 eth0 ,对应 mac 地址是 VMware 虚拟机设置 -> 网络适配器 -> 高级 的 mac 地址。不管连接模式是 nat 还是 bridge ,到虚拟机中对应的都是同一个有线连接。如果有移动网卡就可以通过 虚拟机 -> 可移动设备 给虚拟机用,可以连接周围的 WiFi 。

如果修改了虚拟机的 permanent mac , nm 的 networking 这一项就会关闭,导致 lo 和 eth0 两个网卡都是 strictly unmanaged 状态,只需要输入 nmcli n on 把 networking 打开就好了。

nm 还需要设置 connection ,一般一个 device 设置一个就好了,因为不能同时开启 (不确定有多个网卡是什么情况) 。通过 nmtui 或者 kali 桌面的 Advanced Network Configuration 设置都可以, nmcli 也可以,不过不太方便。

连接校园网

WHU校园网登录认证

WHU校园网自助服务

因为校园网需要在网页上认证,所以在桥接模式下,虽然我的虚拟机可以 ping 到物理机,但是无法上网。要在虚拟机上使用校园网,需要把 mac 地址改成物理机用来上网的无线网卡的地址 (比如我的网卡是 Intel(R) Wi-Fi 6 AX201 160MHz) ,桥接模式下面 "复制物理网络连接状态" 的选项似乎选不选都可以。虚拟机成功登录校园网后,物理机是没法正常上网的状态,将虚拟机挂起可以恢复。

其他

/sys/class/net/ 下可以看到网卡的名字

lspcilsusb 可以查看 pci 和 usb 设备

macchanger 可以改变网卡的 mac 地址,不过好像不能改 permanent mac

sudo systemctl restart networking 重启 networking.service

sudo systemctl restart NetworkManager 重启 NetworkManager.service

0%