轻量级加密lua

来源:互联网 发布:北大软禁季羡林 知乎 编辑:程序博客网 时间:2024/06/05 07:00

     首先是压缩lua文件,代码如下:     

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int write_file_content(const char* folder)  
  2. {  
  3.     //获得文件数据,并压缩文件  
  4.     FILE* fpin = fopen(folder, "wb+");  
  5.     if (fpin == NULL)  
  6.     {  
  7.         printf("无法读取文件: %s\n", folder);  
  8.         return 0;  
  9.     }  
  10.   
  11.     //得到文件大小  
  12.     fseek(fpin, 0, SEEK_END);  
  13.     unsigned int size = ftell(fpin);  
  14.   
  15.     //读出文件内容  
  16.     fseek(fpin, 0, SEEK_SET);  
  17.     void* con = malloc(size);  
  18.     int r = fread(con, size, 1, fpin);    
  19.   
  20.     //进行加密操作  
  21.     unsigned long zip_con_size = size * 2;  
  22.     void* zip_con = malloc(zip_con_size);  
  23.     if (Z_OK != compress((Bytef*)zip_con, &zip_con_size, (Bytef*)con, size))   
  24.     {  
  25.         printf("压缩 %s 时发生错误\n",folder);  
  26.     }  
  27.     printf("%s 压缩前大小:%ld 压缩后大小:%ld\n", folder,  size,  zip_con_size);  
  28.   
  29.     //写文件内容  
  30.     fseek(fpin, 0, SEEK_SET);  
  31.     int len = fwrite(zip_con, zip_con_size, 1, fpin);  
  32.   
  33.     //释放资源  
  34.     fclose(fpin);  
  35.     free(zip_con);  
  36.     free(con);    
  37.     return 0;  
  38. }  

       然后是解密操作,代码如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. void* read_file_content(const char* folder, int& bufflen)  
  2. {  
  3.     FILE* file = fopen(folder, "wb+");  
  4.     if (file)  
  5.     {     
  6.     {  
  7.         printf("无法读取文件: %s\n", folder);  
  8.         return 0;  
  9.     }  
  10.   
  11.     //获取文件大小  
  12.     fseek(file, 0, SEEK_END);  
  13.     unsigned int size = ftell(file);  
  14.   
  15.     //读出文件内容  
  16.     void* con = malloc(size);  
  17.     fseek(file, 0, SEEK_SET);  
  18.     int len = fread(con, size, 1, file);  
  19.   
  20.     //解压缩操作  
  21.     unsigned long zip_size = size * 4;  
  22.     void* zip_con = malloc(zip_size);  
  23.     int code = uncompress((Bytef*)zip_con, &zip_size, (Bytef*)con, size);  
  24.     if (Z_OK != code)  
  25.     {  
  26.         printf("解压 %s 时发生错误 :%d\n", folder, code);  
  27.         return 0;  
  28.     }  
  29.   
  30.     //释放资源  
  31.     fclose(file);  
  32.     free(con);  
  33.   
  34.     //zip_con由外部释放  
  35.     bufflen = zip_size;  
  36.     return zip_con;  
  37. }  




cocos2d-x-lua工程的lua脚本加密

2014/1/26 更新

最近又发现了一个很简单的方法,其实coco2dx已经给我们提供设置loader的方法。

注意:有个局限性,在非android平台下调用pEngine->executeScriptFile是不调用loader的,只有require这种才会调用loader。也就是说你直接executeScriptFile("main.lua")这个脚本不能加密,main.lua里面require的才能加密

 

步骤如下:

1、实现自己的loader(参考int cocos2dx_lua_loader(lua_State *L))

 

复制代码
#define CODE_MASK 250extern "C"{    int decode_lua_loader(lua_State *L)    {        std::string filename(luaL_checkstring(L, 1));        size_t pos = filename.rfind(".lua");        if (pos != std::string::npos)        {            filename = filename.substr(0, pos);        }                pos = filename.find_first_of(".");        while (pos != std::string::npos)        {            filename.replace(pos, 1, "/");            pos = filename.find_first_of(".");        }        filename.append(".lua");                unsigned long codeBufferSize = 0;        unsigned char* codeBuffer = CCFileUtils::sharedFileUtils()->getFileData(filename.c_str(), "rb", &codeBufferSize);                //-------------decode here        for(int i=0; i<codeBufferSize; i++)        {            codeBuffer[i] ^= CODE_MASK; //xor decode        }        //-------------        if (codeBuffer)        {            if (luaL_loadbuffer(L, (char*)codeBuffer, codeBufferSize, filename.c_str()) != 0)            {                luaL_error(L, "error loading module %s from file %s :\n\t%s",                    lua_tostring(L, 1), filename.c_str(), lua_tostring(L, -1));            }            delete []codeBuffer;        }        else        {            CCLog("can not get file data of %s", filename.c_str());        }                return 1;    }}
复制代码

 

 

 

2、添加loader

CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);pEngine->addLuaLoader(decode_lua_loader);//add this

 

我在win32上测试通过

 

----------------------------------------------------------------------------------------分割线----------------------------------------------------------------------------------------

 

发了这篇博客之后好多同学联系我,说感觉还是不太明白,那我再说清楚一些

2014/1/15 更新

转载请注明出处http://www.cnblogs.com/mrblue/admin/EditPosts.aspx?postid=3122543

 

前言部分

1、本文是以cocos2d-x-lua项目为例说明的。

2、我这里只说下我自己遇到的问题和解决方法,当大家也遇到时可以参考下。

3、我所使用的cocos2d-x版本是cocos2d-2.1rc0-x-2.1.3,这个版本使用的是luajit,而不是源生的lua,luajit有很多好处。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

方法一:

这种其实并不是真正意义上的加密,而是用luajit把lua脚本编译成字节码(我之前实验过用luac编译出的字节码不能被luajit执行)。

1)编译luajit,这里并不是编译luajit的库,而是编译luajit的控制台程序,用作后面把lua脚本代码文件编译成字节码用。

  cd到 coco2dx安装目录/scripting/lua/luajit/LuaJIT-2.0.1

2) 输入make(如果控台显示command not found,那就要先安装make,Mac作为UNIX系却没有提供make,需要打开xCode->xCode(菜单栏)->Open Developer Tool->More Developer Tools->注册/登陆AppID->选择你对应的Command Line Tool->下载安装)

  这时会在src文件夹下生成可执行文件luajit(这b玩意我找了好久,根本找不到在哪生成的)

3) 有了luajit这个可执行文件,我们就可以拿它编译lua脚本了。

  这时cd进src目录

  输入./luajit -b hello1.lua hello1.out

  这个hello1.lua应该是你要编译的源文件,必要时请带上路径。

  注意:你不能把luajit这个可执行文件单独拿出来到别处去运行,因为在src里有些它需要依赖的东西,如果你想把luajit移地方,那你把(当前已经在src文件夹了)luajit、jit文件夹、好几个.dasc文件打个包,这样你就可以到其他的地方运行luajit了。

4)把这个hello1.out加到你工程里,就可以直接当成普通的脚本一样运行。

【严重注意】:如果你hello1.lua里面写了require "hello2"那你最好把hello2.lua的生成的文件也命名成hello2.lua,否则再执行hello1.lua的时候就找不到依赖的hello2.lua。当然你也可以require的文件写带后缀名的文件,但这我没有试验过行不行。

方法二:

方法二的前提是你不用luajit,而使用lua。

这样这种方法是真正加密,原理是我们自己替换掉lua的的loader函数。

其实这种方法是因为我之前以为coco2dx用的lua,我在调试lua代码的时候发现的,当然也受到别的大神的启发。

先贴出一段代码

复制代码
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {  LoadF lf;  int status, readstatus;  int c;  int fnameindex = lua_gettop(L) + 1;  /* index of filename on the stack */  lf.extraline = 0;  if (filename == NULL) {    lua_pushliteral(L, "=stdin");    lf.f = stdin;  }  else {    lua_pushfstring(L, "@%s", filename);    lf.f = fopen(filename, "r");    if (lf.f == NULL) return errfile(L, "open", fnameindex);  }  c = getc(lf.f);  if (c == '#') {  /* Unix exec. file? */    lf.extraline = 1;    while ((c = getc(lf.f)) != EOF && c != '\n') ;  /* skip first line */    if (c == '\n') c = getc(lf.f);  }  if (c == LUA_SIGNATURE[0] && filename) {  /* binary file? */    lf.f = freopen(filename, "rb", lf.f);  /* reopen in binary mode */    if (lf.f == NULL) return errfile(L, "reopen", fnameindex);    /* skip eventual `#!...' */   while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;    lf.extraline = 0;  }  ungetc(c, lf.f);  status = lua_load(L, getF, &lf, lua_tostring(L, -1));  readstatus = ferror(lf.f);  if (filename) fclose(lf.f);  /* close file (even in case of errors) */  if (readstatus) {    lua_settop(L, fnameindex);  /* ignore results from `lua_load' */    return errfile(L, "read", fnameindex);  }  lua_remove(L, fnameindex);  return status;}
复制代码

 

每当要加载新的lua文件时都会调用luaL_loadfile,当走到status = lua_load(L, getF, &lf, lua_tostring(L, -1))时就说明要从文件读取内容了,注意这里穿了一个参数getF,它其实是个函数指针,我们把这个贴出来

复制代码
static const char *getF (lua_State *L, void *ud, size_t *size) {  LoadF *lf = (LoadF *)ud;  (void)L;  if (lf->extraline) {    lf->extraline = 0;    *size = 1;    return "\n";  }  if (feof(lf->f)) return NULL;  *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);  return (*size > 0) ? lf->buff : NULL;}
复制代码

这个函数走完了,lf->buff就有了脚本文件的内容,说道这俩大家就明白了把,我们可以在getF里搞点小动作,比如这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#if 0
static const char *getF (lua_State *L, void *ud,size_t *size) {
  LoadF *lf = (LoadF *)ud;
  (void)L;
  if (lf->extraline) {
    lf->extraline = 0;
    *size = 1;
    return "\n";
  }
  if (feof(lf->f))return NULL;
  *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
  return (*size > 0) ? lf->buff : NULL;
}
 
#else
int DeCode(char *pBuffer,int nSize);
 
static const char *getF (lua_State *L, void *ud,size_t *size) {
    LoadF *lf = (LoadF *)ud;
    (void)L;
    if (lf->extraline) {
        lf->extraline = 0;
        *size = 1;
        return "\n";
    }
    if (feof(lf->f))return NULL;
    *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
     
    DeCode(lf->buff,*size);//decode file content
     
    return (*size > 0) ? lf->buff : NULL;
}
#endif

  这样这个lua库编译是会通过,但是链接是不通过的,就需要我们在外面实现一下DeCode函数。

那我们写个测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <stdlib.h>
#include <fstream>
 
#include <Windows.h>
 
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
 
using namespace std;
 
#define CODE_MASK 250   //:)
 
extern "C" {
int EnCode(char *pBuffer,int nSize)
{
    for (size_t i=0; i<nSize; i++)
    {
        pBuffer[i] ^= CODE_MASK;
    }
    return nSize;
}
 
int DeCode(char *pBuffer,int nSize)
{
    return EnCode(pBuffer,nSize);
}
 
}
 
string GetCodeFile(const char* file)
{
    char * pBuffer = NULL;
    size_t nSize = 0;
 
    //read file
    FILE *fp = fopen(file,"rb");
    fseek(fp,0,SEEK_END);
    nSize = ftell(fp);
    fseek(fp,0,SEEK_SET);
    pBuffer = new char[nSize];
    nSize = fread(pBuffer,sizeof(char), nSize,fp);
    fclose(fp);
 
    //encode
    EnCode(pBuffer,nSize);
 
    //save file
    string str = file;
    str+=".out";
    FILE *fpw = fopen(str.c_str(),"wb");
    fwrite(pBuffer, nSize, 1, fpw);
    fclose(fpw);
 
    //free memory
    delete pBuffer;
 
    return str;
}
 
int main(int argc,char* argv[])
{
     
    lua_State   *L = lua_open();
    luaL_openlibs(L);
    if (2==argc)
    {
        //do original file
        //luaL_dofile(L, argv[1]);
 
        //do code file
        luaL_dofile(L, GetCodeFile(argv[1]).c_str());
    }
 
    system("PAUSE");
 
    return 0;
}

这种方法我自己测试可行的。怎么加密在你,我这只是说了个简单的异或加密解密,

需要注意的是:实际上我跟踪代码发现lua并不是一次性把整个文件全部加载,而是每次512的字节。也就是说如果你的文件很大的话,加载它是会多次调用getF

 

   如有疑问eMail我,blue-1986@hotmail.com

 如有错误请指正,大家一起进步。


0 0
原创粉丝点击