dashingsoft / pyarmor

A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.

Home Page:http://pyarmor.dashingsoft.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] `.pyarmor_config` with many entry points don't get obfuscated correctly when `build` command is run

LuisHenri opened this issue · comments

Hello!

First of all, the PyArmor version I'm using is the v7.7.4 and I'm running it with Python v3.8.10.

I have an application which has 2 entry points: main.py and config/__init__.py.
So far, I have used the obfuscate command with many configuration flags in it to obfuscate my code. But since it is error prone, I tried to define the settings inside .pyarmor_config.

My obfuscate command:

pyarmor obfuscate --platform linux.x86_64 --bootstrap 2 --with-license outer --src="." --plugin pyarmor_plugins/check_software.py --plugin pyarmor_plugins/get_features.py --recursive --output=deployment config/__init__.py main.py

Part of my .pyarmor_config file:

{
  ...
  "src": ".",
  "manifest": "include main.py, recursive-include src *.py, recursive-include config *.py",
  "entry": "config/__init__.py, main.py",
  "output": "deployment",
  "restrict_mode": 1,
  ...
  "bootstrap_code": 2,
  ...
}

Then I would run pyarmor build -B.

However, when I use pyarmor build and try to run my obfuscated script, I get:

File "<.../config/init.py>", line 3, in <module>
RuntimeError: Check restrict mode of module failed

After some digging, I found out that it might be a problem on how build function differs from the obfuscate function (I thought build was supposed to be an obfuscate based on the .pyarmor_config file).

The make_entry function is used differently on each of them:
obfuscate function:

        elif is_entry and bootstrap:
            name = os.path.abspath(a)[len(path)+1:]
            make_entry(name, path, output, relative=relative, suffix=suffix,
                       advanced=advanced)

build function:

        if (not supermode) and project.entry and bootstrap_code:
            soutput = os.path.join(output, os.path.basename(project.src)) \
                if project.get('is_package') else output
            make_entry(project.entry, project.src, soutput,
                       rpath=project.runtime_path, relative=relative,
                       suffix=suffix, advanced=advanced)

Basically: In obfuscate it is inside the FOR loop. In build it is outside just after it.
I quickly tested it locally by putting this make_entry function on build inside the FOR loop and it obfuscated correctly just as if I ran my old pyarmor obfuscate command.

Question: Wouldn't it be simpler to just call obfuscate inside build?

Pyarmor 8 has been rewitten, so if it's not bug, I may not spend time refining Pyarmor 7 code.

But I'm curious why make_entry doesn't work in build out of loop.

By this patch check the different output for build and obfuscate command

--- a/src/utils.py
+++ b/src/utils.py
@@ -444,7 +444,7 @@ def _make_entry(filename, rpath=None, relative=None, shell=None, suffix='',
             paras.append('advanced=1')
         f.write(entry_lines[1] % ', '.join(paras))
         f.write(''.join(lines[n:]))
-
+        print(filename, entry_code, entry_lines[1] % ', '.join(paras))

Besides, I close this issue becuase the question is prefer to submit in discussion area

Hi @jondy,

I still think this is a bug somehow.

Isn't project.entry a string like main.py,config/__init__.py? If so, how does make_entry handles it? Because I would assume it makes the filename an entry. And that makes sense if it is inside the FOR loop, because it iterates through each file and checks if is_entry. Which is not the case if you do it outside the FOR loop.

I did a simple test with

  main.py            
  config/__init__.py  # only one line "issue = 1720"

The content main.py

from config import issue
print('hello', issue)

Then I build a project with .pyarmor_config

{
  "version": "2.1",
  "name": "ttt",
  "title": "ttt",
  "src": ".",
  "is_package": null,
  "manifest": "include main.py, recursive-include config *.py",
  "entry": "config/__init__.py,main.py",
  "output": "dist2",
  "runtime_path": null,
  "restrict_mode": 1,
  "obf_code": 1,
  "obf_mod": 2,
  "wrap_mode": 1,
  "advanced_mode": 0,
  "bootstrap_code": 2,
  "cross_protection": 1,
  "mixins": null,
  "plugins": null,
  "platform": null,
  "package_runtime": 1,
  "enable_suffix": 0,
  "license_file": null,
  "build_time": 1711467498.723676
}

Then build it,

...
INFO     Super mode is off
INFO     Super plus mode is off
INFO     	config/__init__.py -> dist2/config/__init__.py
INFO     	main.py -> dist2/main.py
INFO     2 scripts has been obfuscated
INFO     Insert bootstrap code to entry script dist2/config/__init__.py
INFO     Insert bootstrap code to entry script dist2/main.py
INFO     Build project OK.

And run the obfuscated script

$ cd dist2
$ python main.py
hello 1720

$ cp ../main.py test.py
$ python test.py
hello 1720

There is no any issue.

I found you use many plugins, so maybe it's your own code report the error.

If you prefer to move it to loop in build, just apply one simple patch, and use it only for yourself.