結果だけでなく過程も見てください

たい焼きさんの日々の奮闘を綴る日記です。

暗号化等が施されたLuaファイルの読み込み方法

今回はファイル読み込みのお話です。暗号化の話ではないのであしからず。

通常Luaファイルの読み込みは、以下の関数やマクロを使用して行います。

luaL_loadfile(L, filename)
luaL_dofile(L, filename)

テキストで書かれたLuaファイルをロードする場合は上記を使えば十分でしょう。

しかし実際にソフトウェアを配布するときはユーザーからLuaスクリプト
内容が見えないように暗号化したり、1つのファイルにパッキングするのが普通です。

そのため、まずはC言語側の配列にファイル内容をロードして復号等の処理を
施した後にLuaスクリプトをロードさせるような処理を行う必要があります。

具体的な流れとしては、以下のような感じです。

1. バイナリレベルでファイルオープンして配列に格納する
2. 配列に対して復号等の処理を行う。
   (これで配列の内容がLuaのインタプリタが解釈可能なコードになる)
3. 配列のコードをLuaスクリプトとしてロード・実行する

とにかくソース

お待ちかね(?)のソースコード(C++)です。
lua_Stateのセットアップとかは過去の記事を参照してください。

ファイルの読み込みにはWin32のAPIを使用しています。
読み込むファイル名は「map1.dat」とします。

// ファイルの読み込み
HANDLE hFile = ::CreateFile( "map1.dat",
                             GENERIC_READ,
                             0, 
                             NULL, 
                             OPEN_EXISTING, 
                             0, 
                             NULL );
if ( hFile == INVALID_HANDLE_VALUE )
{
  fprintf( stderr, "Luaファイルの読み込み失敗(%d)", GetLastError() );
  return -1;
}

DWORD dwFileSize = ::GetFileSize( hFile, NULL );
if ( dwFileSize == -1 )
{
  fprintf( stderr, "Luaファイルのサイズ取得失敗(%d)", GetLastError() );
  return -1;
}

DWORD dwRead;
char* pTemp = new char[dwFileSize+1];
int rc = ::ReadFile( hFile, pTemp, dwFileSize, &dwRead, NULL );
if ( rc == 0 ||
     dwFileSize != dwRead )
{
  rc = GetLastError();
  fprintf( stderr, "Luaファイルの読み込みに失敗(%d)", GetLastError() );
  goto Cleanup;
}


// TODO:ここに復号等の処理を行うコードを書く


rc = luaL_loadbuffer( L, const_cast<const char*>(pTemp), dwFileSize, NULL );
if ( rc != 0 )
{
  fprintf( stderr, "Luaファイルの読み込み失敗(オンメモリ)(%d)", rc );
  goto Cleanup;
}

// ロードされている関数を実行
rc = lua_pcall( L, 0, LUA_MULTRET, 0 );
if ( rc != 0 )
{
  fprintf( stderr, "Luaファイルの読み込み失敗(pcall)(%d)", rc );
  goto Cleanup;
}

// TODO:ここにLuaファイル内の関数をコールする処理等のコードを書く

Cleanup:

if ( pTemp != NULL )
{
  delete [] pTemp;
  pTemp = NULL;
}

return rc;

暗号化・復号については各自お気に入りのものを選んでくださいね。