unidecompiler-plugin-python-pyc 0.1.1__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/PKG-INFO +2 -2
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/pyproject.toml +2 -2
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc/lifter.py +2 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc/pyc.py +65 -4
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc.egg-info/PKG-INFO +2 -2
- unidecompiler_plugin_python_pyc-0.1.2/src/unidecompiler_plugin_python_pyc.egg-info/requires.txt +1 -0
- unidecompiler_plugin_python_pyc-0.1.1/src/unidecompiler_plugin_python_pyc.egg-info/requires.txt +0 -1
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/README.md +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/setup.cfg +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc/__init__.py +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc/plugin.py +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc/simulation.py +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc/support.py +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc.egg-info/SOURCES.txt +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc.egg-info/dependency_links.txt +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc.egg-info/entry_points.txt +0 -0
- {unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/src/unidecompiler_plugin_python_pyc.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unidecompiler-plugin-python-pyc
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python bytecode frontend plugin for unidecompiler
|
|
5
5
|
Author-email: Wker <1670133844@qq.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/Wker666/unidecompiler
|
|
|
9
9
|
Project-URL: Issues, https://github.com/Wker666/unidecompiler/issues
|
|
10
10
|
Requires-Python: >=3.11
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: unidecompiler<0.2.0,>=0.1.
|
|
12
|
+
Requires-Dist: unidecompiler<0.2.0,>=0.1.2
|
|
13
13
|
|
|
14
14
|
# unidecompiler-plugin-python-pyc
|
|
15
15
|
|
{unidecompiler_plugin_python_pyc-0.1.1 → unidecompiler_plugin_python_pyc-0.1.2}/pyproject.toml
RENAMED
|
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "unidecompiler-plugin-python-pyc"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Python bytecode frontend plugin for unidecompiler"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "AGPL-3.0-or-later"
|
|
11
11
|
authors = [{ name = "Wker", email = "1670133844@qq.com" }]
|
|
12
12
|
requires-python = ">=3.11"
|
|
13
|
-
dependencies = ["unidecompiler>=0.1.
|
|
13
|
+
dependencies = ["unidecompiler>=0.1.2,<0.2.0"]
|
|
14
14
|
|
|
15
15
|
[project.urls]
|
|
16
16
|
Homepage = "https://github.com/Wker666/unidecompiler"
|
|
@@ -79,6 +79,7 @@ from unidecompiler.core.vm_function import (
|
|
|
79
79
|
from unidecompiler.core.vm_bytecode import VMBytecodeStep
|
|
80
80
|
from unidecompiler.core.vm_hints import VMHint
|
|
81
81
|
from unidecompiler.core.vm_operands import VMDecodedInstruction, VMOperand
|
|
82
|
+
from unidecompiler.provenance import ByteRange
|
|
82
83
|
from unidecompiler.core.vm_region import (
|
|
83
84
|
VMLinearState,
|
|
84
85
|
VMRegionCallbacks,
|
|
@@ -811,6 +812,7 @@ def _python_decoded_instruction(instruction, source: SourceRef) -> VMDecodedInst
|
|
|
811
812
|
source=source,
|
|
812
813
|
operands=tuple(operands),
|
|
813
814
|
raw=_raw_instruction_line(instruction),
|
|
815
|
+
artifact_range=(None if instruction.artifact_offset is None or instruction.size is None else ByteRange(instruction.artifact_offset, instruction.size)),
|
|
814
816
|
)
|
|
815
817
|
|
|
816
818
|
|
|
@@ -24,6 +24,8 @@ class PycInstruction:
|
|
|
24
24
|
argval: object
|
|
25
25
|
argrepr: str
|
|
26
26
|
starts_line: int | None
|
|
27
|
+
artifact_offset: int | None = None
|
|
28
|
+
size: int | None = None
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
@dataclass(frozen=True)
|
|
@@ -51,6 +53,7 @@ class PycCodeObject:
|
|
|
51
53
|
instructions: tuple[PycInstruction, ...]
|
|
52
54
|
exception_regions: tuple[PycExceptionRegion, ...]
|
|
53
55
|
children: tuple["PycCodeObject", ...]
|
|
56
|
+
artifact_code_offset: int | None = None
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
@dataclass(frozen=True)
|
|
@@ -85,17 +88,19 @@ def decode_pyc(data: bytes, filename: str | None = None) -> PycModule:
|
|
|
85
88
|
return PycModule(
|
|
86
89
|
magic=data[:4],
|
|
87
90
|
flags=flags,
|
|
88
|
-
code=_decode_code_object(code),
|
|
91
|
+
code=_decode_code_object(code, _marshal_code_offsets(data, code)),
|
|
89
92
|
filename=filename,
|
|
90
93
|
)
|
|
91
94
|
|
|
92
95
|
|
|
93
|
-
def _decode_code_object(code: types.CodeType) -> PycCodeObject:
|
|
96
|
+
def _decode_code_object(code: types.CodeType, code_offsets: dict[int, int]) -> PycCodeObject:
|
|
94
97
|
children = tuple(
|
|
95
|
-
_decode_code_object(const)
|
|
98
|
+
_decode_code_object(const, code_offsets)
|
|
96
99
|
for const in code.co_consts
|
|
97
100
|
if isinstance(const, types.CodeType)
|
|
98
101
|
)
|
|
102
|
+
instructions = tuple(dis.get_instructions(code))
|
|
103
|
+
code_start = code_offsets.get(id(code))
|
|
99
104
|
return PycCodeObject(
|
|
100
105
|
name=code.co_name,
|
|
101
106
|
argcount=code.co_argcount,
|
|
@@ -119,8 +124,10 @@ def _decode_code_object(code: types.CodeType) -> PycCodeObject:
|
|
|
119
124
|
argval=instruction.argval,
|
|
120
125
|
argrepr=instruction.argrepr,
|
|
121
126
|
starts_line=instruction.starts_line,
|
|
127
|
+
artifact_offset=None if code_start is None else code_start + instruction.offset,
|
|
128
|
+
size=None if code_start is None else _instruction_size(instructions, index, len(code.co_code)),
|
|
122
129
|
)
|
|
123
|
-
for instruction in
|
|
130
|
+
for index, instruction in enumerate(instructions)
|
|
124
131
|
),
|
|
125
132
|
exception_regions=tuple(
|
|
126
133
|
PycExceptionRegion(
|
|
@@ -133,4 +140,58 @@ def _decode_code_object(code: types.CodeType) -> PycCodeObject:
|
|
|
133
140
|
for entry in dis.Bytecode(code).exception_entries
|
|
134
141
|
),
|
|
135
142
|
children=children,
|
|
143
|
+
artifact_code_offset=code_start,
|
|
136
144
|
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _instruction_size(instructions: tuple[dis.Instruction, ...], index: int, code_size: int) -> int:
|
|
148
|
+
next_offset = instructions[index + 1].offset if index + 1 < len(instructions) else code_size
|
|
149
|
+
return next_offset - instructions[index].offset
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _marshal_code_offsets(data: bytes, root: types.CodeType) -> dict[int, int]:
|
|
153
|
+
"""Find only unambiguous marshal byte-string records for ``co_code`` values.
|
|
154
|
+
|
|
155
|
+
CPython serializes code bytes as a marshal ``TYPE_STRING`` record. The
|
|
156
|
+
frontend verifies both that record's tag and its length, then accepts a
|
|
157
|
+
location only when that code byte sequence has exactly one candidate. A
|
|
158
|
+
repeated or otherwise ambiguous value is deliberately left unmapped.
|
|
159
|
+
"""
|
|
160
|
+
code_objects = tuple(_walk_code_objects(root))
|
|
161
|
+
candidates: dict[bytes, list[int]] = {}
|
|
162
|
+
for code in code_objects:
|
|
163
|
+
payload = code.co_code
|
|
164
|
+
if payload in candidates:
|
|
165
|
+
continue
|
|
166
|
+
candidates[payload] = _marshal_string_payload_offsets(data, payload)
|
|
167
|
+
assigned: set[int] = set()
|
|
168
|
+
offsets: dict[int, int] = {}
|
|
169
|
+
for code in code_objects:
|
|
170
|
+
matches = [offset for offset in candidates[code.co_code] if offset not in assigned]
|
|
171
|
+
if len(matches) == 1:
|
|
172
|
+
offsets[id(code)] = matches[0]
|
|
173
|
+
assigned.add(matches[0])
|
|
174
|
+
return offsets
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _walk_code_objects(code: types.CodeType):
|
|
178
|
+
yield code
|
|
179
|
+
for value in code.co_consts:
|
|
180
|
+
if isinstance(value, types.CodeType):
|
|
181
|
+
yield from _walk_code_objects(value)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _marshal_string_payload_offsets(data: bytes, payload: bytes) -> list[int]:
|
|
185
|
+
if not payload:
|
|
186
|
+
return []
|
|
187
|
+
result: list[int] = []
|
|
188
|
+
size = len(payload)
|
|
189
|
+
for header in range(PYC_MIN_HEADER_SIZE, len(data) - size - 4):
|
|
190
|
+
if (data[header] & 0x7F) != ord("s"):
|
|
191
|
+
continue
|
|
192
|
+
if int.from_bytes(data[header + 1 : header + 5], "little", signed=True) != size:
|
|
193
|
+
continue
|
|
194
|
+
start = header + 5
|
|
195
|
+
if data[start : start + size] == payload:
|
|
196
|
+
result.append(start)
|
|
197
|
+
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unidecompiler-plugin-python-pyc
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Python bytecode frontend plugin for unidecompiler
|
|
5
5
|
Author-email: Wker <1670133844@qq.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -9,7 +9,7 @@ Project-URL: Repository, https://github.com/Wker666/unidecompiler
|
|
|
9
9
|
Project-URL: Issues, https://github.com/Wker666/unidecompiler/issues
|
|
10
10
|
Requires-Python: >=3.11
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
|
-
Requires-Dist: unidecompiler<0.2.0,>=0.1.
|
|
12
|
+
Requires-Dist: unidecompiler<0.2.0,>=0.1.2
|
|
13
13
|
|
|
14
14
|
# unidecompiler-plugin-python-pyc
|
|
15
15
|
|
unidecompiler_plugin_python_pyc-0.1.2/src/unidecompiler_plugin_python_pyc.egg-info/requires.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
unidecompiler<0.2.0,>=0.1.2
|
unidecompiler_plugin_python_pyc-0.1.1/src/unidecompiler_plugin_python_pyc.egg-info/requires.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
unidecompiler<0.2.0,>=0.1.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|