質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

Q&A

解決済

2回答

2415閲覧

アセンブリ言語でscanfを使いたいです。

kazuyakazuya

総合スコア193

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

0グッド

0クリップ

投稿2019/10/23 03:29

編集2019/10/23 23:21

アセンブリ言語でC言語のscanf関数つまり
ただ受け取るだけのプログラムを作ってみたいです。

とりあえず、見本がないと厳しいので

Cのコードをアセンブラファイルに出力してみました。

c

1#include <stdio.h> 2 3int main(void){ 4 char sample[10]; 5 scanf("%s",sample); 6 return 0; 7} 8

c

1.file "scanf.c" 2 .def ___main; .scl 2; .type 32; .endef 3 .section .rdata,"dr" 4LC0: 5 .ascii "%s\0" 6 .text 7 .globl _main 8 .def _main; .scl 2; .type 32; .endef 9_main: 10LFB10: 11 .cfi_startproc 12 pushl %ebp 13 .cfi_def_cfa_offset 8 14 .cfi_offset 5, -8 15 movl %esp, %ebp 16 .cfi_def_cfa_register 5 17 andl $-16, %esp 18 subl $32, %esp 19 call ___main 20 leal 22(%esp), %eax 21 movl %eax, 4(%esp) 22 movl $LC0, (%esp) 23 call _scanf 24 movl $0, %eax 25 leave 26 .cfi_restore 5 27 .cfi_def_cfa 4, 4 28 ret 29 .cfi_endproc 30LFE10: 31 .ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0" 32 .def _scanf; .scl 2; .type 32; .endef 33

scanf関数は・・・参考サイトより

string

1scanf("変換指定子", &変数名)

より、変数名(変数のアドレス)・変換指定子

この順番でスタックに積んだ後

callで_scanfを呼べば、標準入力を使うことができると考えました。

で、私が作ってみた(少し変えただけ)コード

s

1 .text 2 msg: .ascii "%s\0"; // %s が置いてあるアドレス 3 .globl _main 4 5 _main: 6 7 subl $12,%esp//スタック領域確保 8 //ここで sample が置かれているアドレスを・・・movlする 9 movl $msg,8(%esp) 10 call _scanf 11 add $12, %esp 12 ret 13

sample変数「配列」のアドレスをスタックに積みたいのですが

アドレスの求め方がわかりません。

Cからコンパイルした結果を見ると

s

1leal 22(%esp), %eax 2movl %eax, 4(%esp)

それでも、"sample"と書かれている場所はありませんが・・・。

char sample[10];

の場所(アドレス)はどうやったら求められるのか、

アセンブリ出力ファイルでいうところでは

どこなのかについて教えてください。

以下解決コード

s

1 .text 2 msg: .ascii "%s\0"; 3 msg2: .ascii "Repeat 1 times\n\0"; 4 .globl _main 5 6_main: 7 8 subl $20,%esp 9 leal 8(%esp), %eax #12bytes can be input. 10 movl %eax, 4(%esp) 11 movl $msg,(%esp) 12 call _scanf 13 14 subl $15,%esp 15 movl $msg2,4(%esp) 16 movl $msg,(%esp) #printf("%s",sample); 17 call _printf 18 add $15,%esp 19 20 call _printf 21 add $20,%esp 22 ret 23

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

asm

2019/10/23 03:49

scanf関数を作りたい、のか scanf関数を使いたい どちらなのでしょう? 前者ならば、「中級者でも厳しい課題なので諦めろ」が答えになりますが
kazuyakazuya

2019/10/23 03:50 編集

すみません。 「使いたい」の方です。
rubato6809

2019/10/23 05:40

その解決コードは本当に動作したの?とても疑わしいコードですが。
kazuyakazuya

2019/10/23 06:19 編集

しっかりコンパイルできまた。 exeを実行させてもしっかり 受け取ることができます。 どこに誤りがあるのでしょうか? (正常に実行できたのはたまたま?)
rubato6809

2019/10/23 06:46

タイプして入力した文字列がどこに・どう格納されたのか、確認できるようになってないので、たまたま落ちなかっただけだと思われる。 未初期化変数 foo があって、たとえば int foo; char buf[4]; scanf(foo, "%s", buf);  のような呼出しになっている。
kazuyakazuya

2019/10/23 06:52

ん、ちょっと言っていることがわからないです。 あと、scanfの引数は2つだと思うのですが。。。
kazuyakazuya

2019/10/23 06:58

あ、つまり 変数を入れておく場所のアドレスの 確保の仕方がおかしい ということですか?
rubato6809

2019/10/23 06:58

私も回答を修正した。 ”%s" はスタックトップに代入しなくてはならない。それを君のコードは4(%esp)にセットしている。 スタックトップ (%esp) には何もセットしていない。それは未初期化変数を第一引数としてセットしたことに等しい。
kazuyakazuya

2019/10/23 07:00

というと正しくは movl $msg,(%esp) ってことですか?
rubato6809

2019/10/23 07:03

そうです。そして leal xx(%esp), %eax として得られた配列のアドレスを movl %eax, 4(%esp) と代入しなければならない。
y_waiwai

2019/10/23 07:04

「C++ 呼び出し規約」でぐぐって出てくるのを読め 雰囲気で理解したつもりになってても無駄なだけだぞ
rubato6809

2019/10/23 07:05

xx(%esp) は、この場合 8(%esp) のことだけど。
kazuyakazuya

2019/10/23 07:06

今できないので後で訂正します。 ご教授ありがとうございます。 いい加減にスタックに積んでいましたが 積めなきゃいけないのですね。
kazuyakazuya

2019/10/23 07:07

分かりました。読んでみます
rubato6809

2019/10/24 13:16

表示するだけなら難しくありません。あなた自身で動作するアセンブリコードを作って示したら良いと思う。単に表示するアセンブリコードすら作れないのではシェルコードはなおさらだ。よって、これは必須のステップである。具体的な話はそれからでも十分可能。 ただし、この段階ではシェルコード云々をいったん脇に置くこと。 具体的なコードがあれば、シェルコードへアレンジ可能かどうか、具体的なアドバイスは可能だと思う(ただ、個人的にはこのサイトを使わないほうがやりやすいけど)。
asm

2019/10/24 21:04

windowsでシェルコードにしたいのならば、write関数はどこにあるのか?って事を考えなければいけなくて Linuxならばほぼ常にロードされるlibcにあった気がしますが 結局、攻撃できる状態ならば、バッファオーバーフローを用いた攻撃よりもCreateRemoteThread/WriteProcessMemory使った方が楽です さらに言うならば、CreateRemoteThreadでLoadLibrary呼んでDLL注入するのが一番楽です。 これなら文句なくCコンパイラのみで可能です。
kazuyakazuya

2019/10/24 21:32

ありがとうございます。 調べてみます。 あと、気になるのですが ここで言うところの write関数はシステムコールではないほうですよね? で、その関数の場所って言うのは ソースがおかれている場所のことですか?
asm

2019/10/24 22:14

システムコールが使えるならばシステムコールでもよいですよ 残念ながら、私ではwindowsのコンソール書き込みをsyscallで行う方法が見つかりませんでしたので kernel32.dllのWriteConsole関数を使うことになると思いますが
kazuyakazuya

2019/10/24 23:05

ありがとうございます。 やっぱ前提知識がなくて システムコール・ライブラリ・Windows・Linux・dll などなど認識がめちゃめちゃなので 調べなおします。(聞き直します。)
rubato6809

2019/10/24 23:30

実は私はWindowsのシステムコールとかDLLとか馴染みが無いです。 Windows関係のタグで質問してみるのも手でしょうね。
kazuyakazuya

2019/10/24 23:42

基礎的なことは知恵袋のほうで済ませようと思います。 システムコールの話になるとwindowsとかのOSも 関係しそう(てか、関係する)なのでタグはつけようと思います。
guest

回答2

0

ベストアンサー

as

1 andl $-16, %esp 2 subl $32, %esp 3 call ___main 4 leal 22(%esp), %eax 5 movl %eax, 4(%esp) # オフセット4に sample 配列の先頭アドレス 6 movl $LC0, (%esp) # スタックトップ(オフセット0)に "%s" 7 call _scanf # scanf("%s", sample); 8

subl $32, %esp した直後から、スタックトップから32バイトは、この関数が自由に使えるローカル変数領域です。32 = 4 + 4 + 14 + 10 ですから、回答を修正しますとスタックトップから

  • 4バイト: "%s" 文字列のアドレス、scanf() の第一引数
  • 4バイト: 配列 sample のアドレス、scanf() の第二引数
  • 14バイト: 今のところ何にも使われていない領域
  • 10バイト: char sample[10] 用の領域

と割り当てています。これがわかれば leal 22(%esp), %eax が sample 配列の先頭アドレスを求めているとわかります。

ローカル変数は「スタックポインタ+オフセット」が、その変数のアドレスになることを、当然ながらコンパイラは分かったうえでコードを生成するので、アセンブリコードに変数名を出力することは、まずありません。

P.S.
コンパイルが通っただけでは正しい動作にならないことがたくさんあったはずです。動作しているように見えても、実はおかしな動作をしていた、という経験はありませんでしたか?scanf() が正しく動作したとは、入力したものが期待どおりに変数に格納されたかどうか、結果を確認できて初めて動作できたと言えます。例えば

C

1 char buffer[10]; 2 scanf("%s", buffer); // 入力したものが 3 printf("[%s]\n", buffer); // 格納されたか確認

アセンブリ言語で書いたコードが正しくscanf()を呼べたかどうかも、やはり同じように結果を確認する必要があります。キーボードでタイプできた、というだけでは正しく動作できたことを意味しません。
結果を表示させて確認する、そのためにC言語ではprintf()から学び始めますね。アセンブリ言語の動作確認をするにも、まずはアセンブリコードで表示して確認する手段を手にいれることが大事です。それには

  • printf() にパラメータを渡して表示させる手段
  • Cで自分が書いた表示関数に、手際よく必要なデータを渡す手段

などを、まずは調査することをお勧めしたいと思います。

投稿2019/10/23 03:59

編集2019/10/23 22:19
rubato6809

総合スコア1380

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2019/10/23 04:12

回答ありがとうございます。 つまり・・・ スタック自体にscanfで受け取った文字列を 格納するのだから スタックの適切なアドレス指定してあげれば できる・・・ということでしょうか?
rubato6809

2019/10/23 04:14

そうです。コンパイラはローカル変数をスタックに取るのだから、貴方自身も同じようにすればよい。
kazuyakazuya

2019/10/23 04:18

ありがとうございます。 できました! .textで定数を宣言するとき(アドレスにラベルを振ってあげるとき) みたいにスタックではない領域に文字列を置くのではなく スタック自体に文字列を置く・・・というのは勉強になりました。
kazuyakazuya

2019/10/23 22:28

一応、scanfで受け取った文字列を printfで表示することはできました。 (スタックに積む引数が全く同じだったから。。。)
rubato6809

2019/10/23 22:39

それなら、表示して確認できたコードを「解決コード」とすべきではありませんか。 今現在の解決コードを信用することはできません。
kazuyakazuya

2019/10/23 22:40

あ、すみません。 忘れてました。 今電車でできないので後で張り付けます。
rubato6809

2019/10/24 00:13

了解。2つめの call print が肝心で、ひとつ目はprintfのテストみたいなものですね。
guest

0

char sample[10];

の場所(アドレス)はどうやったら求められるのか、

ローカル変数なので、スタックに確保されてる(はず)なんで、コードを読んでいきましょう
がんばってくださいw

#コレはアセンブラの話じゃなくて、C言語の話ですわな

投稿2019/10/23 23:49

編集2019/10/23 23:50
y_waiwai

総合スコア87719

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rubato6809

2019/10/24 00:10

> アセンブラの話じゃなくて、C言語の話 C言語 一皮むけばアセンブラ (るばーと こころの俳句)
y_waiwai

2019/10/24 00:16

まー、高級アセンブラですからねー<C言語 ろくにエラーチェックもないというのはそこらへんから起因してるんだしw
kazuyakazuya

2019/10/24 03:28

アセンブリ言語の"Hello World" くらいなら分かった気になれたので 質問しますが、なぜ"Hello World"のシェルコードを作成することは 不可能なのですか?(シェルコードという言葉ぼ定義は置いておいて) てか、どこらへんを調べればそこを理解できるのでしょうか? (call _printfしているところ?)
y_waiwai

2019/10/24 03:41

実際にやってみればよろしい。 それでできたなら、そういうことですな。 他の人のコメントにもあったけど、C言語で実装するというのも不可能ということでもない。 家を建てるというときに、金づちやのこぎりの使い方を理解できないやつに、どうやってそれを教えるのかってことですなw ここで説明しても理解できるわけもなし。
kazuyakazuya

2019/10/24 03:48

うーん、わかりました。
rubato6809

2019/10/24 06:23

私から見ても今の時点では不可能に見えます。動作した事例と全く同じ条件を揃えれば真似るだけだが、現実のターゲットには様々な相違点があるので、わけもわからず真似ても動作しません。何が違いなのか(何は違っても構わないのか)、どんなハードルがいくつ待ち受けているのか、ハードルを超えるにはどうすればよいか、何をどう確認すれば個々のハードルを越えたと言えるのか、見えていないと思う。 > call _printfしているところ? その辺りの機械語と文字列を元にしてアレンジした数十バイトにも満たない機械語は "hello world" を表示するシェルコードになりうると思います。シェルコードとは、目的の動作をする、正味の機械語、といった意味でしょう。 そのままでは、まずダメと思う。アレンジが必要。でも動作環境・条件・目的・理由を精度よく把握できないと適切なアレンジはできない。シェルコードを作るためのツールなど無いのだから、工夫も要る。 例えば "call _printf" 命令は、普通シェルコードでは使いものになりません。その理由が分かりますか?絶対使えない、とも言えないが、じゃ使える条件は何か?となる。 さらに、今時のOSだとスタック領域でプログラムが走らないようにガードをかけているはずなので、首尾よくシェルコードを文字配列に上書きできたとしても、そこ(スタック領域だよね)では動作できないでしょう。これもハードル・・・というか、そもそもハードルになっているかどうか確認しただろうか?それは、その確認方法がわかるか?という問いにもなる。 確認すべきことがまだ幾つかあると思う、先は長いよ笑。プラモデルの組立てとは違うので、機械語レベルの動作まで理解せずにハッキングは不可能。Cだけで書ける書けないは、何が必要なのかが見えてないと検討のしようがない。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問