バイトコードのローディング

ちょいとメモ。

require 'fiddle'

class RubyVM
  class InstructionSequence
    addr = Fiddle.dlopen(nil)['rb_iseq_load']
    fn   = Fiddle::Function.new(
             addr, [Fiddle::TYPE_VOIDP] * 3, Fiddle::TYPE_VOIDP)

    define_singleton_method(:load) do |dat, par=nil, opt=nil|
      fn.call(Fiddle.dlwrap(dat), par, opt).to_value
    end
  end
end

bytecode = RubyVM::InstructionSequence.compile("p 1").to_a

RubyVM::InstructionSequence.load(bytecode).eval #=> 1

ここにあったコードがWindowsだからなのかなんなのか動かなかったので動くように直して、テキストを食わせて動かす形にしてみた。

RubyVMを使うようになってからバイトコードを解釈して動作していて、このバイナリをファイルに出力してそれを読むようにすればソースの隠蔽は可能である。問題点はRubyVM::InstructionSequence.loadが「食わせるバイナリを検証する機能がない」という理由でコメントアウトされているところだが、C用のインターフェイスは提供されているので例えばDXRubyから呼ぶというのも手である。しかしFiddleを使えばRubyから呼べる。DLを使うようにすればRuby1.9でもいけるんじゃないかと思う。無論、変なもの食わせるとコケるかもしれん。
ともあれ、これをうまいこと使えればソース隠蔽に道が開けるんじゃないかなーなど。ちなみにto_aした配列は厳密にはバイナリでは無い。