4.5. Insight Into BCC Mode¶
BCC mode could convert most of functions and methods in the scripts to equivalent C functions, those c functions will be compiled to machine instructions directly, then called by obfuscated scripts.
c compiler. In Linux and Darwin,
clang is OK. In Windows, only
clang.exe works. It could be configured by one of these ways:
- If there is any
clang.exe, it’s OK if it could be run in other path.
- Download and install Windows version of LLVM
- Download https://pyarmor.dashingsoft.com/downloads/tools/clang-9.0.zip, it’s about 26M bytes, there is only one file in it. Unzip it and save
$HOMEis home path of current logon user, check the environment variable
HOMEto get the real path.
4.5.1. Enable BCC mode¶
After compiler works, using
--enable-bcc to enable BCC mode:
$ pyarmor gen --enable-bcc foo.py
All the source in module level is not converted to C function.
4.5.2. Trace bcc log¶
To check which functions are converted to C function, enable trace mode before obfuscate the script:
$ pyarmor cfg enable_trace=1 $ pyarmor gen --enable-bcc foo.py
Then check the trace log:
$ ls .pyarmor/pyarmor.trace.log $ grep trace.bcc .pyarmor/pyarmor.trace.log trace.bcc foo:5:hello trace.bcc foo:9:sum2 trace.bcc foo:12:main
The first log means
foo.py line 5 function
hello is protected by bcc.
The second log means
foo.py line 9 function
sum2 is protected by bcc.
4.5.3. Ignore module or function¶
When BCC scripts reports errors, a quick workaround is to ignore these problem modules or functions. Because BCC mode converts some functions to C code, these functions are not compatible with Python function object. They may not be called by outer Python scripts, and can’t be fixed in Pyarmor side. In this case use configuration option
bcc:disabled to ignore function or module, and make all the others work.
To ignore one module
pkgname.modname by this command:
$ pyarmor cfg -p pkgname.modname bcc:disabled=1
To ignore one function in one module by this command:
$ pyarmor cfg -p pkgname.modname bcc:excludes + "function name"
-p to specify module name and option
bcc:excludes for function name. No
-p, same name function in the other scripts will be ignored too.
Exclude more functions by this way:
$ pyarmor cfg -p foo bcc:excludes + "hello foo2"
Let’s enable trace mode to check these functions are ignored:
$ pyarmor cfg enable_trace 1 $ pyarmor gen --enable-bcc foo.py $ grep trace.bcc .pyarmor/pyarmor.trace.log
Another example, in the following commands BCC mode ignores
joker/card.py, but handle all the other scripts in package
$ pyarmor cfg -p joker.card bcc:disabled=1 $ pyarmor gen --enable-bcc /path/to/pkg/joker
By both of
bcc:disabled, make all the problem code fallback to default obfuscation mode, and let others could be converted to c function and work fine.
4.5.4. Changed features¶
Here are some changed features in the BCC mode:
- Calling raise without argument not in the exception handler will raise different exception.
>>> raise RuntimeError: No active exception to re-raise # In BCC mode >>> raise UnboundlocalError: local variable referenced before assignment
- Some exception messages may different from the plain script.
- Most of function attributes which starts with
__doesn’t exists, or the value is different from the original.
4.5.5. Unsupported features¶
If a function uses any unsupported features, it could not be converted into C code.
Here list unsupported features for BCC mode:
unsupport_nodes = ( ast.ExtSlice, ast.AsyncFunctionDef, ast.AsyncFor, ast.AsyncWith, ast.Await, ast.Yield, ast.YieldFrom, ast.GeneratorExp, ast.NamedExpr, ast.MatchValue, ast.MatchSingleton, ast.MatchSequence, ast.MatchMapping, ast.MatchClass, ast.MatchStar, ast.MatchAs, ast.MatchOr )
And unsupported functions:
For example, the following functions are not obfuscated by BCC mode, because they use unsupported features or unsupported functions:
async def nested(): return 42 def foo1(): for n range(10): yield n def foo2(): frame = sys._getframe(2) print('parent frame is', frame)