忍者ブログ

Cyber Bird

   

[PR]

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

C++を逆アセンブルする

以前、C++でnewやクラスをコンパイルしたら、ネイティブコードではどうなるのか
気になったことがあったので、調べてみた。
もしライブラリやOSに依存しないような仕組みだったら、OS開発にもすぐに使えるかも…って。
尤も、newはメモリ確保だからどう頑張ってもシステムコールを使ってるだろうけどなあ。

とりあえず、newの方はまだうまく読破できてないので、クラスを逆アセンブルして
読破した結果を書いてみる。


#include <cstdio>
using namespace std;

class Formula {
private:
	int a, b;
public:
	Formula(int n, int d);
	~Formula();
	int res();
};

Formula::Formula(int n, int d) {
	a = n;
	b = d;
}

Formula::~Formula() {}

int Formula::res() {
	return a + b;
}

int main() {
	Formula f1(1, 3);

	printf("%d\n", f1.res());
}
ソース自体はなんの意味もないけど。
2整数で初期化してあげると、resを呼べば加算した結果を返してくれるだけ。
これだけだけど、途中で3,4回くらいコンパイルに怒られて涙目(´・ω・`)

これをコンパイルしてみる。
$ g++ test.cpp -g -o test
$ objdump -d test > dump
$ view dump
逆アセンブルした結果がこちら(必要な部分だけの部分抜粋です)。
080484f4 <_ZN7FormulaC1Eii>:
 80484f4:	55                   	push   %ebp
 80484f5:	89 e5                	mov    %esp,%ebp
 80484f7:	8b 45 08             	mov    0x8(%ebp),%eax
 80484fa:	8b 55 0c             	mov    0xc(%ebp),%edx
 80484fd:	89 10                	mov    %edx,(%eax)
 80484ff:	8b 45 08             	mov    0x8(%ebp),%eax
 8048502:	8b 55 10             	mov    0x10(%ebp),%edx
 8048505:	89 50 04             	mov    %edx,0x4(%eax)
 8048508:	5d                   	pop    %ebp
 8048509:	c3                   	ret    

0804850a <_ZN7FormulaD1Ev>:
 804850a:	55                   	push   %ebp
 804850b:	89 e5                	mov    %esp,%ebp
 804850d:	5d                   	pop    %ebp
 804850e:	c3                   	ret    
 804850f:	90                   	nop

08048510 <_ZN7Formula3resEv>:
 8048510:	55                   	push   %ebp
 8048511:	89 e5                	mov    %esp,%ebp
 8048513:	8b 45 08             	mov    0x8(%ebp),%eax
 8048516:	8b 10                	mov    (%eax),%edx
 8048518:	8b 45 08             	mov    0x8(%ebp),%eax
 804851b:	8b 40 04             	mov    0x4(%eax),%eax
 804851e:	01 d0                	add    %edx,%eax
 8048520:	5d                   	pop    %ebp
 8048521:	c3                   	ret    

08048522 <main>:
 8048522:	55                   	push   %ebp
 8048523:	89 e5                	mov    %esp,%ebp
 8048525:	53                   	push   %ebx
 8048526:	83 e4 f0             	and    $0xfffffff0,%esp
 8048529:	83 ec 20             	sub    $0x20,%esp
 804852c:	c7 44 24 08 03 00 00 	movl   $0x3,0x8(%esp)
 8048533:	00 
 8048534:	c7 44 24 04 01 00 00 	movl   $0x1,0x4(%esp)
 804853b:	00 
 804853c:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048540:	89 04 24             	mov    %eax,(%esp)
 8048543:	e8 ac ff ff ff       	call   80484f4 <_ZN7FormulaC1Eii>
 8048548:	8d 44 24 18          	lea    0x18(%esp),%eax
 804854c:	89 04 24             	mov    %eax,(%esp)
 804854f:	e8 bc ff ff ff       	call   8048510 <_ZN7Formula3resEv>
 8048554:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048558:	c7 04 24 70 86 04 08 	movl   $0x8048670,(%esp)
 804855f:	e8 ac fe ff ff       	call   8048410 <printf@plt>
 8048564:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048568:	89 04 24             	mov    %eax,(%esp)
 804856b:	e8 9a ff ff ff       	call   804850a <_ZN7FormulaD1Ev>
 8048570:	b8 00 00 00 00       	mov    $0x0,%eax
 8048575:	8b 5d fc             	mov    -0x4(%ebp),%ebx
 8048578:	c9                   	leave  
 8048579:	c3                   	ret    
 804857a:	89 c3                	mov    %eax,%ebx
 804857c:	8d 44 24 18          	lea    0x18(%esp),%eax
 8048580:	89 04 24             	mov    %eax,(%esp)
 8048583:	e8 82 ff ff ff       	call   804850a <_ZN7FormulaD1Ev>
 8048588:	89 d8                	mov    %ebx,%eax
 804858a:	89 04 24             	mov    %eax,(%esp)
 804858d:	e8 9e fe ff ff       	call   8048430 <_Unwind_Resume@plt>
 8048592:	90                   	nop
 8048593:	90                   	nop
 8048594:	90                   	nop
 8048595:	90                   	nop
 8048596:	90                   	nop
 8048597:	90                   	nop
 8048598:	90                   	nop
 8048599:	90                   	nop
 804859a:	90                   	nop
 804859b:	90                   	nop
 804859c:	90                   	nop
 804859d:	90                   	nop
 804859e:	90                   	nop
 804859f:	90                   	nop
とりあえず、main関数のところをC言語風に逆コンパイルしてみると…

void main() {
	int d[2];// 0x18(%esp) ~ 0x1c(%esp)の部分
	_ZN7FormulaC1Eii(d, 0x1, 0x3);
	int tmp = _ZN7Formula3resEv(d);
	printf((const char *)0x8048410, tmp);
	_ZN7FormulaD1Ev(d);
	return;
}
こんな感じになるのだろう。4行目でtmpを媒介にしたのは、あくまで読みやすさを追求しただけで、
本来はない方が望ましいんじゃないかな。

ここからわかるのは、おそらくdという配列、まあアセンブラには配列の概念なんてないけれど、
これがFormula f1というオブジェクトのことを指しているんだろう。

_ZN7FormulaC1Eii ⇒ Formula(コンストラクタ)
_ZN7Formula3resEv ⇒ res
_ZN7FormulaD1Ev ⇒ ~Formula(デストラクタ)

これは、逆アセンブルコードを辿っていくと、抜粋部分の始めの部分に書いてある。
これもC言語に直してみよう。

void _ZN7FormulaC1Eii(int *d, int a, int b) {
	d[0] = a;
	d[1] = b;
	return;
}

void _ZN7FormulaD1Ev(int *d) {
	return;
}

int _ZN7Formula3resEv(int *d) {
	int tmp;
	tmp = d[0] + d[1];
	return tmp;
}
これを元のメソッドと比較してみよう。

Formula::Formula(int n, int d) {
	a = n;
	b = d;
}

Formula::~Formula() {}

int Formula::res() {
	return a + b;
}
何か決定的な違いがないだろうか?

そう、逆アセンブルされると、オブジェクトはすべて引数を通してアドレス渡しされるみたいだ。
クラスをもたないC言語でたまに使う手法だ。


オブジェクト指向なんて、人間が勝手にそう考えただけで、2進数しか理解できないコンピュータに
とってみればいい迷惑。
それでも、機械語に翻訳されてもオブジェクトの欠片が残っているのがわかったので、
なかなか面白かった。



あと…

逆アセンブルコードのmain関数の最後の部分、804857aから804858dが
どうなっているのか全くわからないので、教えていただけると助かります!
PR

COMMENT

NAME
TITLE
MAIL(非公開)
URL
EMOJI
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
COMMENT
PASS(コメント編集に必須です)
SECRET
管理人のみ閲覧できます

804857a以降のコードとか

  • by Liva
  • URL
  • 2012/04/29(Sun)00:00
  • Edit
逆アセンブルは楽しいですが、C++の仕組みを知りたいのであれば、コンパイル時に-save-tempsオプションを付けて、中間アセンブリファイルを出力させた方が楽ですよ。ラベルなんかも残りますし。


804857a以降のコードですが、例外周りで、デストラクタを呼び出すための物なのではないかと思います。(確証はありませんが)

以下のようにコードを修正し、アセンブリを吐かせると、何となく例外が絡んでそうなのが分かるのではないかと。

#include <cstdio>
using namespace std;

class Formula {
private:
int a, b;
public:
Formula(int n, int d);
~Formula();
int res();
};

Formula::Formula(int n, int d) {
a = n;
b = d;
}

Formula::~Formula() {
printf("class \"Formula\" deleted\n");
}

int Formula::res() {
return a + b;
}

int main() {
try {
Formula f1(1, 3);
throw(1);
printf("%d\n", f1.res());
} catch (int num) {
}
}

Re:804857a以降のコードとか

  • by levelfour
  • 2012/05/04 17:42
返信遅れてすみません。

そうか…アセンブリを吐かせればよかったのか…。
と思ってやってみたんですが、throwがやはり__cxa_throwという
関数(に付随するもの?)で隠蔽されていて覗けず、
挫折してしまいました。

でも仰る通り、例外を入れる前後のバイナリを比較すると、
なんとなく例外をキャッチした部分でデストラクタを呼んでるんだな…という
感じはします。

とりあえず、PLT等勉強して行かないととてもアセンブリやバイナリを
読みこなすことはできなさそうなので、頑張って勉強を続けていきます。
(バイナリアンへの道は遠し!)

ブログ内検索

プロフィール

HN:
levelfour
性別:
男性
自己紹介:
ぼちぼち更新を再開する予定です。

twitter

最新コメント

[09/27 菜々氏]
[06/17 NONAME]
[04/30 mithril]
[04/29 Liva]
[01/30 NONAME]

最新トラックバック

コガネモチ

Copyright ©  -- Cyber Bird --  All Rights Reserved
Design by CriCri / Photo by Geralt / powered by NINJA TOOLS / 忍者ブログ / [PR]