[Python] 纯文本查看 复制代码
# -*- coding: utf-8 -*-
import hashlib
import struct
import os
import random
import ctypes
import subprocess
import sys
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
P = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff
A = P - 3
B = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
GX = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
GY = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
N = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
def inv(x, m=P):
return pow(x, -1, m)
def ec_add(p1, p2):
if p1 is None:
return p2
if p2 is None:
return p1
x1, y1 = p1
x2, y2 = p2
if x1 == x2 and (y1 + y2) % P == 0:
return None
if p1 == p2:
l = (3 * x1 * x1 + A) * inv(2 * y1) % P
else:
l = (y2 - y1) * inv(x2 - x1) % P
x3 = (l * l - x1 - x2) % P
return (x3, (l * (x1 - x3) - y1) % P)
def ec_mul(k, pt=(GX, GY)):
r = None
while k:
if k & 1:
r = ec_add(r, pt)
pt = ec_add(pt, pt)
k >>= 1
return r
def sign(d, z, k=None):
k = k or random.randrange(1, N)
R = ec_mul(k)
r = R[0] % N
s = inv(k, N) * (z + r * d) % N
return r, s
OFF_BLOB = 0x1880
OFF_SEAL = 0x2000
OFF_HASH = 0x2018
def seal_hash(data: bytes) -> bytes:
tmp = bytearray(data)
tmp[OFF_HASH:OFF_HASH+32] = b"\x00" * 32
return hashlib.sha256(tmp).digest()
def patch_pubkey(data: bytes, Q) -> bytes:
out = bytearray(data)
x, y = Q
blob = b"ECS1" + struct.pack("<I", 32) + x.to_bytes(32,"big") + y.to_bytes(32,"big")
out[OFF_BLOB:OFF_BLOB+72] = blob
out[OFF_HASH:OFF_HASH+32] = seal_hash(bytes(out))
return bytes(out)
SIG_PREFIX = b"Crackme/Verify/v1"
MC_PREFIX = "MC1-"
VC_PREFIX = "VC1-"
def get_local_machine_code():
import winreg
k = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Cryptography")
guid, _ = winreg.QueryValueEx(k, "MachineGuid")
buf = ctypes.create_string_buffer(260)
ctypes.windll.kernel32.GetWindowsDirectoryA(buf, 260)
root = buf.value[:3].encode() if isinstance(buf.value, str) else buf.value[:3]
vol = ctypes.c_ulong(0)
ctypes.windll.kernel32.GetVolumeInformationA(root, None, 0, ctypes.byref(vol), None, None, None, 0)
fp = hashlib.sha256(b"Crackme/Machine/v1" + guid.lower().encode() + struct.pack("<I", vol.value)).digest()
return MC_PREFIX + fp.hex().upper(), fp
def parse_mc_input(mc_text):
mc_text = mc_text.strip()
if not mc_text.startswith(MC_PREFIX):
return False, "", "机器码必须以 MC1- 开头"
fp_hex = mc_text[len(MC_PREFIX):].strip()
if len(fp_hex) != 64:
return False, "", f"FP‑hex 需要64位,实际 {len(fp_hex)}"
try:
bytes.fromhex(fp_hex)
except ValueError:
return False, "", "包含非法十六进制字符"
return True, fp_hex.upper(), ""
def keygen_from_d_and_mc(d: int, mc_text: str):
ok, fp_hex, err = parse_mc_input(mc_text)
if not ok:
raise Exception(err)
digest = hashlib.sha256(SIG_PREFIX + fp_hex.encode()).digest()
z = int.from_bytes(digest, "big")
r, s = sign(d, z)
lic = VC_PREFIX + r.to_bytes(32,"big").hex().upper() + s.to_bytes(32,"big").hex().upper()
return {
"fp_hex": fp_hex,
"digest_hex": digest.hex(),
"z": z,
"r": r,
"s": s,
"license": lic
}
class KeygenGUI:
def __init__(self, root):
self.root = root
root.title("Crackme 公钥补丁 + 注册机GUI")
root.geometry("860x640")
self.private_d = None
self.patched_exe_path = ""
main = ttk.Frame(root, padding=10)
main.pack(fill=tk.BOTH, expand=True)
file_frm = ttk.LabelFrame(main, text="EXE 文件路径")
file_frm.pack(fill=tk.X, pady=4)
self.var_src = tk.StringVar()
self.var_patch = tk.StringVar()
ttk.Label(file_frm, text="原始Crackme.exe:").grid(row=0, column=0, sticky="w", padx=4, pady=3)
ttk.Entry(file_frm, textvariable=self.var_src, width=70).grid(row=0, column=1, padx=4)
ttk.Button(file_frm, text="选择", command=self.browse_src).grid(row=0, column=2)
ttk.Label(file_frm, text="输出补丁exe:").grid(row=1, column=0, sticky="w", padx=4, pady=3)
ttk.Entry(file_frm, textvariable=self.var_patch, width=70).grid(row=1, column=1, padx=4)
ttk.Button(file_frm, text="另存", command=self.browse_patch).grid(row=1, column=2)
key_frm = ttk.LabelFrame(main, text="密钥与公钥补丁")
key_frm.pack(fill=tk.X, pady=4)
ttk.Button(key_frm, text="生成新P‑256密钥对并打公钥补丁", command=self.do_patch).pack(side=tk.LEFT, padx=4, pady=4)
ttk.Label(key_frm, text="当前私钥d(hex):").pack(side=tk.LEFT, padx=(12,2))
self.var_dhex = tk.StringVar()
ttk.Entry(key_frm, textvariable=self.var_dhex, width=52, font=("Consolas",9)).pack(side=tk.LEFT)
mc_frm = ttk.LabelFrame(main, text="机器码 MC1‑ (支持本机读取 / 自定义粘贴)")
mc_frm.pack(fill=tk.X, pady=4)
self.var_mc = tk.StringVar()
ttk.Entry(mc_frm, textvariable=self.var_mc, font=("Consolas",9)).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=4, pady=4)
ttk.Button(mc_frm, text="读取本机机器码", command=self.fill_local_mc).pack(side=tk.LEFT)
ttk.Button(mc_frm, text="用当前私钥生成授权码", command=self.do_keygen).pack(side=tk.LEFT, padx=6)
out_frm = ttk.LabelFrame(main, text="输出日志")
out_frm.pack(fill=tk.BOTH, expand=True, pady=6)
self.txt_log = tk.Text(out_frm, font=("Consolas",9))
self.txt_log.pack(fill=tk.BOTH, expand=True)
bot_frm = ttk.Frame(main)
bot_frm.pack(fill=tk.X)
ttk.Button(bot_frm, text="运行补丁exe测试授权码", command=self.run_patched_test).pack(side=tk.LEFT)
ttk.Button(bot_frm, text="清空日志", command=self.clear_log).pack(side=tk.LEFT, padx=8)
def log(self, s):
self.txt_log.insert(tk.END, s+"\n")
self.txt_log.see(tk.END)
self.root.update_idletasks()
def clear_log(self):
self.txt_log.delete("1.0", tk.END)
def browse_src(self):
p = filedialog.askopenfilename(filetypes=[("exe","*.exe"),("all","*.*")])
if p:
self.var_src.set(p)
def browse_patch(self):
p = filedialog.asksaveasfilename(defaultextension=".exe", filetypes=[("exe","*.exe")])
if p:
self.var_patch.set(p)
def fill_local_mc(self):
try:
mc,_ = get_local_machine_code()
self.var_mc.set(mc)
self.log(f"[+] 本机机器码已填入: {mc}")
except Exception as e:
messagebox.showerror("错误", str(e))
self.log(f"[!] 获取本机机器码失败: {e}")
def do_patch(self):
src_path = self.var_src.get().strip()
dst_path = self.var_patch.get().strip()
if not os.path.isfile(src_path):
messagebox.showerror("错误","原始exe不存在,请选择源文件")
return
if not dst_path:
messagebox.showerror("错误","请设置补丁exe输出路径")
return
try:
data = open(src_path,"rb").read()
# 校验 seal模型
orig_seal = seal_hash(data)
embedded = data[OFF_HASH:OFF_HASH+32]
if orig_seal != embedded:
self.log("[!] 警告:原文件 seal_hash 校验不匹配,文件可能不是原版Crackme.exe")
# 生成密钥对
d = random.randrange(1, N)
Q = ec_mul(d)
patched_bytes = patch_pubkey(data, Q)
open(dst_path,"wb").write(patched_bytes)
self.private_d = d
self.patched_exe_path = dst_path
self.var_dhex.set(hex(d))
self.log(f"[+] 补丁完成 -> {dst_path}")
self.log(f"[+] 新私钥 d = {hex(d)}")
self.log(f"[+] 公钥 Qx={Q[0]:064x}")
self.log(f"[+] 公钥 Qy={Q[1]:064x}")
except Exception as e:
messagebox.showerror("打补丁异常", str(e))
self.log(f"[!] patch exception: {e}")
def do_keygen(self):
mc_text = self.var_mc.get().strip()
if self.private_d is None:
messagebox.showerror("错误","请先生成密钥并打公钥补丁!")
return
if not mc_text:
messagebox.showerror("错误","请输入机器码 MC1‑...")
return
try:
res = keygen_from_d_and_mc(self.private_d, mc_text)
self.log("\n==== 注册机计算结果 ====")
self.log(f"输入机器码 : {mc_text}")
self.log(f"FP hex : {res['fp_hex']}")
self.log(f"Digest hex : {res['digest_hex']}")
self.log(f"z(int) : {res['z']:x}")
self.log(f"r : {res['r']:x}")
self.log(f"s : {res['s']:x}")
self.log(f"授权License : {res['license']}")
except Exception as e:
messagebox.showerror("注册机失败", str(e))
self.log(f"[!] keygen error: {e}")
def run_patched_test(self):
lic_line = None
for line in self.txt_log.get("1.0", tk.END).splitlines():
if line.startswith("授权License : "):
lic_line = line.split(":",1)[1].strip()
break
if not lic_line:
messagebox.showinfo("提示","日志中未找到授权码,请先生成License")
return
exe = self.patched_exe_path
if not exe or not os.path.isfile(exe):
messagebox.showerror("错误","补丁exe路径无效,请先打补丁")
return
try:
proc = subprocess.run(
[exe],
input=(lic_line+"\n").encode("utf‑8"),
capture_output=True,
timeout=25
)
stdout = proc.stdout.decode(errors="replace")
stderr = proc.stderr.decode(errors="replace")
self.log("\n==== 补丁EXE运行输出 ====")
self.log(stdout)
if stderr:
self.log(f"STDERR:{stderr}")
if "Success" in stdout:
self.log(" 结果:✅ Success 验证通过")
else:
self.log(" 结果:❌ Error 验证失败")
except Exception as e:
self.log(f"[!] run test exception: {e}")
if __name__ == "__main__":
root = tk.Tk()
app = KeygenGUI(root)
root.mainloop()