Skip to content

delon-xie/PyRebuilderSharp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

347 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PyRebuilderSharp 🐍⚡

逐块重建,完整还原 · Block-by-block recovery, complete restoration

块级容错 · 极致压缩失败率 · 比AI更可控 Block-level fault tolerance · Minimal failure rate · More controllable than AI

🇨🇳 中文 | 🇬🇧 English


🇨🇳 中文

一个 Python 字节码反编译器 —— 基于 .NET 10 + Avalonia UI · Python 2.7 ~ 3.14 · 跨平台


PyRebuilderSharp GUI 截图 GUI 界面:左侧文件树 → 中侧字节码(语法高亮)→ 右侧源码(VS Code 风格配色 + 双向滚动锁定)

我们的成果

PyRebuilderSharp 是一个从零构建的 Python 字节码反编译器,使用 C# 13 + .NET 10 + Avalonia UI,全栈自主实现(0 行第三方反编译依赖)。对标业界主流 pycdc(C++),在架构和稳健性上实现了根本性超越。

最新进展 — Phase 7: 标注优先 + 控制块模式目录 🚀

Phase 7 引入全新的 --seq-blocks 反编译架构,以标注优先 + 模式目录驱动为原则。先多轮扫描收集标注信息,再按模式目录的确定性顺序统一链接:

BuildSequentialBlocks():
├── MergeLinearChain                    ← Phase 1 顺序块构建
├── AnnotateSequentialBlock             ← Phase 3 控制块起始标注
├── AnnotateExceptionTableBlocks        ← Phase 2 ExceptionTable 标注
├── AnnotateMatchBlocks                 ← Phase 2a Match/Case 标注
├── AnnotateForWhileSubtypes            ← Phase 2b For/While 细分
├── AnnotateHandlerDepths               ← Phase 2c Handler 深度
├── BuildSequentialBlockGraph           ← 后继图
├── AnnotateMergePointsAndExits         ← Phase 3b 汇聚点/出口
└── AnnotateBackEdges                   ← Phase 4 回边

ParseControlStructures():               ← Phase 5 模式目录驱动链接
├── Try  (IsTryHeader)                  → 模式 T1-T7
├── Loop (IsForLoopHeader/IsWhileLoopHeader) → 模式 F1-F4/W1-W4
├── With (IsWithHeader)                 → 模式 S1-S4
└── IfElse (IsConditionHeader)          → 模式 I1-I4
flowchart TB
    subgraph Input["输入"]
        A[".pyc 字节码"]
    end

    subgraph Build["BuildSequentialBlocks() — 多轮标注"]
        direction TB
        B1["MergeLinearChain<br/><i>Phase 1 — 顺序块合并</i>"]
        B2["AnnotateExceptionTableBlocks<br/><i>Phase 2 — ExceptionTable 标注</i>"]
        B2a["AnnotateMatchBlocks<br/><i>Phase 2a — Match/Case 细分</i>"]
        B2b["AnnotateForWhileSubtypes<br/><i>Phase 2b — For/While 细分</i>"]
        B2c["AnnotateHandlerDepths<br/><i>Phase 2c — Handler 深度</i>"]
        B3["AnnotateSequentialBlock<br/><i>Phase 3 — 控制块起始标注</i>"]
        B3b["AnnotateMergePointsAndExits<br/><i>Phase 3b — 汇聚点/出口</i>"]
        B3c["BuildSequentialBlockGraph<br/><i>后继图构建</i>"]
        B4["AnnotateBackEdges<br/><i>Phase 4 — 回边标注</i>"]
        
        B1 --> B2 --> B2a --> B2b --> B2c --> B3 --> B3b --> B3c --> B4
    end

    subgraph Parse["ParseControlStructures() — 模式目录驱动"]
        direction TB
        P1["IsTryHeader<br/>(模式 T1~T7)"]
        P2["IsForLoopHeader<br/>(模式 F1~F4)"]
        P3["IsWhileLoopHeader<br/>(模式 W1~W4)"]
        P4["IsWithHeader<br/>(模式 S1~S4)"]
        P5["IsConditionHeader<br/>(模式 I1~I4)"]
    end

    subgraph Output["输出"]
        O["AST 语句<br/>Python 源码"]
    end

    A --> B1
    B4 --> P1
    B4 --> P2
    B4 --> P3
    B4 --> P4
    B4 --> P5
    P1 --> O
    P2 --> O
    P3 --> O
    P4 --> O
    P5 --> O

    style A fill:#2d2d2d,stroke:#569CD6,color:#d4d4d4
    style O fill:#2d2d2d,stroke:#4EC9B0,color:#d4d4d4
    style B1 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2a fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2b fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2c fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B3 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B3b fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B3c fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B4 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style P1 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P2 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P3 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P4 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P5 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
Loading
关键指标 数值 状态
孤儿块 0(全覆盖)
运行时崩溃 0/1325 文件
全量基线 100% 成功 1325 文件全部反编译
控制块模式目录 7 大类 28 子模式 已分类 📖 docs/control-block-patterns.md

详见 总体设计文档详细设计文档控制块模式目录--seq-blocks CLI 选项。

当前基线(2026-07-09)

指标 数值 状态
支持版本 2.7, 3.5 ~ 3.14
反编译架构 Phase 7 标注优先 + 模式目录驱动 🚀
全量基线 1325/1325 (100%),0 崩溃,0 孤儿块
CLI 模式 --seq-blocks(默认)/ --no-seq-blocks(降级)
白盒测试通过率 298/405 (73%) 🔄
测试报告 test_data/whitebox_report_*.md(逐次)
设计文档 总体 v2.8 / 详细 v2.7 / 模式目录 v1.0

现存问题(按优先级排序)

优先级 问题 数量 根因 目标
P0 EMPTY_TRY 56 try body 范围计算不精确,SETUP_FINALLY handler 与 body 在同一 seqBlock ↓30
P0 TRY_NO_HANDLER 19 handler preamble 检测不完整(POP_TOP×3 模式需增强) ↓10
P1 BARE_EXPR 83 中间表达式泄漏(comprehension 变量、class 属性、match pattern) ↓50
P2 REDUNDANT_PASS/RAISE/RETURN 68 后处理过滤不完全,空函数体 pass 堆积 ↓40
P2 SYNTAX_ERROR 14 3.5-3.7 comprehension 差异、大文件边界 ↓10
P3 ELSE_CONTAINS_FINALLY 11 测试脚本伪阳性(else 块代码被判定含 finally) ↓11
P3 CLEANUP_LEAK 8 handler cleanup e = None 泄漏 ↓5
P4 FORMAT_ERROR 3 reprlib f-string 双花括号转义 ↓3

里程碑

🏆 Phase 4 P0-1 — 函数定义 (def)

name_0 = CodeObject: <module>def factorial(n): — 项目首次生成正确的 Python 函数定义:

# 修复前 (Phase 3):
name_0 = CodeObject: <module> (5 instrs)    ← 全部垃圾

# 修复后 (Phase 4 P0-1):
def greet(name):                              ← ✅
def add(a, b):                                ← ✅
def factorial(n):                             ← ✅
def abstractmethod(funcobj):                  ← ✅
    pass

🏆 九层塔测试

新增 test_nested_depth_9.py — 4 个函数,9 层混合嵌套,编译 11 个 Python 版本全部验证通过:

  • nine_level_if_for_while_try — if > for > while > try 镜像
  • nine_level_try_except_finally — 9 层 try-except-finally
  • nine_level_all_control — if/elif/else + for + while + try 全混合
  • nine_level_deep_assign — 9 层 if 赋值链

🏆 版本矩阵全覆盖

套件 版本覆盖 通过
Lv0_Expressions 2.7 → 3.14 11/11 ✅
Lv1_Sequential 2.7 → 3.14 11/11 ✅
Lv2_ControlFlow 2.7 → 3.14 11/11 ✅
Lv3_NestedDepth(5层) 2.7 → 3.14 11/11 ✅
Lv3_NestedMixed 2.7 → 3.14 11/11 ✅
Lv3_NestedMatrix 2.7 → 3.14 11/11 ✅
Lv3-1_NestedDepth9(九层塔) 2.7 → 3.14 11/11 ✅

8 个 marshal 3.11+ 修复

Phase 4 P0-1 发现了 Python 3.11+ marshal 格式的根本性变化并逐一修复:

# 发现问题 修复 效果
1 3.11+ 去掉 varnames/freevars/cellvars 改为 localsplusnames + localspluskinds 字段对齐
2 localspluskinds 存为 TYPE_STRING(0x73) ReadRawMarshalBytes 读取 避免 0x73→CODE_SIMPLE EOF
3 ReadRawMarshalBytes 不预留 ref slot 加 FLAG_REF 预插槽 ref 索引对齐
4 容器 FLAG_REF 未处理 容器预留 + 填充 co_names 索引正确
5 exceptiontable 用 TYPE_REF(0x72) PEEK 检查 + 读 TYPE_REF 5 字节不丢
6 0x73 在 names 中被当 CODE_SIMPLE ReadOneMarshalString 单独处理 names 不为空
7 HandleUnknownMarshalType type<4 跳到 EOF 直接 return null, 不跳过 无害通过
8 MAKE_FUNCTION 在 3.12 只 pop 1 项 _isPython312 + pop 1 项 类 body 正确

核心发现:Python 3.11+ marshal Code Object 格式变化

3.10-格式:                   3.11+格式:
  argcount                     argcount
  posonlyargcount              posonlyargcount
  kwonlyargcount               kwonlyargcount
  nlocals                      stacksize
  stacksize                    flags
  flags                        code (bytecodes)
  code (bytecodes)              consts
  consts                       names
  names                        localsplusnames ← 合并 varnames+freevars+cellvars
  varnames                     localspluskinds ← 0x20=local 0x40=cell 0x80=free
  freevars                     filename
  cellvars                     name
  filename                     qualname ← 新增
  name                         firstlineno
  firstlineno                  linetable ← 替代 lnotab
  lnotab                       exceptiontable ← 新增

关键冲突:0x73 = TYPE_STRING = TYPE_CODE_SIMPLE

Python 3.11+ 用 0x73 (TYPE_STRING) 作为 TYPE_CODE_SIMPLE。代码中的上下文区分:

  • ReadRawMarshalBytes → 0x73 = TYPE_STRING (用于 bytecodes/lnotab/localspluskinds)
  • ReadOneMarshalString → 0x73 = TYPE_STRING (用于 names/localsplusnames)
  • ReadMarshalValue → 0x73 = TYPE_CODE_SIMPLE (用于 co_consts 中的 code objects)

设计理念 — 为什么 PyRebuilderSharp 与众不同

⚠️ 常见误解澄清:下述描述确保以下信息在文档中清晰可查—— 避免外部分析者(如 ai 生成的分析报告)误判项目架构。 参见 v2.1 改进计划开头的「核实结论」。

🧱 逐块兜底(核心创新)

传统的反编译器(pycdc、uncompyle6、decompyle3)采用整体编译策略——只要有一个指令无法处理,整个文件就崩溃。PyRebuilderSharp 的每个基本块独立反编译

基本块 B1 ──► 栈机模拟 ──► AST ──► "x = a + b"     ✅
基本块 B2 ──► 栈机模拟 ──► AST ──► "return x"      ✅
基本块 B3 ──► 栈机模拟 ──► ❌ 异常 → 注释兜底       ⚠️
基本块 B4 ──► 栈机模拟 ──► AST ──► "y = 42"        ✅

效果:一个块失败不会让整个文件归零。反编译器永远输出最大可恢复的 Python 源码,不会沉默失败。

🏗️ 完整 CFG + 支配树控制流分析(不是线性扫描)

尽管 Phase 2 分块是从线性扫描起步,Phase 3 的 ControlFlowScanner构建完整的控制流图并运行支配树分析——这是项目的核心架构事实,经常被外部文档误判为「线性模板拼接」:

字节码 → BlockScanner(分块) → ControlFlow(构建 CFG)
  → ComputeImmediateDominators()   ← 立即支配树
  → ComputeDominators()            ← 完整支配集
  → DetectNaturalLoops()           ← 自然循环检测(回边 → 支配节点)
  → StructuredCFG                  ← 结构化控制流
  → AstBuilder(AST构建)            ← 在后继图上递归遍历

关键文件:Scanners/ControlFlowScanner.cs(302 行完整实现)、Models/CFG/ControlFlowGraph.csModels/CFG/BasicBlock.cs(含前驱/后继/异常边)。

🌲 显式 AST 中间表示(不是字符串拼接)

反编译结果生成途径不是指令→模板字符串拼接,而是完整的 C# record AST 树 + 访问者模式代码生成:

每个基本块 → StackMachine.Execute() → AST 节点 (Stmt/Expr)
  → AstBuilder 拼接控制结构 AST
  → PythonCodeGenerator.Visit()     ← 访问者模式
  → 格式化 Python 源码

AST 模型位于 Models/AST/,包含 60+ 节点类型全面覆盖 Python 2.7~3.14 语法:

  • 推导式:ListComp / SetComp / DictComp / GeneratorExp
  • f-string:FormattedValue + JoinedStr
  • 海象运算符:NamedExpr
  • match/case:6 类 MatchPattern 子节点 + Match 语句 ✅

代码生成器 PythonCodeGenerator.cs 是纯访问者模式——不产生任何模板字符串拼接

🔬 AST 语义级比较(优于编译验证)

测试体系使用 token 级语义比较而非字符串匹配——生成的反编译代码只要语义等价即通过,不要求逐字符一致。这意味着代码格式优化、命名差异不会导致假阳性失败。这是比 compile(source, '<exec>') 语法检查更精细的验证方式。

🧩 模块化管道(含完整依赖注入)

pyc 文件
  → PycReader(marshal)              ← 7 个版本策略(隔离)
  → BlockScanner(分块)              ← 跳转目标切割
  → ControlFlowScanner(CFG+支配树)  ← 控制流图构建 + 自然循环
  → AstBuilder(AST构建+逐块容错)    ← 继承图遍历 + 29 后处理 pass
  → PythonCodeGenerator(代码生成)   ← 访问者模式
  → Python 源码

🔀 版本完全隔离(每个版本独立策略文件)

每个 Python 大版本的差异由独立的 VersionStrategy 类封装,绝非「混在一条解析路径」:

策略类 覆盖版本 特性差异
VersionStrategy27 2.7 无 PEP552、无 WORD_OFFSET、marshal TYPE_STRINGREF
VersionStrategyPre311 3.5~3.10 传统 marshal、SETUP_* 指令、无 ExceptionTable
VersionStrategy311 3.11 localsplus、ExceptionTable、CACHE 指令
VersionStrategy312 3.12 CALL=171、RESUME=151、完整 CACHE
VersionStrategy313 3.13 额外 opcode 调整
VersionStrategy314 3.14 最新版支持

每个策略类通过 MapOpcode() 将原始字节映射到统一 Opcode 枚举——核心 AST 构建不感知版本差异。

⚙️ StackMachine 栈模拟 + 表达式折叠(不是简单槽位映射)

StackMachine 是全栈模拟(不是变量槽位映射),包含:

  • 表达式折叠LOAD_CONST func + CALL_FUNCTION → 推断装饰器 @decorator
  • 推导式转换ConvertComprehensionCalls → ListComp/SetComp/DictComp
  • 增强赋值折叠ConvertAugAssigni = i + 1i += 1
  • 死代码消除TrimPostTerminalDeadCode + CollapseRedundantPasses
  • 函数体修复PostProcessFunctionDefs + FixEmptyFunctionBodies
  • 嵌套 CodeObject 递归ConvertChildCodesToFunctionDefs + DecompileNestedCodeObjects

⚙️ CrashCollector 机制

异常发生时自动记录结构化 JSON 到 ~/.pyrebuilder/crashes/

{
  "Timestamp": "2026-06-14T03:05:12.345Z",
  "PythonVersion": "3.12",
  "FileName": "abc.pyc",
  "PycSize": 8839,
  "ExceptionType": "System.InvalidOperationException",
  "ExceptionMessage": "...",
  "StackTrace": "..."
}

通过 CrashCollector.GetCrashHistory() 查询历史,ClearAll() 清除。


当前状态

✅ Phase 1–2 — 基础设施

项目 状态
CLI 命令行工具(含 --seq-blocks / --no-seq-blocks)
Avalonia GUI 暗色主题
文件拖放 + 打开对话框
SelectableTextBlock 语法高亮
跨平台 (Windows/macOS/Linux)

✅ Phase 3 — marshal 收敛 + Lv3 嵌套

项目 状态
8 个 marshal 3.11+ 修复 ✅ 0/938 警告
版本矩阵 2.7→3.14 ✅ 77/77
CrashCollector
Lv3 嵌套 + 九层塔 ✅ 33/33

✅ Phase 4 — 语法覆盖

项目 状态
def / class / yield / @decorator / async / 展开赋值

✅ Phase 5 — 编译脚本

项目 状态
compile_test_data 2.7→3.14 ✅ 628 编译
Benchmark 938/938 ✅ 0 警告

✅ Phase Fix — 7 项 Bug

项目 状态
co_names / class Foo / x = f() / RETURN_CONST / walrus / except* / match opcode ✅ 全部关闭

✅ Phase 6 — v3.11+ 流水线

Lv6 状态
Lv6a–Lv6f (15 opcodes + ExceptionTable + linetable + CACHE + 版本矩阵) ✅ 全部完成

🚀 Phase 7 — Seq-Blocks 三阶段架构(进行中)

项目 状态
SequentialBlockBuilder 顺序块合并 🚀 第一阶段
ParseControlStructures 控制结构解析 🚀 第二阶段
GenerateAstStatementsHybrid 混合遍历 🚀 第三阶段
--seq-blocks CLI 选项 + 默认启用
Fallback 机制(孤儿块降级)
DecompileOptions.EnableSequentialBlocks default=false→true 🔄 待切换
白盒测试 405 用例覆盖率 🔄 收敛中(目前 251/405 通过)

未来计划

🔴 高优先级

项目 说明
match/case (3.10+) CFG 重建 + AST ✅ 完整实现 (11 pattern types + codegen)
except* ExceptionTable → IsGroup 映射 BuildTryFromExceptionTable + CHECK_EG_MATCH
AST 自动对比验证 tools/ast_compare.py
CrashCollector Dashboard ✅ Avalonia 崩溃日志面板
批量反编译模式 ✅ CLI -d <dir>, --stats
walrus 控制流检测 ✅ NamedExpr + COPY+STORE
总计 Phase 1–6 + Phase Fix 全部关闭 · 0 项剩余 🎉

✅ 已完成

项目 完成状态
except* ExceptionTable → IsGroup 映射 BuildTryFromExceptionTable + CHECK_EG_MATCH
AST 自动对比验证 tools/ast_compare.py
CrashCollector Dashboard ✅ Avalonia 崩溃日志面板
批量反编译模式 ✅ CLI -d <dir>, --stats
walrus 控制流检测 ✅ NamedExpr + COPY+STORE
Benchmark 938/938 ✅ 0 警告

✅ Phase Fix — 7 项 Bug

项目 状态
co_names / class Foo / x = f() / RETURN_CONST / walrus / except* / match opcode ✅ 全部关闭

✅ Phase 6 — v3.11+ 流水线

Lv6 状态
Lv6a–Lv6f (15 opcodes + ExceptionTable + linetable + CACHE + 版本矩阵) ✅ 全部完成

未来计划

🔴 高优先级

项目 说明
match/case (3.10+) CFG 重建 + AST ✅ 完整实现 (11 pattern types + codegen)
except* ExceptionTable → IsGroup 映射 BuildTryFromExceptionTable + CHECK_EG_MATCH
AST 自动对比验证 tools/ast_compare.py
CrashCollector Dashboard ✅ Avalonia 崩溃日志面板
批量反编译模式 ✅ CLI -d <dir>, --stats
walrus 控制流检测 ✅ NamedExpr + COPY+STORE
总计 Phase 1–6 + Phase Fix 全部关闭 · 0 项剩余 🎉

✅ 已完成

项目 完成状态
except* ExceptionTable → IsGroup 映射 BuildTryFromExceptionTable + CHECK_EG_MATCH
AST 自动对比验证 tools/ast_compare.py
CrashCollector Dashboard ✅ Avalonia 崩溃日志面板
批量反编译模式 ✅ CLI -d <dir>, --stats
walrus 控制流检测 ✅ NamedExpr + COPY+STORE

项目结构

PyRebuilderSharp.slnx
├── src/
│   ├── PyRebuilderSharp.Core/   # [Core] Reader, Builder, Generator, Scanner
│   ├── PyRebuilderSharp.Cli/    # [CLI] Command-line tool
│   └── PyRebuilderSharp.Gui/    # [GUI] Avalonia desktop app
├── tests/
│   └── PyRebuilderSharp.Tests/  # [Tests] 109 xUnit tests
├── tools/
│   └── compile_test_data.py     # [Tools] Version matrix compiler
└── docs/
    └── (11 documents)           # [Docs] Architecture, Design, Testing

文档索引

文档 说明
Python反编译总体设计.md v2.6 — 架构设计、核心原则
Python反编译详细设计.md v2.5 — 模块设计、API 参考
summary_phase3_close.md Phase 3 收尾总结
summary_phase4_begin.md Phase 4 启动总结
plan_phase4.md Phase 4 语法覆盖计划
TESTING_BASELINE.md v2.1 — 测试基准与版本矩阵
pyc-format-reference.md Python marshal 格式参考
quick_start.md 快速入门(构建+运行+测试)
deepseek_v4_benchmark_report.md 🤖 横向评测 — 与 uncompyle6/decompyle3/pycdc 对比

PyRebuilderSharp — 从 Python 字节码中重建源码,块级容错。

Block-by-block Python bytecode decompiler with fault tolerance.

🐍 .pyc → 🔨 PyRebuilderSharp → 📜 Python source code
                 │
          块级容错 · 极致压缩失败率
          一个块的失败,不会变成整个文件的沉默

🇨🇳 回到顶部 | 🇬🇧 English


🇬🇧 English

A Python bytecode decompiler built on .NET 10 + Avalonia UI · Python 3.5 ~ 3.14 · Cross-platform


Overview

PyRebuilderSharp is a from-scratch Python bytecode decompiler in C# 13 (.NET 10) with zero third-party decompiler dependencies. It surpasses industry-standard pycdc (C++) in architecture and robustness through an annotation-first sequential-block pipeline and block-level fault tolerance.

Phase 7 — Annotation-First Pipeline with Control Block Pattern Catalog 🚀

Phase 7 introduces the --seq-blocks architecture based on annotation-first + pattern-catalog-driven principles. Multiple scan passes collect annotations first, then the pattern catalog links control structures in deterministic order:

BuildSequentialBlocks():
├── MergeLinearChain                    ← Phase 1: sequential block merging
├── AnnotateExceptionTableBlocks        ← Phase 2: ExceptionTable annotation
├── AnnotateMatchBlocks                 ← Phase 2a: Match/Case annotation
├── AnnotateForWhileSubtypes            ← Phase 2b: For/While subtype annotation
├── AnnotateHandlerDepths               ← Phase 2c: Handler depth annotation
├── AnnotateSequentialBlock             ← Phase 3: Control structure markers
├── AnnotateMergePointsAndExits         ← Phase 3b: Merge point / exit annotation
├── BuildSequentialBlockGraph           ← Successor graph
└── AnnotateBackEdges                   ← Phase 4: Back-edge annotation

ParseControlStructures():               ← Phase 5: Pattern-catalog-driven linking
├── Try  (IsTryHeader)                  → Patterns T1-T7
├── Loop (IsForLoopHeader/IsWhileLoopHeader) → Patterns F1-F4 / W1-W4
├── With (IsWithHeader)                 → Patterns S1-S4
└── IfElse (IsConditionHeader)          → Patterns I1-I4
flowchart TB
    subgraph Input["Input"]
        A[".pyc bytecode"]
    end

    subgraph Build["BuildSequentialBlocks() — Multi-pass annotation"]
        direction TB
        B1["MergeLinearChain<br/><i>Phase 1 — Sequential block merging</i>"]
        B2["AnnotateExceptionTableBlocks<br/><i>Phase 2 — ExceptionTable annotation</i>"]
        B2a["AnnotateMatchBlocks<br/><i>Phase 2a — Match/Case subtype</i>"]
        B2b["AnnotateForWhileSubtypes<br/><i>Phase 2b — For/While subtype</i>"]
        B2c["AnnotateHandlerDepths<br/><i>Phase 2c — Handler depth</i>"]
        B3["AnnotateSequentialBlock<br/><i>Phase 3 — Control structure markers</i>"]
        B3b["AnnotateMergePointsAndExits<br/><i>Phase 3b — Merge points / exits</i>"]
        B3c["BuildSequentialBlockGraph<br/><i>Successor graph</i>"]
        B4["AnnotateBackEdges<br/><i>Phase 4 — Back-edge annotation</i>"]
        
        B1 --> B2 --> B2a --> B2b --> B2c --> B3 --> B3b --> B3c --> B4
    end

    subgraph Parse["ParseControlStructures() — Pattern-catalog-driven"]
        direction TB
        P1["IsTryHeader<br/>(Patterns T1~T7)"]
        P2["IsForLoopHeader<br/>(Patterns F1~F4)"]
        P3["IsWhileLoopHeader<br/>(Patterns W1~W4)"]
        P4["IsWithHeader<br/>(Patterns S1~S4)"]
        P5["IsConditionHeader<br/>(Patterns I1~I4)"]
    end

    subgraph Output["Output"]
        O["AST statements<br/>Python source"]
    end

    A --> B1
    B4 --> P1
    B4 --> P2
    B4 --> P3
    B4 --> P4
    B4 --> P5
    P1 --> O
    P2 --> O
    P3 --> O
    P4 --> O
    P5 --> O

    style A fill:#2d2d2d,stroke:#569CD6,color:#d4d4d4
    style O fill:#2d2d2d,stroke:#4EC9B0,color:#d4d4d4
    style B1 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2a fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2b fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B2c fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B3 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B3b fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B3c fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style B4 fill:#1e3a5f,stroke:#569CD6,color:#d4d4d4
    style P1 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P2 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P3 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P4 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
    style P5 fill:#3a2d1e,stroke:#DCDCAA,color:#d4d4d4
Loading
Key Metric Value Status
Python versions 2.7, 3.5 ~ 3.14
Decompilation architecture Phase 7 annotation-first + pattern-catalog 🚀
Full baseline 1325/1325 (100%), 0 crashes, 0 orphans
CLI --seq-blocks (default) / --no-seq-blocks (fallback)
Whitebox pass rate 298/405 (73%) 🔄
Test report test_data/whitebox_report_*.md (per-run)
Design docs Overall v2.8 / Detailed v2.7 / Pattern catalog v1.0 📖
GUI Avalonia dark + drag-drop + syntax highlight + .py comparison
Cross-platform Windows / macOS / Linux (via GitHub Actions)

Remaining Issues (Priority-Ordered)

Priority Issue Count Root Cause Target
P0 EMPTY_TRY 56 Try body range calculation, SETUP_FINALLY handler shares seqBlock ↓30
P0 TRY_NO_HANDLER 19 Handler preamble detection incomplete (POP_TOP×3 pattern) ↓10
P1 BARE_EXPR 83 Intermediate expression leakage (comprehension variables, class attrs, match patterns) ↓50
P2 REDUNDANT_PASS/RAISE/RETURN 68 Post-processing filter incomplete ↓40
P2 SYNTAX_ERROR 14 3.5-3.7 comprehension differences, large file boundaries ↓10
P3 CLEANUP_LEAK 7 Handler cleanup e = None leakage ↓5
Total 258 +40~+60 expected

See overall design, detailed design, and control block patterns for details.


Milestones

🏆 Phase 4 P0-1 — Function Definitions (def)

From name_0 = CodeObject: <module> to def factorial(n): — the project's first correct Python function definitions:

# Before (Phase 3):
name_0 = CodeObject: <module> (5 instrs)    ← garbage

# After (P0-1):
def greet(name):                              ← ✅
def add(a, b):                                ← ✅
def factorial(n):                             ← ✅
def abstractmethod(funcobj):                  ← ✅
    pass

🏆 9-Layer Pagoda Test

New test_nested_depth_9.py — 4 functions with 9 levels of mixed nesting, compiled against 11 Python versions:

  • nine_level_if_for_while_try — if > for > while > try mirror
  • nine_level_try_except_finally — 9-level try-except-finally
  • nine_level_all_control — mixed if/elif/else + for + while + try
  • nine_level_deep_assign — 9-level if assignment chain

🏆 Full Version Matrix

Suite Versions Pass
Lv0_Expressions 2.7 → 3.14 11/11 ✅
Lv1_Sequential 2.7 → 3.14 11/11 ✅
Lv2_ControlFlow 2.7 → 3.14 11/11 ✅
Lv3_NestedDepth 2.7 → 3.14 11/11 ✅
Lv3_NestedMixed 2.7 → 3.14 11/11 ✅
Lv3_NestedMatrix 2.7 → 3.14 11/11 ✅
Lv3-1_NestedDepth9 2.7 → 3.14 11/11 ✅

8 marshal 3.11+ Fixes

Phase 4 P0-1 discovered fundamental marshal format changes in Python 3.11+:

# Problem Fix Effect
1 3.11+ removed varnames/freevars/cellvars localsplusnames + localspluskinds Field alignment
2 localspluskinds stored as TYPE_STRING(0x73) Use ReadRawMarshalBytes Avoid 0x73→CODE_SIMPLE EOF
3 ReadRawMarshalBytes no ref slot FLAG_REF pre-reservation Ref index alignment
4 Container FLAG_REF unhandled Container reservation + fill Correct co_names index
5 exceptiontable uses TYPE_REF(0x72) PEEK check + read TYPE_REF 5 bytes preserved
6 0x73 in names treated as CODE_SIMPLE ReadOneMarshalString Names non-empty
7 HandleUnknownMarshalType type<4 jumps to EOF Return null, no skip Harmless pass-through
8 MAKE_FUNCTION in 3.12 pops only 1 item _isPython312 + pop 1 Class body correct

Key Finding: Python 3.11+ marshal Code Object format

v3.10- format:                v3.11+ format:
  argcount                     argcount
  posonlyargcount              posonlyargcount
  kwonlyargcount               kwonlyargcount
  nlocals                      stacksize
  stacksize                    flags
  flags                        code (bytecodes)
  code (bytecodes)              consts
  consts                       names
  names                        localsplusnames (merged varnames+freevars+cellvars)
  varnames                     localspluskinds (0x20=local 0x40=cell 0x80=free)
  freevars                     filename
  cellvars                     name
  filename                     qualname ← NEW
  name                         firstlineno
  firstlineno                  linetable ← NEW, replaces lnotab
  lnotab                       exceptiontable ← NEW

Design Philosophy

⚠️ Clarifying common misconceptions: The sections below explicitly document architectural facts. External analyses (e.g. AI-generated reports) have incorrectly claimed "template string concatenation," "missing CFG + dominator tree," or "mixed version paths" — because they didn't inspect the source. Each section below provides file paths to the actual implementation for direct verification.

🧱 Block-Level Fault Tolerance (Core Innovation)

Traditional decompilers (pycdc, uncompyle6, decompyle3) use monolithic compilation — one unsupported instruction crashes the entire file. PyRebuilderSharp decompiles each basic block independently:

Block B1 → Stack Machine → AST → "x = a + b"     ✅
Block B2 → Stack Machine → AST → "return x"      ✅
Block B3 → Stack Machine → ❌ Exception → comment  ⚠️
Block B4 → Stack Machine → AST → "y = 42"        ✅

Result: One block failure never zeroes the file. The decompiler always outputs the maximum recoverable Python source.

🏗️ Full CFG + Dominator Tree (not linear scanning)

Phase 2's BlockScanner starts with linear scanning for block splitting, but Phase 3's ControlFlowScanner builds a complete control flow graph and runs dominator tree analysis — this is the core architectural fact most external analyses miss:

bytecode → BlockScanner → ControlFlow(CFG)
  → ComputeImmediateDominators()   ← immediate dominator tree
  → ComputeDominators()            ← full dominator sets
  → DetectNaturalLoops()           ← natural loop detection (back-edge → dominator)
  → StructuredCFG                  ← structured control flow
  → AstBuilder(AST)                ← recursive successor traversal

Key files: Scanners/ControlFlowScanner.cs (302-line full implementation), Models/CFG/ControlFlowGraph.cs, Models/CFG/BasicBlock.cs (with predecessor/successor/exception edges).

🌲 Explicit AST Intermediate Representation (not string concatenation)

Decompiled output is not produced via instruction→template string concatenation. It goes through a complete C# record AST tree + visitor-pattern code generation:

Each block → StackMachine.Execute() → AST nodes (Stmt/Expr)
  → AstBuilder assembles control structure AST
  → PythonCodeGenerator.Visit()     ← visitor pattern
  → formatted Python source

The AST model lives in Models/AST/ with 60+ node types covering Python 2.7~3.14 syntax:

  • Comprehensions: ListComp / SetComp / DictComp / GeneratorExp
  • f-strings: FormattedValue + JoinedStr
  • Walrus operator: NamedExpr
  • match/case: 6 MatchPattern subtypes + Match statement ✅

🔬 AST Semantic Comparison (stronger than compile verification)

Tests use token-level semantic comparison — decompiled code passes if semantically equivalent, not character-by-character identical. This is a finer-grained verification than compile(source, '<exec>') syntax checking: it detects semantic drift that syntax-only checks miss.

🧩 Modular Pipeline (with full dependency separation)

.pyc
  → PycReader(marshal)              ← 7 isolated version strategies
  → BlockScanner(block splitting)   ← jump-target partitioning
  → ControlFlowScanner(CFG+tree)    ← CFG + dominator + natural loops
  → AstBuilder(AST+fault tolerance) ← successor traversal + 7 post-processing passes
  → PythonCodeGenerator(code gen)   ← visitor-pattern traversal
  → Python source

🔀 Full Version Isolation (per-version strategy files)

Each Python major version's differences are encapsulated in independent VersionStrategy classes:

Strategy Versions Key Differences
VersionStrategy27 2.7 No PEP552, no WORD_OFFSET, marshal TYPE_STRINGREF
VersionStrategyPre311 3.5~3.10 Traditional marshal, SETUP_* instructions, no ExceptionTable
VersionStrategy311 3.11 localsplus, ExceptionTable, CACHE instructions
VersionStrategy312 3.12 CALL=171, RESUME=151, full CACHE
VersionStrategy313 3.13 Additional opcode adjustments
VersionStrategy314 3.14 Latest support

Each strategy maps raw opcodes to a unified Opcode enum via MapOpcode() — core AST construction is version-agnostic.

⚙️ StackMachine + Expression Folding (not simple slot mapping)

StackMachine is a full stack simulator (not a variable-slot mapper), with:

  • Expression folding: LOAD_CONST func + CALL_FUNCTION → infer @decorator
  • Comprehension conversion: ConvertComprehensionCalls → ListComp/SetComp/DictComp
  • Augmented assignment folding: ConvertAugAssigni = i + 1i += 1
  • Dead code elimination: TrimPostTerminalDeadCode + CollapseRedundantPasses
  • Function body repair: PostProcessFunctionDefs + FixEmptyFunctionBodies
  • Nested CodeObject recursion: ConvertChildCodesToFunctionDefs + DecompileNestedCodeObjects

Project Structure

PyRebuilderSharp.slnx
├── src/                    # Source code (Core + CLI + GUI)
├── tests/                  # 109 xUnit tests
├── tools/                  # Compilation scripts
└── docs/                   # 11 technical documents

Quick Start

# Build
dotnet build -c Release

# Run GUI
dotnet run --project src/PyRebuilderSharp.Gui -c Release

# Run tests
dotnet test tests/PyRebuilderSharp.Tests -c Release

# Version matrix
dotnet test --filter "Lv3"
dotnet test --filter "Lv3-1"
dotnet test --filter "Matrix"

See quick_start.md for detailed instructions.


Documentation

Document Description
Overall Design v2.6 — Architecture, core principles (Chinese)
Detailed Design v2.5 — Module design, API reference (Chinese)
Testing Baseline v2.1 — Test benchmarks & version matrix
Control Block Patterns 7 categories, 28 sub-patterns
pyc Format Reference Python marshal format reference
Benchmark Report 🤖 Cross-tool comparison: uncompyle6 / decompyle3 / pycdc
Quick Start Build, run, and test instructions

PyRebuilderSharp — Block-by-block Python bytecode decompiler.

Fault tolerance at every block. One block's failure never silences the entire file.

🇨🇳 中文 | 🇬🇧 Back to top

About

Block-by-block reconstruction, complete restoration; block-level fault tolerance · ultimate compression of failure rate · a Python 2.7 to 3.14 bytecode decompiler more controllable than AI — built on .NET 10 + Avalonia UI for cross-platform support逐块重建,完整还原; 块级容错 · 极致压缩失败率 · 比AI更可控的Python 2.7--3.14 字节码反编译器 —— 基于 .NET 10 + Avalonia UI 跨平台

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages