search
LoginSignup
2

posted at

JVMバイトコード入門(第1回)

JVMバイトコード入門(第1回)

目的

難読化ツールを自作できるようになる・難読化を解読できるようになる。

JVMの動作原理

JVMは「スタックマシン」と呼ばれます。スタックマシンというのは、読み込まれたデータをスタックという場所の一番上に積んでいき、そのスタックに対して命令を実行することで上に積まれたデータに対して処理を実行する仕組みのことです。

JVM命令の例

以下のような例を考えてみます。

int i = 100 + 10 - 1;

この場合のJVM命令は以下のようになります。

BIPUSH 100
BIPUSH 10
IADD
ICONST_M1
ISUB
ISAVE 0

ではこの場合の例について、順を追って見ていきましょう。

1行目: BIPUSH 100

これは「100」という数字をスタックに載せるということを意味しています。

2行目: BIPUSH 10

2行目もBIPUSHですね。スタックマシンでは読み込まれたデータを上に積んでいくので、スタックマシンは上から「10」、「100」という順番で載っています。

3行目: IADD

3行目にはIADD命令が来ました。IADD命令は、スタックの一番上と二番目に上のintを加算して、計算結果をスタックの一番上に格納します。この際計算に使われた数値はスタックから取り除かれます。従ってスタックに載っていた「100」、「10」を加算すると「110」ですから、スタックには「110」という数値のみが残ることになります。

4行目: ICONST_M1

4行目にはICONST_M1が来ました。ICONST_M1は「-1」をスタックに載せるという意味です。BIPUSH命令はintをスタックに載せる命令ですからBIPUSHでいいんじゃないの?なぜ-1だけ別の命令があるの?と思うかもしれませんが、JVMは最適化のために数値を読み込む命令が複数あり、-1から5までの範囲ならICONST命令、byteの範囲ならBIPUSH、shortの範囲ならSIPUSH、intもしくはlongの範囲であればLDC命令を使います。ただ必ずしもBIPUSHを使わなければいけないというわけでもなく、「BIPUSH -1」などとしても正常に動作します。あくまでも最適化のためだけの命令というわけです。

5行目: ISUB

5行目にはISUBとありますが、これはIADDとほぼ同じで、スタックの二番目に上のintから一番上のintを減算して、スタックに載せます。従ってスタックに載っていた「-1」、「110」に対してISUB命令を行うとスタックには「109」が残ることになります。

6行目: ISAVE 0

次で最後です!ISAVE命令は、スタックの一番上にあるintをローカル変数に格納します。JVMバイトコードの世界ではローカル変数に名前はなく、0、1、・・・というように0からの連番で管理されています(デバッグ情報としてデコンパイラで見たときにローカル変数の名前を残すこともできる)。すなわち「ISAVE 0」は、この「メソッド内の0番目のローカル変数にintを格納する」という意味になります。ここで格納されたローカル変数は、ILOAD命令を呼び出すことでローカル変数からスタックに取り出すことができます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2