pyprivate-obf 1.0.0__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.
- pyprivate_obf-1.0.0/LICENSE +28 -0
- pyprivate_obf-1.0.0/PKG-INFO +347 -0
- pyprivate_obf-1.0.0/README.md +292 -0
- pyprivate_obf-1.0.0/pyprivate_obf/__init__.py +18 -0
- pyprivate_obf-1.0.0/pyprivate_obf/__main__.py +4 -0
- pyprivate_obf-1.0.0/pyprivate_obf/cli.py +476 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encoding_methods/__init__.py +5 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encoding_methods/bytecode_obfuscation.py +83 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encoding_methods/cpython_obfuscation.py +111 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encoding_methods/encode_strings.py +129 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encoding_methods/simple_marshal.py +12 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encryption/__init__.py +0 -0
- pyprivate_obf-1.0.0/pyprivate_obf/encryption/script.py +52 -0
- pyprivate_obf-1.0.0/pyprivate_obf/layers/__init__.py +7 -0
- pyprivate_obf-1.0.0/pyprivate_obf/layers/base.py +18 -0
- pyprivate_obf-1.0.0/pyprivate_obf/layers/check_version.py +31 -0
- pyprivate_obf-1.0.0/pyprivate_obf/layers/enter_channel.py +78 -0
- pyprivate_obf-1.0.0/pyprivate_obf/layers/expiry_time.py +27 -0
- pyprivate_obf-1.0.0/pyprivate_obf/layers/libraries_installer.py +34 -0
- pyprivate_obf-1.0.0/pyprivate_obf.egg-info/PKG-INFO +347 -0
- pyprivate_obf-1.0.0/pyprivate_obf.egg-info/SOURCES.txt +25 -0
- pyprivate_obf-1.0.0/pyprivate_obf.egg-info/dependency_links.txt +1 -0
- pyprivate_obf-1.0.0/pyprivate_obf.egg-info/entry_points.txt +2 -0
- pyprivate_obf-1.0.0/pyprivate_obf.egg-info/requires.txt +3 -0
- pyprivate_obf-1.0.0/pyprivate_obf.egg-info/top_level.txt +1 -0
- pyprivate_obf-1.0.0/pyproject.toml +42 -0
- pyprivate_obf-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 pooraddyy
|
|
4
|
+
Original Py Private tool Copyright (c) PSH Team (t.me/psh_team)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
This project is a Python reconstruction of the Py Private v4.1.2 Android
|
|
17
|
+
application originally created by the PSH Team. All obfuscation algorithms,
|
|
18
|
+
guard logic, and the CPython/Cython-based compilation approach are derived
|
|
19
|
+
from the original work of PSH Team. This package does not claim original
|
|
20
|
+
authorship of those techniques.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyprivate-obf
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python source obfuscator — encode strings, bytecode, and CPython C compilation
|
|
5
|
+
License: MIT License
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2025 pooraddyy
|
|
8
|
+
Original Py Private tool Copyright (c) PSH Team (t.me/psh_team)
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
This project is a Python reconstruction of the Py Private v4.1.2 Android
|
|
21
|
+
application originally created by the PSH Team. All obfuscation algorithms,
|
|
22
|
+
guard logic, and the CPython/Cython-based compilation approach are derived
|
|
23
|
+
from the original work of PSH Team. This package does not claim original
|
|
24
|
+
authorship of those techniques.
|
|
25
|
+
|
|
26
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
27
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
28
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
29
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
30
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
31
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
32
|
+
SOFTWARE.
|
|
33
|
+
|
|
34
|
+
Project-URL: Homepage, https://github.com/pooraddyy/pyprivate
|
|
35
|
+
Project-URL: Repository, https://github.com/pooraddyy/pyprivate
|
|
36
|
+
Project-URL: Issues, https://github.com/pooraddyy/pyprivate/issues
|
|
37
|
+
Keywords: obfuscation,python,bytecode,cython,protection
|
|
38
|
+
Classifier: Development Status :: 4 - Beta
|
|
39
|
+
Classifier: Intended Audience :: Developers
|
|
40
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
41
|
+
Classifier: Programming Language :: Python :: 3
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
47
|
+
Classifier: Topic :: Security
|
|
48
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
49
|
+
Requires-Python: >=3.9
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
License-File: LICENSE
|
|
52
|
+
Provides-Extra: cpython
|
|
53
|
+
Requires-Dist: cython>=0.29; extra == "cpython"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
<div align="center">
|
|
57
|
+
|
|
58
|
+
<h1>PyPrivate-Obf</h1>
|
|
59
|
+
|
|
60
|
+
<p>A Python source obfuscator reconstructed from the <strong>Py Private</strong> Android application.<br>
|
|
61
|
+
The original author and owner of this encoder is the <strong>PSH Team</strong> — <a href="https://t.me/psh_team">t.me/psh_team</a>.<br>
|
|
62
|
+
This repository is a reverse-engineered Python reconstruction of their work from the APK source.</p>
|
|
63
|
+
|
|
64
|
+
<a href="https://pypi.org/project/pyprivate-obf"><img src="https://img.shields.io/pypi/v/pyprivate-obf?color=blue&label=PyPI" alt="PyPI"></a>
|
|
65
|
+
<a href="https://pypi.org/project/pyprivate-obf"><img src="https://img.shields.io/pypi/pyversions/pyprivate-obf" alt="Python"></a>
|
|
66
|
+
<img src="https://img.shields.io/github/license/pooraddyy/pyprivate" alt="License">
|
|
67
|
+
<img src="https://img.shields.io/pypi/dm/pyprivate-obf?label=downloads" alt="Downloads">
|
|
68
|
+
|
|
69
|
+
<br><br>
|
|
70
|
+
|
|
71
|
+
<a href="#installation"><kbd>Installation</kbd></a>
|
|
72
|
+
|
|
73
|
+
<a href="#cli-usage"><kbd>CLI Usage</kbd></a>
|
|
74
|
+
|
|
75
|
+
<a href="#encoding-methods"><kbd>Encoders</kbd></a>
|
|
76
|
+
|
|
77
|
+
<a href="#guard-layers"><kbd>Guards</kbd></a>
|
|
78
|
+
|
|
79
|
+
<a href="#python-api"><kbd>Python API</kbd></a>
|
|
80
|
+
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
## CLI Preview
|
|
84
|
+
|
|
85
|
+
<div align="center">
|
|
86
|
+
<img src="img/1.jpeg" alt="pyprivate-obf CLI demo" width="820">
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Installation
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install pyprivate-obf
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
To use **CPython obfuscation** (Cython + GCC compilation), also install:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install cython
|
|
101
|
+
|
|
102
|
+
# Debian / Ubuntu
|
|
103
|
+
sudo apt install gcc python3-dev
|
|
104
|
+
|
|
105
|
+
# Termux
|
|
106
|
+
pkg install clang python-dev
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## CLI Usage
|
|
112
|
+
|
|
113
|
+
### Interactive wizard
|
|
114
|
+
|
|
115
|
+
Run without any arguments to get a step-by-step menu:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
pyprivate-obf
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Or force interactive mode explicitly:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
pyprivate-obf --interactive
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Non-interactive (flags)
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
pyprivate-obf <input.py> [OPTIONS] [-o output.py]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
<details>
|
|
134
|
+
<summary><strong>All available flags</strong></summary>
|
|
135
|
+
|
|
136
|
+
| Flag | Description |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `--encode-strings` | Replace every string literal with `bytes([...]).decode()` |
|
|
139
|
+
| `--bytecode` | Marshal bytecode + opcode-pattern swap |
|
|
140
|
+
| `--cpython` | Cython `--embed` → C source → GCC native binary launcher |
|
|
141
|
+
| `--layers N` | Number of marshal layers to apply (default: 1, max: 20) |
|
|
142
|
+
| `--re-check-version` | Re-prepend Python version guard inside every layer |
|
|
143
|
+
| `--expiry "YYYY-MM-DD HH:MM:SS.000000"` | Add an expiry date guard |
|
|
144
|
+
| `--expiry-message "..."` | Message shown when expired (default: "This file has expired.") |
|
|
145
|
+
| `--pip PKG1 PKG2 ...` | Auto-install packages on first run |
|
|
146
|
+
| `--check-version` | Lock script to the current Python major.minor version |
|
|
147
|
+
| `--telegram-bot-token TOKEN` | Telegram channel guard — bot token |
|
|
148
|
+
| `--telegram-channel-id @channel` | Telegram channel guard — channel id |
|
|
149
|
+
| `-o / --output FILE` | Output file path (default: `<input>.enc.py`) |
|
|
150
|
+
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
### Examples
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Encode strings + 3 bytecode layers
|
|
157
|
+
pyprivate-obf script.py --encode-strings --bytecode --layers 3
|
|
158
|
+
|
|
159
|
+
# CPython (native binary) obfuscation
|
|
160
|
+
pyprivate-obf script.py --cpython
|
|
161
|
+
|
|
162
|
+
# Add an expiry date
|
|
163
|
+
pyprivate-obf script.py --bytecode --expiry "2025-12-31 23:59:59.000000"
|
|
164
|
+
|
|
165
|
+
# Auto-install dependencies on first run
|
|
166
|
+
pyprivate-obf script.py --bytecode --pip requests numpy pillow
|
|
167
|
+
|
|
168
|
+
# Lock to current Python version
|
|
169
|
+
pyprivate-obf script.py --bytecode --check-version
|
|
170
|
+
|
|
171
|
+
# Telegram channel membership gate
|
|
172
|
+
pyprivate-obf script.py --bytecode \
|
|
173
|
+
--telegram-bot-token 123456:ABCdef \
|
|
174
|
+
--telegram-channel-id @mychannel
|
|
175
|
+
|
|
176
|
+
# Chain everything with a custom output path
|
|
177
|
+
pyprivate-obf script.py --encode-strings --bytecode --layers 2 \
|
|
178
|
+
--check-version -o protected.py
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Encoding Methods
|
|
184
|
+
|
|
185
|
+
There are four independent encoding methods. They live in `pyprivate_obf/encoding_methods/` and each one accepts a `source: str` and returns an obfuscated `str`.
|
|
186
|
+
|
|
187
|
+
### `encode_strings`
|
|
188
|
+
|
|
189
|
+
Rewrites every string literal in the source as `bytes([...]).decode()`.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pyprivate-obf script.py --encode-strings
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Before:
|
|
196
|
+
```python
|
|
197
|
+
print("hello world")
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
After:
|
|
201
|
+
```python
|
|
202
|
+
print(bytes([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]).decode())
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### `bytecode_obfuscation`
|
|
208
|
+
|
|
209
|
+
Compiles the source, serialises it with `marshal`, then swaps a known opcode pattern in the bytecode so it cannot be cleanly disassembled with stock `dis`. Output format:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
import marshal
|
|
213
|
+
exec(marshal.loads(b'...'))
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pyprivate-obf script.py --bytecode
|
|
218
|
+
pyprivate-obf script.py --bytecode --layers 5 # 5 nested marshal layers
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### `cpython_obfuscation`
|
|
224
|
+
|
|
225
|
+
Compiles the source to C using Cython `--embed`, strips the compressed string-table sections so only clean ASCII C code remains, then wraps it in a Python launcher that writes the `.c` file to `.py_private/<timestamp>`, compiles it with GCC, and runs the native binary.
|
|
226
|
+
|
|
227
|
+
Requires: `cython` (pip) + `gcc` + Python headers.
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
pyprivate-obf script.py --cpython
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The output `.py` file contains only the clean C source as a plain string — no binary or base64 data.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### `simple_marshal`
|
|
238
|
+
|
|
239
|
+
Plain `marshal` wrap with no opcode swap. Used as a fallback when no encoding method is selected, and in DEBUG mode.
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# applied automatically when no --bytecode / --cpython flag is given
|
|
243
|
+
pyprivate-obf script.py
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Guard Layers
|
|
249
|
+
|
|
250
|
+
Guards are injected at the top of the output script before encoding. Multiple guards can be combined.
|
|
251
|
+
|
|
252
|
+
### Expiry Time
|
|
253
|
+
|
|
254
|
+
Refuses to run after a given date and time.
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
pyprivate-obf script.py --expiry "2025-06-30 23:59:59.000000"
|
|
258
|
+
pyprivate-obf script.py --expiry "2025-06-30 23:59:59.000000" --expiry-message "License expired."
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Python Version Lock
|
|
262
|
+
|
|
263
|
+
Refuses to run on any Python version other than the one used to obfuscate.
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
pyprivate-obf script.py --check-version
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Pip Installer
|
|
270
|
+
|
|
271
|
+
Auto-installs missing packages on first run.
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
pyprivate-obf script.py --pip requests numpy pillow
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Telegram Channel Guard
|
|
278
|
+
|
|
279
|
+
Verifies that the user has joined a Telegram channel before allowing execution.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
pyprivate-obf script.py \
|
|
283
|
+
--telegram-bot-token 123456:ABCxyz \
|
|
284
|
+
--telegram-channel-id @mychannel
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Python API
|
|
290
|
+
|
|
291
|
+
Use the encoders and guards directly from Python:
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
from pyprivate_obf import encode_strings, bytecode_obfuscation
|
|
295
|
+
from pyprivate_obf import ExpiryTime, CheckVersion, LibrariesInstaller, EnterChannel
|
|
296
|
+
|
|
297
|
+
source = open("script.py").read()
|
|
298
|
+
|
|
299
|
+
# Encode strings
|
|
300
|
+
source = encode_strings(source)
|
|
301
|
+
|
|
302
|
+
# Bytecode obfuscation
|
|
303
|
+
source = bytecode_obfuscation(source)
|
|
304
|
+
|
|
305
|
+
# CPython obfuscation (requires cython + gcc)
|
|
306
|
+
from pyprivate_obf.encoding_methods.cpython_obfuscation import cpython_obfuscation
|
|
307
|
+
source = cpython_obfuscation(source)
|
|
308
|
+
|
|
309
|
+
# Add expiry guard
|
|
310
|
+
source = ExpiryTime(
|
|
311
|
+
time="2025-12-31 23:59:59.000000",
|
|
312
|
+
message="This script has expired."
|
|
313
|
+
).get_new_source(source)
|
|
314
|
+
|
|
315
|
+
# Add pip installer guard
|
|
316
|
+
source = LibrariesInstaller(
|
|
317
|
+
package_names=["requests", "numpy"]
|
|
318
|
+
).get_new_source(source)
|
|
319
|
+
|
|
320
|
+
# Add Python version lock
|
|
321
|
+
source = CheckVersion().get_new_source(source)
|
|
322
|
+
|
|
323
|
+
# Add Telegram channel guard
|
|
324
|
+
source = EnterChannel(
|
|
325
|
+
bot_token="123456:ABCxyz",
|
|
326
|
+
channel_id="@mychannel"
|
|
327
|
+
).get_new_source(source)
|
|
328
|
+
|
|
329
|
+
with open("protected.py", "w") as f:
|
|
330
|
+
f.write(source)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Credits
|
|
336
|
+
|
|
337
|
+
This project is a reverse-engineered Python reconstruction of the **Py Private v4.1.2** Android application.
|
|
338
|
+
|
|
339
|
+
The original encoder was authored by the **PSH Team**: [t.me/psh_team](https://t.me/psh_team)
|
|
340
|
+
|
|
341
|
+
The APK was decompiled using apktool. The inner Python source was bundled via Chaquopy as `.pyc` files (Python 3.9 bytecode) inside `assets/chaquopy/app.imy`. Each `.pyc` was decompiled and reconstructed into clean Python source.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT © pooraddyy
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<h1>PyPrivate-Obf</h1>
|
|
4
|
+
|
|
5
|
+
<p>A Python source obfuscator reconstructed from the <strong>Py Private</strong> Android application.<br>
|
|
6
|
+
The original author and owner of this encoder is the <strong>PSH Team</strong> — <a href="https://t.me/psh_team">t.me/psh_team</a>.<br>
|
|
7
|
+
This repository is a reverse-engineered Python reconstruction of their work from the APK source.</p>
|
|
8
|
+
|
|
9
|
+
<a href="https://pypi.org/project/pyprivate-obf"><img src="https://img.shields.io/pypi/v/pyprivate-obf?color=blue&label=PyPI" alt="PyPI"></a>
|
|
10
|
+
<a href="https://pypi.org/project/pyprivate-obf"><img src="https://img.shields.io/pypi/pyversions/pyprivate-obf" alt="Python"></a>
|
|
11
|
+
<img src="https://img.shields.io/github/license/pooraddyy/pyprivate" alt="License">
|
|
12
|
+
<img src="https://img.shields.io/pypi/dm/pyprivate-obf?label=downloads" alt="Downloads">
|
|
13
|
+
|
|
14
|
+
<br><br>
|
|
15
|
+
|
|
16
|
+
<a href="#installation"><kbd>Installation</kbd></a>
|
|
17
|
+
|
|
18
|
+
<a href="#cli-usage"><kbd>CLI Usage</kbd></a>
|
|
19
|
+
|
|
20
|
+
<a href="#encoding-methods"><kbd>Encoders</kbd></a>
|
|
21
|
+
|
|
22
|
+
<a href="#guard-layers"><kbd>Guards</kbd></a>
|
|
23
|
+
|
|
24
|
+
<a href="#python-api"><kbd>Python API</kbd></a>
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
## CLI Preview
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
31
|
+
<img src="img/1.jpeg" alt="pyprivate-obf CLI demo" width="820">
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install pyprivate-obf
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
To use **CPython obfuscation** (Cython + GCC compilation), also install:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install cython
|
|
46
|
+
|
|
47
|
+
# Debian / Ubuntu
|
|
48
|
+
sudo apt install gcc python3-dev
|
|
49
|
+
|
|
50
|
+
# Termux
|
|
51
|
+
pkg install clang python-dev
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## CLI Usage
|
|
57
|
+
|
|
58
|
+
### Interactive wizard
|
|
59
|
+
|
|
60
|
+
Run without any arguments to get a step-by-step menu:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
pyprivate-obf
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or force interactive mode explicitly:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
pyprivate-obf --interactive
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Non-interactive (flags)
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
pyprivate-obf <input.py> [OPTIONS] [-o output.py]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
<details>
|
|
79
|
+
<summary><strong>All available flags</strong></summary>
|
|
80
|
+
|
|
81
|
+
| Flag | Description |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `--encode-strings` | Replace every string literal with `bytes([...]).decode()` |
|
|
84
|
+
| `--bytecode` | Marshal bytecode + opcode-pattern swap |
|
|
85
|
+
| `--cpython` | Cython `--embed` → C source → GCC native binary launcher |
|
|
86
|
+
| `--layers N` | Number of marshal layers to apply (default: 1, max: 20) |
|
|
87
|
+
| `--re-check-version` | Re-prepend Python version guard inside every layer |
|
|
88
|
+
| `--expiry "YYYY-MM-DD HH:MM:SS.000000"` | Add an expiry date guard |
|
|
89
|
+
| `--expiry-message "..."` | Message shown when expired (default: "This file has expired.") |
|
|
90
|
+
| `--pip PKG1 PKG2 ...` | Auto-install packages on first run |
|
|
91
|
+
| `--check-version` | Lock script to the current Python major.minor version |
|
|
92
|
+
| `--telegram-bot-token TOKEN` | Telegram channel guard — bot token |
|
|
93
|
+
| `--telegram-channel-id @channel` | Telegram channel guard — channel id |
|
|
94
|
+
| `-o / --output FILE` | Output file path (default: `<input>.enc.py`) |
|
|
95
|
+
|
|
96
|
+
</details>
|
|
97
|
+
|
|
98
|
+
### Examples
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Encode strings + 3 bytecode layers
|
|
102
|
+
pyprivate-obf script.py --encode-strings --bytecode --layers 3
|
|
103
|
+
|
|
104
|
+
# CPython (native binary) obfuscation
|
|
105
|
+
pyprivate-obf script.py --cpython
|
|
106
|
+
|
|
107
|
+
# Add an expiry date
|
|
108
|
+
pyprivate-obf script.py --bytecode --expiry "2025-12-31 23:59:59.000000"
|
|
109
|
+
|
|
110
|
+
# Auto-install dependencies on first run
|
|
111
|
+
pyprivate-obf script.py --bytecode --pip requests numpy pillow
|
|
112
|
+
|
|
113
|
+
# Lock to current Python version
|
|
114
|
+
pyprivate-obf script.py --bytecode --check-version
|
|
115
|
+
|
|
116
|
+
# Telegram channel membership gate
|
|
117
|
+
pyprivate-obf script.py --bytecode \
|
|
118
|
+
--telegram-bot-token 123456:ABCdef \
|
|
119
|
+
--telegram-channel-id @mychannel
|
|
120
|
+
|
|
121
|
+
# Chain everything with a custom output path
|
|
122
|
+
pyprivate-obf script.py --encode-strings --bytecode --layers 2 \
|
|
123
|
+
--check-version -o protected.py
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Encoding Methods
|
|
129
|
+
|
|
130
|
+
There are four independent encoding methods. They live in `pyprivate_obf/encoding_methods/` and each one accepts a `source: str` and returns an obfuscated `str`.
|
|
131
|
+
|
|
132
|
+
### `encode_strings`
|
|
133
|
+
|
|
134
|
+
Rewrites every string literal in the source as `bytes([...]).decode()`.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pyprivate-obf script.py --encode-strings
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Before:
|
|
141
|
+
```python
|
|
142
|
+
print("hello world")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
After:
|
|
146
|
+
```python
|
|
147
|
+
print(bytes([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]).decode())
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### `bytecode_obfuscation`
|
|
153
|
+
|
|
154
|
+
Compiles the source, serialises it with `marshal`, then swaps a known opcode pattern in the bytecode so it cannot be cleanly disassembled with stock `dis`. Output format:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
import marshal
|
|
158
|
+
exec(marshal.loads(b'...'))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
pyprivate-obf script.py --bytecode
|
|
163
|
+
pyprivate-obf script.py --bytecode --layers 5 # 5 nested marshal layers
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### `cpython_obfuscation`
|
|
169
|
+
|
|
170
|
+
Compiles the source to C using Cython `--embed`, strips the compressed string-table sections so only clean ASCII C code remains, then wraps it in a Python launcher that writes the `.c` file to `.py_private/<timestamp>`, compiles it with GCC, and runs the native binary.
|
|
171
|
+
|
|
172
|
+
Requires: `cython` (pip) + `gcc` + Python headers.
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
pyprivate-obf script.py --cpython
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
The output `.py` file contains only the clean C source as a plain string — no binary or base64 data.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### `simple_marshal`
|
|
183
|
+
|
|
184
|
+
Plain `marshal` wrap with no opcode swap. Used as a fallback when no encoding method is selected, and in DEBUG mode.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# applied automatically when no --bytecode / --cpython flag is given
|
|
188
|
+
pyprivate-obf script.py
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Guard Layers
|
|
194
|
+
|
|
195
|
+
Guards are injected at the top of the output script before encoding. Multiple guards can be combined.
|
|
196
|
+
|
|
197
|
+
### Expiry Time
|
|
198
|
+
|
|
199
|
+
Refuses to run after a given date and time.
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
pyprivate-obf script.py --expiry "2025-06-30 23:59:59.000000"
|
|
203
|
+
pyprivate-obf script.py --expiry "2025-06-30 23:59:59.000000" --expiry-message "License expired."
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Python Version Lock
|
|
207
|
+
|
|
208
|
+
Refuses to run on any Python version other than the one used to obfuscate.
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
pyprivate-obf script.py --check-version
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Pip Installer
|
|
215
|
+
|
|
216
|
+
Auto-installs missing packages on first run.
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
pyprivate-obf script.py --pip requests numpy pillow
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Telegram Channel Guard
|
|
223
|
+
|
|
224
|
+
Verifies that the user has joined a Telegram channel before allowing execution.
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
pyprivate-obf script.py \
|
|
228
|
+
--telegram-bot-token 123456:ABCxyz \
|
|
229
|
+
--telegram-channel-id @mychannel
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Python API
|
|
235
|
+
|
|
236
|
+
Use the encoders and guards directly from Python:
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
from pyprivate_obf import encode_strings, bytecode_obfuscation
|
|
240
|
+
from pyprivate_obf import ExpiryTime, CheckVersion, LibrariesInstaller, EnterChannel
|
|
241
|
+
|
|
242
|
+
source = open("script.py").read()
|
|
243
|
+
|
|
244
|
+
# Encode strings
|
|
245
|
+
source = encode_strings(source)
|
|
246
|
+
|
|
247
|
+
# Bytecode obfuscation
|
|
248
|
+
source = bytecode_obfuscation(source)
|
|
249
|
+
|
|
250
|
+
# CPython obfuscation (requires cython + gcc)
|
|
251
|
+
from pyprivate_obf.encoding_methods.cpython_obfuscation import cpython_obfuscation
|
|
252
|
+
source = cpython_obfuscation(source)
|
|
253
|
+
|
|
254
|
+
# Add expiry guard
|
|
255
|
+
source = ExpiryTime(
|
|
256
|
+
time="2025-12-31 23:59:59.000000",
|
|
257
|
+
message="This script has expired."
|
|
258
|
+
).get_new_source(source)
|
|
259
|
+
|
|
260
|
+
# Add pip installer guard
|
|
261
|
+
source = LibrariesInstaller(
|
|
262
|
+
package_names=["requests", "numpy"]
|
|
263
|
+
).get_new_source(source)
|
|
264
|
+
|
|
265
|
+
# Add Python version lock
|
|
266
|
+
source = CheckVersion().get_new_source(source)
|
|
267
|
+
|
|
268
|
+
# Add Telegram channel guard
|
|
269
|
+
source = EnterChannel(
|
|
270
|
+
bot_token="123456:ABCxyz",
|
|
271
|
+
channel_id="@mychannel"
|
|
272
|
+
).get_new_source(source)
|
|
273
|
+
|
|
274
|
+
with open("protected.py", "w") as f:
|
|
275
|
+
f.write(source)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Credits
|
|
281
|
+
|
|
282
|
+
This project is a reverse-engineered Python reconstruction of the **Py Private v4.1.2** Android application.
|
|
283
|
+
|
|
284
|
+
The original encoder was authored by the **PSH Team**: [t.me/psh_team](https://t.me/psh_team)
|
|
285
|
+
|
|
286
|
+
The APK was decompiled using apktool. The inner Python source was bundled via Chaquopy as `.pyc` files (Python 3.9 bytecode) inside `assets/chaquopy/app.imy`. Each `.pyc` was decompiled and reconstructed into clean Python source.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT © pooraddyy
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from .encoding_methods.encode_strings import encode_strings
|
|
2
|
+
from .encoding_methods.bytecode_obfuscation import bytecode_obfuscation
|
|
3
|
+
from .encoding_methods.simple_marshal import simple_marshal
|
|
4
|
+
from .layers.expiry_time import ExpiryTime
|
|
5
|
+
from .layers.check_version import CheckVersion
|
|
6
|
+
from .layers.libraries_installer import LibrariesInstaller
|
|
7
|
+
from .layers.enter_channel import EnterChannel
|
|
8
|
+
|
|
9
|
+
__version__ = "1.0.0"
|
|
10
|
+
__all__ = [
|
|
11
|
+
"encode_strings",
|
|
12
|
+
"bytecode_obfuscation",
|
|
13
|
+
"simple_marshal",
|
|
14
|
+
"ExpiryTime",
|
|
15
|
+
"CheckVersion",
|
|
16
|
+
"LibrariesInstaller",
|
|
17
|
+
"EnterChannel",
|
|
18
|
+
]
|