import os import re import sys from collections import defaultdict import win32com.client
ET_FILE_PATH = r"A:\2026AAfic\reworking\保险箱的秘密.et"
XOR_KEY = 85 CHAR_SPACING = 25 DOT_SPACING = 4
FONT_MAP = { "0": [[1, 0], [2, 0], [0, 1], [3, 1], [0, 2], [3, 2], [0, 3], [3, 3], [1, 4], [2, 4]], "1": [[2, 0], [1, 1], [2, 1], [2, 2], [2, 3], [1, 4], [2, 4], [3, 4]], "2": [[1, 0], [2, 0], [0, 1], [3, 1], [2, 2], [1, 3], [0, 4], [1, 4], [2, 4], [3, 4]], "3": [[0, 0], [1, 0], [2, 0], [3, 1], [1, 2], [2, 2], [3, 3], [0, 4], [1, 4], [2, 4]], "4": [[3, 0], [2, 1], [3, 1], [1, 2], [3, 2], [0, 3], [1, 3], [2, 3], [3, 3], [4, 3], [3, 4]], "5": [[0, 0], [1, 0], [2, 0], [0, 1], [0, 2], [1, 2], [2, 2], [3, 3], [0, 4], [1, 4], [2, 4]], "6": [[1, 0], [2, 0], [0, 1], [0, 2], [1, 2], [2, 2], [0, 3], [3, 3], [1, 4], [2, 4]], "7": [[0, 0], [1, 0], [2, 0], [3, 0], [3, 1], [2, 2], [1, 3], [1, 4]], "8": [[1, 0], [2, 0], [0, 1], [3, 1], [1, 2], [2, 2], [0, 3], [3, 3], [1, 4], [2, 4]], "9": [[1, 0], [2, 0], [0, 1], [3, 1], [1, 2], [2, 2], [3, 2], [3, 3], [2, 4]], "a": [[1, 2], [2, 2], [3, 2], [0, 3], [3, 3], [1, 4], [2, 4], [3, 4]], "b": [[0, 0], [0, 1], [0, 2], [1, 2], [2, 2], [0, 3], [3, 3], [0, 4], [1, 4], [2, 4]], "c": [[1, 0], [2, 0], [3, 0], [0, 1], [0, 2], [0, 3], [1, 4], [2, 4], [3, 4]], "d": [[3, 0], [3, 1], [1, 2], [2, 2], [3, 2], [0, 3], [3, 3], [1, 4], [2, 4], [3, 4]], "e": [[1, 0], [2, 0], [0, 1], [0, 2], [1, 2], [2, 2], [0, 3], [1, 4], [2, 4]], "f": [[1, 0], [2, 0], [1, 1], [0, 2], [1, 2], [2, 2], [1, 3], [1, 4]], "g": [[1, 2], [2, 2], [3, 2], [0, 3], [3, 3], [1, 4], [2, 4], [3, 4], [3, 5], [1, 6], [2, 6]], "h": [[0, 0], [0, 1], [0, 2], [1, 2], [2, 2], [0, 3], [3, 3], [0, 4], [3, 4]], "i": [[1, 0], [1, 2], [1, 3], [1, 4]], "j": [[2, 0], [2, 2], [2, 3], [2, 4], [2, 5], [1, 6], [0, 5]], "k": [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [2, 2], [1, 3], [3, 3], [2, 4]], "l": [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]], "m": [[0, 1], [1, 1], [2, 1], [3, 1], [4, 1], [0, 2], [2, 2], [4, 2], [0, 3], [4, 3]], "n": [[0, 1], [1, 0], [2, 0], [0, 2], [3, 2], [0, 3], [3, 3], [0, 4], [3, 4]], "o": [[1, 1], [2, 1], [0, 2], [3, 2], [1, 3], [2, 3]], "p": [[0, 2], [1, 2], [2, 2], [0, 3], [3, 3], [0, 4], [1, 4], [2, 4], [0, 5], [0, 6]], "q": [[1, 2], [2, 2], [0, 3], [3, 2], [3, 3], [3, 4], [3, 5], [4, 5]], "r": [[0, 2], [0, 3], [0, 4], [1, 2], [2, 2]], "s": [[1, 0], [2, 0], [3, 0], [0, 1], [1, 2], [2, 2], [3, 3], [0, 4], [1, 4], [2, 4]], "t": [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [0, 2], [2, 2]], "u": [[0, 2], [0, 3], [3, 2], [3, 3], [1, 4], [2, 4], [3, 4]], "v": [[0, 0], [4, 0], [1, 2], [3, 2], [2, 4]], "w": [[0, 2], [0, 3], [1, 4], [2, 3], [3, 4], [4, 2], [4, 3]], "x": [[0, 0], [4, 0], [1, 1], [3, 1], [2, 2], [1, 3], [3, 3], [0, 4], [4, 4]], "y": [[0, 0], [4, 0], [1, 1], [3, 1], [2, 2], [2, 3], [1, 4]], "z": [[0, 0], [1, 0], [2, 0], [3, 0], [2, 1], [1, 2], [0, 3], [0, 4], [1, 4], [2, 4], [3, 4]], ":": [[1, 1], [1, 3]], "@": [[1, 0], [2, 0], [0, 1], [3, 1], [0, 2], [2, 2], [3, 2], [0, 3], [1, 4], [2, 4]], ".": [[1, 4]], }
def build_signature(points): """ 将点阵排序、去重,生成可用于匹配的特征。 """ return tuple(sorted(set((int(x), int(y)) for x, y in points)))
SIGNATURE_TO_CHAR = { build_signature(points): char for char, points in FONT_MAP.items() }
def open_wps(): """ 连接 WPS 表格。
常见 WPS 表格 COM ProgID 为 ket.Application。 同时提供几个备用名称。 """ prog_ids = [ "ket.Application", "KET.Application", "et.Application", "Excel.Application", ] errors = [] for prog_id in prog_ids: try: app = win32com.client.DispatchEx(prog_id) return app, prog_id except Exception as exc: errors.append(f"{prog_id}: {exc}") raise RuntimeError( "无法启动 WPS 表格或 Excel。\n" "请确认已经安装 WPS Office,并且使用 Windows 系统。\n\n" + "\n".join(errors) )
def read_alternative_texts(sheet): """ 读取一张工作表所有形状中的 AlternativeText。 """ values = [] try: shape_count = sheet.Shapes.Count except Exception: return values for index in range(1, shape_count + 1): try: shape = sheet.Shapes.Item(index) alt_text = shape.AlternativeText if alt_text is None: continue alt_text = str(alt_text).strip() if re.fullmatch(r"\d+", alt_text): values.append(int(alt_text)) except Exception: continue return values
def decode_values(encoded_values): """ 根据原始 JavaScript 编码公式进行逆向解密。
原公式: value = (((x + 100) ^ 85) * 1000) + ((y + 100) ^ 85) """ character_groups = defaultdict(list)
for encoded_value in encoded_values: encoded_x = encoded_value // 1000 encoded_y = encoded_value % 1000 original_x = (encoded_x ^ XOR_KEY) - 100 original_y = (encoded_y ^ XOR_KEY) - 100 if original_x < 0 or original_y < 0: continue character_index = original_x // CHAR_SPACING local_x = original_x - character_index * CHAR_SPACING if local_x % DOT_SPACING != 0: continue if original_y % DOT_SPACING != 0: continue dot_x = local_x // DOT_SPACING dot_y = original_y // DOT_SPACING character_groups[character_index].append((dot_x, dot_y)) if not character_groups: return "" max_index = max(character_groups) result = [] for index in range(max_index + 1): points = character_groups.get(index) if not points: result.append(" ") continue signature = build_signature(points) char = SIGNATURE_TO_CHAR.get(signature, "?") result.append(char) return "".join(result)
def decode_et_file(file_path): file_path = os.path.abspath(file_path) if not os.path.isfile(file_path): raise FileNotFoundError(f"文件不存在:{file_path}") app = None workbook = None try: app, prog_id = open_wps() app.Visible = False try: app.DisplayAlerts = False except Exception: pass print(f"使用程序:{prog_id}") print(f"正在读取:{file_path}") workbook = app.Workbooks.Open(file_path) results = [] for sheet_index in range(1, workbook.Worksheets.Count + 1): sheet = workbook.Worksheets.Item(sheet_index) sheet_name = str(sheet.Name) encoded_values = read_alternative_texts(sheet) if not encoded_values: continue decoded_text = decode_values(encoded_values) results.append({ "sheet": sheet_name, "shape_count": len(encoded_values), "text": decoded_text, }) return results finally: if workbook is not None: try: workbook.Close(False) except Exception: pass if app is not None: try: app.Quit() except Exception: pass
def main(): try: results = decode_et_file(ET_FILE_PATH) print("\n" + "=" * 60) if not results: print("未找到可解密的 AlternativeText 数字数据。") return print("解密结果:") for result in results: print("-" * 60) print(f"工作表:{result['sheet']}") print(f"有效形状:{result['shape_count']}") print(f"明文结果:{result['text']}") print("=" * 60) except Exception as exc: print(f"\n运行失败:{exc}") sys.exit(1)
if __name__ == "__main__": main()
|