トップ «前の日記(2008-08-07) 最新 次の日記(2008-08-09)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2008-08-08

_ スクリプトエンコーダ

ActiveScriptのエンコーダについて調べた。

「スクリプトエンコーダを使用する」

screncというツールを使って、コメント内に**Script Encode**を埋め込んだVBScriptやJScriptをエンコードする仕組みだ。

エンコードしたスクリプトは、通常のVBScriptではなく、VBScript.Encodeというクラス名で作成できるActiveScriptエンジンが処理する。

screncでエンコードした結果を見ると、quoted-printable encodingされた文字列に見える。といっても、デコードしても良くわからないバイナリーとなる。多分、キーワードを固定辞書でバイナリ値に置き換えているのではないだろうか。いずれにしろ、暗号化しているわけではないというような説明がされている。

なんの役に立つかと言うと、難読化と一種のハッシュ埋め込み(字が変わればデコードできないので安心)ということらしい。

いかにもありそうではあるが、脆弱性も見つかったりしている。

それはそれとして、Rubyで似たような仕組みを考えてみる。難読化とハッシュ。デコードして書き変えて再エンコードを防ぐ必要はないということ。だったら圧縮でバイナリにして、それをBase64でエンコードすれば良さそうだ。

こんな感じ。

c:\temp>type hello.rb                 ← 元のスクリプト
#**Start Encode**
puts("what your name ?")
name = gets
puts("hello #{name.chop} !")
 
c:\temp>ruby screnc.rb hello.rb hello2.rb ← エンコーダでエンコード
 
c:\temp>type hello2.rb                ← エンコードしたスクリプト
#**Start Encode**#@~eJzjKigtKdZQKs9ILFGozC8tUshLzE1VsFfS5AIzbBXSU0uKuSCKMlJzcvIV
lKtBMnrJGfkFtQqKQIUA7ikViA==
~@
c:\home\arton\temp>ruby scrdec.rb hello2.rb ← デコーダで実行
what your name ?
anonymous                      ← getsがARGFになるので最初びっくりした。
hello anonymous !

エンコーダはこんな感じで作ってみた。

require 'zlib'
 
if ARGV.size != 2 || !File.exist?(ARGV[0])
  $stderr.puts("usage: ruby screnc.rb src dst")
else
  File.open(ARGV[1], 'w') do |dst|
    s = File::read(ARGV[0])
    if s =~ /\#\*\*Start Encode\*\*(.*)$\Z/m
      dst.write($`)
      dst.write("#**Start Encode**")
      dst.write("#\@~")
      dst.write([Zlib::Deflate.deflate($1)].pack('m'))
      dst.write("~\@")
    else
      dst.write(s)
    end
  end
end

デコーダはこんな感じかな。

require 'tempfile'
require 'zlib'
 
alias _org_require require
 
def scr_require(scr)
  s = File::read(scr)
  if s =~ /\#\*\*Start Encode\*\*\#\@\~(.*)\~\@/m
    tmpf = Tempfile.new('scrf')
    begin
      tmpf.write($`)
      tmpf.write(Zlib::Inflate.inflate($1.unpack('m')[0]))
      tmpf.close(false)
      File.rename(tmpf.path, "#{tmpf.path}.rb")
      _org_require(tmpf.path)
    ensure
      File.delete("#{tmpf.path}.rb")
    end
  else
    _org_require(scr)
  end
end
 
def require(s)
  if File.exist?("#{s}.rb")
    scr_require("#{s}.rb")
  elsif File.exist?(s)
    scr_require(s)
  else
    _org_require(s)
  end
end
 
if $0 == __FILE__
  if ARGV.size != 1 || !File.exist?(ARGV[0])
    $stderr.puts("usage: ruby scrdec.rb encoded")
  else
    def gets
      $stdin.gets
    end
    require ARGV[0]
  end
end

_ Visual Basicの配列の次元

残念ながら、木村さんが間違っているのだが、何しろ、VB6以前はひげ(.NET)の世界より昔なので、土に埋もれてなかなか見つからない。それともVB.NETの話をしているのだろうか?

とりあえず、XLソフトの資料が見つかったので、リンクしとこう。

Basic コード:
 
	Declare Sub FORTARRAY Lib "fortarr.dll" (Barray as Single)
	DIM barray (1 to 3, 1 to 7) As Single
	Call FORTARRAY(barray (1,1))
 
Fortran コード:
 
	Subroutine FORTARRAY(arr)
	  REAL arr(3,7)

実際のところ、効率を無視すれば、どっちがどっちでも動くことは動くので、仕事プログラムでも逆に書いているのをたくさん見つけて頭を抱えたものだ(直さなかったけど。というか、VBプログラマは仕様を読まない。その代わりに、どこぞのCプログラマから聞かされた与太話を信じて仕事をするということはわかった)。このあたりは、SAFEARRAYの定義を読むとわかることはわかる(と思って読み返したらわからなかった)。

追記:やっぱりSAFEARRAYの仕様でわかるや。rgsabound単位にLboundが設定できるということと、rgsabound[0]がleft-most dimensionだということ、あるいは(同じことだけど)Redim(10)をRedim(10,10)に変えられること(.NETではできない)というように、各ランクが独立していることと、最初のランクが左端ということから、メモリ配置はランク単位に行われることになる。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|

ジェズイットを見習え