-
-
Save maboloshi/5baecbddacf43855f13240b63be5673d to your computer and use it in GitHub Desktop.
Sublime Text & Sublime Merge破解
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# -*- coding: utf-8 -* | |
import re | |
import os | |
import shutil | |
import sys | |
import hashlib | |
import socks | |
import socket | |
from tqdm import tqdm | |
from urllib import request | |
from urllib.error import HTTPError | |
import tarfile | |
import zipfile | |
import ssl # Fix ssl error | |
ssl._create_default_https_context = ssl._create_unverified_context # Fix ssl error | |
def quit(): | |
sys.exit() | |
def get_url_extract_file(app_type, version): | |
base_url = "https://download.sublimetext.com/" | |
url_win = f"{base_url}{app_type}_build_{version}_x64.zip" | |
url_linux = f"{base_url}{app_type}_build_{version}_x64.tar.xz" | |
url_osx = f"{base_url}{app_type}_build_{version}_mac.zip" | |
extract_file_win = f"{app_type}.exe" | |
extract_file_linux = f"{app_type}/{app_type}" | |
extract_file_osx = ( | |
f"{'Sublime Text' if app_type == 'sublime_text' else 'Sublime Merge'}.app/Contents/MacOS/{app_type}" | |
) | |
return (url_win, extract_file_win), (url_linux, extract_file_linux), (url_osx, extract_file_osx) | |
def download_file(url, filename=None, progress_bar=True, proxy=False, force=False): | |
# 呈现下载进度条 | |
def my_hook(t): | |
last_b = [0] | |
def inner(b=1, bsize=1, tsize=None): | |
if tsize is not None: | |
t.total = tsize | |
if b > 0: | |
t.update((b - last_b[0]) * bsize) | |
last_b[0] = b | |
return inner | |
# 如果proxy为True,设置SOCKS5代理 | |
if proxy: | |
socks.set_default_proxy(socks.SOCKS5, addr="127.0.0.1", port=7890) # 设置socks代理 | |
socket.socket = socks.socksocket # 把代理应用到socket | |
# 如果没有指定文件名,使用URL的最后一部分作为文件名 | |
file_basename = url.split('/')[-1] | |
filename = filename if filename else file_basename | |
# force 表示是否强制下载 | |
print(f"[*] Download: {file_basename}, from: {url} ...") if log else None | |
if os.path.exists(filename): | |
print(f"[*] The {filename} already exists.") if log else None | |
if force or not os.path.exists(filename): | |
try: | |
if progress_bar: | |
with tqdm(unit='B', unit_scale=True, miniters=1, desc=">>>") as t: | |
tmp_download_filename, _ = request.urlretrieve(url, reporthook=my_hook(t)) | |
# pass | |
else: | |
tmp_download_filename, _ = request.urlretrieve(url) | |
except (KeyboardInterrupt, SystemExit): | |
quit() | |
except HTTPError: | |
print("[!] HTTP Error 404: Not Found.\n" + | |
" Please check if the application type and the version are correct.") | |
quit() | |
except PermissionError: | |
print(f"[!] Permission denied: {tmp_download_filename}.") | |
quit() | |
else: | |
# 下载完成后,将文件移动到指定的位置 | |
try: | |
shutil.move(tmp_download_filename, filename) | |
except PermissionError: | |
print(f"[!] Permission denied: {filename}.") | |
quit() | |
def extract(filename, extract_file, target_dir="."): | |
def file_exists(*filepath): | |
full_path = os.path.join(*filepath) | |
return os.path.exists(full_path) | |
if file_exists(target_dir, extract_file): | |
print(f"[*] The {extract_file} already exists.\n") | |
else: | |
print(f"[*] Extract: {extract_file}, from: {filename} ...\n") | |
if not file_exists(target_dir): | |
os.makedirs(target_dir.upper()) | |
try: | |
if filename.endswith("zip"): | |
with zipfile.ZipFile(filename) as zip: | |
zip.extract(extract_file, path=target_dir) | |
elif filename.endswith("xz"): | |
with tarfile.open(filename, 'r:xz') as tar: | |
tar.extract(extract_file, path=target_dir) | |
except Exception as e: | |
print(f"An error occurred while extracting the file: {e}") | |
class File(): | |
def __init__(self, filename, app_type=None): | |
self.filename = filename | |
try: | |
with open(self.filename, 'rb') as file: | |
self.binary = file.read() | |
except (FileNotFoundError): | |
print(f"[!] {self.filename} file not found") | |
quit() | |
except (IsADirectoryError, PermissionError): | |
print(f"[!] {self.filename} is not a valid file") | |
quit() | |
self.patternes = self.check_pattern(app_type) | |
self.backup() | |
def md5sum(self, filename, blocksize=65536): | |
hash_md5 = hashlib.md5() | |
with open(filename, "rb") as f: | |
for block in iter(lambda: f.read(blocksize), b""): | |
hash_md5.update(block) | |
return hash_md5.hexdigest().upper() | |
def check_pattern(self, app_type=None): | |
def file_detection(filename=self.filename, binary=self.binary, app_type=None): | |
def detect_executable_file_format(filename=self.filename, binary=self.binary): | |
flag1 = binary[0:2] | |
offset = ord(binary[0x3c:0x3c+1]) | |
flag2 = binary[offset:offset + 6] | |
if flag1 == b'MZ' and flag2 == b'PE\x00\x00\x64\x86': # 判断是否为PE文件的典型特征签名, \x64\x86 -> AMD64 | |
return "Win64" | |
elif flag1 == b'MZ' and flag2 == b'PE\x00\x00\x4C\x01': # \x4C\x01 -> Intel x86 | |
return "Win32" | |
elif binary[0:4] == b'\x7fELF' and binary[4] != 1: | |
return "Linux" | |
elif binary[0:4] == b'\xCA\xFE\xBA\xBE' and binary[8:12] == b'\x01\x00\x00\x07': | |
return "macOS" | |
else: | |
print( | |
"[!] Failed to recognize a binary file.\n " + | |
"Are you sure this is a 64-bit executable binary file for Sublime Text or Sublime Merge?'" | |
) if log else None | |
quit() | |
# return False | |
def detect_app_type(binary=self.binary, app_type=None): | |
# print("[>] Attempting to autodetect application type ...") if log else None | |
if app_type == "sublime_text": | |
return "Sublime Text" | |
elif app_type == "sublime_merge": | |
return "Sublime Merge" | |
sm_check_pattern = b'That appears to be a Sublime Text' | |
st_check_pattern = b'That appears to be a Sublime Merge' | |
match_st = re.search(st_check_pattern, binary, re.DOTALL) | |
match_sm = re.search(sm_check_pattern, binary, re.DOTALL) | |
# Only one of these patterns can exist in the application. | |
# If neither is found, it's not a known application. | |
if match_st == match_sm is None: | |
print( | |
"[!] Failed to identify binary. Are you sure this is a Sublime Text or Sublime Merge binary?" | |
) if log else None | |
quit() | |
elif match_st and match_sm: | |
print( | |
"[!] Both identity signatures detected in the binary! Cannot detect what application this is." | |
) if log else None | |
quit() | |
elif match_st is None and match_sm: | |
return "Sublime Merge" | |
else: | |
return "Sublime Text" | |
def get_update_channel_and_version(binary=self.binary): | |
# print("[>] Attempt to auto detect update channel type and release version ...") if log else None | |
stable_check_pattern = b'stable_update_check\\?version=' | |
match_stable_channel = re.search(stable_check_pattern, binary, re.DOTALL) | |
dev_check_pattern = b'dev_update_check\\?version=' | |
match_dev_channel = re.search(dev_check_pattern, binary, re.DOTALL) | |
def get_version(binary, offset): | |
return binary[offset:offset+4].decode('ascii') | |
if match_stable_channel: | |
return ("Stable Channel", get_version(binary, match_stable_channel.end())) | |
elif match_dev_channel: | |
return ("Dev Channel", get_version(binary, match_dev_channel.end())) | |
print("[>] Attempting to autodetect input file ...") if log else None | |
exe_file_format = detect_executable_file_format() | |
app_type = detect_app_type() | |
update_channel, version = get_update_channel_and_version() | |
print( | |
f"[*] Input file -> {app_type}, {exe_file_format}, {update_channel}, Build {version}\n" | |
f" MD5 Checksum -> {self.md5sum(self.filename)}\n" | |
) if log else None | |
return (exe_file_format, app_type) | |
exe_file_format, app_type = file_detection(app_type) | |
if app_type == "Sublime Text": | |
if exe_file_format == "Win64": | |
return st_win_patternes | |
# elif exe_file_format == "Win32": | |
# return st_win_32_patternes | |
elif exe_file_format == "Linux": | |
return st_linux_patternes | |
elif exe_file_format == "macOS": | |
return st_osx_patternes | |
else: | |
if exe_file_format == "Win64": | |
return sm_win_patternes | |
# elif exe_file_format == "Win32": | |
# return sm_win_32_patternes | |
elif exe_file_format == "Linux": | |
return sm_linux_patternes | |
elif exe_file_format == "macOS": | |
return sm_osx_patternes | |
def backup(self): | |
if PATCH: | |
original = self.filename | |
target = self.filename + ".bak" | |
if not os.path.exists(target): | |
# os.rename(os.path.realpath(filename), os.path.realpath(filename)+".bak") | |
shutil.copy2(original, target) | |
print(f"[>] Backup \"{os.path.basename(original)}\" successfully.\n") if log else None | |
def patched(self): | |
if PATCH: | |
print(f"[<] MD5 checksum of the patched file -> {self.md5sum(self.filename)}") | |
print("[<] Successfully patched the application!") | |
class Pattern(object): | |
def __init__(self, filename, binary, name, regex, displacement, patch_code, rva=False): # binary, | |
self.filename = filename # 输入文件路径 | |
self.binary = binary | |
self.name = name # 模式的名称 | |
self.regex = regex # 模式的正则表达式 如: br'\xE8....\x3D....\x75\x14' | |
self.displacement = displacement # 模式的偏量值 | |
self.patch_code = patch_code # 模式的二进制补丁 | |
self.rva = rva # RVA 标记符 | |
if self.set_offset(): | |
self.patch() | |
def set_offset(self): | |
# Converts 4 byte chunk of a bytearray() into a 32-bit Little-Endian encoded integer. | |
def LE32(value): | |
return value[3] << 24 | value[2] << 16 | value[1] << 8 | value[0] | |
# Calculates an absolute offset from a relative virtual address using a base offset and instruction length. | |
def RVA2ABS(base, rva, instruction_len): | |
return ((base + instruction_len) + rva) & 0xFFFFFFFF | |
match_object = re.search(self.regex, self.binary, re.DOTALL) | |
if match_object: | |
self.offset = match_object.start() | |
else: | |
print(f"[!] No pattern found for \"{self.name}\" ...\n") if log else None | |
return False | |
self.offset += self.displacement # 添加 模式所需位移 | |
# Calculate the absolute offset from an RVA instruction if required. | |
if self.rva: | |
# The RVA value is stored after the first byte relative to the found offset as a 4-byte LE integer. | |
rva = LE32(self.binary[self.offset + 1: self.offset + 5]) # Reverse byte order due to CPU encoding | |
offset_abs = RVA2ABS(self.offset, rva, 5) # Get true offset from referenced pointer | |
print( | |
f"[>] Found RVA pattern for \"{self.name}\" at 0x{self.offset:X} -> 0x{rva:X} -> 0x{offset_abs:X} ..." | |
) if log else None | |
self.offset = offset_abs | |
else: | |
# Not an RVA so no additional calculations required | |
print(f"[>] Found pattern for \"{self.name}\" at 0x{self.offset:X} ...") if log else None | |
return True | |
def patch(self): | |
def B2A_HEX(data): | |
lin = ['%02X' % i for i in data] | |
return " ".join(lin) | |
original_code = self.binary[self.offset:self.offset + len(self.patch_code)] | |
print(f"[*] Rewrite data \'{B2A_HEX(original_code)}\' -> \'{B2A_HEX(self.patch_code)}\' ...") if log else None | |
if PATCH: | |
try: | |
with open(self.filename, 'r+b') as file: | |
file.seek(self.offset) | |
file.write(self.patch_code) | |
except IOError: | |
print(f"[!] Error writing to {self.filename}.") if log else None | |
else: | |
print(f"[=] Patched \"{self.name}\" successfully.") if log else None | |
print("\n") | |
st_osx_patternes = ( | |
# ("isValidLicense" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\xC7\xC0\x00\x00\x00\x00\xC3' , 1), # noqa: E203,E501 | |
# ("invalidationFunction", br'\xE8....\x48\x89\x9D....\x48\x8B\xB3' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("validationFunction" , br'\xE8....\x48\x8D\x3D....\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("invalidationFunction for 4139 ", br'\xE8..(\x12|\x13)\x00\x48\x8B\xB3\x88\x02\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction for 4139" , br'\xE8..(\x12|\x13)\x00\x48\x89\xDF\xE8...\x00\xBF' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("invalidationFunction for 4150 ", br'\xE8..\x13\x00\x48\x8B\xB3\x88\x02\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("validationFunction for 4150" , br'\xE8..\x13\x00\x48\x89\xDF\xE8...\x00\xBF' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
#("serverThread" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x53\x50\x41\x89\xF6\x49\x89\xFF\x6A\x20' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 0), # noqa: E203,E501 | |
("serverThread" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x53\x50\x41\x89\xF6\x49\x89\xFF\x6A\x20' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread" , br'\x55\x48\x89\xE5\x53\x48\x81\xEC....\x48\x89\xFB\x48\x8B\x05....\x48\x8B\x00\x48\x89\x45\xF0\x48\x8D\x3D....', 0, b'\xC3' , 0), # noqa: E203,E501 | |
#("crashReporter" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC....\x41\x89\xCE\x49\x89\xF7' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("isValidLicense_arm64 for 4114", br'\x08\x00\x80\x52...\x14\xE6\x03\x1E\xAA...\x94\xFE\x03\x06\xAA' , 8, b'\xE0\x03\x1F\xAA\xC0\x03\x5F\xD6', 0), # noqa: E203,E501 | |
# ("isValidLicense_arm64 for 4150", br'\x08\x00\x80\x52...\x14....\xE6\x03\x1E\xAA...\x94\xFE\x03\x06\xAA' , 8, b'\xE0\x03\x1F\xAA\xC0\x03\x5F\xD6', 0), # noqa: E203,E501 | |
("isValidLicense_arm64 for 4150", br'\x08\x00\x80\x52...\x14....\xE6\x03\x1E\xAA...\x94\xFE\x03\x06\xAA' , 8, b'\x00\x00\x80\xD2\xC0\x03\x5F\xD6', 0), # noqa: E203,E501 | |
("invalidationFunction_arm64" , br'...\x94..\x41\xF9..\x00\x10\x1F\x20\x03\xD5\x02\x53\x87\x52' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
# ("validationFunction_arm64" , br'\x02..\x52...\x94..\x00....\x91...\x91\xE0.\x00\xF9' , 4, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
# 等效 ("validationFunction_arm64" , br'...\x94..\x00.\xF7..\x91\xE0..\x91\xE0\x6F\x00\xF9' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
("validationFunction_arm64 for 4139", br'...\x94\xE0\x03.\xAA...\x94\x00\x45\x80\x52' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
("serverThread_arm64" , br'\xF6\x57\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91...\x94...\x94\xF3\x03\x00\xAA...\x94\x74\x1A\x00\xB9', 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
("licenseNotifyThread_arm64" , br'\xFC\x6F\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91\xFF\x43\x0C\xD1\xF3\x03\x00\xAA' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
#("crashReporte_arm64" , br'\xFC\x6F\xBC\xA9\xF6\x57\x01\xA9\xF4\x4F\x02\xA9\xFD\x7B\x03\xA9\xFD\xC3\x00\x91\xFF\x03\x0F\xD1' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
) | |
st_linux_patternes = ( | |
#("isValidLicense" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\xC7\xC0\x00\x00\x00\x00\xC3' , 1), # noqa: E203,E501 | |
# ("invalidationFunction", br'\xE8....\x48\x89\x5C\x24.\x48\x8B\xB3' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("invalidationFunction for 4121", br'\xBA....\xE8....\x49\x8B\xB7' , 5, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("invalidationFunction for 4139", br'\xBA....\xE8....\x48\x8B\xB5' , 5, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("invalidationFunction for 4139", br'\xE8..\x12\x00.\x8B.\xD8\x02\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("invalidationFunction for 4153", br'\xE8..\x14\x00.\x8B.\x88\x02\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("validationFunction" , br'\xE8....\xBF....\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction for 4139" , br'\xE8..\x12\x00.\x89.\xE8..\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction for 4153" , br'\xE8..\x14\x00.\x89.\xE8..\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("serverThread" , br'\x55\x41\x56\x53\x41\x89\xF6\x48\x89\xFD\x6A\x28' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3', 0), # noqa: E203,E501 | |
#("serverThread for 4153", br'\x55\x41\x56\x53\x41\x89\xF6\x48\x89\xFD\x6A\x20' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3', 0), # noqa: E203,E501 | |
("serverThread for 4153", br'\x55\x41\x56\x53\x41\x89\xF6\x48\x89\xFD\x6A\x20' , 0, b'\xC3', 0), # noqa: E203,E501 | |
("licenseNotifyThread" , br'\x41\x56\x53\x48\x81\xEC....\x48\x89\xFB\xBF....\xE8....\x4C\x8D\xB4\x24....' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread for 4146" , br'\x41\x56\x53\x48\x81\xEC....\x48\x89\xFB\x48\x8D\x3D....\xE8....\x48\x8D\x15....' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
# ("crashReporter" , br'\x55\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC....\x41\x89\xD4\x48\x89\xFD' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
) | |
st_win_patternes = ( | |
#("isValidLicense for 4117", br'\x45\x31\xC9\xE8....\x85\xC0\x75\x15' , 3, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 for 4117 | |
("isValidLicense for 4117", br'\x45\x31\xC9\xE8....\x85\xC0\x75\x15' , 3, b'\x48\xC7\xC0\x00\x00\x00\x00\xC3' , 1), # noqa: E203,E501 for 4117 | |
# ("isValidLicense" , br'\xE8....\x48\x8B\x8B....\x85\xC0' , 0, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 | |
("invalidationFunction" , br'\x41\xB8....\xE8....(\x49|\x48)\x8B\x96' , 6, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("validationFunction" , br'\xE8....\xE8....(\x4C|\x48)\x89\xF1\xE8' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction for 4139", br'\xE8.....\x89\xF1\xE8..\x00\x00\xB9' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
# ("serverThread" , br'\x55\x56\x57\x48\x83\xEC\x30\x48\x8D\x6C\x24.\x48\xC7\x45.....\x89\xD6\x48\x89\xCF\x6A\x28' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3', 0), # noqa: E203,E501 | |
("serverThread" , br'\x55\x56\x57\x48\x83\xEC\x30\x48\x8D\x6C\x24.\x48\xC7\x45.....\x89\xD6\x48\x89\xCF\x6A\x28' , 0, b'\xC3', 0), # noqa: E203,E501 | |
("licenseNotifyThread" , br'\x55\x56\x57\x48\x81\xEC....\x48\x8D\xAC\x24....\x0F\x29\xB5....\x48\xC7\x85........\x48\x89\xCF' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread for 4146" , br'\x55\x56\x57\x48\x81\xEC....\x48\x8D\xAC\x24....\x48\xC7\x85........\x48\x89\xCF' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
# ("crashReporter" , br'\x41\x57\x41\x56\x41\x55\x41\x54\x56\x57\x55\x53\xB8....\xE8....\x48\x29\xC4\x8A\x84\x24....' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
# ("crashReporter for 4153 *guess*" , br'\x55\x48\x89\xE5\x9C\xC7\x41\x30\x0F\x00\x10\x00\x48\x89\x41\x78' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
) | |
sm_osx_patternes = ( | |
("isValidLicense" , br'\xE8....\x3D....\x75\x14' , 0, b'\x48\xC7\xC0\x19\x01\x00\x00\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense" , br'\xE8....\x3D....\x75\x14' , 0, b'\x48\xC7\xC0\x19\x01\x00\x00\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense2" , br'\xE8....\x83\xF8\x01\x75\x14' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense_st" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 | |
("invalidationFunction", br'\xE8....\x48\x89\x9D....\x48\x8B\xB3' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction" , br'\xE8....\x48\x8D\x3D....\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("serverThread" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x53\x50\x41\x89\xF6\x49\x89\xFF\x6A\x20' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread" , br'\x55\x48\x89\xE5\x53\x48\x81\xEC....\x48\x89\xFB\x48\x8B\x05....\x48\x8B\x00\x48\x89\x45\xF0\x48\x8D\x3D....', 0, b'\xC3' , 0), # noqa: E203,E501 | |
# ("crashReporter" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC....\x41\x89\xCE\x49\x89\xF7' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
# ("crashReporter for 4153 *guess*" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC....\x41\x89\xCE\x49\x89\xF7' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("isValidLicense_arm64 for 2062", br'\x17\xf8\x5f\xbc\xa9\xf6\x57\x01\xa9\xf4\x4f\x02\xa9\xfd\x7b\x03\xa9\xFD\xC3\x00\x91\xFF\x03\x08\xD1', 1, b'\x20\x23\x80\xD2\xC0\x03\x5F\xD6', 0), # noqa: E203,E501 | |
("isValidLicense_arm64 for 2075", br'\x00\x04\x40\xF9...\x17\xE6\x03\x1E\xAA...\x94\xFE\x03\x06\xAA' , 8, b'\xE0\x03\x1F\xAA\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
("isValidLicense_arm64 for 2083", br'\x00\x04\x40\xF9...\x17....\xE6\x03\x1E\xAA...\x94\xFE\x03\x06\xAA' , 8, b'\xE0\x03\x1F\xAA\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
("invalidationFunction_arm64 for 2065" , br'...\x94\x61.\x41\xF9..\x00\x10\x1F\x20\x03\xD5\x02\x53\x87\x52' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
# ("invalidationFunction_arm64 for 2065" , br'\x02..\x52...\x94\x61\x62\x41\xF9...\x10' , 4, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
("validationFunction_arm64 for 2065" , br'\x02..\x52...\x94..\x00....\x91...\x91\xE0.\x00\xF9' , 4, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
# ("validationFunction_arm64 for 2065" , br'\x02..\x52...\x94..\x00.\x5a..\x91\x40..\x91' , 4, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
("validationFunction_arm64 for 2078" , br'\x02..\x52...\x94..\x00....\x91\xE0.\x00\xF9' , 4, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501 | |
("serverThread_arm64" , br'\xF6\x57\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91...\x94...\x94\xF3\x03\x00\xAA...\x94\x74\x1A\x00\xB9', 0, b'\xC0\x03\x5F\xD6', 0), # noqa: E203,E501 | |
# ("serverThread_arm64" , br'\xC0\x03\x5F\xD6\xF6\x57\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91...\x94...\x94\xF3\x03\x00\xAA', 4, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
("licenseNotifyThread_arm64" , br'\xFC\x6F\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91\xFF\x43\x0C\xD1' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
#("crashReporter_arm64" , br'\xFC\x6F\xBC\xA9\xF6\x57\x01\xA9\xF4\x4F\x02\xA9\xFD\x7B\x03\xA9\xFD\xC3\x00\x91\xFF\x03\x0F\xD1' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
## ("crashReporter_arm64 4153 *guess*" , br'\xFC\x6F\xBC\xA9\xF6\x57\x01\xA9\xF4\x4F\x02\xA9\xFD\x7B\x03\xA9\xFD\xC3\x00\x91\xFF\x03\x0F\xD1' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501 | |
) | |
sm_linux_patternes = ( | |
("isValidLicense" , br'\xE8....\x3D....\x75\x12' , 0, b'\x48\xC7\xC0\x19\x01\x00\x00\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense2" , br'\xE8....\x83\xF8\x01\x75\x12' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense_st" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense for 2082", br'\xE8....\x49\x8B\xBF....\x3D\x19' , 0, b'\x48\xC7\xC0\x19\x01\x00\x00\xC3' , 1), # noqa: E203,E501 | |
("invalidationFunction", br'\xE8....\x48\x89\x5C\x24.\x48\x8B\xB3' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("invalidationFunction for 2078", br'\xBA...\x00\xE8....\x49\x8B\xB6\x10\x03\x00\x00\xBF...\x00' , 5, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("invalidationFunction for 2086", br'\xBA...\x00\xE8....\x48\x8B\xB3\xC0\x02\x00\x00\x48' , 5, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction" , br'\xE8....\xBF....\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction for 2082" , br'\xE8....\x48......\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("serverThread" , br'\x55\x41\x56\x53\x41\x89\xF6\x48\x89\xFD\x6A' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread" , br'\x41\x56\x53\x48\x81\xEC....\x48\x89\xFB\xBF....' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread for 2086" , br'\x41\x56\x53\x48\x81\xEC....\x48\x89\xFB\x48\x8D\x3D' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
#("crashReporter" , br'\x55\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC....\x41\x89\xD4\x48\x89\xFD' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
) | |
sm_win_patternes = ( | |
("isValidLicense" , br'\xE8....\x3D....\x75\x15' , 0, b'\x48\xC7\xC0\x19\x01\x00\x00\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense2" , br'\xE8....\x49\x8B\x8E....\x83\xF8\x01' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 1), # noqa: E203,E501 | |
("isValidLicense_st" , br'\x45\x31\xC9\xE8....\x85\xC0\x75\x15' , 3, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501 for 4117 | |
("invalidationFunction", br'\x41\xB8....\xE8....\x48\x8B\x96....' , 6, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("validationFunction" , br'\x41\xB8....\xE8....\xE8....\xB9' , 6, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501 | |
("serverThread" , br'\x55\x56\x57\x48\x83\xEC\x30\x48\x8D\x6C\x24.\x48\xC7\x45.....\x89\xD6\x48\x89\xCF\x6A\x28' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread" , br'\x55\x56\x57\x48\x81\xEC....\x48\x8D\xAC\x24....\x0F\x29\xB5....' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread for 2082" , br'\x55\x56\x57\x48\x81\xEC....\x48\x8D\xAC\x24....\x48\xC7\x85\x48\x03\x00\x00\xFE\xFF\xFF\xFF\x48\x89\xCF', 0, b'\xC3' , 0), # noqa: E203,E501 | |
("licenseNotifyThread for 2091" , br'\x55\x56\x57\x48\x81\xEC....\x48\x8D\xAC\x24....\x48\xC7\x85\x58\x03\x00\x00\xFE\xFF\xFF\xFF\x48\x89\xCF', 0, b'\xC3' , 0), # noqa: E203,E501 | |
#("crashReporter" , br'\x41\x57\x41\x56\x41\x55\x41\x54\x56\x57\x55\x53\xB8....\xE8....\x48\x29\xC4\x8A\x84\x24....' , 0, b'\xC3' , 0), # noqa: E203,E501 | |
) | |
global log, PATCH | |
log = True | |
PATCH = False | |
def crack(filename, app_type=None, target_dir="."): | |
filename = os.path.join(target_dir.upper(), filename) | |
sublime = File(filename, app_type) | |
for pat in sublime.patternes: | |
Pattern(filename, sublime.binary, pat[0], pat[1], pat[2], pat[3], pat[4]) | |
sublime.patched() | |
def main(): | |
if len(sys.argv) > 1: | |
if sys.argv[1][0:2] == "st" and int(sys.argv[1][2:6]) and len(sys.argv[1][2:6]) == 4: | |
app_type = "sublime_text" | |
elif sys.argv[1][0:2] == "sm" and int(sys.argv[1][2:6]) and len(sys.argv[1][2:6]) == 4: | |
app_type = "sublime_merge" | |
else: | |
crack(sys.argv[1]) | |
quit() | |
version = sys.argv[1][2:6] | |
for url, extract_file in get_url_extract_file(app_type, version): | |
print("="*90) if log else None | |
filename = url.split('/')[-1] | |
download_file(url, proxy=True) | |
extract(filename, extract_file, sys.argv[1]) | |
crack(extract_file, app_type, sys.argv[1]) | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
E8 ? ? ? ? 3D ? ? ? ? 75 14 | |
E8 ? ? ? ? 3D ? ? ? ? 75 14 | |
E8 CA D0 FF FF 3D 19 01 00 00 75 14 | |
'\xE8....\x3D....\x75\x14' | |
0x290EC -->移动5个字节(+ 0x5)--> 0x290F1 | |
->(+ 0xFFFFFFFFFFFFD0CA) -->0x261BB | |
0x290EC 读取 后面4个字节 CA D0 FF FF -->字节翻转 --> FF FF D0 CA -->补全offset --> 0xFFFFFFFFFFFFD0CA | |
0xFFFFFFFF | |
file=open('/Users/maboloshi/sublime_merge','rb').read() | |
# 读取二进制偏量值 | |
s=file[0x290EC+1:0x290EC+5] | |
# 字节翻转 | |
a=struct.unpack('<I', s) | |
s=struct.pack('>I',*a) | |
'0xFFFFFFFF' + ''.join([format(x, '02X') for x in s]) | |
# 输出16进制变量值 | |
''.join([format(x, '02X') for x in s]) | |
--- | |
0xFFFFFFFFFFFFD0CA | |
0xFFFFD0CA | |
hex(0x290EC + 0x5 + 0xFFFFD0CA - 0x100000000) | |
--- | |
'0x261bb' | |
# 输出最终(initial_license_check函数)偏量值 | |
"0x{:X}".format(0x290EC + 0x5 + 0xFFFFD0CA -0x100000000) | |
"0x{:X}".format((0x290EC + 0x5 + 0xFFFFD0CA) & 0xFFFFFFFF) | |
--- | |
'0x261BB' | |
=== | |
f = open('/Users/maboloshi/Downloads/sublime_merge', 'rb') | |
data = f.read() | |
f.close() | |
pattern = "\xE8....\x3D....\x75\x14" | |
regex = re.compile(pattern) | |
for match_obj in regex.finditer(data): | |
offset = match_obj.start() | |
print "decimal: {}".format(offset) | |
# print "hex(): " + hex(offset) | |
# print "hex(): " + hex(offset).upper() | |
# print 'formatted hex: {:02X} \n'.format(offset) | |
print 'formatted hex: 0x{:02X} \n'.format(offset) | |
====== | |
name isValidLicense | |
binary open(, 'rb') | |
rva | |
class car() | |
def __init__(self, name, binary, rva): | |
self.name = model | |
self.binary = color | |
self.rva = | |
def locate(binary): | |
pattern = b"\xE8....\x3D....\x75\x14" | |
offset = re.search(pattern,binary).start() | |
def locate(pattern,binary): | |
offset = re.search(pattern,binary).start() | |
class xxxx(): | |
def __init__(self, binary,): | |
self.binary= binary | |
def locate(self.binary): | |
return re.search(pattern,self.binary).start() # 十进制 offset | |
def displacement(): | |
pattern = xxxxx() | |
offset = pattern.locate(self.binary) | |
offset += pattern.displacement() |
SM linux?
41 5D 41 5E 41 5F 5D C3 55 48 89 E5 41 57 -> 41 5D 41 5E 41 5F 5D C3 B8 00 00 00 00 C3
1200之前 参考 https://gist.github.com/cipherknight/bd3c7c8786f056e83490482696921245#sublime-merge---build-11091111---linux-x64
Name | Original | Patched |
---|---|---|
Initial License Check | 3F 00 0F [84] ED 00 00 | 3F 00 0F [85] ED 00 00 |
Persistent License Check | C7 02 [75] 2E 41 | C7 02 [74] 2E 41 |
Disable Nag | 33 A1 D3 26 [48] | 33 A1 D3 26 [C3] |
Better mac patterns for sublime text
("isValidLicense" , br'\xE8....\x49\x8B\xBF....\x85\xC0' , 0, b'\x48\x31\xC0\xC3' , 1), # noqa: E203,E501
# ("invalidationFunction", br'\xE8....\x48\x89\x9D....\x48\x8B\xB3' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501
# ("validationFunction" , br'\xE8....\x48\x8D\x3D....\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501
#("invalidationFunction for 4139 ", br'\xE8..\x13\x00\x48\x8B\xB3\x88\x02\x00\x00' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501
#("validationFunction for 4139" , br'\xE8..\x13\x00\x48\x89\xDF\xE8...\x00\xBF' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501
("invalidationFunction for 4152" , br'\x48\x8B\xB3\x88\x02\x00\x00\x48\x8D\x3D..\x00\x00\xBA\x88\x13\x00\x00\xE8...\x00\x48' , 19, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501
("validationFunction for 4152" , br'\xE8....\x48\x8D\x3D....\xE8....\x83\x25' , 0, b'\x90\x90\x90\x90\x90' , 0), # noqa: E203,E501
("serverThread" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x53\x50\x41\x89\xF6\x49\x89\xFF\x6A\x20' , 0, b'\x48\x31\xC0\x48\xFF\xC0\xC3' , 0), # noqa: E203,E501
("licenseNotifyThread" , br'\x55\x48\x89\xE5\x53\x48\x81\xEC....\x48\x89\xFB\x48\x8B\x05....\x48\x8B\x00\x48\x89\x45\xF0\x48\x8D\x3D....', 0, b'\xC3' , 0), # noqa: E203,E501
("crashReporter" , br'\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x41\x54\x53\x48\x81\xEC....\x41\x89\xCE\x49\x89\xF7' , 0, b'\xC3' , 0), # noqa: E203,E501
#("isValidLicense_arm64 for 4114", br'\x08\x00\x80\x52...\x14\xE6\x03\x1E\xAA...\x94\xFE\x03\x06\xAA' , 8, b'\xE0\x03\x1F\xAA\xC0\x03\x5F\xD6', 0), # noqa: E203,E501
("isValidLicense_arm64 NOP for 4152", br'\xFC....\x03\x1E\xAA..\x0E\x94\xFE\x03.\xAA\xFD\x7B.\xA9\xFD.\x01\x91\xFF\xC3\x07\xD1' , 0, b'\x1F\x20\x03\xD5' , 0),
("isValidLicense_arm64 for 4152", br'.\x03\x1E\xAA..\x0E\x94\xFE\x03.\xAA\xFD\x7B.\xA9\xFD.\x01\x91\xFF\xC3\x07\xD1' , 0, b'\x00\x00\x80\xD2\xC0\x03\x5F\xD6', 0),
#("invalidationFunction_arm64" , br'...\x94\x61.\x41\xF9..\x00\x10\x1F\x20\x03\xD5\x02\x53\x87\x52' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
#等效 ("invalidationFunction_arm64" , br'...\x94\x61\x46\x41\xF9..\x00\x10\x1F\x20\x03\xD5\x02\x53\x87\x52' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
("invalidationFunction_arm64 for 4152", br'\x1F\x20\x03\xD5\x02\x71\x82\x52..\x03\x94.\x46\x41\xf9' , 8, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
#("validationFunction_arm64" , br'\x02..\x52...\x94..\x00....\x91...\x91\xE0.\x00\xF9' , 4, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
#等效 ("validationFunction_arm64" , br'...\x94..\x00.\xF7..\x91\xE0..\x91\xE0\x6F\x00\xF9' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
#("validationFunction_arm64 for 4139", br'...\x94\xE0\x03\x13\xAA...\x94\x00\x45\x80\x52' , 0, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
("validationFunction_arm64 for 4152", br'\x1F\x20\x03\xD5\x02\x53\x87\x52..\x03\x94' , 8, b'\x1F\x20\x03\xD5' , 0), # noqa: E203,E501
("serverThread_arm64" , br'\xF6\x57\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91...\x94...\x94\xF3\x03\x00\xAA...\x94\x74\x1A\x00\xB9', 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501
("licenseNotifyThread_arm64" , br'\xFC\x6F\xBD\xA9\xF4\x4F\x01\xA9\xFD\x7B\x02\xA9\xFD\x83\x00\x91\xFF\x43\x0C\xD1\xF3\x03\x00\xAA' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501
("crashReporte_arm64" , br'\xFC\x6F\xBC\xA9\xF6\x57\x01\xA9\xF4\x4F\x02\xA9\xFD\x7B\x03\xA9\xFD\xC3\x00\x91\xFF\x03\x0F\xD1' , 0, b'\xC0\x03\x5F\xD6' , 0), # noqa: E203,E501
Tested them and they work from build 4107 to 4152 so hopefully they will last longer.
"isValidLicense_arm64 NOP" is needed because since a few builds ago the compiler is changing the stack pointer at the start of that function which breaks the patch. So I just add an extra NOP if that instruction is found.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
dd.exe
出处:https://packages.msys2.org/package/coreutils?repo=msys&variant=x86_64