Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ISeqで遊ぼう

Tsukasa OISHI
September 22, 2018

 ISeqで遊ぼう

Tsukasa OISHI

September 22, 2018
Tweet

More Decks by Tsukasa OISHI

Other Decks in Programming

Transcript

  1. class HookLoadIseq def attach RubyVM::InstructionSequence.singleton_class.prepend build_module end private def build_module

    inst = self Module.new do define_method("load_iseq") do |path| source_code = File.read(path) ruby_code = inst.syntax(source_code) RubyVM::InstructionSequence.compile(ruby_code) end end end end
  2. class HookLoadIseq def attach RubyVM::InstructionSequence.singleton_class.prepend build_module end private def build_module

    inst = self Module.new do define_method("load_iseq") do |path| source_code = File.read(path) ruby_code = inst.syntax(source_code) RubyVM::InstructionSequence.compile(ruby_code) end end end end
  3. class HookLoadIseq def attach RubyVM::InstructionSequence.singleton_class.prepend build_module end private def build_module

    inst = self Module.new do define_method("load_iseq") do |path| source_code = File.read(path) ruby_code = inst.syntax(source_code) RubyVM::InstructionSequence.compile(ruby_code) end end end end
  4. class HookLoadIseq def attach RubyVM::InstructionSequence.singleton_class.prepend build_module end private def build_module

    inst = self Module.new do define_method("load_iseq") do |path| source_code = File.read(path) ruby_code = inst.syntax(source_code) RubyVM::InstructionSequence.compile(ruby_code) end end end end
  5. class HookLoadIseq def attach RubyVM::InstructionSequence.singleton_class.prepend build_module end private def build_module

    inst = self Module.new do define_method("load_iseq") do |path| source_code = File.read(path) ruby_code = inst.syntax(source_code) RubyVM::InstructionSequence.compile(ruby_code) end end end end
  6. class HookLoadIseq def attach RubyVM::InstructionSequence.singleton_class.prepend build_module end private def build_module

    inst = self Module.new do define_method("load_iseq") do |path| source_code = File.read(path) ruby_code = inst.syntax(source_code) RubyVM::InstructionSequence.compile(ruby_code) end end end end
  7. class Tsuka var kazu int = 1 var moji string

    = "tsuka" var kuji bool = false end ͜Μͳจ๏΋࣮ߦՄೳʹ
  8. ͜Μͳจ๏΋࣮ߦՄೳʹ දࣔ 1 + 2 ശ Ͷ͜ ಈ࡞ ͳ͘ "ʹΌʔ"

    ͓ΘΓ ͓ΘΓ ͨ· = Ͷ͜.͏·ΕΔ දࣔ ͨ·.ͳ͘
  9. 0000 getinstancevariable :@user, <is:0> 0003 dup 0004 branchnil 12 0006

    send <callinfo!mid:address, argc:0, …>,… 0010 jump 12 0012 leave
  10. ["YARVInstructionSequence/SimpleDataFormat", 2, 5, 1, {:arg_size=>0, :local_size=>0, :stack_max=>1, :code_range=>[1, 0, 1,

    13]}, "<compiled>", "<compiled>", nil, 1, :top, [], {}, [], [1, :RUBY_EVENT_LINE, [:getinstancevariable, :@user, 0], [:send, {:mid=>:address, :flag=>32, :orig_argc=>0}, false, nil], [:leave]]]
  11. ["YARVInstructionSequence/SimpleDataFormat", 2, 5, 1, {:arg_size=>0, :local_size=>0, :stack_max=>1, :code_range=>[1, 0, 1,

    13]}, "<compiled>", "<compiled>", nil, 1, :top, [], {}, [], [1, :RUBY_EVENT_LINE, [:getinstancevariable, :@user, 0], [:send, {:mid=>:address, :flag=>32, :orig_argc=>0}, false, nil], [:leave]]]
  12. ϝιουίʔϧͷ෦෼Λ΅ͬͪΦϖϨʔλʹॻ͖׵͑Δ ary = iseq.to_a new_bytecode = [] bytecode = ary[13]

    pc = 0 bytecode.each do |b| unless b.is_a?(Array) new_bytecode << b next end unless [ :send, :opt_send_without_block].include?(b[0]) pc += b.size new_bytecode << b next end
  13. ϝιουίʔϧͷ෦෼Λ΅ͬͪΦϖϨʔλʹॻ͖׵͑Δ buffer = [] pc += 1 buffer << [

    :dup ] pc += 2 buffer << [ :branchnil, :temp ] pc += b.size buffer << b pc += 2 label = "label_#{pc}".to_sym buffer << [ :jump, label ] buffer[1][1] = label buffer << label new_bytecode += buffer end ary[13] = new_bytecode
  14. pEEMFΛ࢖ͬͯ$ͷؔ਺ΛݺͿ def load_from_array(ary) rb_iseq_load.call(Fiddle.dlwrap(ary), nil, nil).to_value end def rb_iseq_load return

    @rb_iseq_load if @rb_iseq_load address = Fiddle::Handle::DEFAULT['rb_iseq_load'] @rb_iseq_load = Fiddle::Function.new( address, [Fiddle::TYPE_VOIDP] * 3, Fiddle::TYPE_VOIDP ) end
  15. module GuardNil2 def translate(iseq) ary = iseq.to_a ary2 = {όΠτίʔυॻ͖׵͑ॲཧ}(ideq)

    load_from_array(ary2) end end RubyVM::InstructionSequence.singleton_class.prepend GuardNil2