0x3C50 / pyobf2

An in-place obfuscator for python 3.11
BSD 3-Clause "New" or "Revised" License
52 stars 8 forks source link

Renamer crashes when attempting to concatenate a string with None #16

Closed mirko closed 1 year ago

mirko commented 1 year ago

For one of my python projects pyobf2 crashes with the following trace:

Traceback (most recent call last):
  File "/data/src/pyobf2/examples/api/batch/main.py", line 47, in <module>
    main()
  File "/data/src/pyobf2/examples/api/batch/main.py", line 36, in main
    for _ in obf.do_obfuscation_batch_ast(list(in_asts.values()), list(in_asts.keys())):
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/__init__.py", line 108, in do_obfuscation_batch_ast
    source_asts[i] = fix_missing_locations(x.transform(s_ast, s_fn, source_asts, source_file_names))
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/transformers/memberRenamerTransformer.py", line 30, in transform
    MappingApplicator(generator.mappings).visit(ast)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 398, in visit_ClassDef
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 371, in visit_FunctionDef
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ast.py", line 428, in generic_visit
    self.visit(value)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 416, in visit_Call
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 416, in visit_Call
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ast.py", line 428, in generic_visit
    self.visit(value)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 416, in visit_Call
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 387, in visit_ListComp
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 426, in generic_visit
    self.visit(item)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ast.py", line 428, in generic_visit
    self.visit(value)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 416, in visit_Call
    self.generic_visit(node)
  File "/usr/lib/python3.11/ast.py", line 428, in generic_visit
    self.visit(value)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ast.py", line 428, in generic_visit
    self.visit(value)
  File "/usr/lib/python3.11/ast.py", line 418, in visit
    return visitor(node)
           ^^^^^^^^^^^^^
  File "/data/src/pyobf2.venv/lib/python3.11/site-packages/pyobf2/lib/renamer.py", line 407, in visit_Call
    search_str = "mt_" + node.func.id + "_arg_" + k.arg
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
TypeError: can only concatenate str (not "NoneType") to str

Unfortunately it doesn't reveal which code / part of my project might be at fault here :/

0x3C50 commented 1 year ago

The code making trouble seems to be in a list comprehension in a function in a class somewhere, can you share all snippets that match that description? should roughly look something like this:

class Abc:
  def abc():
    [something() for x in something]  # OR:
    [x for x in something()]  # OR:
    [x for x in something if something()]  # etc

Or, if you're fine with sharing all of your code, please do that.

Alternatively, you can DM me the code on discord @ 0x150, if you don't want to publicly post it

0x3C50 commented 1 year ago

on further inspection, it might have something to do with keyword args. if you have a call somewhere that uses keyword args, in a list comprehension, in a method definition in a class, that might be it

mirko commented 1 year ago

Thanks for the immediate response - is there a way to narrow it down for me? Like, at least which file is currently being parsed / operated on? I do use list-comprehension quite a lot.

mirko commented 1 year ago

Found the offending part: '{proto}://{host}:{port}/{path}/{call}?{cgi_params}'.format(proto=X['proto'], host=X['host'], port=X['port'], path=X['path'], call=call, cgi_params=''.join(["%s=%s&"%(k,v) for k,v in dict(**cgiparams, **X['params']).items()]))

0x3C50 commented 1 year ago

that sounds about right, yeah i know what went wrong. i'll fix it in a bit

mirko commented 1 year ago

Alternatively, you can DM me the code on discord @ 0x150, if you don't want to publicly post it

I'm not familiar with navigating through discord, but the only seemingly feasible option was adding a user as "friend" - which resulted in it telling me 0x150 doesn't accept friend requests.

0x3C50 commented 1 year ago

fixed in a rather unsatisfying manner with 12a236a