アセンブリ言語で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
scanf関数を作りたい、のか
scanf関数を使いたい
どちらなのでしょう?
前者ならば、「中級者でも厳しい課題なので諦めろ」が答えになりますが
すみません。
「使いたい」の方です。
その解決コードは本当に動作したの?とても疑わしいコードですが。
しっかりコンパイルできまた。
exeを実行させてもしっかり
受け取ることができます。
どこに誤りがあるのでしょうか?
(正常に実行できたのはたまたま?)
タイプして入力した文字列がどこに・どう格納されたのか、確認できるようになってないので、たまたま落ちなかっただけだと思われる。
未初期化変数 foo があって、たとえば
int foo;
char buf[4];
scanf(foo, "%s", buf); のような呼出しになっている。
ん、ちょっと言っていることがわからないです。
あと、scanfの引数は2つだと思うのですが。。。
あ、つまり
変数を入れておく場所のアドレスの
確保の仕方がおかしい
ということですか?
私も回答を修正した。
”%s" はスタックトップに代入しなくてはならない。それを君のコードは4(%esp)にセットしている。
スタックトップ (%esp) には何もセットしていない。それは未初期化変数を第一引数としてセットしたことに等しい。
というと正しくは
movl $msg,(%esp)
ってことですか?
そうです。そして
leal xx(%esp), %eax として得られた配列のアドレスを
movl %eax, 4(%esp) と代入しなければならない。
「C++ 呼び出し規約」でぐぐって出てくるのを読め
雰囲気で理解したつもりになってても無駄なだけだぞ
xx(%esp) は、この場合 8(%esp) のことだけど。
今できないので後で訂正します。
ご教授ありがとうございます。
いい加減にスタックに積んでいましたが
積めなきゃいけないのですね。
分かりました。読んでみます
https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11189364111
これを見ただけならそこまで難しそうに見えないのですが
実際厳しいのですか?
表示するだけなら難しくありません。あなた自身で動作するアセンブリコードを作って示したら良いと思う。単に表示するアセンブリコードすら作れないのではシェルコードはなおさらだ。よって、これは必須のステップである。具体的な話はそれからでも十分可能。
ただし、この段階ではシェルコード云々をいったん脇に置くこと。
具体的なコードがあれば、シェルコードへアレンジ可能かどうか、具体的なアドバイスは可能だと思う(ただ、個人的にはこのサイトを使わないほうがやりやすいけど)。
了解です。
windowsでシェルコードにしたいのならば、write関数はどこにあるのか?って事を考えなければいけなくて
Linuxならばほぼ常にロードされるlibcにあった気がしますが
結局、攻撃できる状態ならば、バッファオーバーフローを用いた攻撃よりもCreateRemoteThread/WriteProcessMemory使った方が楽です
さらに言うならば、CreateRemoteThreadでLoadLibrary呼んでDLL注入するのが一番楽です。
これなら文句なくCコンパイラのみで可能です。
ありがとうございます。
調べてみます。
あと、気になるのですが
ここで言うところの
write関数はシステムコールではないほうですよね?
で、その関数の場所って言うのは
ソースがおかれている場所のことですか?
システムコールが使えるならばシステムコールでもよいですよ
残念ながら、私ではwindowsのコンソール書き込みをsyscallで行う方法が見つかりませんでしたので
kernel32.dllのWriteConsole関数を使うことになると思いますが
ありがとうございます。
やっぱ前提知識がなくて
システムコール・ライブラリ・Windows・Linux・dll
などなど認識がめちゃめちゃなので
調べなおします。(聞き直します。)
実は私はWindowsのシステムコールとかDLLとか馴染みが無いです。
Windows関係のタグで質問してみるのも手でしょうね。
基礎的なことは知恵袋のほうで済ませようと思います。
システムコールの話になるとwindowsとかのOSも
関係しそう(てか、関係する)なのでタグはつけようと思います。
回答2件
あなたの回答
tips
プレビュー