Metadata-Version: 2.4
Name: pyc-revive
Version: 1.0.0
Summary: Stdlib-only .pyc -> .py reconstructor with native and pycdas backends
Author: opsecalyzer
License: MIT
Project-URL: Homepage, https://github.com/opsecalyzer/pyc_revive
Project-URL: Source, https://github.com/opsecalyzer/pyc_revive
Keywords: pyc,decompiler,bytecode,reverse-engineering,malware-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Disassemblers
Classifier: Operating System :: OS Independent
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# pyc_revive

`.pyc` -> `.py` reconstructor. no uncompyle6. no pycdc. no xdis.

## use

```bash
python -m pyc_revive my file.pyc
python -m pyc_revive ./dist/app.pyc --out ./revived.py
```

input handling: exact path, spaces with no quotes, basename search in
cwd + all subfolders + parent folder.

## versions

every CPython from 2.0 through 3.15 resolves by magic number
(`pymagic.py`, full table + nearest fallback + header sizes).

two backends, one pipeline:

- native: `.pyc` matches the running interpreter. stdlib marshal loads
  the code object, stdlib dis disassembles. zero dependencies.
- pycdas: anything else. the bundled `pycdas.exe` disassembles the
  foreign version, `pycdas_parser.py` parses the dump into code trees,
  `shim.py` adapts them to the pipeline. everything downstream
  (normalize, segment, translate, CFG, emit, verify x3) runs unchanged.

## pipeline

1. find file (`finder.py`)
2. detect version via magic (`pymagic.py`)
3. load: native marshal, else pycdas backend (`loader.py`,
   `pycdas_parser.py`, `shim.py`)
4. disassemble + abstract (`bytecode.py`: `Inst`, `EditableBytecode`,
   opcode/oparg/value-stack/metadata tables)
5. normalize / mask consts + names (`normalizer.py`)
6. opcode-aware B/I/E segmentation (`segmenter.py`)
7. statement translation (`translator.py`: stack machine, defaults
   recovery, lambdas inline, 2.x print/exec/class ops)
8. control-flow graph from jumps (`cfg.py`: if/for/while/try/except-as
   (bare `except:` too)/with/finally, clauses + clusters, 3.11+
   exception table, SETUP-region splits)
9. emit + repairs (`emitter.py`: source-order splicing onto def/class
   stub lines, bases recovery, `@decorator` restore, `global` decls,
   cond chains, ternaries, nested if/else, loop ranges, break/continue
   recovery, indent + suite-guard passes)
10. equivalence verify, 3 sweeps (`verifier.py`: recompile revived source,
    compare opcode structure, repair, repeat x3)

## layout

```
pyc_revive/
  finder.py  pymagic.py  loader.py  pycdas_parser.py  shim.py
  bytecode.py  normalizer.py  segmenter.py  translator.py  cfg.py
  emitter.py  verifier.py  reconstructor.py  cli.py  __main__.py
  pycdas.exe  README.md  requirements.txt
```

## known limits

- inline comprehensions/genexps render as `func(...)` placeholders.
- `try` bodies that fall through into always-run handlers keep flat
  order instead of guarded flow.
- exotic decorators reduce to bare defs; exotic call shapes degrade to
  commented disassembly rather than failing.
- pre-3.8 default-argument recovery is best-effort (flag-style MAKE
  from 3.8+ recovers exactly).
- verifier scores dip across versions: opcode sets drift between
  releases, so cross-version similarity reads lower than same-version.
