好了,进入本文的主题——脚本加密:


 


Lua 是一个小巧的脚本语言。Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,Ini等文件格式,并且更容易理解和维护。在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。


lua是明文形式,如果不对脚本进行处理,那么我们所写的代码将可能暴露给别人。


luajit来实现加密的目的。

这种其实并不是真正意义上的加密,而是用luajit把lua脚本编译成字节码。

首先我们来用luajit来实现脚本的编译。其实就是一句话:

luajit -b source des

其含义即把源代码编译成二进制文件,达到加密的目的  

当然我们不可以每一个文件都来运行一遍,这样太麻烦,不符合我们程序员‘懒’的内涵。

第一种加密办法:利用xcode

这种方法的好处是新生产的文件结构依然是按照源码目录。

既然我们使用xcode作为IDE,那我们完全可以创建一个scheme来实现时时编译的目的。

利用xcode创建scheme步骤:

1.新建一个target 选择 external build system,build tool 选择 usr/bin/sh 即可。名称:build-lua

lua隐藏脚本 lua脚本加密教程_2d

2.然后配置如下调用。


lua隐藏脚本 lua脚本加密教程_2d_02

我把luajit -b source des利用python 扩展了一下, 基本的含义就是把遍历lua目录,分别编译脚本到新的目录。

# -*- coding: utf8 -*-

# this is single line comment
import os
import inspect
import ConfigParser
import re
import sys
import shutil


def findAllLuaFiles(dir):
	
	targets = []
	for f in os.listdir(dir):
		p = os.path.join(dir, f)
		if os.path.isfile(p):
			targets.append(p)
		else:
			rs = findAllLuaFiles(p)
			for rf in rs:
				targets.append(rf)
	
	return targets
		
def main():
	from optparse import OptionParser

	parser = OptionParser("usage: %prog [options]")
	parser.add_option("-s", action="store", type="string", dest="source", help="specifies the source folder")
	parser.add_option("-t", action="store", type="string", dest="target", help="specifies the target folder")

	(opts, args) = parser.parse_args()
	
	workingdir = os.path.dirname(inspect.getfile(inspect.currentframe()))
	sourceDir = opts.source
	targetDir = opts.target
	if os.path.exists(targetDir):
		shutil.rmtree(targetDir)
	
	shutil.copytree(sourceDir, targetDir)
	
	luaFiles = findAllLuaFiles(targetDir)
	
	from string import Template
	
	cmdTemplate = Template("/usr/local/bin/luajit -b $src $dist")
	for lf in luaFiles:
		command = cmdTemplate.substitute(src=lf, dist=lf)
		print "[Compile]", command
		os.system(command)



3.在我们的主程序中设置如下,把新建的build-lua 添加进来,使其在每次build的时候都能运行一遍。


lua隐藏脚本 lua脚本加密教程_lua_03

4.最后我们还要删除掉源代码,(注意在程序使用过程中,需要require 的时obj/下的文件。


lua隐藏脚本 lua脚本加密教程_Lua_04

Ps:在lua脚本引用的时候需要requrie的是des 目录,不是source目录。

 如果你嫌上面的方法繁琐的话,可以你可以试试quick-cocos2d-x gitHub地址为:https://github.com/dualface/quick-cocos2d-x

第二种加密办法:利用quick-cocos2d-x 

  Ps:quick-cocos2d-x 是最新版是基于cocos2dx2.2.3所以无法在cocos2dx3.0里面使用,除非仿写ccLuaStack.h/.cpp 对比发现工程量浩大。

设置加密密钥和加密签名,是将源目录直接打包成zip包。

  quick 是 cocos2d-x 针对 Lua 的豪华套装威力加强版。 可喜的是,quick团队在年初被触控科技收购了,以后我们就可以时时看到稳定更新了。

 quick 和 cocos2d-x 的主要区别有如下几点:

  1. 更完善的 Lua 支持,包括一个 Lua 框架对 C++ 接口进行了二次封装
  2. 补充了大量 cocos2d-x 没有提供,但游戏需要的功能
  3. 为提高开发效率,提供了 Objective-C 和 Java 的桥接模块,以及强化的 Windows/Mac 模拟器

  本文接下来将要讲述的就是quick的新功能,脚本加密。

在quick-cocos2d-x-develop/bin/目录下存在多个sh脚本,今天我们需要用到的就是compile_scripts.sh


lua隐藏脚本 lua脚本加密教程_lua隐藏脚本_05

compile_scripts.sh中带有不少的参数,详情如下: 

1、 -h 帮助。显示参数的解释及使用,英文的。 
2、-i 源码目录。 
3、-o 输出文件或目录。 
4、-p 包前缀。 
5、-x 不包含在内的包。如果你有些源文件不想被编译进去的话,将会用到这个参数,只能设置包(对应文件夹),不能指定到文件,多个包的话用,(逗号)隔开。示例:-x app.test,server,指的是app/test/.*,server/.* 这两个目录下的所有文件都不会被编译。
6、-m 编译模式。有两个值 : 
-m zip 默认,生成的是zip格式文件; 
-m files 生成的是一个个文件,不打包,这个时候-o参数指的就是输出的目录。 
7、-e 加密模式。可以对编译后的文件再进行 XXTEA 加密,有两个值: 
-e xxtea_zip 对应-m zip,对打包后的zip格式文件进行加密,之后再打包成zip格式。 
-e xxtea_chunk 对编译后的文件加密,最后打不打包取决于-m。 
8、-ek 加密密钥。对-e有效,且设置了-e之后一定要设置-ek。 
9、-es 加密签名。对-e有效,默认值为"XXTEA",这个只是为了让引擎知道文件是否被加密过,意义不大,所以可不设置。

10、-ex 编译后的文件的后缀名。对-m files有效,默认值为"lua"。 
11、-c 从一个文件加载参数列表。 
12、-q 生成过程不输出信息。

使用步骤:

1.复制quick-cocos2d-x-develop/lib/cocos2d-x/scripting/lua/cocos2dx_support下的CCLuaStack.h 和CCLuaStack.cpp 替换程序cocos2dx相应的文件。

quick帮我们扩展了三个文件,也就是我编译加密需要的三个函数:

virtual int loadChunksFromZip(const char *zipFilePath);
   virtual void setXXTEAKeyAndSign(const char *key, int keyLen);
   virtual void setXXTEAKeyAndSign(const char *key, int keyLen, const char *sign, int signLen);

2.可以直接在终端运行如下命令,也可以利用scheme执行下面的命令,

compile_scripts.sh -i scripts -o files/desc.zip -e xxtea_zip -ek 123456 -es 654321

123456 为加密密钥

654321 为加密签名

3.在代码调用的时候:

bool AppDelegate::applicationDidFinishLaunching()
{
	...
    CCLuaStack *pStack = pEngine->getLuaStack();
   
	// 第二,四参数分别为第一 三 字符串的长度
	pStack->setXXTEAKeyAndSign("123456", 6, "654321", 6);
	
    // load framework
    pStack->loadChunksFromZip("res/framework_precompiled.zip");
    pStack->loadChunksFromZip("res/game.zip");
	...

}




4. 删掉源代码文件

好了,我们的脚本已经编译加密了,再也不用担心被抄袭了。