ソースを隠蔽する手段

コンパイルして実行形式にしてしまう言語であれば、公開する人の意思でソースを出すかどうかを決めることができる。
その場合、ソースを出すのは一手間かかるため、どっちかというと公開したいという思いが無ければされない。
Rubyのようなスクリプト言語の場合、基本的にソースを公開することがソフトを配布することと同義になる。
こっちの場合だと、ソースを隠蔽するほうに一手間かかることになる。
exerbやocraでexe化して配布すると、とりあえず隠蔽はできるが、見ようと思えば簡単に見れる。もう一段のソース隠蔽をしたい、どうしても隠したいという人には、スクリプト言語は少し微妙な選択肢だ。
実際、exerbもocraもソースを隠すのが目的ではなく、現時点ではRubyの世界にはそのような需要が無い。
隠したい人は使うな、と言ってしまえば楽ではあるのだが、一手間かけてでも隠したい人がいるのならば、その一手間を提供する余地はあるのだろう。
ちなみに俺は作ったものはほぼすべてソース公開の方針なので、そういう人の気持ちは想像はできるが厳密にはわからない。確固たる信念があるわけでもないが、読みにくかろうが何だろうが、これで動いてるんだからいいじゃない、みたいな。
サンプルとかライブラリばっかりできちんとしたゲームを作ってないからなんだけど。


ソース隠蔽に関して、複雑な仕組みを作りこもうと思えばいくらでもできるのだが、どこまで難しくしても気合の入った人であればなんとかして見てしまうものだ。
動作を変えずに見た目だけ読みにくくする難読化も手としてはアリだが、これも気合の入った人は読み解くだろう。ゲームであれば実行速度が遅くなるような変更はできないから、難読化にも限界がある。
完璧に隠すことはスクリプト言語である限り難しいのだ。
じゃあどうしようか、と言うことで、気合の入った人の対策はあきらめて、ディレクトリ覗いたりエディタで開いたりしたらそこにあるよ、と言った状態を回避すれば、とりあえずはマシなのではないかと考えてみる。
具体的にはこのような感じで。

def encode(src)
  data = ""
  src.each_byte do |b|
    data << '\x' << (b ^ 255).to_s(16)
  end
  data
end

def decode(src)
  data = ""
  src.each_byte do |b|
    data << (b ^ 255).chr
  end
  data
end

puts encode('p "hello world"') # => \x8f\xdf\xdd\x97\x9a\x93\x93\x90\xdf\x88\x90\x8d\x93\x9b\xdd

eval decode(
%Q!\x8f\xdf\xdd\x97\x9a\x93\x93\x90\xdf\x88\x90\x8d\x93\x9b\xdd!
) # => "hello world"

encodeは入力した文字列を1バイト単位で255とxorして16進化、decodeをそれを戻す。xorはとりあえず最低限の暗号化ということで入れてみたが、好きなように置き換えれる。
これをRubyで書くと戻すときのevalをpに置き換えるだけでソースが見れてしまうので、decodeメソッドをevalまでするようにしてCで書いて提供する、とか。
もちろんDXRubyに組み込んだところでオープンソースだから、アルゴリズムは見ればわかるだろうし、スクリプトを書けば簡単に見ることはできる。でも、とりあえず手作業で手軽に見れる状態にはならないのではないかと思う。


このような形にする場合、Rubyのrequireはそれが拡張ライブラリなのかRubyディレクトリにあるライブラリなのか、ユーザーのファイルなのかが区別つかないから、できるなら元ソースを改変しなくていいのが望ましい。
隠蔽ツールの出力は

require 'dxruby'
DXRuby::decode_eval(%Q!文字列〜〜〜〜〜〜〜〜!)

みたいな感じか。
これで、元ソースと同じ名前で同じ場所に置けば、元とまったく同じように動くなら、あんまり手間はかからないかもしれないし、exerbにこれを突っ込めばそうそう簡単には読まれなくなるのではないかと思う。