吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6557|回复: 91
收起左侧

[原创] 从Typora来学习AES CBC算法(详细版)

    [复制链接]
小朋友呢 发表于 2025-1-12 15:50
本帖最后由 小朋友呢 于 2025-6-27 09:18 编辑

环境信息

描述 说明
程序平台 Windows x64
程序名称 Typora_1.0.4
使用工具 ida8.3 winhex Exeinfo asar Vscode Cyberchef
程序架构 Electron
系统版本 Windows 10
下载地址 https://typora.io/releases/all

准备工作

1、软件下载:

20250110151236913.png

2、软件架构分析:

  • Typora采用的Electron架构进行开发的,如何看出来的?
  • 下载安装好以后在软件的resources目录可以看一个app.asar,这个就是基于Electron构架开发的软件特征

20250110153849819.png

3、准备node.js环境及其安装asar模块,如果环境都准备好了,可以使用如下命令查看版本信息:

node -v
asar -V

20250110160303379.png

备注:这里不一定要跟作者的版本一个,能正常运行即可

静态分析

分析js文件

1、我们首先打开软件尝试进行激活,观察软件给我们反馈

  • 从下面我们可以看到它是:(邮箱 + 序列号)的形式进行授权的

20250110154438427.png

2、将app.asar进行解包,命令如下:

# 将app.asar 解压到source文件夹
asar e app.asar source

20250110160241394.png

3、这里我们看到了有一个License.js文件,但是内容经过了Base64编码

20250110154338718.png

4、尝试将它进行解码,发现都是乱码,看来文件是经过了加密

20250111183927113.png

初探main.node

1、我们打开packages.json文件,查看配置信息:main字段所代表的就是程序所执行的入口文件

20250110154558052.png

2、我们将它放到winhex中查看一下文件的16进制信息,发现它是4D 5A开头,是一个标准的PE模块

20250110154812937.png

3、我们使用Exeinfo PE看一下main.node的基本信息,发现是64位的一个DLL文件

20250110155008135.png

分析main.node

1、这里我们将main.node载入到ida中进行静态分析,分析之前设置一下文件的基址

  • 依次点击:Edit->Segments->Rebase program

20250110162133043.png

2、这里将基址设置成0,方便我们后续分析

20250110161443008.png

3、我们之前看到js文件是经过了base64编码,那么程序在调用这些js文件的时候肯定会进行解码操作,所以我们就在IDA中搜索字符串base64相关的内容,具体如下图所示:

20250110161903477.png

搜索字符串的方法:SHIFT + F12

4、然后我们在aBase64x进行交叉引用来到此处,发现这里都调用了一个函数:napi_get_named_property来进行一些操作

  • 翻译成python就是:base64.b64decode(Buffer),是进行了一个base64解码操作

20250110161817077.png

关于:napi_get_named_property 是 Node.js N-API 中的一个函数,用于从对象中获取指定名称的属性。

N-API 是 Node.js 提供的一个稳定的 API 层,用于构建本地插件。这个函数通常用于在 C/C++ 代码中与 JavaScript 对象进行交互。

分析加密算法

分析AES轮数

1、在上面我们分析js文件的时候知道,base64解码过后是乱码,文件过经过了加密,那么它在执行的时候一定会进行解密操作,接下来我们就要寻找解密算法

  • 使用FindCrypt来分析程序用了哪些加密的算法,依次点击:Edit->Plugins->FindCrypt,发现了有AES加密的特征

20250110165330284.png

2、这里我们双击最后一行(为什么呢?经过了反复验证最后一个是关键点)

20250110165343569.png

3、同样来到这里按x交叉引用,找到调用处

20250110165403189.png

4、补充:我们知道了程序使用了AES加密算法后,我们还需要知道它的一些参数:

  • 加密模式,加密轮数,密钥,密钥长度,IV

5、首先来看我们交叉引用过来的地方,这里有一个do while循环,循环次数由变量v6控制,一共是13次

20250111162449060.png

  • 在 AES 中,轮数与密钥长度的关系如下:

    • 13 轮:这对应于 AES-256,因为 AES-256 的加密轮数是 14 轮(包括初始轮和主轮)。
    • 初始轮:1 次(AddRoundKey)
    • 主轮:13 次(SubBytes、ShiftRows、MixColumns、AddRoundKey)
    • 最终轮:1 次(SubBytes、ShiftRows、AddRoundKey)
  • 那么我们就知道代码中的13对应的是AES-256,密钥长度是32字节

6、我们这里列一张表,记录我们得到的信息

属性
加密算法 AES
加密模式 /
加密轮数 14
密钥 /
密钥长度 32
IV /
分析AES模式

1、我们知道AES的轮数及密钥长度后继续往逆向分析,在函数开头继续交叉引用,看是谁调用了它

20250111162638886.png

2、如下图所示:sub_EEC0函数就是刚刚上方我们分析AES轮数的地方,再看到它正文有一个异或操作

  • 那么在这段代码中,一个循环里,有解密函数与异或操作的是什么加密模式呢,我们继续往下看

20250111162840894.png

3、它就是AES CBC 模式:

  • 流程图版本

20250111163022317.png

  • 代码版本

20250111193406058.png

4、记录一下我们得到的信息

属性
加密算法 AES
加密模式 CBC
加密轮数 14
密钥 /
密钥长度 32
IV /
分析AES密钥

1、现在我们来分析AES的密钥在哪里,继续我在函数开头交叉引用找到上层调用的函数

20250111163102104.png

2、继续往上

20250111163114363.png

3、直到我们来到sub_3A8F调用这里,再往上翻,就是我们在最开始通过base64字符串定位到的地方,下方呢就是AES的解密操作

20250111163434498.png

4、记录下这个偏移AD7C,此处调用的call sub_3A8F,为我们下面动态分析作准备

20250111195104349.png

动态分析

配置环境

1、在ida中打开Typora.exe文件

20250110165908284.png

2、设置为本地调试器:依次点击:Debugger->Select a debugger->Local Windows

20250110165956792.png

3、设置调试选项:依次点击:Debugger -> Debugger options,勾选在载动态库时断下来,停下来的条件是:加载main.node模块时

get_event_id() == LIB_LOADED && strstr(get_event_module_name(), "main.node") != -1

20250111214833137.png

分析密钥

1、接下来我们在ida中今天动态调试,F9运行程序,在加载main.node模块处时ida暂停了下来

20250110175533358.png

2、定位到 AES解密函数处:7FF96C540000 + AD6A = 7FF96C54AD6A(模块基址 + 偏移 )

20250110175715141.png

补充:在 Windows x64 架构中,使用的调用约定是Fastcall,其规则如下:

  • 前 4 个参数通过寄存器传递(简称CD89):
    • 第 1 个参数RCX
    • 第 2 个参数RDX
    • 第 3 个参数R8
    • 第 4 个参数R9
  • 其余参数通过栈传递(从右到左)。
  • 调用者负责清理栈。

3、我们在CALL处下一个断点并让程序运行到此处

20250110175934652.png

4、参数1:32字节的AES KEY

4E E1 B3 82 94 9A 02 4B 80 2F 52 B4 B4 FE 57 F1 BE F4 08 53 10 92 56 E2 C2 0D EC A3 DD 8D D5 6D

20250110180452455.png

5、参数2:欲解密的数据,也就是base64解码后的atom.js,具体如下图所示:

20250110180830198.png

疑问:

  • 这里为什么是atom.js而不是其它的js呢?因为程序加载的顺序,是从小到大,这里就是从字母a开头的文件。
  • 为什么解密的时候跳过了前16字节呢,前16个字节是干嘛的呢?这个问题就是接下来分析的重点

6、参数3:它就是atom.js base64解码后的字节大小:0x4030

20250110181001344.png

7、现在AES KEY有了接下来就是寻找IV了。

分析IV

1、经过上访的分析我们知道它是AES CBC的解密模式,那么在还原明文最后一步的时候是将aes_decrypt的数据与IV进行异或

  • 我们跟进sub_E440函数进行查看,具体如下图所示:

20250110181542066.png

2、我们在result变量处按tab来到反汇编视图,待会呢我们在这E4A0偏移处下一个断点,看看IV是什么

20250110181638974.png

3、回到调试的IDA中观察rdi+rbx地址处的值是什么,会发现正是前面AES解密时跳过的那16字节,所以我们就可以知道,AES的IV就是文件前16字节

20250110181852558.png

解密文件

1、我们将收集到的数据进行汇总

属性
加密算法 AES
加密模式 CBC
加密轮数 14
密钥 4E E1 B3 82 94 9A 02 4B 80 2F 52 B4 B4 FE 57 F1 BE F4 08 53 10 92 56 E2 C2 0D EC A3 DD 8D D5 6D
密钥长度 32
IV 文件前16字节

2、我们在Cyberchef里面进行AES解密操作,可以看到成功的解密出正常的js代码来

20250110182515306.png

编写脚本

1、编写一个pytho脚本自动化这个解密过程

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from base64 import b64decode, b64encode
from jsbeautifier import beautify
from jsmin import jsmin
from os import urandom
import argparse
import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler()  # 输出到控制台
    ]
)

# AES 密钥(32 字节,AES-256)
aes_key = bytes.fromhex('4E E1 B3 82 94 9A 02 4B 80 2F 52 B4 B4 FE 57 F1 BE F4 08 53 10 92 56 E2 C2 0D EC A3 DD 8D D5 6D')

def decrypt_script(b64: bytes) -> bytes:
    """解密脚本"""
    try:
        lCode = b64decode(b64)
        aesIv = lCode[:16]  # 前 16 字节为 IV
        cipherText = lCode[16:]  # 剩余部分为密文

        # 使用 AES-256 CBC 模式解密
        cipher = AES.new(key=aes_key, iv=aesIv, mode=AES.MODE_CBC)
        decrypted = unpad(cipher.decrypt(cipherText), 16, 'pkcs7')

        # 美化代码
        return beautify(decrypted.decode()).encode()
    except Exception as e:
        logging.error(f"解密失败: {e}")
        raise

def encrypt_script(code: bytes) -> bytes:
    """加密脚本"""
    try:
        # 压缩代码
        code = jsmin(code.decode(), quote_chars="'\"`").encode()

        # 生成随机的 IV
        aesIv = urandom(16)

        # 使用 AES-256 CBC 模式加密
        cipher = AES.new(key=aes_key, iv=aesIv, mode=AES.MODE_CBC)
        encrypted = aesIv + cipher.encrypt(pad(code, 16, 'pkcs7'))

        # 返回 Base64 编码的结果
        return b64encode(encrypted)
    except Exception as e:
        logging.error(f"加密失败: {e}")
        raise

def process_file(input_file: str, output_file: str, mode: str):
    """处理文件(加密或解密)"""
    try:
        logging.info(f"开始处理文件: {input_file}")
        with open(input_file, 'rb') as f:
            data = f.read()

        if mode == 'd':
            result = decrypt_script(data)
        elif mode == 'e':
            result = encrypt_script(data)
        else:
            raise ValueError("无效的模式,请选择 'encrypt' 或 'decrypt'")

        with open(output_file, 'wb') as f:
            f.write(result)
        logging.info(f"操作成功!结果已保存到 {output_file}")
    except Exception as e:
        logging.error(f"处理文件时出错: {e}")

def main():
    """主函数:解析命令行参数并执行操作"""
    parser = argparse.ArgumentParser(description="AES-256 加密/解密工具")
    parser.add_argument('mode', choices=['e', 'd'], help="选择模式:encrypt(加密)或 decrypt(解密)")
    parser.add_argument('input_file', help="输入文件路径")
    parser.add_argument('output_file', help="输出文件路径")
    args = parser.parse_args()

    process_file(args.input_file, args.output_file, args.mode)

if __name__ == '__main__':
    main()

2、使用方法

解密:python typora.py d enc.js dec.js
加密:python typora.py e dec.js enc.js

20250111164724397.png

3、解密License.js文件

 python .\typora.py d .\source\License.js .\source\License_dec.js

20250111164821789.png

20250111164412303.png

补丁文件

<center><b>接下来我们对License.js进行Patch达到本地激活的目的</b><center>

1、第1处:搜索doActivation,修改如下:

return [!0, ""];

20250110190230384.png

2、第2处:搜索unfillLicense,修改如下:

20250110190144480.png

3、第3处:搜索onUnfillLicense,修改如下:

20250110190211133.png

4、第4处:搜索hasLicense,修改如下:

20250110190311945.png

5、修改完以后再重新加密回去

python .\typora.py e .\source\License_dec.js .\source\License.js  

20250111164956096.png

6、替换原app.asar文件

# 备份原来的文件
copy app.asar app.asar.old

# 将修改后的文件进行打包替换
asar  p source app.asar

7、成功激活

20250110185932841.png

免费评分

参与人数 54吾爱币 +47 热心值 +47 收起 理由
nuanyy110 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
笑嘻嘻0_o + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
古酒道人1 + 1 + 1 用心讨论,共获提升!
wdnmd8843 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
morrow-lee + 1 + 1 我很赞同!
PhiFever + 1 + 1 谢谢@Thanks!
AE86-GL + 1 我很赞同!
NortonIt + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
_莫逸 + 1 + 1 我很赞同!楼主怎么下的1.04版本, 1.04只有mac版吧
Lollipop、柯 + 1 鼓励转贴优秀软件安全工具和文档!
VirusCollector + 1 + 1 我很赞同!
geesehoward + 1 + 1 写的太好了
笙若 + 1 + 1 谢谢@Thanks!
wshwxq + 1 + 1 鼓励转贴优秀软件安全工具和文档!
LHSBLHSB + 1 用心讨论,共获提升!
贪睡的叶浠 + 1 + 1 用心讨论,共获提升!
孤独尽头是自由 + 1 + 1 我很赞同!
落英飘渺 + 1 谢谢@Thanks!
allspark + 1 + 1 用心讨论,共获提升!
xiao2xing + 1 + 1 用心讨论,共获提升!
stilt6642 + 1 + 1 用心讨论,共获提升!
MysteryX + 1 热心回复!
WoAiPoJie5678 + 1 + 1 虽然看不懂,感觉很赞
星期日 + 1 + 1 我很赞同!
LazySheep + 1 谢谢@Thanks!
jinlide1101 + 1 鼓励转贴优秀软件安全工具和文档!
WANG52pojie + 1 + 1 用心讨论,共获提升!
chly0828 + 1 + 1 热心回复!
腰围两尺99 + 1 + 1 用心讨论,共获提升!
kankanba + 1 + 1 用心讨论,共获提升!
ps122 + 1 + 1 用心讨论,共获提升!
maza_2000 + 1 + 1 我很赞同!
vLove0 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
五虎上将 + 1 + 1 谢谢@Thanks!
tou + 1 + 1 用心讨论,共获提升!
DouH9Yue + 1 + 1 我很赞同!
PastYiHJ + 1 + 1 我很赞同!
GhostOO + 1 谢谢@Thanks!
jgs + 1 + 1 谢谢@Thanks!
q2212282 + 1 + 1 我很赞同!
ravi + 1 + 1 我很赞同!
温柔 + 1 + 1 谢谢@Thanks!
Milonc + 1 用心讨论,共获提升!
kuiba + 1 + 1 用心讨论,共获提升!
warmlight814 + 1 + 1 用心讨论,共获提升!
二十瞬 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
FitContent + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
lj0822 + 1 + 1 我很赞同!
smilerfu + 1 分析得很好,感谢分享
mainblog + 1 用心讨论,共获提升!
飘零星夜 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
danieljia + 1 + 1 我很赞同!
swiftR + 1 + 1 用心讨论,共获提升!
shengruqing + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

sunflash 发表于 2025-1-14 12:43
震惊于楼主充满逻辑的表达能力。即便0基础也能看懂大概意思。

Typora真是一款宝藏软件,不但带来了简洁好用的MD工具,还科普了+解密算法。

在此也向原作者致以真诚的敬意

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
小朋友呢 + 2 + 1 我很赞同!

查看全部评分

moshouhot 发表于 2025-1-14 08:45
太棒了 ,终于知道动态分析怎么弄了。 建议结合这个帖子一起看:https://www.52pojie.cn/forum.php?mod=viewthread&tid=1990569
Arctic7 发表于 2025-1-13 17:34
这个相当于typora激活的时候没做文件防篡改hash校验,估计开发者看了后续版本就补上了
geesehoward 发表于 2025-2-14 17:00
文章思路清楚,过程完整,连思考过程都写的很详细,只要耐心看完,都会有收获,给楼主点赞
hanhai 发表于 2025-1-13 10:11
多谢分享,学习了
Gu1617217829 发表于 2025-1-13 10:19
已收藏,慢慢学
tyron 发表于 2025-1-13 10:35
有点东西,感谢分享
hXxXh 发表于 2025-1-13 10:37
真是一场酣畅淋漓的分析
xzbk01 发表于 2025-1-13 10:44
写的非常的详细,可以跟着照做,谢谢了
chishingchan 发表于 2025-1-13 11:37
为什么不以转折版本 1.3.9 作示范?1.0.4 版太旧了
Sias 发表于 2025-1-13 11:40
大佬  学习了
sssdddffg 发表于 2025-1-13 13:25
谢谢指导
llfly 发表于 2025-1-13 14:32
非常的详细 , 感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-4-15 08:41

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表