pyarmor icon indicating copy to clipboard operation
pyarmor copied to clipboard

[BUG] Can't use obfuscated scripts under path that contain Chinese character

Open zhong-xian-guang opened this issue 3 years ago • 10 comments

Scripts obfuscated by pyarmor works fine under path that with only ascii-character. But when I moved it to the path contains Chinese character, it won't work anymore with error message.

UnicodeDecodeError: 'mbcs' codec can't decode bytes in position 0--1: No mapping for the Unicode character exists in the target code page.

here is my file structure +D:/測試檔案/test/ |-+my_pyarmor_test.py |-+my_pyarmor_test_second.py

which contains following content

#### my_pyarmor_test.py
import os
def FunctionName():
    from my_pyarmor_test_second import class_b
    class_b.haha()
    print('hello world')

FunctionName()
#### my_pyarmor_test_second.py
class class_b():
    inner_value = 20
    @classmethod
    def haha(cls):
        print('inner_value',cls.inner_value)

Note that I'm running pyarmor on python version 35 (which is my use case ). but pyarmor it self is installed under path of Python38. the command I use in the following line

C:/Users/Graphics/AppData/Local/Programs/Python/Python35/python.exe C:/Users/Graphics/AppData/Local/Programs/Python/Python38/Lib/site-packages/pyarmor/pyarmor.py  obfuscate --recursive D:/測試檔案/test/

here is PyArmor INFO message

INFO     PyArmor Version 7.6.0
INFO     Python 3.5.0
INFO     Target platforms: Native
INFO     Source path is "D:\blenderh測試檔案\20220818\pyarmor_test"
INFO     Entry scripts are []
INFO     Use cached capsule C:\Users\Graphics\.pyarmor\.pyarmor_capsule.zip
INFO     Search scripts mode: Recursive
INFO     Save obfuscated scripts to "dist"
INFO     Read product key from capsule
INFO     Obfuscate module mode is 2
INFO     Obfuscate code mode is 1
INFO     Obfuscate string value is False
INFO     Wrap mode is 1
INFO     Restrict mode is 1
INFO     Advanced value is 0
INFO     Super mode is False
INFO     Super plus mode is not enabled
INFO     Generating runtime files to dist\pytransform
INFO     Extract pytransform.key
INFO     Read default license from capsule
INFO     Copying C:\Users\Graphics\AppData\Local\Programs\Python\Python38\Lib\site-packages\pyarmor\platforms\windows\x86_64\_pytransform.dll
INFO     Patch library dist\pytransform\_pytransform.dll
INFO     Patch library file OK
INFO     Copying C:\Users\Graphics\AppData\Local\Programs\Python\Python38\Lib\site-packages\pyarmor\pytransform.py
INFO     Rename it to pytransform/__init__.py
INFO     Generate runtime files OK
INFO     Start obfuscating the scripts...
INFO            my_pyarmor_test.py -> dist\my_pyarmor_test.py
INFO            my_pyarmor_test_second.py -> dist\my_pyarmor_test_second.py
INFO     Obfuscate 2 scripts OK.

than I copied the obfuscated file to form the following file structure +D:/測試檔案/dest/ | - +pytransform <- created by PyArmor
| |-+__init__.py | |-+_pytransform.dll |-+my_pyarmor_test.py |-+my_pyarmor_test_second.py

running the following command will get the error

python D:/測試檔案/dest/my_pyarmor_test.py

something worth noting

  1. my operation system is Windows 10
  2. not all Chinese characters will lead to this error, it needs to be a certain combination such as '測試檔案'
  3. the simplest test case I can make require import another obfuscated python file.

Is there any way to solve this issue?

zhong-xian-guang avatar Aug 18 '22 13:08 zhong-xian-guang

Try to make a link to the source path, for example,

mklink /d src D:/測試檔案/dest
pyarmor obfuscate -r src

jondy avatar Aug 25 '22 07:08 jondy

I have tried this but it raised another problem.

After creating link under the path and run the code (Noted that the path is a python script rather than a folder which I say it wrong last time)

mklink /d src D:\測試檔案\test\
C:/Users/Graphics/AppData/Local/Programs/Python/Python35/python.exe C:/Users/Graphics/AppData/Local/Programs/Python/Python38/Lib/site-packages/pyarmor/pyarmor.py  obfuscate --recursive src/my_pyarmor_text.py

The content of the script is different and raised error when running the python script

#### my_pyarmor_test.py
from pytransform import pyarmor_runtime  #<- won't have this line if obfuscate through link path
pyarmor_runtime()                        #<- won't have this line if obfuscate through link path
__pyarmor__(__name__, __file__, b'\x50......\x61', 2)

Following error message

PS D:\測試檔案\dist> python D:\測試檔案\dist\my_pyarmor_test.py   <-- running python script
Traceback (most recent call last):
  File "D:\測試檔案\dist\my_pyarmor_test.py", line 1, in <module>
    __pyarmor__(__name__, __file__, b'\x50......\x61', 2)
NameError: name '__pyarmor__' is not defined

Thanks for your reply, but is there any way to fix this?

zhong-xian-guang avatar Aug 29 '22 09:08 zhong-xian-guang

Please read this page for this problem https://pyarmor.readthedocs.io/en/latest/questions.html

jondy avatar Aug 29 '22 12:08 jondy

I've tried making a link and do it again but still got the same error.

UnicodeDecodeError: 'mbcs' codec can't decode bytes in position 0--1: No mapping for the Unicode character exists in the target code page.

zhong-xian-guang avatar Sep 05 '22 03:09 zhong-xian-guang

Run pyarmor command with option -d to get traceback, and where to raise this exception?

jondy avatar Sep 06 '22 13:09 jondy

I did not get any exception raised when obfuscate script with pyarmor. The error is coming from running the obfuscated script under the path contains Chinese character.

zhong-xian-guang avatar Sep 16 '22 08:09 zhong-xian-guang

After reading the first report, I find the problem. Try to run a normal python script in Chinese path, it will report the same issue. So it's Python's issue

jondy avatar Sep 16 '22 10:09 jondy

It sound odd. If not obfuscated, I did not get the error with the script I used in the first comment.

Does it mean the script obfuscated by pyarmor may not work in that situation?

zhong-xian-guang avatar Sep 19 '22 08:09 zhong-xian-guang

Do you use outer license? If not, try to hack D:/測試檔案/dest/pytransform/__init__.py

at line 331 in _load_library

-        m.set_option(1, path.encode() if sys.version_info[0] == 3 else path)
+       pass # m.set_option(1, path.encode() if sys.version_info[0] == 3 else path)

jondy avatar Sep 20 '22 00:09 jondy

I'm not using outer license. And I still got the error after hack the pytransform/__init__.py file.

The error seems not came from pyarmor_runtime() but __pyarmor__() in the obfuscated script.

zhong-xian-guang avatar Sep 20 '22 06:09 zhong-xian-guang

I test it in Win 7, just run an obfuscated scripts in the path 測試檔案, it works fine.

I have no win10. Could you do a simple test, replace __file__ with string constant `"test.py" in the obfuscated scripts, and run it again.

If there is restrict error, obfuscate script with extra option --restrict 0

jondy avatar Sep 28 '22 12:09 jondy

I've tried replace __file__ with "test.py" constant, and get restrict error. After obfuscate the script with restrict 0 and doing it again, the code is running correctly!

Does replacing __file__ with "test.py" constant change obfuscate code's behavior?

zhong-xian-guang avatar Oct 06 '22 06:10 zhong-xian-guang

It seems the pyarmor() function can not take Chinese characters as __file__ value, and it does look like Python's issue.

I can work around this problem by predefined __file__ inside my script before obfuscate and then replacing __file__ with an empty string and it worked under my use case.

import os  #<- added text
__file__ = os.getcwd() + '/somepath/script.py'  #<- added text

...  #reset of script

However, I wish there was a way to not do this as it uses os.getcwd() and may not work in some cases.

zhong-xian-guang avatar Oct 06 '22 13:10 zhong-xian-guang

Does replacing file with "test.py" constant change obfuscate code's behavior?

No. It almost not.

jondy avatar Oct 06 '22 23:10 jondy