mirror of
https://github.com/Mas0nShi/typoraCracker.git
synced 2023-07-10 13:41:20 +08:00
Compare commits
6 Commits
1.2.4
...
auto-analy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1beef1a98 | ||
|
|
d16428a8b2 | ||
|
|
d13b7df457 | ||
|
|
f09cf7a8b5 | ||
|
|
43b858c3ce | ||
|
|
937e3aa178 |
33
README.md
33
README.md
@@ -1,7 +1,11 @@
|
||||
**typoraCracker STOPS MAINTENANCE NOW. [why](https://github.com/Mas0nShi/typoraCracker/issues/39#issuecomment-1083117056)?**
|
||||
|
||||
|
||||
# typora Cracker
|
||||
|
||||

|
||||

|
||||
[](https://github.com/Mas0nShi/typoraCracker/actions/workflows/manual.yml)
|
||||
|
||||
A extract & decryption and pack & encryption tools for typora.
|
||||
|
||||
@@ -17,17 +21,28 @@ ANY PROBLEMS ARISING FROM THIS WILL BE BORNE BY THE USER (YOU).
|
||||
```
|
||||
|
||||
## Features
|
||||
- Supports Version 1.0.0+ (At least for now.)
|
||||
- tested fine in Windows, Ubuntu
|
||||
- Supports Version 1.0.0 - 1.2.0 [(old archive)](https://github.com/Mas0nShi/typoraCracker/tree/backup-raw)
|
||||
- Supports Version 1.2.+ [(Experimental archive)](https://github.com/Mas0nShi/typoraCracker/tree/master)
|
||||
|
||||
## Support List
|
||||
2022.4.4: Experimental support for automatic binary analysis to generate scripts. (v1.2.+)
|
||||
|
||||
| OS / ARCH | x86 | x64 | arm64 |
|
||||
|:---------:|:---:|:---:|:-----:|
|
||||
| win | ✅ | ✅ | ❌ |
|
||||
| linux | ❌ | ❌ | ❌ |
|
||||
| macOS | ❌ | ❌ | ❌ |
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
1. `pip install -r requirements.txt`
|
||||
2. `python typora.py --help`
|
||||
3. read and use.
|
||||
4. do something.
|
||||
5. pack and replace app.asar.
|
||||
6. enjoy it.
|
||||
1. download in [Release Pages](https://github.com/Mas0nShi/typoraCracker/releases)
|
||||
2. unzip
|
||||
3. `pip install -r requirements.txt`
|
||||
4. `python typora.py --help`
|
||||
5. read and use.
|
||||
6. do something.
|
||||
7. pack and replace app.asar.
|
||||
8. enjoy it.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
31
README_CN.md
31
README_CN.md
@@ -1,3 +1,6 @@
|
||||
**typoraCracker 停止维护. [为什么](https://github.com/Mas0nShi/typoraCracker/issues/39#issuecomment-1083117056)**
|
||||
|
||||
|
||||
# typora Cracker
|
||||
|
||||
一个typora的解包&解密,打包&加密工具
|
||||
@@ -12,18 +15,30 @@
|
||||
```
|
||||
|
||||
## Features
|
||||
- 版本 1.0.0 - 1.2.0 [(使用旧的存档)](https://github.com/Mas0nShi/typoraCracker/tree/backup-raw)
|
||||
- 版本 1.2.+ [(使用测试存档)](https://github.com/Mas0nShi/typoraCracker/tree/master)
|
||||
|
||||
|
||||
## Support List
|
||||
2022.4.4: 支持自动化分析二进制文件并生成脚本(测试性功能 v1.2.+)
|
||||
|
||||
| OS / ARCH | x86 | x64 | arm64 |
|
||||
|:---------:|:---:|:---:|:-----:|
|
||||
| win | ✅ | ✅ | ❌ |
|
||||
| linux | ❌ | ❌ | ❌ |
|
||||
| macOS | ❌ | ❌ | ❌ |
|
||||
|
||||
- 支持版本1.0.0以上(至少现在是这样)
|
||||
- 测试通过平台:Win/Ubuntu
|
||||
|
||||
## 食用方式
|
||||
|
||||
1. `pip install -r requirements.txt`
|
||||
2. `python typora.py --help`
|
||||
3. 阅读帮助文档及使用。
|
||||
4. 做你想做的事。
|
||||
5. 打包并替换原目录下的 app.asar。
|
||||
6. 享受成果。
|
||||
1. 前往[Release Pages](https://github.com/Mas0nShi/typoraCracker/releases) 下载对应版本
|
||||
2. 解压
|
||||
3. 安装依赖:`pip install -r requirements.txt`
|
||||
4. 使用说明:`python typora.py --help`
|
||||
5. 使用。
|
||||
6. 做你想做的事。
|
||||
7. 打包并替换原目录下的 app.asar。
|
||||
8. 享受成果。
|
||||
|
||||
|
||||
## 示例
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
from utils import get_version, download_file, extract_file, log, DOWNLOAD_LINK
|
||||
from utils import get_version, download_file, extract_file, log
|
||||
from config import DOWNLOAD_LINK
|
||||
import os
|
||||
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
|
||||
def win_x64_version():
|
||||
url = DOWNLOAD_LINK["win"]["x64"]
|
||||
dir = os.path.join(BASE_DIR, "win/x64")
|
||||
def run_version(download_os, download_arch):
|
||||
from_url = DOWNLOAD_LINK[download_os][download_arch]
|
||||
to_dir = os.path.join(BASE_DIR, f"{download_os}/{download_arch}")
|
||||
|
||||
download_path = os.path.join(dir, os.path.basename(url))
|
||||
download_file(url, download_path)
|
||||
extract_file(download_path, dir)
|
||||
version = get_version(dir)
|
||||
|
||||
open(os.path.join(dir, "LATEST_VERSION"), "w").write(version)
|
||||
log.success(version)
|
||||
download_path = os.path.join(to_dir, os.path.basename(from_url))
|
||||
download_file(from_url, download_path)
|
||||
extract_file(download_path, to_dir)
|
||||
version = get_version(to_dir)
|
||||
open(os.path.join(to_dir, "LATEST_VERSION"), "w").write(version)
|
||||
log.success(f"{download_os}-{download_arch} the latest version is {version}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
win_x64_version()
|
||||
|
||||
run_version("win", "x64")
|
||||
# run_version("win", "x86")
|
||||
# run_version("linux", "x64")
|
||||
|
||||
20
auto-analysis/config.py
Normal file
20
auto-analysis/config.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
"""
|
||||
@Author: Mas0n
|
||||
@File: config.py
|
||||
@Time: 2022/4/4 19:50
|
||||
@Desc: It's all about getting better.
|
||||
"""
|
||||
|
||||
|
||||
DOWNLOAD_LINK = {
|
||||
"win": {
|
||||
"x86": "https://typora.io/windows/typora-setup-ia32.exe",
|
||||
"x64": "https://typora.io/windows/typora-setup-x64.exe",
|
||||
"arm64": "https://typora.io/windows/typora-setup-arm64.exe",
|
||||
},
|
||||
"linux": {
|
||||
"x64": "https://download.typora.io/linux/Typora-linux-x64.tar.gz",
|
||||
"arm64": "https://download.typora.io/linux/Typora-linux-arm64.tar.gz",
|
||||
},
|
||||
}
|
||||
32
auto-analysis/linux/x64/analysis.py
Normal file
32
auto-analysis/linux/x64/analysis.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
"""
|
||||
@Author: Mas0n
|
||||
@Name: typora_linux_x64_analysis
|
||||
@Time: 2022/4/4 19:48
|
||||
@Desc: It's all about getting better.
|
||||
"""
|
||||
import json
|
||||
import r2pipe
|
||||
|
||||
|
||||
def get_aes_key_and_iv(file_path):
|
||||
r = r2pipe.open(file_path)
|
||||
|
||||
r.cmd("aaa")
|
||||
regex = r.cmdj("axtj @@ str.base64")
|
||||
assert len(regex) == 1
|
||||
|
||||
func = regex[0]["fcn_name"]
|
||||
r.cmd(f"s {func}")
|
||||
asm = r.cmdj("pdfj")['ops']
|
||||
assert len(asm) != 0
|
||||
|
||||
if 'str.dip3' in json.dumps(asm):
|
||||
r.cmd('s str.dip3 - 32')
|
||||
data = r.cmdj('xj 48')
|
||||
key = bytearray(data[0:32])
|
||||
iv = bytearray(data[32:48])
|
||||
else:
|
||||
raise "need rewrite scripts for linux x64"
|
||||
|
||||
return key, iv
|
||||
@@ -8,5 +8,7 @@
|
||||
import utils
|
||||
|
||||
if __name__ == '__main__':
|
||||
utils.win_x86_run()
|
||||
utils.win_x64_run()
|
||||
utils.linux_x64_run()
|
||||
|
||||
|
||||
@@ -6,26 +6,13 @@
|
||||
@Desc: It's all about getting better.
|
||||
"""
|
||||
from loguru import logger as log
|
||||
from config import DOWNLOAD_LINK
|
||||
import subprocess
|
||||
import json
|
||||
import os
|
||||
|
||||
# Usage:
|
||||
# innoextract
|
||||
#
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
DOWNLOAD_LINK = {
|
||||
"win": {
|
||||
"x86": "https://typora.io/windows/typora-setup-ia32.exe",
|
||||
"x64": "https://typora.io/windows/typora-setup-x64.exe",
|
||||
"arm": "https://typora.io/windows/typora-setup-arm64.exe",
|
||||
},
|
||||
"linux": {
|
||||
"x64": "https://download.typora.io/linux/Typora-linux-x64.tar.gz",
|
||||
"arm": "https://download.typora.io/linux/Typora-linux-arm64.tar.gz",
|
||||
},
|
||||
}
|
||||
BASE_DIR = os.path.dirname(__file__)
|
||||
|
||||
|
||||
def get_version(to_path):
|
||||
@@ -57,10 +44,7 @@ def patch_file(_key, _iv, to_dir):
|
||||
open(patch_file_path, "w").write(content)
|
||||
|
||||
|
||||
def win_x64_run():
|
||||
from win.x64 import analysis
|
||||
basedir = os.path.join(BASE_DIR, "win/x64")
|
||||
link = DOWNLOAD_LINK["win"]["x64"]
|
||||
def scheduler(func, basedir, link):
|
||||
|
||||
download_path = os.path.join(basedir, os.path.basename(link))
|
||||
log.info(f"downloading from {link}")
|
||||
@@ -71,24 +55,35 @@ def win_x64_run():
|
||||
log.info("preparation stage completed")
|
||||
main_node_path = os.path.join(basedir, "app/resources/app.asar.unpacked/main.node")
|
||||
log.info("auto analysis start")
|
||||
key, iv = analysis.get_aes_key_and_iv(main_node_path)
|
||||
key, iv = func.get_aes_key_and_iv(main_node_path)
|
||||
log.success("analysis done")
|
||||
|
||||
patch_file(key.hex(), iv.hex(), basedir)
|
||||
log.success("patch done")
|
||||
|
||||
|
||||
def win_x64_run():
|
||||
from win.x64 import analysis
|
||||
dirs = os.path.join(BASE_DIR, "win/x64")
|
||||
url = DOWNLOAD_LINK["win"]["x64"]
|
||||
scheduler(func=analysis, basedir=dirs, link=url)
|
||||
|
||||
|
||||
def win_x86_run():
|
||||
from win.x86 import analysis
|
||||
dirs = os.path.join(BASE_DIR, "win/x86")
|
||||
url = DOWNLOAD_LINK["win"]["x86"]
|
||||
scheduler(func=analysis, basedir=dirs, link=url)
|
||||
|
||||
|
||||
def linux_x64_run():
|
||||
from linux.x64 import analysis
|
||||
dirs = os.path.join(BASE_DIR, "linux/x64")
|
||||
url = DOWNLOAD_LINK["linux"]["x64"]
|
||||
scheduler(func=analysis, basedir=dirs, link=url)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
win_x86_run()
|
||||
win_x64_run()
|
||||
|
||||
# hashString = open("LATEST_VERSION", "r").read()
|
||||
# if hashString == "":
|
||||
# log.info("not history for typora version")
|
||||
# exit()
|
||||
|
||||
# basedir = os.path.dirname(__file__)
|
||||
# for h1 in DOWNLOAD_LINK.keys():
|
||||
# h1dir = os.path.join(basedir, h1)
|
||||
# for h2 in DOWNLOAD_LINK.get(h1).keys():
|
||||
# h2dir = os.path.join(h1dir, h2)
|
||||
# print(h2dir)
|
||||
linux_x64_run()
|
||||
|
||||
@@ -9,29 +9,30 @@ import struct
|
||||
import r2pipe
|
||||
|
||||
|
||||
def regex_key_iv(asm_obj):
|
||||
asm_regex = []
|
||||
for body in asm_obj:
|
||||
if "=[4]" in body["esil"] and body['type'] == 'mov':
|
||||
opcode, value = body["disasm"].split(", ")
|
||||
if "0x" in value:
|
||||
asm_regex.append({"opcode": opcode, "value": value})
|
||||
return asm_regex
|
||||
|
||||
|
||||
def get_aes_key_and_iv(file_path):
|
||||
r = r2pipe.open(file_path)
|
||||
# auto analysis
|
||||
r.cmd("aaa")
|
||||
# string "base64" x-cross reference
|
||||
regex = r.cmdj("axtj @@ str.base64")
|
||||
assert len(regex) == 1
|
||||
|
||||
func = regex[0]["fcn_name"]
|
||||
# disasm func
|
||||
r.cmd(f"s {func}")
|
||||
asm = r.cmdj("pdfj")['ops']
|
||||
assert len(asm) != 0
|
||||
|
||||
asm_regex = []
|
||||
for body in asm:
|
||||
if "=[4]" in body["esil"] and body['type'] == 'mov':
|
||||
opcode, value = body["disasm"].split(", ")
|
||||
asm_regex.append({"opcode": opcode, "value": value})
|
||||
|
||||
asm_regex = regex_key_iv(asm)
|
||||
assert len(asm_regex) == 12
|
||||
|
||||
iv = struct.pack("<4L", *[int(asm_regex[i]['value'], 16) for i in range(4)])
|
||||
key = struct.pack("<8L", *[int(asm_regex[i]['value'], 16) for i in range(4, 12)])
|
||||
# print(key, iv)
|
||||
return key, iv
|
||||
45
auto-analysis/win/x86/analysis.py
Normal file
45
auto-analysis/win/x86/analysis.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
"""
|
||||
@Author: Mas0n
|
||||
@Name: typora_win_x86_analysis
|
||||
@Time: 2022/4/3 18:36
|
||||
@Desc: It's all about getting better.
|
||||
"""
|
||||
import struct
|
||||
import r2pipe
|
||||
|
||||
|
||||
def regex_key_iv(asm_obj):
|
||||
asm_regex = []
|
||||
for body in asm_obj:
|
||||
if "=[4]" in body["esil"] and body['type'] == 'mov':
|
||||
opcode, value = body["disasm"].split(", ")
|
||||
if "0x" in value:
|
||||
asm_regex.append({"opcode": opcode, "value": value})
|
||||
return asm_regex
|
||||
|
||||
|
||||
def get_aes_key_and_iv(file_path):
|
||||
r = r2pipe.open(file_path)
|
||||
r.cmd("aaa")
|
||||
regex = r.cmdj("axtj @@ str.base64")
|
||||
assert len(regex) == 1
|
||||
|
||||
func = regex[0]["fcn_name"]
|
||||
r.cmd(f"s {func}")
|
||||
asm = r.cmdj("pdfj")['ops']
|
||||
assert len(asm) != 0
|
||||
|
||||
asm_regex = regex_key_iv(asm)
|
||||
|
||||
iv = struct.pack("<4L", *[int(asm_regex[i]['value'], 16) for i in range(4)])
|
||||
|
||||
# find the set key func
|
||||
call_regex = [i for i in asm if i['size'] == 5 and i['type'] == 'call']
|
||||
r.cmd(f"s {call_regex[1]['jump']}")
|
||||
asm = r.cmdj("pdfj")["ops"]
|
||||
asm_regex = regex_key_iv(asm)
|
||||
assert len(asm_regex) == 8
|
||||
|
||||
key = struct.pack("<8L", *[int(asm_regex[i]['value'], 16) for i in range(8)])
|
||||
return key, iv
|
||||
Reference in New Issue
Block a user