Skip to content

Commit f8df897

Browse files
committed
Refine protection and license code
1 parent ef453fa commit f8df897

File tree

4 files changed

+247
-217
lines changed

4 files changed

+247
-217
lines changed

src/protect_code.pt

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
def protect_pytransform():
22

3-
try:
4-
import pytransform{suffix} as pytransform
5-
except ImportError:
6-
from . import pytransform{suffix} as pytransform
3+
{relative}import pytransform{suffix} as pytransform
74

85
def assert_builtin(func):
96
type = ''.__class__.__class__
@@ -53,16 +50,13 @@ def protect_pytransform():
5350
if checksum not in {checksum}:
5451
raise RuntimeError('unexpected %s' % filename)
5552

56-
try:
57-
assert_builtin(sum)
58-
assert_builtin(open)
59-
assert_builtin(len)
53+
assert_builtin(sum)
54+
assert_builtin(open)
55+
assert_builtin(len)
6056

61-
check_obfuscated_script()
62-
check_mod_pytransform()
63-
check_lib_pytransform()
64-
except Exception as e:
65-
raise RuntimeError("Protection Fault: %s" % e)
57+
check_obfuscated_script()
58+
check_mod_pytransform()
59+
check_lib_pytransform()
6660

6761

6862
protect_pytransform()

src/protect_code2.pt

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
def protect_pytransform():
22

3-
try:
4-
import pytransform{suffix} as pytransform
5-
except ImportError:
6-
from . import pytransform{suffix} as pytransform
7-
83
def assert_builtin(func):
94
type = ''.__class__.__class__
105
builtin_function = type(''.join)
@@ -22,26 +17,21 @@ def protect_pytransform():
2217
raise RuntimeError('unexpected obfuscated script')
2318

2419
def check_lib_pytransform():
25-
from struct import unpack
20+
{relative}import pytransform{suffix} as pytransform
2621
filename = pytransform.__file__
2722
with open(filename, 'rb') as f:
28-
buf = f.read()
29-
size = len(buf) & 0xFFFFFFF0
30-
n = size >> 2
31-
fmt = 'I' * n
32-
checksum = sum(unpack(fmt, buf[:size])) & 0xFFFFFFFF
33-
if checksum not in {checksum}:
23+
buf = bytearray(f.read())
24+
value = sum(buf) & 0xFFFFFFFF
25+
if value not in {checklist}:
3426
raise RuntimeError('unexpected %s' % filename)
3527

36-
try:
37-
assert_builtin(sum)
38-
assert_builtin(open)
39-
assert_builtin(len)
28+
assert_builtin(bytearray)
29+
assert_builtin(sum)
30+
assert_builtin(open)
31+
assert_builtin(len)
4032

41-
check_obfuscated_script()
42-
check_lib_pytransform()
43-
except Exception as e:
44-
raise RuntimeError("Protection Fault: %s" % e)
33+
check_obfuscated_script()
34+
check_lib_pytransform()
4535

4636

4737
protect_pytransform()

src/pyarmor.py

Lines changed: 91 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@
5252
get_product_key, register_keyfile, query_keyinfo, \
5353
get_platform_list, download_pytransform, update_pytransform,\
5454
check_cross_platform, compatible_platform_names, \
55-
get_name_suffix, get_bind_key, make_super_bootstrap
55+
get_name_suffix, get_bind_key, make_super_bootstrap, \
56+
make_protection_code
5657

5758
import packer
5859

@@ -227,6 +228,41 @@ def _build(args):
227228
if hasattr(project, 'advanced_mode') else 0
228229
supermode = adv_mode > 1
229230

231+
protection = project.cross_protection \
232+
if hasattr(project, 'cross_protection') else 1
233+
234+
bootstrap_code = project.get('bootstrap_code', 1)
235+
relative = True if bootstrap_code == 3 else \
236+
False if (bootstrap_code == 2 or
237+
(args.no_runtime and bootstrap_code == 1)) else None
238+
239+
if args.no_runtime:
240+
if protection == 1:
241+
logging.warning('No cross protection because no runtime generated')
242+
protection = 0
243+
else:
244+
routput = output if args.output is not None and args.only_runtime \
245+
else os.path.join(output, os.path.basename(project.src)) \
246+
if project.get('is_package') else output
247+
if not os.path.exists(routput):
248+
logging.info('Make path: %s', routput)
249+
os.mkdir(routput)
250+
251+
package = project.get('package_runtime', 0) \
252+
if args.package_runtime is None else args.package_runtime
253+
254+
licfile = project.license_file
255+
if not restrict and not licfile:
256+
licfile = 'no-restrict'
257+
258+
checklist = make_runtime(capsule, routput, licfile=licfile,
259+
platforms=platforms, package=package,
260+
suffix=suffix, supermode=supermode)
261+
if protection == 1:
262+
protection = make_protection_code((relative, checklist, suffix),
263+
multiple=bool(platforms),
264+
supermode=supermode)
265+
230266
if not args.only_runtime:
231267
src = project.src
232268
if os.path.abspath(output).startswith(src):
@@ -264,11 +300,6 @@ def _build(args):
264300
wrap_mode = 0
265301
obf_code = 0 if project.obf_code_mode == 'none' else 1
266302

267-
bootstrap_code = project.get('bootstrap_code', 1)
268-
relative = True if bootstrap_code == 3 else \
269-
False if (bootstrap_code == 2 or
270-
(args.no_runtime and bootstrap_code == 1)) else None
271-
272303
def v(t):
273304
return 'on' if t else 'off'
274305
logging.info('Obfuscating the whole module is %s', v(obf_mod))
@@ -279,8 +310,6 @@ def v(t):
279310

280311
entries = [build_path(s.strip(), project.src)
281312
for s in project.entry.split(',')] if project.entry else []
282-
protection = project.cross_protection \
283-
if hasattr(project, 'cross_protection') else 1
284313

285314
for x in sorted(files):
286315
a, b = os.path.join(src, x), os.path.join(soutput, x)
@@ -315,41 +344,13 @@ def v(t):
315344
project['build_time'] = time.time()
316345
project.save(args.project)
317346

318-
if adv_mode < 2 and project.entry and bootstrap_code:
347+
if (not supermode) and project.entry and bootstrap_code:
319348
soutput = os.path.join(output, os.path.basename(project.src)) \
320349
if project.get('is_package') else output
321350
make_entry(project.entry, project.src, soutput,
322351
rpath=project.runtime_path, relative=relative,
323352
suffix=suffix)
324353

325-
if not args.no_runtime:
326-
routput = output if args.output is not None and args.only_runtime \
327-
else os.path.join(output, os.path.basename(project.src)) \
328-
if project.get('is_package') else output
329-
if not os.path.exists(routput):
330-
logging.info('Make path: %s', routput)
331-
os.mkdir(routput)
332-
333-
package = project.get('package_runtime', 0) \
334-
if args.package_runtime is None else args.package_runtime
335-
make_runtime(capsule, routput, platforms=platforms, package=package,
336-
suffix=suffix, supermode=supermode)
337-
338-
licfile = project.license_file
339-
if licfile:
340-
logging.info('Project has customized license file: %s', licfile)
341-
licpath = os.path.join(routput, 'pytransform' + suffix) \
342-
if package else routput
343-
logging.info('Copy project license file to %s', licpath)
344-
shutil.copy(licfile, licpath)
345-
elif not restrict:
346-
licode = '*FLAGS:%c*CODE:PyArmor-Project' % chr(1)
347-
licpath = os.path.join(routput, 'pytransform' + suffix) \
348-
if package else routput
349-
licfile = os.path.join(licpath, license_filename)
350-
logging.info('Generate no restrict mode license file: %s', licfile)
351-
make_license_key(capsule, licode, licfile)
352-
353354
logging.info('Build project OK.')
354355

355356

@@ -518,7 +519,7 @@ def _obfuscate(args):
518519
if check_cross_platform(platforms) is not False:
519520
return
520521

521-
for x in ('entry', 'cross-protection'):
522+
for x in ('entry',):
522523
if getattr(args, x.replace('-', '_')) is not None:
523524
logging.warning('Option --%s has been deprecated', x)
524525

@@ -606,6 +607,7 @@ def _obfuscate(args):
606607

607608
advanced = args.advanced if args.advanced else 0
608609
logging.info('Advanced mode is %d', advanced)
610+
supermode = advanced > 1
609611

610612
restrict = args.restrict
611613
logging.info('Restrict mode is %d', restrict)
@@ -614,6 +616,25 @@ def _obfuscate(args):
614616
relative = True if n == 3 else False if n == 2 else None
615617
bootstrap = (not args.no_bootstrap) and n
616618
elist = [os.path.abspath(x) for x in entries]
619+
620+
if args.no_runtime:
621+
if cross_protection == 1:
622+
logging.warning('No cross protection because no runtime generated')
623+
cross_protection = 0
624+
else:
625+
package = args.package_runtime
626+
licfile = args.license_file
627+
if (not restrict) and (licfile is not None):
628+
licfile = 'no-restrict'
629+
checklist = make_runtime(capsule, output, platforms=platforms,
630+
licfile=licfile, package=package,
631+
suffix=suffix, supermode=supermode)
632+
if cross_protection == 1:
633+
cross_protection = make_protection_code(
634+
(relative, checklist, suffix),
635+
multiple=bool(platforms),
636+
supermode=supermode)
637+
617638
for x in sorted(files):
618639
if os.path.isabs(x):
619640
a, b = x, os.path.join(output, os.path.basename(x))
@@ -634,30 +655,12 @@ def _obfuscate(args):
634655
plugins=plugins, suffix=suffix, obf_code=args.obf_code,
635656
obf_mod=args.obf_mod, wrap_mode=args.wrap_mode)
636657

637-
if advanced > 1:
658+
if supermode:
638659
make_super_bootstrap(a, b, relative=relative, suffix=suffix)
639660
elif is_entry and bootstrap:
640661
name = os.path.abspath(a)[len(path)+1:]
641662
make_entry(name, path, output, relative=relative, suffix=suffix)
642663

643-
logging.info('%d scripts have been obfuscated', len(files))
644-
645-
if args.no_runtime:
646-
logging.info('Obfuscate %d scripts OK.', len(files))
647-
return
648-
649-
package = args.package_runtime
650-
make_runtime(capsule, output, platforms=platforms,
651-
package=package, suffix=suffix, supermode=advanced > 1)
652-
653-
if not args.restrict:
654-
licode = '*FLAGS:%c*CODE:PyArmor-Project' % chr(1)
655-
licpath = (os.path.join(output, 'pytransform' + suffix) if package
656-
else output)
657-
licfile = os.path.join(licpath, license_filename)
658-
logging.info('Generate no restrict mode license file: %s', licfile)
659-
make_license_key(capsule, licode, licfile)
660-
661664
logging.info('Obfuscate %d scripts OK.', len(files))
662665

663666

@@ -795,15 +798,26 @@ def _runtime(args):
795798
package = not args.no_package
796799
platforms = compatible_platform_names(args.platforms)
797800
suffix = get_name_suffix() if args.enable_suffix else ''
798-
make_runtime(capsule, output, licfile=args.with_license,
799-
platforms=platforms, package=package, suffix=suffix,
800-
restrict=False, supermode=args.super_mode)
801-
802-
filename = os.path.join(output, '__init__.py') if args.inside else \
803-
os.path.join(args.output, name + '.py')
804-
logging.info('Generating bootstrap script ...')
805-
make_bootstrap_script(filename, capsule=capsule, suffix=suffix)
806-
logging.info('Generating bootstrap script %s OK', filename)
801+
licfile = 'no' if args.no_license else args.license_file
802+
checklist = make_runtime(capsule, output, licfile=licfile,
803+
platforms=platforms, package=package,
804+
suffix=suffix, restrict=False,
805+
supermode=args.super_mode)
806+
807+
logging.info('Generating protection script ...')
808+
filename = os.path.join(output, 'pytransform_protection.py')
809+
data = make_protection_code((args.inside, checklist, suffix),
810+
multiple=bool(platforms),
811+
supermode=args.super_mode)
812+
with open(filename, 'r') as f:
813+
f.write(data)
814+
815+
if not args.super_mode:
816+
filename = os.path.join(output, '__init__.py') if args.inside else \
817+
os.path.join(args.output, name + '.py')
818+
logging.info('Generating bootstrap script ...')
819+
make_bootstrap_script(filename, capsule=capsule, suffix=suffix)
820+
logging.info('Generating bootstrap script %s OK', filename)
807821

808822

809823
def _version_action():
@@ -876,9 +890,6 @@ def _parser():
876890
dest='bootstrap_code',
877891
type=int, default=1, choices=(0, 1, 2, 3),
878892
help='How to insert bootstrap code to entry script')
879-
cparser.add_argument('--no-cross-protection', action='store_true',
880-
help='Do not insert cross protection code to entry '
881-
'script')
882893
cparser.add_argument('scripts', metavar='SCRIPT', nargs='+',
883894
help='List scripts to obfuscated, the first script '
884895
'is entry script')
@@ -887,8 +898,6 @@ def _parser():
887898
'in the top most path')
888899
cparser.add_argument('-e', '--entry', metavar='SCRIPT',
889900
help=argparse.SUPPRESS)
890-
cparser.add_argument('--cross-protection', choices=(0, 1),
891-
help=argparse.SUPPRESS)
892901
cparser.add_argument('--plugin', dest='plugins', metavar='NAME',
893902
action='append',
894903
help='Insert extra code to entry script, '
@@ -912,6 +921,14 @@ def _parser():
912921
help='DO NOT generate runtime files')
913922
cparser.add_argument('--enable-suffix', action='store_true',
914923
help='Make unique runtime files and bootstrap code')
924+
cparser.add_argument('--with-license', dest='license_file',
925+
help='Use this license file other than default')
926+
group = cparser.add_mutually_exclusive_group()
927+
group.add_argument('--no-cross-protection', action='store_true',
928+
help='Do not insert protection code to entry script')
929+
group.add_argument('--cross-protection', metavar='SCRIPT',
930+
help='Specify cross protection script')
931+
915932
cparser.set_defaults(func=_obfuscate)
916933

917934
#
@@ -1214,7 +1231,10 @@ def _parser():
12141231
help='Generate bootstrap script which is used '
12151232
'inside one package')
12161233
cparser.add_argument('-L', '--with-license', metavar='FILE',
1234+
dest='license_file',
12171235
help='Replace default license with this file')
1236+
cparser.add_argument('without-license', dest='no_license',
1237+
action='store_true', help=argparse.SUPPRESS)
12181238
cparser.add_argument('--platform', dest='platforms', metavar='NAME',
12191239
action='append',
12201240
help='Generate runtime package for this platform, '

0 commit comments

Comments
 (0)