From 4d15e2a66519b1352312f72b06c7dbf227a7a93e Mon Sep 17 00:00:00 2001 From: mason Date: Mon, 14 Mar 2022 21:07:22 +0800 Subject: [PATCH 01/21] updaate aesKey for 1.2.2-dev --- typora.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typora.py b/typora.py index b9f22de..a26a865 100644 --- a/typora.py +++ b/typora.py @@ -28,7 +28,7 @@ if DEBUG: else: log.add(sys.stderr, level="INFO") -AES_KEY = struct.pack("<4Q", *[0x4B029A9482B3E14E, 0xF157FEB4B4522F80, 0xE25692105308F4BE, 0x6DD58DDDA3EC0DC2]) +AES_KEY = struct.pack("<4Q", *[0x252A4C7BD0B85281, 0xA31BD92CE099F719, 0x13E283392646D82D, 0x118BDE501CF74120]) def _mkDir(_path): From 768f9e870ac0ef780c4fee5496fa8457c1a84cfd Mon Sep 17 00:00:00 2001 From: mason Date: Tue, 15 Mar 2022 12:24:26 +0800 Subject: [PATCH 02/21] updaate aesIv for 1.2.2-dev --- typora.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/typora.py b/typora.py index a26a865..53d52a2 100644 --- a/typora.py +++ b/typora.py @@ -29,6 +29,7 @@ else: log.add(sys.stderr, level="INFO") AES_KEY = struct.pack("<4Q", *[0x252A4C7BD0B85281, 0xA31BD92CE099F719, 0x13E283392646D82D, 0x118BDE501CF74120]) +AES_IV = struct.pack("<4L", *[0x33706964, 0x5387CDD2, 0xD05F336D, 0x53F82468]) def _mkDir(_path): @@ -43,10 +44,10 @@ def _mkDir(_path): def decScript(b64: bytes, prettify: bool): lCode = b64decode(b64) - # iv: the first 16 bytes of the file - aesIv = lCode[0:16] + # iv + aesIv = AES_IV # cipher text - cipherText = lCode[16:] + cipherText = lCode[:] # AES 256 CBC ins = AES.new(key=AES_KEY, iv=aesIv, mode=AES.MODE_CBC) code = unpad(ins.decrypt(cipherText), 16, 'pkcs7') @@ -106,10 +107,10 @@ def extractWdec(asarPath, path, prettify): def encScript(_code: bytes, compress): if compress: _code = jsmin(_code.decode(), quote_chars="'\"`").encode() - aesIv = urandom(16) + aesIv = AES_IV cipherText = _code ins = AES.new(key=AES_KEY, iv=aesIv, mode=AES.MODE_CBC) - enc = aesIv + ins.encrypt(pad(cipherText, 16, 'pkcs7')) + enc = ins.encrypt(pad(cipherText, 16, 'pkcs7')) lCode = b64encode(enc) return lCode From df83d9cae444191888b30c6ccb9a2ccd27497442 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 19:28:39 +0800 Subject: [PATCH 03/21] updaate aesIv for 1.2.2-dev --- auto-analysis/linux/arm/LATEST_VERSION | 0 auto-analysis/linux/x64/LATEST_VERSION | 0 auto-analysis/version_download.py | 77 ++++++++++++++++++++++++++ auto-analysis/win/arm/LATEST_VERSION | 0 auto-analysis/win/x64/LATEST_VERSION | 0 auto-analysis/win/x64/analysis.py | 37 +++++++++++++ auto-analysis/win/x86/LATEST_VERSION | 0 typora.py | 4 +- 8 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 auto-analysis/linux/arm/LATEST_VERSION create mode 100644 auto-analysis/linux/x64/LATEST_VERSION create mode 100644 auto-analysis/version_download.py create mode 100644 auto-analysis/win/arm/LATEST_VERSION create mode 100644 auto-analysis/win/x64/LATEST_VERSION create mode 100644 auto-analysis/win/x64/analysis.py create mode 100644 auto-analysis/win/x86/LATEST_VERSION diff --git a/auto-analysis/linux/arm/LATEST_VERSION b/auto-analysis/linux/arm/LATEST_VERSION new file mode 100644 index 0000000..e69de29 diff --git a/auto-analysis/linux/x64/LATEST_VERSION b/auto-analysis/linux/x64/LATEST_VERSION new file mode 100644 index 0000000..e69de29 diff --git a/auto-analysis/version_download.py b/auto-analysis/version_download.py new file mode 100644 index 0000000..8970b25 --- /dev/null +++ b/auto-analysis/version_download.py @@ -0,0 +1,77 @@ +# -*- coding:utf-8 -*- +""" +@Author: Mas0n +@File: version_download.py +@Time: 2022/4/3 18:36 +@Desc: It's all about getting better. +""" +from loguru import logger as log +import subprocess +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", + }, +} + + +def download_file(from_link, to_path): + log.info(f"downloading from {from_link}") + subprocess.check_call(["wget", from_link, "-O", to_path]) + log.info("ready extract package") + subprocess.check_call(["md5sum", "-b", to_path, ">", "LATEST_VERSION"]) + + + +def patch_file(_key, _iv): + patch_file_path = os.path.join(BASE_DIR, "../typora.py") + fd = open(patch_file_path, "a") + content = fd.read() + content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") + content = content.replace("{AES_IV}", f"b''.fromhex('{_iv}')") + fd.write(content) + + +def win_x64_run(): + from win.x64 import analysis + basedir = os.path.join(BASE_DIR, "win/x64") + link = DOWNLOAD_LINK["win"]["x64"] + download_path = os.path.join(basedir, os.path.basename(link)) + + download_file(link, download_path) + subprocess.check_call(["innoextract", download_path]) + 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) + log.success("analysis done") + patch_file(key.hex(), iv.hex()) + log.success("patch done") + + +if __name__ == '__main__': + 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) diff --git a/auto-analysis/win/arm/LATEST_VERSION b/auto-analysis/win/arm/LATEST_VERSION new file mode 100644 index 0000000..e69de29 diff --git a/auto-analysis/win/x64/LATEST_VERSION b/auto-analysis/win/x64/LATEST_VERSION new file mode 100644 index 0000000..e69de29 diff --git a/auto-analysis/win/x64/analysis.py b/auto-analysis/win/x64/analysis.py new file mode 100644 index 0000000..2390071 --- /dev/null +++ b/auto-analysis/win/x64/analysis.py @@ -0,0 +1,37 @@ +# -*- coding:utf-8 -*- +""" +@Author: Mas0n +@Name: typora_win_x64_analysis +@Time: 2022/4/3 18:26 +@Desc: It's all about getting better. +""" +import struct +import r2pipe + + +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}) + + 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 \ No newline at end of file diff --git a/auto-analysis/win/x86/LATEST_VERSION b/auto-analysis/win/x86/LATEST_VERSION new file mode 100644 index 0000000..e69de29 diff --git a/typora.py b/typora.py index 53d52a2..bdaf7fc 100644 --- a/typora.py +++ b/typora.py @@ -28,8 +28,8 @@ if DEBUG: else: log.add(sys.stderr, level="INFO") -AES_KEY = struct.pack("<4Q", *[0x252A4C7BD0B85281, 0xA31BD92CE099F719, 0x13E283392646D82D, 0x118BDE501CF74120]) -AES_IV = struct.pack("<4L", *[0x33706964, 0x5387CDD2, 0xD05F336D, 0x53F82468]) +AES_KEY = {AES_KEY} +AES_IV = {AES_IV} def _mkDir(_path): From 2a7fd5622a9c9f4b8d017210e7375b5f4eceee38 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 19:50:15 +0800 Subject: [PATCH 04/21] dev commits. --- auto-analysis/check_version.py | 11 ++++ auto-analysis/utils.py | 86 +++++++++++++++++++++++++++++++ auto-analysis/version_download.py | 13 ++++- 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 auto-analysis/check_version.py create mode 100644 auto-analysis/utils.py diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py new file mode 100644 index 0000000..9290de5 --- /dev/null +++ b/auto-analysis/check_version.py @@ -0,0 +1,11 @@ +from utils import get_version, download_file +import os + +if __name__ == '__main__': + DOWNLOAD_URL = "https://typora.io/windows/typora-setup-x64.exe" + BASE_DIR = os.path.join(os.path.dirname(__file__), "win/x64") + + download_path = os.path.join(BASE_DIR, os.path.basename(DOWNLOAD_URL)) + download_file(DOWNLOAD_URL, download_path) + version = get_version(download_path) + diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py new file mode 100644 index 0000000..f0957f2 --- /dev/null +++ b/auto-analysis/utils.py @@ -0,0 +1,86 @@ +# -*- coding:utf-8 -*- +""" +@Author: Mas0n +@File: utils.py +@Time: 2022/4/3 18:36 +@Desc: It's all about getting better. +""" +from loguru import logger as log +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", + }, +} + +def get_version(to_path): + package_file_path = os.path.join(to_path, "app/resources/package.json") + package_info = open(package_file_path, "r").read() + package_obj = json.loads(package_info) + return package_obj["version"] + + +def download_file(from_link, to_path): + log.info(f"downloading from {from_link}") + subprocess.check_call(["wget", from_link, "-O", to_path]) + log.info("ready extract package") + + + +def patch_file(_key, _iv): + patch_file_path = os.path.join(BASE_DIR, "../typora.py") + fd = open(patch_file_path, "a") + content = fd.read() + content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") + content = content.replace("{AES_IV}", f"b''.fromhex('{_iv}')") + fd.write(content) + + +def win_x64_run(): + from win.x64 import analysis + basedir = os.path.join(BASE_DIR, "win/x64") + link = DOWNLOAD_LINK["win"]["x64"] + + download_path = os.path.join(basedir, os.path.basename(link)) + download_file(link, download_path) + + subprocess.check_call(["innoextract", download_path]) + 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) + log.success("analysis done") + + patch_file(key.hex(), iv.hex()) + log.success("patch done") + + +if __name__ == '__main__': + 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) diff --git a/auto-analysis/version_download.py b/auto-analysis/version_download.py index 8970b25..0453f24 100644 --- a/auto-analysis/version_download.py +++ b/auto-analysis/version_download.py @@ -7,6 +7,7 @@ """ from loguru import logger as log import subprocess +import json import os # Usage: @@ -26,12 +27,17 @@ DOWNLOAD_LINK = { }, } +def get_version(to_path): + package_file_path = os.path.join(to_path, "app/resources/package.json") + package_info = open(package_file_path, "r").read() + package_obj = json.loads(package_info) + return package_obj["version"] + def download_file(from_link, to_path): log.info(f"downloading from {from_link}") subprocess.check_call(["wget", from_link, "-O", to_path]) log.info("ready extract package") - subprocess.check_call(["md5sum", "-b", to_path, ">", "LATEST_VERSION"]) @@ -48,15 +54,18 @@ def win_x64_run(): from win.x64 import analysis basedir = os.path.join(BASE_DIR, "win/x64") link = DOWNLOAD_LINK["win"]["x64"] - download_path = os.path.join(basedir, os.path.basename(link)) + download_path = os.path.join(basedir, os.path.basename(link)) download_file(link, download_path) + subprocess.check_call(["innoextract", download_path]) 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) log.success("analysis done") + patch_file(key.hex(), iv.hex()) log.success("patch done") From 11589aff49af20fff6d445f5938df1add8a5fd9d Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 19:57:35 +0800 Subject: [PATCH 05/21] dev commits. --- auto-analysis/check_version.py | 2 +- auto-analysis/utils.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py index 9290de5..3a6f73f 100644 --- a/auto-analysis/check_version.py +++ b/auto-analysis/check_version.py @@ -7,5 +7,5 @@ if __name__ == '__main__': download_path = os.path.join(BASE_DIR, os.path.basename(DOWNLOAD_URL)) download_file(DOWNLOAD_URL, download_path) - version = get_version(download_path) + version = get_version(BASE_DIR) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index f0957f2..a4062c3 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -40,6 +40,9 @@ def download_file(from_link, to_path): log.info("ready extract package") +def extract_file(_path): + subprocess.check_call(["innoextract", _path]) + log.info("preparation stage completed") def patch_file(_key, _iv): patch_file_path = os.path.join(BASE_DIR, "../typora.py") @@ -58,8 +61,7 @@ def win_x64_run(): download_path = os.path.join(basedir, os.path.basename(link)) download_file(link, download_path) - subprocess.check_call(["innoextract", download_path]) - log.info("preparation stage completed") + extract_file(download_path) main_node_path = os.path.join(basedir, "app/resources/app.asar.unpacked/main.node") log.info("auto analysis start") From d5f9fa40266adfc33b791c68cb3ece223ec1ba59 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 19:58:21 +0800 Subject: [PATCH 06/21] dev commits. --- auto-analysis/check_version.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py index 3a6f73f..292c1cf 100644 --- a/auto-analysis/check_version.py +++ b/auto-analysis/check_version.py @@ -1,4 +1,4 @@ -from utils import get_version, download_file +from utils import get_version, download_file, extract_file import os if __name__ == '__main__': @@ -7,5 +7,6 @@ if __name__ == '__main__': download_path = os.path.join(BASE_DIR, os.path.basename(DOWNLOAD_URL)) download_file(DOWNLOAD_URL, download_path) + extract_file(download_path) version = get_version(BASE_DIR) From 1c879400fd228ee189cb28f83ba8defee372f07c Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:05:35 +0800 Subject: [PATCH 07/21] dev commits. --- auto-analysis/check_version.py | 2 +- auto-analysis/utils.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py index 292c1cf..8c047c6 100644 --- a/auto-analysis/check_version.py +++ b/auto-analysis/check_version.py @@ -7,6 +7,6 @@ if __name__ == '__main__': download_path = os.path.join(BASE_DIR, os.path.basename(DOWNLOAD_URL)) download_file(DOWNLOAD_URL, download_path) - extract_file(download_path) + extract_file(download_path, BASE_DIR) version = get_version(BASE_DIR) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index a4062c3..2b26025 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -40,8 +40,8 @@ def download_file(from_link, to_path): log.info("ready extract package") -def extract_file(_path): - subprocess.check_call(["innoextract", _path]) +def extract_file(from_path, to_path): + subprocess.check_call(["innoextract", from_path, "-d", to_path]) log.info("preparation stage completed") def patch_file(_key, _iv): @@ -61,7 +61,7 @@ def win_x64_run(): download_path = os.path.join(basedir, os.path.basename(link)) download_file(link, download_path) - extract_file(download_path) + extract_file(download_path, basedir) main_node_path = os.path.join(basedir, "app/resources/app.asar.unpacked/main.node") log.info("auto analysis start") From 25cb04e00fa28b9511b607df4865255372344754 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:09:41 +0800 Subject: [PATCH 08/21] dev commits. --- auto-analysis/check_version.py | 3 ++- auto-analysis/utils.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py index 8c047c6..6cbd4fc 100644 --- a/auto-analysis/check_version.py +++ b/auto-analysis/check_version.py @@ -1,4 +1,4 @@ -from utils import get_version, download_file, extract_file +from utils import get_version, download_file, extract_file, log import os if __name__ == '__main__': @@ -9,4 +9,5 @@ if __name__ == '__main__': download_file(DOWNLOAD_URL, download_path) extract_file(download_path, BASE_DIR) version = get_version(BASE_DIR) + os.system(f"export TYPORA_VERSION={version}") diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 2b26025..a6027de 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -42,7 +42,7 @@ def download_file(from_link, to_path): def extract_file(from_path, to_path): subprocess.check_call(["innoextract", from_path, "-d", to_path]) - log.info("preparation stage completed") + def patch_file(_key, _iv): patch_file_path = os.path.join(BASE_DIR, "../typora.py") @@ -62,7 +62,7 @@ def win_x64_run(): download_file(link, download_path) extract_file(download_path, basedir) - + 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) From 76c9a5b398f9a100ddb718ef45fb391b4aae8d1e Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:12:42 +0800 Subject: [PATCH 09/21] dev commits. --- auto-analysis/check_version.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py index 6cbd4fc..76b26db 100644 --- a/auto-analysis/check_version.py +++ b/auto-analysis/check_version.py @@ -9,5 +9,4 @@ if __name__ == '__main__': download_file(DOWNLOAD_URL, download_path) extract_file(download_path, BASE_DIR) version = get_version(BASE_DIR) - os.system(f"export TYPORA_VERSION={version}") - + log.info(f"the latest version: {version}") From d870e234c3827e7d0923baf4fadccfcc9c4d9ffc Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:14:34 +0800 Subject: [PATCH 10/21] dev commits. --- auto-analysis/version_download.py | 78 +------------------------------ 1 file changed, 2 insertions(+), 76 deletions(-) diff --git a/auto-analysis/version_download.py b/auto-analysis/version_download.py index 0453f24..f263df2 100644 --- a/auto-analysis/version_download.py +++ b/auto-analysis/version_download.py @@ -5,82 +5,8 @@ @Time: 2022/4/3 18:36 @Desc: It's all about getting better. """ -from loguru import logger as log -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", - }, -} - -def get_version(to_path): - package_file_path = os.path.join(to_path, "app/resources/package.json") - package_info = open(package_file_path, "r").read() - package_obj = json.loads(package_info) - return package_obj["version"] - - -def download_file(from_link, to_path): - log.info(f"downloading from {from_link}") - subprocess.check_call(["wget", from_link, "-O", to_path]) - log.info("ready extract package") - - - -def patch_file(_key, _iv): - patch_file_path = os.path.join(BASE_DIR, "../typora.py") - fd = open(patch_file_path, "a") - content = fd.read() - content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") - content = content.replace("{AES_IV}", f"b''.fromhex('{_iv}')") - fd.write(content) - - -def win_x64_run(): - from win.x64 import analysis - basedir = os.path.join(BASE_DIR, "win/x64") - link = DOWNLOAD_LINK["win"]["x64"] - - download_path = os.path.join(basedir, os.path.basename(link)) - download_file(link, download_path) - - subprocess.check_call(["innoextract", download_path]) - 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) - log.success("analysis done") - - patch_file(key.hex(), iv.hex()) - log.success("patch done") - +import utils if __name__ == '__main__': - win_x64_run() + utils.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) From 18e2562146d7a17785c8d74af76de0b768e62b13 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:16:16 +0800 Subject: [PATCH 11/21] dev commits. --- auto-analysis/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index a6027de..56b4f33 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -46,7 +46,7 @@ def extract_file(from_path, to_path): def patch_file(_key, _iv): patch_file_path = os.path.join(BASE_DIR, "../typora.py") - fd = open(patch_file_path, "a") + fd = open(patch_file_path, "a+") content = fd.read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") content = content.replace("{AES_IV}", f"b''.fromhex('{_iv}')") From e21922b1f18068dcfbb550900c847ba47b576483 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:22:25 +0800 Subject: [PATCH 12/21] dev commits. --- auto-analysis/utils.py | 14 ++++++++------ LICENSE => exports/LICENSE | 0 README.md => exports/README.md | 0 README_CN.md => exports/README_CN.md | 0 masar.py => exports/masar.py | 0 requirements.txt => exports/requirements.txt | 0 typora.py => exports/typora.py | 0 7 files changed, 8 insertions(+), 6 deletions(-) rename LICENSE => exports/LICENSE (100%) rename README.md => exports/README.md (100%) rename README_CN.md => exports/README_CN.md (100%) rename masar.py => exports/masar.py (100%) rename requirements.txt => exports/requirements.txt (100%) rename typora.py => exports/typora.py (100%) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 56b4f33..25924d5 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -44,13 +44,15 @@ def extract_file(from_path, to_path): subprocess.check_call(["innoextract", from_path, "-d", to_path]) -def patch_file(_key, _iv): - patch_file_path = os.path.join(BASE_DIR, "../typora.py") - fd = open(patch_file_path, "a+") - content = fd.read() +def patch_file(_key, _iv, to_dir): + patch_file_path = os.path.join(BASE_DIR, "../exports/typora.py") + content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") content = content.replace("{AES_IV}", f"b''.fromhex('{_iv}')") - fd.write(content) + save_dir = os.path.join(to_dir, "build") + os.makedirs() + open(os.path.join(to_dir, "typora.py"), "w").write(content) + def win_x64_run(): @@ -68,7 +70,7 @@ def win_x64_run(): key, iv = analysis.get_aes_key_and_iv(main_node_path) log.success("analysis done") - patch_file(key.hex(), iv.hex()) + patch_file(key.hex(), iv.hex(), basedir) log.success("patch done") diff --git a/LICENSE b/exports/LICENSE similarity index 100% rename from LICENSE rename to exports/LICENSE diff --git a/README.md b/exports/README.md similarity index 100% rename from README.md rename to exports/README.md diff --git a/README_CN.md b/exports/README_CN.md similarity index 100% rename from README_CN.md rename to exports/README_CN.md diff --git a/masar.py b/exports/masar.py similarity index 100% rename from masar.py rename to exports/masar.py diff --git a/requirements.txt b/exports/requirements.txt similarity index 100% rename from requirements.txt rename to exports/requirements.txt diff --git a/typora.py b/exports/typora.py similarity index 100% rename from typora.py rename to exports/typora.py From d84a6b9041e93b3bad6afcf1fdaa76134ce06ff7 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:26:41 +0800 Subject: [PATCH 13/21] dev commits. --- auto-analysis/utils.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 25924d5..fd6d748 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -45,14 +45,17 @@ def extract_file(from_path, to_path): def patch_file(_key, _iv, to_dir): - patch_file_path = os.path.join(BASE_DIR, "../exports/typora.py") + exports_path = os.path.join(BASE_DIR, "../exports") + save_dir = os.path.join(to_dir, "build") + if not os.path.exists(save_dir): + os.makedirs(save_dir) + + subprocess.check_call(["cp", f"{exports_path}/*", save_dir]) + patch_file_path = os.path.join(save_dir, "typora.py") content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") content = content.replace("{AES_IV}", f"b''.fromhex('{_iv}')") - save_dir = os.path.join(to_dir, "build") - os.makedirs() - open(os.path.join(to_dir, "typora.py"), "w").write(content) - + open(patch_file_path, "w").write(content) def win_x64_run(): From 643c0f3e3cdfadf7d945d189ddffce51a9b70643 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:33:02 +0800 Subject: [PATCH 14/21] dev commits. --- auto-analysis/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index fd6d748..fa3ceae 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -50,7 +50,7 @@ def patch_file(_key, _iv, to_dir): if not os.path.exists(save_dir): os.makedirs(save_dir) - subprocess.check_call(["cp", f"{exports_path}/*", save_dir]) + subprocess.call(["cp", f"{exports_path}/*", save_dir]) patch_file_path = os.path.join(save_dir, "typora.py") content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") From 16c225bb1fa9671f4663e964513087b4fc5670d1 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:38:48 +0800 Subject: [PATCH 15/21] dev commits. --- auto-analysis/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index fa3ceae..56e30a0 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -50,7 +50,7 @@ def patch_file(_key, _iv, to_dir): if not os.path.exists(save_dir): os.makedirs(save_dir) - subprocess.call(["cp", f"{exports_path}/*", save_dir]) + subprocess.call(["cp", "-r", exports_path, save_dir]) patch_file_path = os.path.join(save_dir, "typora.py") content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") From 3c9d47b625746c44b229c7c5dd14409606f1d621 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:41:22 +0800 Subject: [PATCH 16/21] dev commits. --- auto-analysis/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 56e30a0..4318c7f 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -50,7 +50,7 @@ def patch_file(_key, _iv, to_dir): if not os.path.exists(save_dir): os.makedirs(save_dir) - subprocess.call(["cp", "-r", exports_path, save_dir]) + subprocess.call(["cp", "-r", f"{exports_path}/*", save_dir]) patch_file_path = os.path.join(save_dir, "typora.py") content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") From 60a7f39b16c35d892621e218ff7fe46127a1d950 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:47:37 +0800 Subject: [PATCH 17/21] dev commits. --- auto-analysis/utils.py | 4 ++-- exports.tar.gz | Bin 0 -> 5647 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 exports.tar.gz diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 4318c7f..382270a 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -45,12 +45,12 @@ def extract_file(from_path, to_path): def patch_file(_key, _iv, to_dir): - exports_path = os.path.join(BASE_DIR, "../exports") + exports_file_path = os.path.join(BASE_DIR, "../exports.tar.gz") save_dir = os.path.join(to_dir, "build") if not os.path.exists(save_dir): os.makedirs(save_dir) - subprocess.call(["cp", "-r", f"{exports_path}/*", save_dir]) + subprocess.check_call(["tar", "-zxvf", exports_file_path, save_dir]) patch_file_path = os.path.join(save_dir, "typora.py") content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") diff --git a/exports.tar.gz b/exports.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..3ac50b7622412a071081f4e4bec420f0cfb7e796 GIT binary patch literal 5647 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 Date: Sun, 3 Apr 2022 20:47:47 +0800 Subject: [PATCH 18/21] dev commits. --- exports/LICENSE | 21 ----- exports/README.md | 70 --------------- exports/README_CN.md | 64 -------------- exports/masar.py | 176 ------------------------------------- exports/requirements.txt | 4 - exports/typora.py | 183 --------------------------------------- 6 files changed, 518 deletions(-) delete mode 100644 exports/LICENSE delete mode 100644 exports/README.md delete mode 100644 exports/README_CN.md delete mode 100644 exports/masar.py delete mode 100644 exports/requirements.txt delete mode 100644 exports/typora.py diff --git a/exports/LICENSE b/exports/LICENSE deleted file mode 100644 index 591f59a..0000000 --- a/exports/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Mason Shi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/exports/README.md b/exports/README.md deleted file mode 100644 index 93089f1..0000000 --- a/exports/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# typora Cracker - -![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FMas0nShi%2FtyporaCracker.svg?type=shield) -![GitHub](https://img.shields.io/github/license/Mas0nShi/typoraCracker) - -A extract & decryption and pack & encryption tools for typora. - -中文说明请戳[这里](README_CN.md) - -## WARNING - -**NOTE: typoraCracker doesn't provide support for crack.** - -``` -FOR STUDY AND DISCUSSION ONLY, PLEASE DO NOT ENGAGE IN ANY ILLEGAL ACTS. -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 - -## 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. - - -## Example - -```shell -> python typora.py --help -usage: typora.py [-h] [-u] [-f] asarPath dirPath - -[extract and decryption / pack and encryption] app.asar file from [Typora]. - -positional arguments: - asarPath app.asar file path/dir [input/ouput] - dirPath as tmp and out directory. - -optional arguments: - -h, --help show this help message and exit - -u pack & encryption (default: extract & decryption) - -f enabled prettify/compress (default: disabled) - -If you have any questions, please contact [ MasonShi@88.com ] - -> python typora.py {installRoot}/Typora/resources/app.asar workstation/outfile/ -⋯ -# (patch code by yourself in workstation/outfile/dec_app) -> python typora.py -u workstation/outfile/dec_app workstation/outappasar -⋯ -> cp {installRoot}/Typora/resources/app.asar {installRoot}/Typora/resources/app.asar.bak -> mv workstation/outappasar/app.asar {installRoot}/Typora/resources/app.asar -> node example/keygen.js -XXXXXX-XXXXXX-XXXXXX-XXXXXX -> typora -# (input info) -email: crack@example.com -serial: XXXXXX-XXXXXX-XXXXXX-XXXXXX -``` - -## LICENSE - MIT LICENSE - -[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FMas0nShi%2FtyporaCracker.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FMas0nShi%2FtyporaCracker?ref=badge_large) diff --git a/exports/README_CN.md b/exports/README_CN.md deleted file mode 100644 index 3817e7a..0000000 --- a/exports/README_CN.md +++ /dev/null @@ -1,64 +0,0 @@ -# typora Cracker - -一个typora的解包&解密,打包&加密工具 - -## 敬告 - -**请注意:** typoraCracker不会提供破解相关支持,包括但不限于思路、流程、成品。 - -``` -仅供学习和讨论,请不要从事任何非法行为。 -由此产生的任何问题都将由用户(您)承担。 -``` - -## Features - -- 支持版本1.0.0以上(至少现在是这样) -- 测试通过平台:Win/Ubuntu - -## 食用方式 - -1. `pip install -r requirements.txt` -2. `python typora.py --help` -3. 阅读帮助文档及使用。 -4. 做你想做的事。 -5. 打包并替换原目录下的 app.asar。 -6. 享受成果。 - - -## 示例 - -```shell -> python typora.py --help -usage: typora.py [-h] [-u] [-f] asarPath dirPath - -[extract and decryption / pack and encryption] app.asar file from [Typora]. - -positional arguments: - asarPath app.asar file path/dir [input/ouput] - dirPath as tmp and out directory. - -optional arguments: - -h, --help show this help message and exit - -u pack & encryption (default: extract & decryption) - -f enabled prettify/compress (default: disabled) - -If you have any questions, please contact [ MasonShi@88.com ] - -> python typora.py {installRoot}/Typora/resources/app.asar workstation/outfile/ -⋯ -# (patch code by yourself in workstation/outfile/dec_app) -> python typora.py -u workstation/outfile/dec_app workstation/outappasar -⋯ -> cp {installRoot}/Typora/resources/app.asar {installRoot}/Typora/resources/app.asar.bak -> mv workstation/outappasar/app.asar {installRoot}/Typora/resources/app.asar -> node example/keygen.js -XXXXXX-XXXXXX-XXXXXX-XXXXXX -> typora -# (input info) -email: crack@example.com -serial: XXXXXX-XXXXXX-XXXXXX-XXXXXX -``` - -## LICENSE - MIT LICENSE diff --git a/exports/masar.py b/exports/masar.py deleted file mode 100644 index 65f81d5..0000000 --- a/exports/masar.py +++ /dev/null @@ -1,176 +0,0 @@ -# -*- coding:utf-8 -*- -""" -@Author: Mas0n -@File: masar.py -@Time: 2021-11-29 22:34 -@Desc: It's all about getting better. -""" -import os -import errno -import io -import struct -import shutil -import fileinput -import json - - -def round_up(i, m): - return (i + m - 1) & ~(m - 1) - - -class Asar: - def __init__(self, path, fp, header, base_offset): - self.path = path - self.fp = fp - self.header = header - self.base_offset = base_offset - - @classmethod - def open(cls, path): - fp = open(path, 'rb') - data_size, header_size, header_object_size, header_string_size = struct.unpack('<4I', fp.read(16)) - header_json = fp.read(header_string_size).decode('utf-8') - return cls( - path=path, - fp=fp, - header=json.loads(header_json), - base_offset=round_up(16 + header_string_size, 4) - ) - - @classmethod - def compress(cls, path): - offset = 0 - paths = [] - - def _path_to_dict(path): - nonlocal offset, paths - result = {'files': {}} - for f in os.scandir(path): - if os.path.isdir(f.path): - result['files'][f.name] = _path_to_dict(f.path) - elif f.is_symlink(): - result['files'][f.name] = { - 'link': os.path.realpath(f.name) - } - # modify - elif f.name == "main.node": - size = f.stat().st_size - result['files'][f.name] = { - 'size': size, - "unpacked": True - } - else: - paths.append(f.path) - size = f.stat().st_size - result['files'][f.name] = { - 'size': size, - 'offset': str(offset) - } - offset += size - return result - - def _paths_to_bytes(paths): - _bytes = io.BytesIO() - with fileinput.FileInput(files=paths, mode="rb") as f: - for i in f: - _bytes.write(i) - return _bytes.getvalue() - - header = _path_to_dict(path) - header_json = json.dumps(header, sort_keys=True, separators=(',', ':')).encode('utf-8') - header_string_size = len(header_json) - data_size = 4 - aligned_size = round_up(header_string_size, data_size) - header_size = aligned_size + 8 - header_object_size = aligned_size + data_size - diff = aligned_size - header_string_size - header_json = header_json + b'\0' * diff if diff else header_json - fp = io.BytesIO() - fp.write(struct.pack('<4I', data_size, header_size, header_object_size, header_string_size)) - fp.write(header_json) - fp.write(_paths_to_bytes(paths)) - - return cls( - path=path, - fp=fp, - header=header, - base_offset=round_up(16 + header_string_size, 4)) - - def _copy_unpacked_file(self, source, destination): - unpacked_dir = self.path + '.unpacked' - if not os.path.isdir(unpacked_dir): - print("Couldn't copy file {}, no extracted directory".format(source)) - return - - src = os.path.join(unpacked_dir, source) - if not os.path.exists(src): - print("Couldn't copy file {}, doesn't exist".format(src)) - return - - dest = os.path.join(destination, source) - shutil.copyfile(src, dest) - - def _extract_file(self, source, info, destination): - if 'offset' not in info: - self._copy_unpacked_file(source, destination) - return - - self.fp.seek(self.base_offset + int(info['offset'])) - r = self.fp.read(int(info['size'])) - - dest = os.path.join(destination, source) - with open(dest, 'wb') as f: - f.write(r) - - def _extract_link(self, source, link, destination): - dest_filename = os.path.normpath(os.path.join(destination, source)) - link_src_path = os.path.dirname(os.path.join(destination, link)) - link_to = os.path.join(link_src_path, os.path.basename(link)) - - try: - os.symlink(link_to, dest_filename) - except OSError as e: - if e.errno == errno.EXIST: - os.unlink(dest_filename) - os.symlink(link_to, dest_filename) - else: - raise e - - def _extract_directory(self, source, files, destination): - dest = os.path.normpath(os.path.join(destination, source)) - - if not os.path.exists(dest): - os.makedirs(dest) - - for name, info in files.items(): - item_path = os.path.join(source, name) - - if 'files' in info: - self._extract_directory(item_path, info['files'], destination) - elif 'link' in info: - self._extract_link(item_path, info['link'], destination) - else: - self._extract_file(item_path, info, destination) - - def extract(self, path): - if not os.path.isdir(path): - raise NotADirectoryError() - self._extract_directory('.', self.header['files'], path) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - self.fp.close() - - -def pack_asar(source, dest): - with Asar.compress(source) as a: - with open(dest, 'wb') as fp: - a.fp.seek(0) - fp.write(a.fp.read()) - - -def extract_asar(source, dest): - with Asar.open(source) as a: - a.extract(dest) diff --git a/exports/requirements.txt b/exports/requirements.txt deleted file mode 100644 index 68ad2b6..0000000 --- a/exports/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -jsbeautifier==1.14.0 -jsmin==3.0.0 -loguru==0.5.3 -pycryptodome==3.11.0 diff --git a/exports/typora.py b/exports/typora.py deleted file mode 100644 index bdaf7fc..0000000 --- a/exports/typora.py +++ /dev/null @@ -1,183 +0,0 @@ -# -*- coding:utf-8 -*- -""" -@Author: Mas0n -@File: typora.py -@Time: 2021-11-29 21:24 -@Desc: It's all about getting better. -""" -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 listdir, urandom, makedirs -from os.path import isfile, isdir, join as pjoin, split as psplit, exists, abspath -from loguru import logger as log -from masar import extract_asar, pack_asar -from shutil import rmtree -from argparse import ArgumentParser -import struct -import sys - -# DEBUG -DEBUG = False - -log.remove() -if DEBUG: - log.add(sys.stderr, level="DEBUG") -else: - log.add(sys.stderr, level="INFO") - -AES_KEY = {AES_KEY} -AES_IV = {AES_IV} - - -def _mkDir(_path): - if not exists(_path): - makedirs(_path) - else: - if _path == psplit(__file__)[0]: - log.warning("plz try not to use the root dir.") - else: - log.warning(f"May FolderExists: {_path}") - - -def decScript(b64: bytes, prettify: bool): - lCode = b64decode(b64) - # iv - aesIv = AES_IV - # cipher text - cipherText = lCode[:] - # AES 256 CBC - ins = AES.new(key=AES_KEY, iv=aesIv, mode=AES.MODE_CBC) - code = unpad(ins.decrypt(cipherText), 16, 'pkcs7') - if prettify: - code = beautify(code.decode()).encode() - return code - - -def extractWdec(asarPath, path, prettify): - """ - :param prettify: bool - :param asarPath: asar out dir - :param path: out dir - :return: None - """ - # try to create empty dir to save extract files - path = pjoin(path, "typoraCrackerTemp") - - if exists(path): - rmtree(path) - _mkDir(path) - - log.info(f"extract asar file: {asarPath}") - # extract app.asar to {path}/* - extract_asar(asarPath, path) - log.success(f"extract ended.") - - log.info(f"read Directory: {path}") - # construct the save directory {pathRoot}/dec_app - outPath = pjoin(psplit(path)[0], "dec_app") - # try to create empty dir to save decryption files - if exists(outPath): - rmtree(outPath) - _mkDir(outPath) - - log.info(f"set Directory: {outPath}") - # enumerate extract files - fileArr = listdir(path) - for name in fileArr: - # read files content - fpath = pjoin(path, name) - scode = open(fpath, "rb").read() - log.info(f"open file: {name}") - # if file suffix is *.js then decryption file - if isfile(fpath) and name.endswith(".js"): - scode = decScript(scode, prettify) - else: - log.debug(f"skip file: {name}") - # save content {outPath}/{name} - open(pjoin(outPath, name), "wb").write(scode) - log.success(f"decrypt and save file: {name}") - - rmtree(path) - log.debug("remove temp dir") - - -def encScript(_code: bytes, compress): - if compress: - _code = jsmin(_code.decode(), quote_chars="'\"`").encode() - aesIv = AES_IV - cipherText = _code - ins = AES.new(key=AES_KEY, iv=aesIv, mode=AES.MODE_CBC) - enc = ins.encrypt(pad(cipherText, 16, 'pkcs7')) - lCode = b64encode(enc) - return lCode - - -def packWenc(path, outPath, compress): - """ - :param path: out dir - :param outPath: pack path app.asar - :param compress: Bool - :return: None - """ - # check out path - if isfile(outPath): - log.error("plz input Directory for app.asar") - raise NotADirectoryError - - _mkDir(outPath) - - encFilePath = pjoin(psplit(outPath)[0], "typoraCrackerTemp") - if exists(encFilePath): - rmtree(encFilePath) - _mkDir(encFilePath) - - outFilePath = pjoin(outPath, "app.asar") - log.info(f"set outFilePath: {outFilePath}") - fileArr = listdir(path) - - for name in fileArr: - fpath = pjoin(path, name) - if isdir(fpath): - log.error("TODO: found folder") - raise IsADirectoryError - - scode = open(fpath, "rb").read() - log.info(f"open file: {name}") - if isfile(fpath) and name.endswith(".js"): - scode = encScript(scode, compress) - - open(pjoin(encFilePath, name), "wb").write(scode) - log.success(f"encrypt and save file: {name}") - - log.info("ready to pack") - pack_asar(encFilePath, outFilePath) - log.success("pack done") - - rmtree(encFilePath) - log.debug("remove temp dir") - - -def main(): - argParser = ArgumentParser( - description="[extract and decryption / pack and encryption] app.asar file from [Typora].", - epilog="If you have any questions, please contact [ MasonShi@88.com ]") - argParser.add_argument("asarPath", type=str, help="app.asar file path/dir [input/ouput]") - argParser.add_argument("dirPath", type=str, help="as tmp and out directory.") - - argParser.add_argument('-u', dest='mode', action='store_const', - const=packWenc, default=extractWdec, - help='pack & encryption (default: extract & decryption)') - argParser.add_argument('-f', dest='format', action='store_const', - const=True, default=False, - help='enabled prettify/compress (default: disabled)') - args = argParser.parse_args() - - args.mode(args.asarPath, args.dirPath, args.format) - log.success("Done!") - - -if __name__ == '__main__': - main() From 1710c83f99e5c0336e8dbf32449fccba719d7162 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 20:51:11 +0800 Subject: [PATCH 19/21] dev commits. --- auto-analysis/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 382270a..73a386c 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -27,6 +27,7 @@ DOWNLOAD_LINK = { }, } + def get_version(to_path): package_file_path = os.path.join(to_path, "app/resources/package.json") package_info = open(package_file_path, "r").read() @@ -50,7 +51,7 @@ def patch_file(_key, _iv, to_dir): if not os.path.exists(save_dir): os.makedirs(save_dir) - subprocess.check_call(["tar", "-zxvf", exports_file_path, save_dir]) + subprocess.check_call(["tar", "-zxvf", exports_file_path, "-C", save_dir]) patch_file_path = os.path.join(save_dir, "typora.py") content = open(patch_file_path, "r").read() content = content.replace("{AES_KEY}", f"b''.fromhex('{_key}')") From 5489c3b664babc6e0b5c462950ec4fa57f54d964 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 21:47:37 +0800 Subject: [PATCH 20/21] dev commits. --- auto-analysis/check_version.py | 2 +- auto-analysis/{version_download.py => patch.py} | 2 +- auto-analysis/utils.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename auto-analysis/{version_download.py => patch.py} (86%) diff --git a/auto-analysis/check_version.py b/auto-analysis/check_version.py index 76b26db..c0c3375 100644 --- a/auto-analysis/check_version.py +++ b/auto-analysis/check_version.py @@ -9,4 +9,4 @@ if __name__ == '__main__': download_file(DOWNLOAD_URL, download_path) extract_file(download_path, BASE_DIR) version = get_version(BASE_DIR) - log.info(f"the latest version: {version}") + print(version+"") diff --git a/auto-analysis/version_download.py b/auto-analysis/patch.py similarity index 86% rename from auto-analysis/version_download.py rename to auto-analysis/patch.py index f263df2..6ac3a26 100644 --- a/auto-analysis/version_download.py +++ b/auto-analysis/patch.py @@ -1,7 +1,7 @@ # -*- coding:utf-8 -*- """ @Author: Mas0n -@File: version_download.py +@File: patch.py @Time: 2022/4/3 18:36 @Desc: It's all about getting better. """ diff --git a/auto-analysis/utils.py b/auto-analysis/utils.py index 73a386c..5007f6b 100644 --- a/auto-analysis/utils.py +++ b/auto-analysis/utils.py @@ -36,9 +36,7 @@ def get_version(to_path): def download_file(from_link, to_path): - log.info(f"downloading from {from_link}") subprocess.check_call(["wget", from_link, "-O", to_path]) - log.info("ready extract package") def extract_file(from_path, to_path): @@ -65,7 +63,9 @@ def win_x64_run(): link = DOWNLOAD_LINK["win"]["x64"] download_path = os.path.join(basedir, os.path.basename(link)) + log.info(f"downloading from {link}") download_file(link, download_path) + log.info("ready extract package") extract_file(download_path, basedir) log.info("preparation stage completed") From 8f467159c79b55984d46713b6a7eaa71a67dc4a3 Mon Sep 17 00:00:00 2001 From: MasOnShi Date: Sun, 3 Apr 2022 21:50:23 +0800 Subject: [PATCH 21/21] dev commits. --- LICENSE | 21 ++++++++++++++++ README.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README_CN.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) create mode 100644 LICENSE create mode 100644 README.md create mode 100644 README_CN.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..591f59a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Mason Shi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..93089f1 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# typora Cracker + +![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FMas0nShi%2FtyporaCracker.svg?type=shield) +![GitHub](https://img.shields.io/github/license/Mas0nShi/typoraCracker) + +A extract & decryption and pack & encryption tools for typora. + +中文说明请戳[这里](README_CN.md) + +## WARNING + +**NOTE: typoraCracker doesn't provide support for crack.** + +``` +FOR STUDY AND DISCUSSION ONLY, PLEASE DO NOT ENGAGE IN ANY ILLEGAL ACTS. +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 + +## 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. + + +## Example + +```shell +> python typora.py --help +usage: typora.py [-h] [-u] [-f] asarPath dirPath + +[extract and decryption / pack and encryption] app.asar file from [Typora]. + +positional arguments: + asarPath app.asar file path/dir [input/ouput] + dirPath as tmp and out directory. + +optional arguments: + -h, --help show this help message and exit + -u pack & encryption (default: extract & decryption) + -f enabled prettify/compress (default: disabled) + +If you have any questions, please contact [ MasonShi@88.com ] + +> python typora.py {installRoot}/Typora/resources/app.asar workstation/outfile/ +⋯ +# (patch code by yourself in workstation/outfile/dec_app) +> python typora.py -u workstation/outfile/dec_app workstation/outappasar +⋯ +> cp {installRoot}/Typora/resources/app.asar {installRoot}/Typora/resources/app.asar.bak +> mv workstation/outappasar/app.asar {installRoot}/Typora/resources/app.asar +> node example/keygen.js +XXXXXX-XXXXXX-XXXXXX-XXXXXX +> typora +# (input info) +email: crack@example.com +serial: XXXXXX-XXXXXX-XXXXXX-XXXXXX +``` + +## LICENSE + MIT LICENSE + +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FMas0nShi%2FtyporaCracker.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FMas0nShi%2FtyporaCracker?ref=badge_large) diff --git a/README_CN.md b/README_CN.md new file mode 100644 index 0000000..3817e7a --- /dev/null +++ b/README_CN.md @@ -0,0 +1,64 @@ +# typora Cracker + +一个typora的解包&解密,打包&加密工具 + +## 敬告 + +**请注意:** typoraCracker不会提供破解相关支持,包括但不限于思路、流程、成品。 + +``` +仅供学习和讨论,请不要从事任何非法行为。 +由此产生的任何问题都将由用户(您)承担。 +``` + +## Features + +- 支持版本1.0.0以上(至少现在是这样) +- 测试通过平台:Win/Ubuntu + +## 食用方式 + +1. `pip install -r requirements.txt` +2. `python typora.py --help` +3. 阅读帮助文档及使用。 +4. 做你想做的事。 +5. 打包并替换原目录下的 app.asar。 +6. 享受成果。 + + +## 示例 + +```shell +> python typora.py --help +usage: typora.py [-h] [-u] [-f] asarPath dirPath + +[extract and decryption / pack and encryption] app.asar file from [Typora]. + +positional arguments: + asarPath app.asar file path/dir [input/ouput] + dirPath as tmp and out directory. + +optional arguments: + -h, --help show this help message and exit + -u pack & encryption (default: extract & decryption) + -f enabled prettify/compress (default: disabled) + +If you have any questions, please contact [ MasonShi@88.com ] + +> python typora.py {installRoot}/Typora/resources/app.asar workstation/outfile/ +⋯ +# (patch code by yourself in workstation/outfile/dec_app) +> python typora.py -u workstation/outfile/dec_app workstation/outappasar +⋯ +> cp {installRoot}/Typora/resources/app.asar {installRoot}/Typora/resources/app.asar.bak +> mv workstation/outappasar/app.asar {installRoot}/Typora/resources/app.asar +> node example/keygen.js +XXXXXX-XXXXXX-XXXXXX-XXXXXX +> typora +# (input info) +email: crack@example.com +serial: XXXXXX-XXXXXX-XXXXXX-XXXXXX +``` + +## LICENSE + MIT LICENSE