2015年12月30日
はじめての逆アセンブラ
VBでポインタの付け替えがしたくて
始めたアセンブラの勉強。
でもいっこうにできるようになる気配がない。
C++側からアセンブラ側の関数にポインタ&a、&bを渡して
mov rax, rcx
mov r8, rdx
mov rcx, r8
mov rdx, rax
でポインタを入れ替えても
C++側のaとbの値は全く入れ替わっていなかった。
、、、レジスタはレジスタだから
メモリではないということか?
レジスタではなくaとbを記憶している「メモリ」
をいじらないといけないということか?
アセンブラでメモリを操作することを覚えないといけない、、のか?
先が遠いなあ。
で、考えた。
c++では簡単(なはず)なのだ。
void swap(int *x, int *y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
という関数はよく見かける。(パッと見簡単そう。)
試しにC++で実行してみる。
ん、、、
関数にポインタ渡して、関数の中で処理されたことが
関数の外に反映される、、、どこかで見たような。
VBAの参照渡しと同じか?
&aと&bのアドレスが関数の前と後で変わっていない、、、
どうやら下記のサイトによると
ポインタではなく
「ポインタのポインタ」というものを使うらしい。
>二つのポインタ値を交換する関数はどのように実現すればよいでしょうか。
>http://www.bohyoh.com/CandCPP/FAQ/FAQ00024.html
ただ、上記サイトをそのままコピーしたら
エラーで回らなかった。
void **xをchar**xにしないと回らなかった。
(intにしても回らなかった、、なんでだろ)
まあ、charでもいいか。
その結果の実行画面は下記の写真。
おー、ちゃんと数値もポインタも入れ替わってる。
やったー。
これがポインタの付け替えか。
試しに上記コードをC++で書いて、ビルドしてexeファイルを作って
逆アセンブルしてコードをアセンブリ言語のコードを確認すれば
アセンブリ言語のポインタの付け替えが分かるのではないか?
よし、逆アセンブラで検索。
で下記の連続したサイトを見つける。
>第3章 逆アセンブル(1)
>http://masm.kmycode.net/pecoff/3.html
>第4章 逆アセンブル(2)
>http://masm.kmycode.net/pecoff/4.html
サイトに書いてあるように
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\binの中には
「dumpbin.exe」があった。
サイトの記載と違って
「mspdb140.dll」もあるようだから、とくにdllをどこかから入手する必要はないのだろう。
ダブルクリックしてもコマンドプロンプトにコマンドのオプションがきちんと
列挙された。
、、いける気がする。
まずはC++からアセンブリ言語の関数を呼び出すように作った
exeファイルを逆アセンブリしてみよう。
2つ目のサイトに記載してあったコマンドを
コピーペーストするが、エラーでそのようなコマンドはないと表示される。
、、、だめじゃん。
ん、、でも前にも似たようなことがあったような?
環境変数でpathを設定すればいいのかな?
ということでシステムの詳細設定で環境変数で
dumpbin.exeのあるフォルダのパスを設定。
コマンドプロンプトを一端閉じて再度開いて、
test.exeのある場所にcdコマンドで移動して、、
いざ
dumpbin /disasm /out:dump.txt test.exe
お、なんか動いた!
そしてtest.exeのあるフォルダの中に、
dump.txtファイルができてるー。
やったー!
でテキストファイルを開いてみると、、
あれ?長いぞ。
こんなに長いコード書いてないのに。
中身を見ていると
全体の1/5くらいのところに確かに自分が書いた
アセンブリ言語の9行のコードがあった!
逆アセンブラ成功だ。すごいな。
ただ、それ以外の部分がほんとに長い。
C++が高級言語だということを表しているのか?
それとも#includeで読み込んでいる部分か?
まあ、いいや。
次はswap関数をC++で書いてexeファイルを逆アセンブラしてみよう。
char *temp = *x;
*x = *y;
*y = temp;
C++だとたった3行が
逆アセンブラすると下記の25行にもなる。
8割がたまだ勉強していないレジスタ名やコマンド名。
少しずつ理解していくしかないな。
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+8],rcx
push rbp
push rdi
sub rsp,0E8h
mov rbp,rsp
mov rdi,rsp
mov ecx,3Ah
mov eax,0CCCCCCCCh
rep stos dword ptr [rdi]
mov rcx,qword ptr [rsp+108h]
mov rax,qword ptr [rbp+100h]
mov rax,qword ptr [rax]
mov qword ptr [rbp+8],rax
mov rax,qword ptr [rbp+100h]
mov rcx,qword ptr [rbp+108h]
mov rcx,qword ptr [rcx]
mov qword ptr [rax],rcx
mov rax,qword ptr [rbp+108h]
mov rcx,qword ptr [rbp+8]
mov qword ptr [rax],rcx
lea rsp,[rbp+0E8h]
pop rdi
pop rbp
ret
ただ、上記のアセンブリ言語で書いた関数を
C++から呼び出して実行すると
ほんとにC++で書いた時と同じ実行結果が得られる。
さすがアセンブリ言語。一対一対応が強みだな。
あとは
関数の宣言文。
**xや**yの部分をどう記述しているかだな。
main関数の中の、
swapptr(&a, &b);
は下記のようになっているのかな?
call @ILT+10(?swapptr@@YAXPEAPEAD0@Z)
mov rdx,qword ptr [rbp+8]
lea rcx,[??_C@_07LLAODNH@a?5?$DN?5?$CFs?6?$AA@]
もう適当なアルファベットの羅列すぎて判別できないな。
始めたアセンブラの勉強。
でもいっこうにできるようになる気配がない。
C++側からアセンブラ側の関数にポインタ&a、&bを渡して
mov rax, rcx
mov r8, rdx
mov rcx, r8
mov rdx, rax
でポインタを入れ替えても
C++側のaとbの値は全く入れ替わっていなかった。
、、、レジスタはレジスタだから
メモリではないということか?
レジスタではなくaとbを記憶している「メモリ」
をいじらないといけないということか?
アセンブラでメモリを操作することを覚えないといけない、、のか?
先が遠いなあ。
で、考えた。
c++では簡単(なはず)なのだ。
void swap(int *x, int *y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
という関数はよく見かける。(パッと見簡単そう。)
試しにC++で実行してみる。
ん、、、
関数にポインタ渡して、関数の中で処理されたことが
関数の外に反映される、、、どこかで見たような。
VBAの参照渡しと同じか?
&aと&bのアドレスが関数の前と後で変わっていない、、、
どうやら下記のサイトによると
ポインタではなく
「ポインタのポインタ」というものを使うらしい。
>二つのポインタ値を交換する関数はどのように実現すればよいでしょうか。
>http://www.bohyoh.com/CandCPP/FAQ/FAQ00024.html
ただ、上記サイトをそのままコピーしたら
エラーで回らなかった。
void **xをchar**xにしないと回らなかった。
(intにしても回らなかった、、なんでだろ)
まあ、charでもいいか。
その結果の実行画面は下記の写真。
おー、ちゃんと数値もポインタも入れ替わってる。
やったー。
これがポインタの付け替えか。
試しに上記コードをC++で書いて、ビルドしてexeファイルを作って
逆アセンブルしてコードをアセンブリ言語のコードを確認すれば
アセンブリ言語のポインタの付け替えが分かるのではないか?
よし、逆アセンブラで検索。
で下記の連続したサイトを見つける。
>第3章 逆アセンブル(1)
>http://masm.kmycode.net/pecoff/3.html
>第4章 逆アセンブル(2)
>http://masm.kmycode.net/pecoff/4.html
サイトに書いてあるように
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\binの中には
「dumpbin.exe」があった。
サイトの記載と違って
「mspdb140.dll」もあるようだから、とくにdllをどこかから入手する必要はないのだろう。
ダブルクリックしてもコマンドプロンプトにコマンドのオプションがきちんと
列挙された。
、、いける気がする。
まずはC++からアセンブリ言語の関数を呼び出すように作った
exeファイルを逆アセンブリしてみよう。
2つ目のサイトに記載してあったコマンドを
コピーペーストするが、エラーでそのようなコマンドはないと表示される。
、、、だめじゃん。
ん、、でも前にも似たようなことがあったような?
環境変数でpathを設定すればいいのかな?
ということでシステムの詳細設定で環境変数で
dumpbin.exeのあるフォルダのパスを設定。
コマンドプロンプトを一端閉じて再度開いて、
test.exeのある場所にcdコマンドで移動して、、
いざ
dumpbin /disasm /out:dump.txt test.exe
お、なんか動いた!
そしてtest.exeのあるフォルダの中に、
dump.txtファイルができてるー。
やったー!
でテキストファイルを開いてみると、、
あれ?長いぞ。
こんなに長いコード書いてないのに。
中身を見ていると
全体の1/5くらいのところに確かに自分が書いた
アセンブリ言語の9行のコードがあった!
逆アセンブラ成功だ。すごいな。
ただ、それ以外の部分がほんとに長い。
C++が高級言語だということを表しているのか?
それとも#include
まあ、いいや。
次はswap関数をC++で書いてexeファイルを逆アセンブラしてみよう。
char *temp = *x;
*x = *y;
*y = temp;
C++だとたった3行が
逆アセンブラすると下記の25行にもなる。
8割がたまだ勉強していないレジスタ名やコマンド名。
少しずつ理解していくしかないな。
mov qword ptr [rsp+10h],rdx
mov qword ptr [rsp+8],rcx
push rbp
push rdi
sub rsp,0E8h
mov rbp,rsp
mov rdi,rsp
mov ecx,3Ah
mov eax,0CCCCCCCCh
rep stos dword ptr [rdi]
mov rcx,qword ptr [rsp+108h]
mov rax,qword ptr [rbp+100h]
mov rax,qword ptr [rax]
mov qword ptr [rbp+8],rax
mov rax,qword ptr [rbp+100h]
mov rcx,qword ptr [rbp+108h]
mov rcx,qword ptr [rcx]
mov qword ptr [rax],rcx
mov rax,qword ptr [rbp+108h]
mov rcx,qword ptr [rbp+8]
mov qword ptr [rax],rcx
lea rsp,[rbp+0E8h]
pop rdi
pop rbp
ret
ただ、上記のアセンブリ言語で書いた関数を
C++から呼び出して実行すると
ほんとにC++で書いた時と同じ実行結果が得られる。
さすがアセンブリ言語。一対一対応が強みだな。
あとは
関数の宣言文。
**xや**yの部分をどう記述しているかだな。
main関数の中の、
swapptr(&a, &b);
は下記のようになっているのかな?
call @ILT+10(?swapptr@@YAXPEAPEAD0@Z)
mov rdx,qword ptr [rbp+8]
lea rcx,[??_C@_07LLAODNH@a?5?$DN?5?$CFs?6?$AA@]
もう適当なアルファベットの羅列すぎて判別できないな。
この記事へのコメント
Hello, I check your はじめての逆アセンブラ: サラリーマンとパソコンと僕 blog regularly. Your humoristic style is witty, keep up the good work! prediksi euro 2016 http://www.prediksieuro2016.com/
Posted by prediksi euro 2016 at 2016年06月29日 14:05
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/4573446
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック