KENJI’S BLOG このページをアンテナに追加 RSSフィード

Freezed...

2008-11-01

よく使うASM命令ベスト100位に説明つけてみた(7/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

ベスト50位の中から、最低限これだけ覚えておけばきっと解析できる命令をまとめてみた。


関数呼び出しやEIP変更関連の命令

push	スタックへ値を格納
pop	スタックから値を取り出す
call	スタックに次の実行命令のアドレスを入れてジャンプ
leave	retの前に置かれるもの("mov esp, ebp"+"pop ebp"と同じ)
ret	スタックのトップにある値を取り出してそこへジャンプ
jmp	指定アドレスへジャンプ

値の操作系の命令

mov	レジスタ値やメモリの値を転送
movzx	渡したレジスタ値やメモリ値のサイズが異っても転送可能なmov
lea	説明しにくい。まぁ[]の中の計算結果がレジスタへ入ると覚えておけばおk
xchg	2つのオペランドを交換する(xchg eax, ebxでeaxとebxの値が交換される)
add	値を加算(足し算)
sub	値を減算(引き算)
inc	インクリメント 値に1加算
dec	デクリメント 値から1減算

条件分岐系の命令(重要

cmp	値を評価してフラグに反映
test	フラグだけ変化するAND命令(真 or 偽 だけを判断する時によく使う)
je	ZF=1 同じならジャンプ
jz	jeと同じ意味
jne	ZF=0 違うならジャンプ
jnz	jneと同じ意味
ja	CF=0 && ZF=0 符号なしで、大きいならジャンプ
jae	CF=0 符号なしで、以上ならジャンプ
jb	CF=1 符号なしで、小さいならジャンプ
jbe	CF=1 && ZF=1 符号なしで、以下ならジャンプ
jl	SF!=OF 符号ありで、小さいならジャンプ
jle	ZF=1 or SF!=OF 符号あり以下ならジャンプ
jg	ZF=0 && SF=OF 符号ありで、大きいならジャンプ
jge	SF=OF 符号ありで、以上ならジャンプ

ビット操作系の命令

xor	ただのxor(C言語の ^ ←これ)
and	ただのand(C言語の & ←これ)
or	ただのor (C言語の | ←これ)
shl	左方向にシフト(C言語でいう << ←これ)
shr	右方向にシフト(C言語の >> ←これ)
not	1の補数値にする(要するにビット反転命令)
neg	2の補数値にする(符号ありの値に対して、符号を反転させる)

データ列の操作命令(文字列処理など)

rep	ECXが0になるまで次の命令を繰り返す(比較命令時はZFフラグも見る)
movs	repと組み合わせることで大量のデータを一気に転送できる(EDIやESIと連動)

デバッグ系命令

int3	デバッグ用割り込み
nop	何もしない

並べてみると少し心許ない気もしますが、とりあえずこれだけ暗記しておけば何とかなると思う。

関連記事:http://07c00.com/text/revasm/revasm.txt

2008-09-04

よく使うASM命令ベスト100位に説明つけてみた(6/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

ベスト71〜80に説明つけてみた(間違いあるかも…)

  22341 ds	セグメントオーバーライドプリフィックス(データセグメント)
  21736 jp	PF=1 PFが1ならジャンプ(JPEとも書く)
  21175 fnstsw	FSTフラグをオペランドへ転送(FSTSWとも書く)
  20458 not	1の補数、要するにビット反転命令
  19998 cs	セグメントオーバーライドプリフィックス(コードセグメント)
  19554 fild	符号付き整数を浮動小数点数に変換しst0へ格納
  18972 lock	割り込み禁止に設定
  18866 sete	ZFフラグの値をオペランドへ格納
  18297 setne	ZFフラグと逆の値をオペランドへ格納
  18055 lods	メモリの内容をEAXに読み込みESIをその分加算or減算する

いろいろとマニアックな命令が出てきましたが、50位以降は、浮動小数点演算で使う命令が目立ちます。ここではfnstswとかfild辺りですね。あと、コメントで教えてもらったセグメントオーバーライドプリフィックスというものは、「セグメントをまたぐコール命令やジャンプ命令の前に置かれる命令」らしいです。

セグメントとは、えっと…、説明するのが難しいです(ぉぃ)。

例えば、すべてのメモリが地球だとすると、セグメントは大陸です。確か世界に大陸は6つありますよね。それらをそれぞれ、CS、SS、DS、ES、FS、GS、とかいう名前にします。それぞれの大陸は海で区切られているため、行き来できません。それで、例えばCSには命令コード人が住んでるとか、DSにはデータ人が住んでるとか、SSにはスタック人が住んでるとかします。要するにそれぞれのセグメントをだいたいの用途に分けるんです。それらは、すでにだいたいの用途に分けられているから、あんまり大陸間で行き来する必要ないんだけど、でもたまに行き来したい時があったりするんだ。そんなときに、ただ、call命令やjmp命令を呼んでも、海は渡れないから、自分のセグメント内にしか移動できない。それで、しかたなく船を作ろうか、みたいな。要するにそういう話です(えっどういう話?)。要するに海を渡りたい時はセグメントオーバーライドプリフィックスを呼べよ、ということですね。うん。そういうこと。うんうん、そういうことだね。うん…、えっと、ここに「google」置いときますね。

2008-09-02

よく使うASM命令ベスト100位に説明つけてみた(5/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

ベスト61〜70に説明つけてみた(間違いあるかも…)

  37928 repz	repと同じだが、次の命令が転送命令ならrepを比較命令ならrepzを使うのが一般的らしい
  36217 out	外部デバイスの入出力ポートへデータを送る(outsのパワーダウン版?)
  34432 cdq	EAXレジスタを符号付き整数としてEDX:EAXに型変換する
  33914 movsx	基本的に16ビット版mov(メモリ上の16ビット以下のデータを転送する)
  30026 pusha	全レジスタの値をスタックへ格納する
  28262 fadd	浮動小数点演算での足し算(st0と渡されたオペランドが足される)
  27495 rol	左方向へのローテート(CFは含まれない)
  24020 aas	アンパックBCDの減算結果ALを補正(繰り下がりが発生するとah--)
  23651 jno	OF=0 オーバーフローでないならジャンプ
  23371 ror	右方向へのローテート(CFは含まれない)

ついに出てきたローテート(rol、ror)。といっても、このランキング位置。ローテートってあまり使わないんだなぁとつくづく感じた。僕も何かの暗号アルゴリズムで見ただけで、他ではお目にかからなかったような…。シフトと違ってC言語命令もないし…。ローテートって何? という方はこちらを。

あと、aaaとaasは、一応、以下のコードを見れば、動作原理はだいたい分かるかと。

004011DB     33C0           XOR EAX,EAX
004011DD     B0 08          MOV AL,8(AH=00, AL=08)
004011DF     04 04          ADD AL,4(AH=00, AL=0C)
004011E1     37             AAA     (AH=01, AL=02)
004011E2     2C 04          SUB AL,4(AH=01, AL=FE)
004011E4     3F             AAS     (AH=00, AL=08)

アンパックBCDというのは、簡単に言えば、10進数の数値の1桁ずつを8ビットで表す方法。例えば、1024という10進数の数値は、0x01000204という4バイトの値になる。256なら、0x020506という感じ。つまり、8なら、0x0008なわけです。そこで0x0008に4を加算すると、当然0x000Cになるわけですが、でも10進数だと12なので、0x0102とかになったらいいなぁと思ったらAAAを実行せよと。するとAAAが勝手に0x0102に補正してくれます。逆に、0x0102の0x02(=AL)から4を減算すると、当然0xFEなわけですが、でも10進数だと8なので、0x0008とかに戻ったらいいなぁと思ったらAASを実行せよと。

かなり適当な説明ですが、aaaとaasはこんな感じの理解で大丈夫だと思います。というか、解析作業時、こんな命令ほとんど見たことないんですが…orz。

それにしても検索時間が長くなってきたw。71位〜80位は明後日(4日)くらいにて。

2008-09-01

よく使うASM命令ベスト100位に説明つけてみた(4/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

ベスト51〜60に説明つけてみた(間違いあるかも…)

  62273 stos	EAXの値をES:EDIの指すメモリへ格納する(REPと組み合わせることで初期化処理になる)
  60421 jns	SF=0 マイナスじゃないならジャンプ
  58573 movq	MMXレジスタで使われるmovで64ビット転送に使用する(最適化とかそういう話)
  58422 fmul	浮動小数点演算での掛け算(st0と渡されたオペランドが掛けられる)
  53800 jg	ZF=0 && SF=OF 符号ありで、大きいならジャンプ
  50155 movaps	XMMレジスタで使われるmovで128ビット転送に使用する(これも最適化とかそういう話)
  45608 sar	符号ありで右シフト(シフト系は符号のありなしで少し複雑)
  45156 bound	int3と似たようなものだが、こちらは境界チェックの例外
  38960 data16	?
  38840 in	外部デバイスの入出力ポートからデータを受け取る(insのパワーダウン版?)

stosは初期化関連で良く使われてそうだけど、実際は51位ということで、それほど頻出しているわけではない。あとmovqやmovapsは最適化処理関連で良く見かける命令ですが、僕自身それほど知らないです。とりあえず「MMX命令」「SIMD命令」辺りを見ておけばOKかと。

↓こういう感じで一気に128ビットのデータの計算(掛け算)ができます。

movaps      xmm0, [edi];
mulps       xmm0, [esi];
movaps      [edi], xmm0;

あとは、シフト系の命令で、符号ありと符号なしでの、右左シフトそれぞれの場合の命令とかが、結構覚えにくいので、余裕があるなら覚えておいてもよいかも(シフト命令)。個人的には、bound命令が最後まで分からなかった。意味としては理解しているけど、実際に使い方を知らないw。


うーん、しかし、この辺りから本当に「調べないと分からない」命令ばかりになってきた。そろそろ年貢の納め時、というわけで勉強しながら更新していくことにします。

61位〜70位は明日(2日)にて。

2008-08-30

よく使うASM命令ベスト100位に説明つけてみた(3/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

ベスト41〜50に説明つけてみた(間違いあるかも…)

 113117 jo	OF=1 オーバーフローしたらジャンプ
 111416 jle	ZF=1 or SF!=OF (符号あり)以下ならジャンプ
 111125 shl	左方向にシフト(C言語でいう << ←これ)
 104434 fstp	st0レジスタからデータを取得(浮動小数点系の演算でよく使われる)
 103882 rep	ECXが0になるまで次の命令を繰り返す(比較命令時はZFフラグも見る)
  91023 xchg	2つのオペランドを交換する(xchg eax, ebxでeaxとebxの値が交換される)
  74925 addr16	?
  72425 fs	?
  71879 neg	2の補数値にする(符号ありの値に対して、符号を反転させる)
  63106 js	SF=1 マイナスならジャンプ

改めて思いましたが、ベスト50位まで覚えておけば、アセンブルコード読むだけならまったく問題ない。というか、50位以内でもいらない命令結構あるです。

逆に、必須なのは、やはりジャンプ系かなと思います。cmp命令に代表されるように、アセンブラ命令はフラグを変更することで条件を変えます。その変えられた条件によってジャンプするかどうか? という二択がよく出てくるので、それは抑えておくべきかなと思います。

fldやfstpについては、浮動小数点演算によって使用される命令で、例えばfloat型とかdouble型とかで加減乗除すると、このような命令が出現します。詳しい内容を知りたければ「MASMインラインアセンブラ」が参考になるかと。

51位〜60位は、明後日(1日)にて。

2008-08-29

よく使うASM命令ベスト100位に説明つけてみた(2/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

ベスト21〜40に説明つけてみた(間違いあるかも…)

 416677 outs	外部デバイスの入出力ポートへデータを送る(repと組み合わせて使おう)
 393871 jb	CF=1 符号なしで、小さいならジャンプ
 362616 (bad)	解析できなかった命令?
 311007 imul	符号ありの乗算(掛け算)EAXと渡された値を掛けてEDX:EAXへ入れる
 295376 ins	外部デバイスの入出力ポートからデータを受け取る(repと組み合わせて使おう)
 290626 jl	SF!=OF 符号あり(マイナスの数値あり)で、小さいならジャンプ
 249056 jae	CF=0 符号なし(0が最小値)で、以上ならジャンプ
 220561 leave	retの前に置かれるもの("mov esp, ebp"+"pop ebp"と同じ)
 205579 popa	全レジスタ分のデータをスタックから取り出し
 201044 gs	
 181922 movzx	渡したレジスタ値やメモリ値のサイズが異っても転送可能なmov
 172773 sbb	基本的にsubと同じ(異なるのはCF=1の場合にさらに1を減算する点)
 168170 adc	基本的にaddと同じ(異なるのはCF=1の場合にさらに1を加算する点)
 158961 jbe	CF=1 && ZF=1 符号なしで、以下ならジャンプ
 149619 movs	repと組み合わせることで大量のデータを一気に転送できる(EDIやESIと連動)
 143792 jge	SF=OF 符号ありで、以上ならジャンプ
 138609 arpl	特権レベルを調整する(1行では説明不能、解析屋には必要ない?)
 131230 shr	右方向にシフト(C言語の >> ←これ)
 125488 fld	st0レジスタにデータを格納(浮動小数点系の演算でよく使われる)
 122132 ja	CF=0 && ZF=0 符号なしで、大きいならジャンプ

gsは分からなかった。一度も見たことない?

arplは知ってるけれど解析作業にはあまり使わないかな?

sbbやadcは使い方を知らないと、なぜこんな命令が存在するか理解できないかもしれない。

一応、↓こんな感じで使われまつ

// レジスタのサイズより大きいデータの加算をやりたい時
mov eax, 0FFFFFFFFh
mov edx, 5h
mov esi, 0FFFFFFFFh
mov edi, 2h
// 05FFFFFFFFh(edx:eax) + 02FFFFFFFFh(edi:esi) という計算結果を(edx:eax)へ入れたい
add eax, esi
adc edx, edi
// 最初のaddで繰り上がりが起こるためCF=1となる。
// 次のadcでedxにCF=1となった値(1)も加算されるため、結果的に(edx:eax)へ加算結果が入る
// 結果、edx=8h、eax=FFFFFFFEhとなり、無事08FFFFFFFEh(edx:eax)となる。

間違い指摘はウェルカム(;^o^b

41位〜50位は明日(30日)にて

2008-08-28

よく使うASM命令ベスト100位に説明つけてみた(1/10)

http://d.hatena.ne.jp/rootkit/20080818/1219042285

とりあえずベスト20に説明つけてみた

11378610 mov	レジスタ値やメモリの値を転送
9156176 push	スタックへ値を格納
3825704 add	値を加算(足し算)
3638244 call	スタックに次の実行命令のアドレスを入れてジャンプ
2329166 int3	デバッグ用割り込み
2271495 pop	スタックから値を取り出す
2105874 cmp	値を評価してフラグに反映
2000442 je	ZF=1 同じならジャンプ
1920361 lea	説明しにくい。まぁ[]の中の計算結果がレジスタへ入ると覚えておけばおk
1673045 nop	何もしない
1495072 test	フラグだけ変化するAND命令(真 or 偽 だけを判断する時によく使う)
1426586 jmp	指定アドレスへジャンプ
1217054 jne	ZF=0 違うならジャンプ
1031610 xor	ただのxor(C言語の ^ ←これ)
 971938 inc	インクリメント 値に1加算
 914353 ret	スタックのトップにある値を取り出してそこへジャンプ
 843280 and	ただのand(C言語の & ←これ)
 601980 dec	デクリメント 値から1減算
 561539 sub	値を減算(引き算)
 437624 or	ただのor(C言語の | ←これ)

解析屋としてはこの辺までは即答できないとダメかも…

21位〜40位は明日(29日)にて