cafebabe.jp 日々のよしなしごとをのたまうブログ.

194月/110

増分難読化

DotfuscatorDash-O に代表される難読化ツールに搭載されている機能の一つで,最近見る難読化ツールにはよく見られる.

難読化はプログラムコードを読みにくく変換する.そして,その変換作業において,プログラムコード上の多くの様々な情報と整合性を持たせて,変換後のプログラムも実行に支障がでないようにする必要がある.そのため,従来の難読化ツールはプログラムの実行に要する全てのファイルを与えられなければ正常に実行できる難読化後のプログラムを得ることはできなかった.

この増分難読化は上記の従来の制限を取り外すもので,難読化ツールにプログラム全体を常に与える必要はないものである.難読化処理にも時間がかかるため,プログラムの規模が大きくなると,毎回全てのプログラムコードを難読化していると,オーバーヘッドが無視できない場合がでてくる.そのため,変更が行われた部分のみを難読化ツールに与えて実行可能なプログラムを得る機構である.

具体的な方法として,名前難読化であれば,名前をどのように変換したのかのマッピング情報を同時に与えることで可能である.この増分難読化の実装はツールに依存し,全ての難読化手法で有効であるとは限らない.

 
154月/110

難読化手法 ― If 文をtry-catchに置換

If文を隠すため,If文の代わりにtry-catch節を使う難読化手法.ダミーの例外クラスを作成し,try 節の中で作成した例外クラスを投げる.投げられた例外クラスに応じた catch 節で条件分岐を行う.

作成された例外クラス間の継承関係が複雑なほど,また,どの例外クラスのインスタンスが作成されたのかがわからないほど制御フローがわかりにくくなる.実際に作成される例外クラスはOpaque Predicateで隠すことになるだろう.

難読化前
class Example{
  public void m(){
    int i = 0;
    if(some condition) i = 3;
    else               i = 0;
  }
}
難読化後
class BranchException extends Exception{ ... }
class E1 extends BranchException{ ... }
class E2 extends BranchException{ ... }
class E3 extends BranchException{ ... }
class E4 extends BranchException{ ... }
class E5 extends BranchException{ ... }
class RIITCBObfuscationExample{
  public void m{
    int i = 0;
    try{
      BranchException e = new BranchException();
      if(opaque predicate 1)      e = new E1();
      else if(opaque predicate 2) e = new E2();
      else if(opaque predicate 3) e = new E3();
      else if(opaque predicate 4) e = new E4();
      else if(opaque predicate 5) e = new E5();
      throw e;
    }
    catch(E1 e1){ i = 1; }
    catch(E2 e2){ i = 2; }
    catch(E3 e3){ i = 3; }
    catch(E4 e4){ i = 4; }
    catch(E5 e5){ i = 5; }
    catch(BranchException e){ i = 0; }
  }
}
 
144月/110

難読化手法 ― オーバーロード誘導 (Overload induction)

PreEmptive Solutions 社が特許を保有する名前難読化の1 アルゴリズム.具体的な実装として,Java言語用の Dash-O と .Net用の Dotfuscatorが存在する.

http://www.freepatentsonline.com/6102966.html
http://www.agtech.co.jp/products/preemptive/dasho/overload_induction.html
http://www.agtech.co.jp/support/faq/PreEmptive/DotfuscatorV1_2/20040123015.html

直感的なアルゴリズムはシンボル名(クラス名,メソッド名,フィールド名,ローカル変数名)にできるだけ同じ名前を使いまわそうというものである.またメソッド間同士でも引数の数と型が異なれば異なるメソッドと判断されるため,同じ名前を使うことが可能である.C#では確認していないが,ローカル変数の場合,バイナリレベルではインデックスのみで参照され,名前は参照されないため,同じ名前を使うことが可能である.

また,拡張オーバーロード誘導という上に記したオーバーロード誘導を拡張したものがある.その拡張とは,同じメソッドか否かを判定するルールに従来は引数の数と型のみに着目していたが,拡張オーバーロード誘導ではメソッドの帰り値も参照する.バイナリレベルでは引数の数と型が同じでも帰り値が異なれば異なるメソッドであると判断されるので,このルールを使うことが可能である.ただし,これは仕様に合致しているかどうかは微妙なところである.