Import Submodule NamesObfuscator error
While playing around with example python API provided by the docs I have encountered an error in NamesObfuscator.
Take following source as example:
import urllib.request
from urllib.error import URLError, HTTPError
url = 'http://example.com/'
with urllib.request.urlopen(url) as response:
html = response.read()
html = html.decode('utf-8')
print(html)
While trying to obfuscate the code the following error is thrown:
Traceback (most recent call last):
File "pof_obfuscator.py", line 117, in <module>
open('pof_testing.py','w').write(obfuscate(source))
~~~~~~~~~^^^^^^^^
File "pof_obfuscator.py", line 101, in obfuscate
tokens = NamesObfuscator(generator=generator).obfuscate_tokens(tokens)
File "venv/lib/python3.13/site-packages/pof/obfuscator/names.py", line 493, in obfuscate_tokens
return self.import_as(result, new_names)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
File "venv/lib/python3.13/site-packages/pof/obfuscator/names.py", line 343, in import_as
raise e
File "venv/lib/python3.13/site-packages/pof/obfuscator/names.py", line 320, in import_as
n.name = inew_names[n.name]
~~~~~~~~~~^^^^^^^^
KeyError: 'oL_9_VR62F._238'
To understand the issue a little more I added couple of debug prints, here is the contents of new_names variable:
{'urllib': 'oL_9_VR62F', 'request': '_238', 'error': 'errnos', 'URLError': 'blob', 'HTTPError': 'mod_name', 'url': 'stdev', 'urlopen': 'tag_remove', 'response': 'listobj', 'html': 'writeHeader'}
It looks like AST library threats urllib.request as a single token, while the pof code splits it into two.
The error is coming from the line in the Python API example:
okens = NamesObfuscator(generator=generator).obfuscate_tokens(tokens)
This is a known bug in POF and there is some explanations in pof/main.py.
Here is a full example (fixed) of the API usage:
import random
from pof import BaseObfuscator
from pof.obfuscator import (
BuiltinsObfuscator,
CommentsObfuscator,
ConstantsObfuscator,
ExceptionObfuscator,
GlobalsObfuscator,
LoggingObfuscator,
# NamesObfuscator,
NumberObfuscator,
PrintObfuscator,
StringsObfuscator,
)
from pof.utils.extract_names import NameExtract
from pof.utils.generator import AdvancedGenerator, BaseGenerator, BasicGenerator
class ExampleObfuscator(BaseObfuscator):
def obfuscate(self, source):
tokens = self._get_tokens(source)
# get all the names and add them to the RESERVED_WORDS for the generators
reserved_words_add = NameExtract.get_names(tokens)
BaseGenerator.extend_reserved(reserved_words_add)
tokens = CommentsObfuscator().obfuscate_tokens(tokens)
tokens = LoggingObfuscator().obfuscate_tokens(tokens)
tokens = PrintObfuscator().obfuscate_tokens(tokens)
ex_generator = BasicGenerator.number_name_generator()
tokens = ExceptionObfuscator(
add_codes=True,
generator=ex_generator,
).obfuscate_tokens(tokens)
# configure generator
gen_dict = {
86: AdvancedGenerator.realistic_generator(),
10: BasicGenerator.alphabet_generator(),
4: BasicGenerator.number_name_generator(length=random.randint(2, 5)),
}
generator = AdvancedGenerator.multi_generator(gen_dict)
# core obfuscation
tokens = ConstantsObfuscator(
generator=generator,
obf_number_rate=0.7,
obf_string_rate=0.1,
obf_builtins_rate=0.3,
).obfuscate_tokens(tokens)
# FIXME: broken for the moment
# tokens = NamesObfuscator(generator=generator).obfuscate_tokens(tokens)
tokens = GlobalsObfuscator().obfuscate_tokens(tokens)
tokens = BuiltinsObfuscator().obfuscate_tokens(tokens)
b64decode_name = next(generator)
b85decode_name = next(generator)
string_obfuscator = StringsObfuscator(
import_b64decode=True,
import_b85decode=True,
b64decode_name=b64decode_name,
b85decode_name=b85decode_name,
)
tokens = string_obfuscator.obfuscate_tokens(tokens)
string_obfuscator.import_b64decode = False
string_obfuscator.import_b85decode = False
for _ in range(2):
tokens = NumberObfuscator().obfuscate_tokens(tokens)
tokens = BuiltinsObfuscator().obfuscate_tokens(tokens)
for _ in range(2):
tokens = string_obfuscator.obfuscate_tokens(tokens)
return self._untokenize(tokens)
print(ExampleObfuscator().obfuscate(open("source.py", "r").read()))
Hope this helps.
README is fixed in 90036e895fabc0332a6a5b5dc90f00bd03f4d0ef