powershell-pro-obfuscator 1.0.0__py3-none-any.whl
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.
- examples/PowerShellProObfuscatorExample.py +236 -0
- examples/PowerShellProObfuscatorExampleIsDemo.py +52 -0
- examples/PowerShellProObfuscatorExampleSimple.py +72 -0
- powershell_pro_obfuscator-1.0.0.dist-info/METADATA +629 -0
- powershell_pro_obfuscator-1.0.0.dist-info/RECORD +9 -0
- powershell_pro_obfuscator-1.0.0.dist-info/WHEEL +5 -0
- powershell_pro_obfuscator-1.0.0.dist-info/top_level.txt +2 -0
- powershellproobfuscator/__init__.py +1 -0
- powershellproobfuscator/powershellproobfuscator.py +414 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
###############################################################################
|
|
4
|
+
#
|
|
5
|
+
# PowerShell Pro Obfuscator is a source code obfuscator for PowerShell scripts.
|
|
6
|
+
# Obfuscate, virtualize and protect your PowerShell .ps1 scripts against
|
|
7
|
+
# analysis, reverse engineering and technology theft.
|
|
8
|
+
#
|
|
9
|
+
# PowerShell Pro Obfuscator provides advanced PowerShell source code parsing
|
|
10
|
+
# based on AST trees, multiple advanced obfuscation, virtualization and
|
|
11
|
+
# protection strategies are available.
|
|
12
|
+
#
|
|
13
|
+
# Version : Python SDK v1.0.0
|
|
14
|
+
# Python : Python v3
|
|
15
|
+
# Dependencies : requests (https://pypi.python.org/pypi/requests/)
|
|
16
|
+
# Author : Bartosz Wójcik (support@pelock.com)
|
|
17
|
+
# Project : https://www.pelock.com/products/powershell-pro-obfuscator
|
|
18
|
+
# Homepage : https://www.pelock.com
|
|
19
|
+
#
|
|
20
|
+
###############################################################################
|
|
21
|
+
|
|
22
|
+
import zlib
|
|
23
|
+
import base64
|
|
24
|
+
|
|
25
|
+
# required external package - install with "pip install requests"
|
|
26
|
+
import requests
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PowerShellProObfuscator(object):
|
|
30
|
+
"""PowerShell Pro Obfuscator module"""
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# @var string default PowerShell Pro Obfuscator WebApi endpoint
|
|
34
|
+
#
|
|
35
|
+
API_URL = "https://www.pelock.com/api/powershell-pro-obfuscator/v1"
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# @var string WebApi key for the service
|
|
39
|
+
#
|
|
40
|
+
_apiKey = ""
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# @var bool should the source code be compressed
|
|
44
|
+
#
|
|
45
|
+
enableCompression = False
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# @var bool protection against tampering with protected code (integrity verification)
|
|
49
|
+
#
|
|
50
|
+
selfDefending = True
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# @var bool protection linker (decoy call graph)
|
|
54
|
+
#
|
|
55
|
+
protectionLinker = True
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# @var bool rename variable names to random string values
|
|
59
|
+
#
|
|
60
|
+
renameVariables = True
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# @var bool rename parameter names to random string values
|
|
64
|
+
#
|
|
65
|
+
renameParameters = True
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
# @var bool rename function names to random string values
|
|
69
|
+
#
|
|
70
|
+
renameFunctions = True
|
|
71
|
+
|
|
72
|
+
#
|
|
73
|
+
# @var bool shuffle function order in the output source
|
|
74
|
+
#
|
|
75
|
+
shuffleFunctions = True
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# @var bool change linear code execution flow via control-flow flattening
|
|
79
|
+
#
|
|
80
|
+
controlFlowFlatten = True
|
|
81
|
+
|
|
82
|
+
#
|
|
83
|
+
# @var bool rewrite statement blocks into finite-state automata (state-machine obfuscation)
|
|
84
|
+
#
|
|
85
|
+
stateMachine = True
|
|
86
|
+
|
|
87
|
+
#
|
|
88
|
+
# @var bool lift selected statements into a VM engine (virtualized statements)
|
|
89
|
+
#
|
|
90
|
+
vmStrategy = True
|
|
91
|
+
|
|
92
|
+
#
|
|
93
|
+
# @var bool encrypt integers
|
|
94
|
+
#
|
|
95
|
+
encryptIntegers = True
|
|
96
|
+
|
|
97
|
+
#
|
|
98
|
+
# @var bool split strings into concatenated chunks
|
|
99
|
+
#
|
|
100
|
+
splitStrings = True
|
|
101
|
+
|
|
102
|
+
#
|
|
103
|
+
# @var bool encrypt strings using randomly generated polymorphic encryption algorithms
|
|
104
|
+
#
|
|
105
|
+
encryptStrings = True
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# @var bool move integers to arrays
|
|
109
|
+
#
|
|
110
|
+
integersToArrays = True
|
|
111
|
+
|
|
112
|
+
#
|
|
113
|
+
# @var bool move floats to arrays
|
|
114
|
+
#
|
|
115
|
+
floatsToArrays = True
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# @var bool insert dead code
|
|
119
|
+
#
|
|
120
|
+
insertDeadCode = True
|
|
121
|
+
|
|
122
|
+
#
|
|
123
|
+
# @var bool replace boolean conditions with equivalent complex expressions
|
|
124
|
+
#
|
|
125
|
+
complexifyBooleans = True
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# @var bool represent integers via floating-point math
|
|
129
|
+
#
|
|
130
|
+
integersToFloating = True
|
|
131
|
+
|
|
132
|
+
#
|
|
133
|
+
# @var bool encrypt floating point numbers
|
|
134
|
+
#
|
|
135
|
+
encryptFloating = True
|
|
136
|
+
|
|
137
|
+
#
|
|
138
|
+
# @var bool insert decoy functions
|
|
139
|
+
#
|
|
140
|
+
decoyFunctions = True
|
|
141
|
+
|
|
142
|
+
#
|
|
143
|
+
# @var bool insert anti-debugging detections
|
|
144
|
+
#
|
|
145
|
+
detectDebugger = True
|
|
146
|
+
|
|
147
|
+
#
|
|
148
|
+
# @var bool insert fake dot-source comment markers
|
|
149
|
+
#
|
|
150
|
+
fakeDotSourceMarkers = True
|
|
151
|
+
|
|
152
|
+
#
|
|
153
|
+
# @var bool insert opaque predicate branches
|
|
154
|
+
#
|
|
155
|
+
opaqueBranches = True
|
|
156
|
+
|
|
157
|
+
#
|
|
158
|
+
# @var bool insert scriptblock decoys
|
|
159
|
+
#
|
|
160
|
+
scriptblockDecoys = True
|
|
161
|
+
|
|
162
|
+
#
|
|
163
|
+
# @var bool insert here-string padding
|
|
164
|
+
#
|
|
165
|
+
literalPadding = True
|
|
166
|
+
|
|
167
|
+
#
|
|
168
|
+
# @var bool use indirect command invocation
|
|
169
|
+
#
|
|
170
|
+
reflectInvokeCommands = True
|
|
171
|
+
|
|
172
|
+
#
|
|
173
|
+
# @var bool store string fragments in char-code array vaults
|
|
174
|
+
#
|
|
175
|
+
stringCharArrayVault = True
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
# @var bool wrap code in try/finally blocks with dead noise
|
|
179
|
+
#
|
|
180
|
+
tryFinallyNoise = True
|
|
181
|
+
|
|
182
|
+
#
|
|
183
|
+
# @var bool apply redundant xor / affine integer masks
|
|
184
|
+
#
|
|
185
|
+
affineIntegerMask = True
|
|
186
|
+
|
|
187
|
+
#
|
|
188
|
+
# @var bool insert dead event/timer stubs
|
|
189
|
+
#
|
|
190
|
+
eventStub = True
|
|
191
|
+
|
|
192
|
+
#
|
|
193
|
+
# @var bool strip comments from the output source
|
|
194
|
+
#
|
|
195
|
+
removeComments = True
|
|
196
|
+
|
|
197
|
+
#
|
|
198
|
+
# @var integer success
|
|
199
|
+
#
|
|
200
|
+
ERROR_SUCCESS = 0
|
|
201
|
+
|
|
202
|
+
#
|
|
203
|
+
# @var integer invalid size for source code (it's 1000 bytes max. for demo version)
|
|
204
|
+
#
|
|
205
|
+
ERROR_INPUT_SIZE = 1
|
|
206
|
+
|
|
207
|
+
#
|
|
208
|
+
# @var integer input source is empty
|
|
209
|
+
#
|
|
210
|
+
ERROR_INPUT = 2
|
|
211
|
+
|
|
212
|
+
#
|
|
213
|
+
# @var integer PowerShell source code parsing error
|
|
214
|
+
#
|
|
215
|
+
ERROR_PARSING = 3
|
|
216
|
+
|
|
217
|
+
#
|
|
218
|
+
# @var integer PowerShell parsed code obfuscation error
|
|
219
|
+
#
|
|
220
|
+
ERROR_OBFUSCATION = 4
|
|
221
|
+
|
|
222
|
+
#
|
|
223
|
+
# @var integer error while generating output code
|
|
224
|
+
#
|
|
225
|
+
ERROR_OUTPUT = 5
|
|
226
|
+
|
|
227
|
+
def __init__(self, api_key=None, enable_all_obfuscation_options=True):
|
|
228
|
+
"""Initialize PowerShell Pro Obfuscator class
|
|
229
|
+
|
|
230
|
+
:param api_key: Activation key for the service (it can be empty for demo mode)
|
|
231
|
+
:param enable_all_obfuscation_options: Enable or disable all of the obfuscation options
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
self._apiKey = api_key
|
|
235
|
+
|
|
236
|
+
# compression stays disabled by default (API does not decompress today)
|
|
237
|
+
self.enableCompression = False
|
|
238
|
+
|
|
239
|
+
self.selfDefending = enable_all_obfuscation_options
|
|
240
|
+
self.protectionLinker = enable_all_obfuscation_options
|
|
241
|
+
self.renameVariables = enable_all_obfuscation_options
|
|
242
|
+
self.renameParameters = enable_all_obfuscation_options
|
|
243
|
+
self.renameFunctions = enable_all_obfuscation_options
|
|
244
|
+
self.shuffleFunctions = enable_all_obfuscation_options
|
|
245
|
+
self.controlFlowFlatten = enable_all_obfuscation_options
|
|
246
|
+
self.stateMachine = enable_all_obfuscation_options
|
|
247
|
+
self.vmStrategy = enable_all_obfuscation_options
|
|
248
|
+
self.encryptIntegers = enable_all_obfuscation_options
|
|
249
|
+
self.splitStrings = enable_all_obfuscation_options
|
|
250
|
+
self.encryptStrings = enable_all_obfuscation_options
|
|
251
|
+
self.integersToArrays = enable_all_obfuscation_options
|
|
252
|
+
self.floatsToArrays = enable_all_obfuscation_options
|
|
253
|
+
self.insertDeadCode = enable_all_obfuscation_options
|
|
254
|
+
self.complexifyBooleans = enable_all_obfuscation_options
|
|
255
|
+
self.integersToFloating = enable_all_obfuscation_options
|
|
256
|
+
self.encryptFloating = enable_all_obfuscation_options
|
|
257
|
+
self.decoyFunctions = enable_all_obfuscation_options
|
|
258
|
+
self.detectDebugger = enable_all_obfuscation_options
|
|
259
|
+
self.fakeDotSourceMarkers = enable_all_obfuscation_options
|
|
260
|
+
self.opaqueBranches = enable_all_obfuscation_options
|
|
261
|
+
self.scriptblockDecoys = enable_all_obfuscation_options
|
|
262
|
+
self.literalPadding = enable_all_obfuscation_options
|
|
263
|
+
self.reflectInvokeCommands = enable_all_obfuscation_options
|
|
264
|
+
self.stringCharArrayVault = enable_all_obfuscation_options
|
|
265
|
+
self.tryFinallyNoise = enable_all_obfuscation_options
|
|
266
|
+
self.affineIntegerMask = enable_all_obfuscation_options
|
|
267
|
+
self.eventStub = enable_all_obfuscation_options
|
|
268
|
+
self.removeComments = enable_all_obfuscation_options
|
|
269
|
+
|
|
270
|
+
def login(self):
|
|
271
|
+
"""Login to the service and get the information about the current license limits
|
|
272
|
+
|
|
273
|
+
:return: An array with the results or False on error
|
|
274
|
+
:rtype: bool,dict
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
# parameters
|
|
278
|
+
params = {"command": "login"}
|
|
279
|
+
|
|
280
|
+
return self.post_request(params)
|
|
281
|
+
|
|
282
|
+
def obfuscate_script_file(self, script_file_path):
|
|
283
|
+
"""Obfuscate PowerShell script source code file using provided parameters
|
|
284
|
+
|
|
285
|
+
:param script_file_path: PowerShell compatible script *.ps1 file path
|
|
286
|
+
:return: An array with the results or False on error
|
|
287
|
+
:rtype: bool,dict
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
source_file = open(script_file_path, 'r')
|
|
291
|
+
source = source_file.read()
|
|
292
|
+
source_file.close()
|
|
293
|
+
|
|
294
|
+
if not source:
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
return self.obfuscate_script_source(source)
|
|
298
|
+
|
|
299
|
+
def obfuscate_script_source(self, script_source):
|
|
300
|
+
"""Obfuscate PowerShell script source code using provided parameters
|
|
301
|
+
|
|
302
|
+
:param script_source: PowerShell compatible script *.ps1 source code
|
|
303
|
+
:return: An array with the results or False on error
|
|
304
|
+
:rtype: bool,dict
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
# additional parameters
|
|
308
|
+
params_array = {"command": "obfuscate", "source": script_source}
|
|
309
|
+
|
|
310
|
+
return self.post_request(params_array)
|
|
311
|
+
|
|
312
|
+
def post_request(self, params_array):
|
|
313
|
+
"""Send a POST request to the server
|
|
314
|
+
|
|
315
|
+
:param params_array: An array with the parameters
|
|
316
|
+
:return: An array with the results or false on error
|
|
317
|
+
:rtype: bool,dict
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
# add activation key to the parameters array
|
|
321
|
+
if self._apiKey:
|
|
322
|
+
params_array["key"] = self._apiKey
|
|
323
|
+
|
|
324
|
+
#
|
|
325
|
+
# obfuscation strategies
|
|
326
|
+
#
|
|
327
|
+
if self.selfDefending:
|
|
328
|
+
params_array["self_defending"] = "1"
|
|
329
|
+
if self.protectionLinker:
|
|
330
|
+
params_array["protection_linker"] = "1"
|
|
331
|
+
if self.renameVariables:
|
|
332
|
+
params_array["rename_variables"] = "1"
|
|
333
|
+
if self.renameParameters:
|
|
334
|
+
params_array["rename_parameters"] = "1"
|
|
335
|
+
if self.renameFunctions:
|
|
336
|
+
params_array["rename_functions"] = "1"
|
|
337
|
+
if self.shuffleFunctions:
|
|
338
|
+
params_array["shuffle_functions"] = "1"
|
|
339
|
+
if self.controlFlowFlatten:
|
|
340
|
+
params_array["control_flow_flatten"] = "1"
|
|
341
|
+
if self.stateMachine:
|
|
342
|
+
params_array["state_machine"] = "1"
|
|
343
|
+
if self.vmStrategy:
|
|
344
|
+
params_array["vm_strategy"] = "1"
|
|
345
|
+
if self.encryptIntegers:
|
|
346
|
+
params_array["encrypt_integers"] = "1"
|
|
347
|
+
if self.splitStrings:
|
|
348
|
+
params_array["split_strings"] = "1"
|
|
349
|
+
if self.encryptStrings:
|
|
350
|
+
params_array["encrypt_strings"] = "1"
|
|
351
|
+
if self.integersToArrays:
|
|
352
|
+
params_array["integers_to_arrays"] = "1"
|
|
353
|
+
if self.floatsToArrays:
|
|
354
|
+
params_array["floats_to_arrays"] = "1"
|
|
355
|
+
if self.insertDeadCode:
|
|
356
|
+
params_array["insert_dead_code"] = "1"
|
|
357
|
+
if self.complexifyBooleans:
|
|
358
|
+
params_array["complexify_booleans"] = "1"
|
|
359
|
+
if self.integersToFloating:
|
|
360
|
+
params_array["integers_to_floating"] = "1"
|
|
361
|
+
if self.encryptFloating:
|
|
362
|
+
params_array["encrypt_floating"] = "1"
|
|
363
|
+
if self.decoyFunctions:
|
|
364
|
+
params_array["decoy_functions"] = "1"
|
|
365
|
+
if self.detectDebugger:
|
|
366
|
+
params_array["detect_debugger"] = "1"
|
|
367
|
+
if self.fakeDotSourceMarkers:
|
|
368
|
+
params_array["fake_dot_source_markers"] = "1"
|
|
369
|
+
if self.opaqueBranches:
|
|
370
|
+
params_array["opaque_branches"] = "1"
|
|
371
|
+
if self.scriptblockDecoys:
|
|
372
|
+
params_array["scriptblock_decoys"] = "1"
|
|
373
|
+
if self.literalPadding:
|
|
374
|
+
params_array["literal_padding"] = "1"
|
|
375
|
+
if self.reflectInvokeCommands:
|
|
376
|
+
params_array["reflect_invoke_commands"] = "1"
|
|
377
|
+
if self.stringCharArrayVault:
|
|
378
|
+
params_array["string_char_array_vault"] = "1"
|
|
379
|
+
if self.tryFinallyNoise:
|
|
380
|
+
params_array["try_finally_noise"] = "1"
|
|
381
|
+
if self.affineIntegerMask:
|
|
382
|
+
params_array["affine_integer_mask"] = "1"
|
|
383
|
+
if self.eventStub:
|
|
384
|
+
params_array["event_stub"] = "1"
|
|
385
|
+
if self.removeComments:
|
|
386
|
+
params_array["remove_comments"] = "1"
|
|
387
|
+
|
|
388
|
+
#
|
|
389
|
+
# check if compression is enabled
|
|
390
|
+
#
|
|
391
|
+
if "source" in params_array and self.enableCompression and params_array["source"]:
|
|
392
|
+
|
|
393
|
+
compressed_data = zlib.compress(bytes(params_array["source"], 'utf-8'), 9)
|
|
394
|
+
base64_encoded_data = base64.b64encode(compressed_data).decode()
|
|
395
|
+
|
|
396
|
+
params_array["source"] = base64_encoded_data
|
|
397
|
+
params_array["compression"] = "1"
|
|
398
|
+
|
|
399
|
+
response = requests.post(self.API_URL, data=params_array)
|
|
400
|
+
|
|
401
|
+
# no response at all or an invalid response code
|
|
402
|
+
if not response or not response.ok:
|
|
403
|
+
return False
|
|
404
|
+
|
|
405
|
+
# decode to json array
|
|
406
|
+
result = response.json()
|
|
407
|
+
|
|
408
|
+
# depack output code back into the string
|
|
409
|
+
if "output" in result and self.enableCompression and result["error"] == self.ERROR_SUCCESS:
|
|
410
|
+
|
|
411
|
+
result["output"] = str(zlib.decompress(base64.b64decode(result["output"])), "utf-8")
|
|
412
|
+
|
|
413
|
+
# return original JSON response code
|
|
414
|
+
return result
|