CGIアセンブリ言語?!? -簡単!

この記事はかなり長い間インターネット上にありましたが、著者が考えるように、私はここに再投稿する権利があります。 ここに書かれているものの多く(すべてではないにしても)は時代遅れで、一見役に立たないように思えるかもしれませんが、このように進んだ後、6年後、それは余計なものではなかったと言えます。 だから。
この記事では、CGIインターフェース全般、Windows用の実装、特にCGIプログラムを作成する際のアセンブリ言語の使用について説明します。 CGIの完全な説明はこの記事の範囲には含まれていません。このテーマについてはインターネット上に単に多くの資料があり、ここでこれらすべてを語る意味がわからないからです。


CGI理論

CGI-(共通ゲートウェイインターフェイス) -共通ゲートウェイインターフェイス。 推測するのは難しいことではないので、このインターフェイスは、サーバー(ここではサーバープログラム)と、このサーバーが実行されているOS向けに作成された外部プログラムとの間のゲートウェイとして機能します。 したがって、CGIは、データがサーバープログラムからCGIプログラムに、またその逆にどのように転送されるかについて責任を負います。 インターフェイスは、CGIプログラムの書き込み対象に制限を課しません。通常の実行可能ファイルまたはその他のファイルのいずれかを使用できます。主なことは、サーバーがそれを実行できることです(たとえば、Windowsでは、拡張子のあるファイル、任意のプログラムに関連付けられています)。
CGIプログラムを呼び出した(たとえば、CGIプログラムへの呼び出しが接続されているフォームボタンをクリックした)後、ブラウザウィンドウで結果を受け取るまで、次のことが発生します。
-Webクライアント(ブラウザなど)は、URLで指定されたサーバーへの接続を作成します。
-Webクライアントはサーバーにリクエストを送信します。通常、このリクエストは2つのGETまたはPOSTメソッドを使用して行われます。
-クライアントのリクエストからのデータ(フォームフィールドの値など)は、CGIインターフェイスを使用して、URLで指定されたCGIプログラムにサーバーによって送信されます。
-CGIプログラムは、サーバーから受信したクライアントデータを処理し、この処理に基づいてクライアントへの応答を生成し、同じCGIインターフェイスを介してサーバーに渡し、クライアントに直接転送します。
-サーバーはクライアントから切断します。
標準のCGI仕様では、サーバーは次の方法でプログラムと交換できます。
-環境変数-プログラムの起動時にサーバーによって設定できます。
-標準入力ストリーム(STDIN)-サーバーの助けを借りて、サーバーはデータをプログラムに転送できます。
-標準出力ストリーム(STDOUT)-プログラムは独自の出力を書き込むことができ、サーバーに送信されます。
-コマンドライン-サーバーは、いくつかのパラメーターをプログラムに渡すことができます。
標準入力/出力ストリームは非常に便利で、UNIXシステムでは広く使用されていますが、Windowsについては言えません。したがって、Windowsシステム用に特別に開発された、いわゆる「Windows CGI」があります。 しかし、もちろん、標準の入力/出力ストリームはWindows CGIプログラミングでも使用できます。 ここでは、「Windows CGI」標準については触れません。少なくとも2つの理由があります。最初で最も重要な理由は、現時点では、Windowsのすべてのhttpサーバーがこの仕様をサポートしているわけではありません(特に、私のお気に入りのApache 1.3.19) 。 検索エンジンで「Windows CGI」と入力すると、2番目の理由を確認できます。 このインターフェイスに関する一般的な詳細のみに注意します。サーバーからクライアントへのすべてのデータは、通常のwindows * .iniファイルを使用して送信されます。このファイルの名前はコマンドラインでプログラムに渡されます。 同時に、ファイル内のすべてのデータは既にサーバーによって慎重にセクションに分割されており、GetPrivateProfile *関数を使用してそこから抽出するだけです。 サーバーへの応答は、対応するiniファイルエントリに名前が示されているファイルを介して再度送信されます。
クライアントがCGIプログラムに転送できるデータは何ですか? -ほとんどすべて。 一般に、プログラムはクライアントが入力するフォームフィールドの値を受け取りますが、任意のバイナリデータ、たとえば画像や音楽のあるファイルも可能です。 データは2つの異なる方法でサーバーに転送できます-これはGETメソッドとPOSTメソッドです。 ページに記入するフォームを作成するとき、ユーザー入力を送信する上記のメソッドのいずれかを明示的に示します。これは、メインフォームタグで次のように行われます。
GETメソッドを使用してデータを送信する場合、データはブラウザによってフォームから読み取られ、疑問符の後ろのスクリプトURLの後に配置されます。フォームにいくつかの重要なフィールドがある場合、それらはすべて「&」アイコンを介して送信され、フィールド名とその値は「 = "。 たとえば、フォームの最初のフィールドが「your_name」および2番目の「your_age」と呼ばれることを考慮して、スクリプト「/cgi-bin/test.exe」がバインドされているボタンをクリックすると、ブラウザーがフォームから生成する要求は次のようになります。
GET /cgi-bin/test.exe?your_name=Pupkin&your_age=90 HTTP / 1.0
GETメソッドを使用すると、一度にいくつかの弱点があります-最初で最も重要なこと- データはURLに転送されるため、この最も送信されるデータの量に制限があります。 2番目の弱点はURLからも続きます-それは機密性であり、そのような転送では、データは完全に開かれたままです。 したがって、フォームに2〜3個の小さなフィールドがあると便利です。データがさらにある場合はどうすればよいでしょうか。 答えはPOSTメソッドを使用することです!
POSTメソッドを使用する場合、データはURLではなくデータブロックとしてサーバーに送信されます。これにより、送信される情報量が増加します。上記のPOSTフォームの例では、サーバーに送信されるブロックは次のようになります。

POST /cgi-bin/test.exe HTTP/1.0
Accept: text/plain
Accept: text/html
Accept: */*
Content-type: application/x-www-form-urlencoded
Content-length: 36
your_name=Pupkin&your_age=90


前述のように、サーバーはデータを受信した後、それを変換してCGIプログラムに転送する必要があります。 標準CGI仕様では、GET要求中にクライアントが入力したデータは、サーバーによってQUERY_STRINGプログラム環境変数に配置されます。 POSTが要求されると、データはアプリケーションの標準入力ストリームに配置され、そこからデータを読み取ることができます。 さらに、このようなリクエストでは、サーバーはさらに2つの環境変数-CONTENT_LENGTHとCONTENT_TYPEを設定します。これらの変数を使用して、リクエストの長さをバイト数とその内容で判断できます。
データ自体に加えて、サーバーは呼び出されたプログラムの他の環境変数を設定します。それらのいくつかを提供します。

REQUEST_METHOD
データの受信方法を説明します。
例:REQUEST_METHOD = GET

QUERY_STRING
GETメソッドが使用された場合のクエリ文字列
例:QUERY_STRING = your_name = Pupkin&your_age = 90&hobby = asm

CONTENT_LENGTH
要求本文のバイト単位の長さ
例:CONTENT_LENGTH = 31

CONTENT_TYPE
リクエストボディタイプ

GATEWAY_INTERFACE
CGIプロトコルバージョン
例:GATEWAY_INTERFACE = CGI / 1.1

REMOTE_ADDR
リモートホストのIPアドレス、つまり、フォームのボタンをクリックしたクライアント
例:REMOTE_ADDR = 10.21.23.10

REMOTE_HOST
リモートホストの名前。ドメイン名またはWindows環境のコンピューター名など、取得できない場合はフィールドにそのIPが含まれます。
例:REMOTE_HOST = wasm.ru

SCRIPT_NAME
リクエストで使用されるスクリプトの名前。
例:SCRIPT_NAME = / cgi-bin / gols.pl

SCRIPT_FILENAME
サーバー上のスクリプトファイルの名前。
例:SCRIPT_FILENAME = c:/page/cgi-bin/gols.pl

SERVER_SOFTWARE
サーバーソフトウェア
例:Apache / 1.3.19(WIN32)
呼び出されたCGIプログラムは、サーバーによって設定された環境変数のいずれかを読み取り、それを有利に使用できます。
一般に、これは簡単にすべてです。CommonGateway Interfaceの詳細については、専門のドキュメントを参照してください。思い出させるためにこの説明を作成しました。知らない場合は、知っておいてください。 実際に何かを試してみましょう。

実用部

練習のために、少なくとも3つのものが必要です-Windows用のHTTPサーバー、Windows用のApache 1.3.19のすべての例を試しました。サーバーは無料です。iからダウンロードできます。
はい、とにかくサーバーが必要です-どのサーバーですが、cgi-scriptsを実行するように構成されています! 使用しているサーバーでこれを行う方法については、ドキュメントを参照してください。 2番目に必要なことは、もちろんアセンブラです。また、コンパイラはコンソールWIN32アプリケーションの作成をサポートする必要があります。私はTasmを使用しますが、FasmとMasmおよび他の多くの* asmは正常に機能します。 そして最後に、最も重要なことは、この欲求が必要であることです。
したがって、サーバーが正常にインストールおよび設定されたため、index.htmlファイルはサーバードキュメントのルートディレクトリにあり、アドレス127.0.0.1を入力するとブラウザーに正常に表示されます。 また、サーバーフォルダーの荒野のどこかに、スクリプトの実行が許可されているcgi-binフォルダーがあることも考慮します。
サーバーのセットアップを確認し、同時に小さなスクリプトを作成しましょう。 スクリプトは通常の* .batファイルになります。 私は質問を予見します-どうやって? 本当に? はい、これは通常のバッチファイルです。前述のとおり、CGI仕様ではファイルタイプを区別していません。主なことは、サーバーがそれを起動できることです。そして、彼は、stdin / stdoutおよび環境変数、batファイル、完全ではありませんが、たとえば、私たちは非常に満足しています。 次の内容のファイルを作成しましょう。

@echo off
rem
echo Content-type: text/html
echo.
rem
echo "!<br>
echo " GET : %QUERY_STRING%


ファイルtest.batを呼び出して、スクリプトを実行するためのディレクトリに配置します。ほとんどの場合、「cgi-bin」ディレクトリになります。 次に行う必要があるのは、何らかの方法でこのスクリプトを呼び出すことです。原則として、ブラウザのアドレスウィンドウに次の「http://127.0.0.1/cgi-bin/test.bat」を入力することで直接実行できますが、メインページから呼び出しを行い、同時にGETメソッドの動作を確認します。 サーバールートに次の内容のindex.htmlファイルを作成します。

 <html> <head>
 <meta content = "text / html; charset = windows-1251" http-equiv = Content-Type>
 </ head>
 <フォーム名= "テスト"メソッド= getアクション= "/ cgi-bin / test.bat">
 <center> <table border = 1 cellspacing = 0>
 <tr bgcolor = "#e0e0e0"> <td colspan = 2> <font face = arial size = 2>
 <center> <b>サーバーに転送するデータを入力します:</ b> </ center>
 </ font> </ td> </ tr>
 <tr> <td> <font face = arial size = 2>
 <b>データ:</ b> </ font> </ td>
 <td> <font face = arial size = 2>
 <textarea rows = "3" cols = "55" warp = "physical" name = "data"> </ textarea>
 </ font> </ td> </ tr> <tr bgcolor = "#e0e0e0">
 <td colspan = 2> <center>
 <入力タイプ= "送信"値= "送信!">
 </ center> </ td>
 </ tr> </ table> </ center> </ form> </ body> </ html> 


サーバー(ブラウザーのアドレスバーにhttp://127.0.0.1)を入力すると、フォームが表示され、そこに何かを入力して[送信]ボタンをクリックします。すべてが正しく行われた場合、ブラウザーウィンドウにbat-の答えが表示されますスクリプト。 それでは、何が得られたか見てみましょう。
ご想像のとおり、echoコマンドはstdoutに出力します。最初に行うことは、サーバーに応答のヘッダーを送信することです-echo Content-type:text / html。 これはCGI仕様の標準的な見出しです。テキストまたはhtmlドキュメントを送信したいが、他のヘッダーがあります。 非常に重要なポイント-ヘッダーは空の行で応答本文から分離する必要があります。これは次のコマンド「echo。」で行います。 次に、応答の本文自体が転送されます-これは通常のhtmlドキュメントです。わかりやすくするために、サーバーから渡された環境変数の1つを表示します。この変数allでGETメソッド(これはまさにユーザーが入力したデータ。スクリプトの応答で確認できます。 ファイルの最後の2行に「echo」の直後に「引用符が正しくない」ことに気付く場合があります。これは、batファイルの特異性のためにあります。htmlタグは「<」および「>」同時に、これらのシンボルは、batファイルの入力/出力のリダイレクトとして機能するため、ここでは自由に使用できません。
このようなbatスクリプトを少し試してみることをお勧めします。非常に便利です。他の環境変数を見てみてください。 少し話を戻しますが、UNIXシステムでは、シェル言語は非常に開発されており、シェル言語のプログラミングと「実際の」プログラミング言語のプログラミングとの境界線は非常に曖昧な場合があります。これはコマンドインタープリターの言語ですが、windows-interpreter cmd.exeまたは以前のcommand.comは明らかにこれらの目的には弱いです。
それでは、実際にアセンブラーでCGIプログラムを作成するという、この記事の最も重要なタスクに移りましょう。 原則として、CGIに関する上記のすべてを考慮すると、CGIインターフェースにはプログラムが必要であると結論付けることができます。

これで完全なCGIアプリケーションを作成できます。
最後の段落から始めましょう。 Windowsアプリケーションの環境変数にアクセスするには、GetEnvironmentStrings API関数を使用します。関数には引数がなく、ゼロで区切られた環境変数(NAME = VALUE)の配列へのポインターを返します。サーバーがプログラム環境に加えてプログラムを開始すると、配列は二重ゼロで閉じられます標準変数には上記の特定のCGI変数が追加されますが、コマンドラインからプログラムを起動すると、もちろん表示されません。
stdoutに何かを書き込む、またはstdinから読み取るには、まずこれらのストリームのハンドルを取得する必要があります。これは、API関数「GetStdHandle」を使用して行われ、次の値のいずれかが関数パラメーターとして渡されます。



この関数は、読み取り/書き込み操作に必要なハンドルを返します。 次に行う必要があるのは、これらのスレッドの書き込み/読み取りです。 これは、通常のファイルの読み取り/書き込み操作、つまり ReadFileおよびWriteFile。 ここには微妙な点が1つあります。これらの目的でWriteConsole / ReadConsoleを使用できると思うかもしれません。はい、それはコンソールにとって本当に公平であり、うまく機能します。結果はWriteFileと同様にコンソールに表示されますが、これは実行するまで続きますサーバー上のスクリプトとしてのプログラム。 これは、プログラムがサーバーを起動すると、GetStdHandle関数によって返される戻り値がコンソールのハンドルではなく、パイプハンドルになり、2つのアプリケーションを接続するために必要になるためです。
CGIアセンブラプログラムがどのように見えるかを示す小さな例を次に示します。

.386
.model flat,stdcall
includelib import32.lib
.const
PAGE_READWRITE = 4h
MEM_COMMIT = 1000h
MEM_RESERVE = 2000h
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11

.data
hStdout dd ?
hStdin dd ?
hMem dd ?
header:
db 'Content-Type: text/html',13,10,13,10,0
start_html:
db ' CGI- : <br>',13,10,0
for_stdin:
db ' STDIN : <br>',13,10,0
end_html:

db '',13,10,0
nwritten dd ?
toscr db 10 dup (32)
db ' - ',0
.code
_start:

xor ebx,ebx
call GetStdHandle,STD_OUTPUT_HANDLE
mov hStdout,eax
call GetStdHandle,STD_INPUT_HANDLE
mov hStdin,eax

call write_stdout, offset header
call write_stdout, offset start_html

call VirtualAlloc,ebx,1000,MEM_COMMIT+MEM_RESERVE,PAGE_READWRITE
mov hMem,eax
mov edi,eax
call GetEnvironmentStringsA
mov esi,eax
next_symbol:
mov al,[esi]
or al,al
jz end_string
mov [edi],al
next_string:
cmpsb
jmp short next_symbol
end_string:
mov [edi],'>rb<'
add edi,3
cmp byte ptr [esi+1],0
jnz next_string
inc edi
stosb
call write_stdout, hMem
call write_stdout, offset for_stdin

call GetFileSize,[hStdin],ebx
mov edi,hMem
call ReadFile,[hStdin],edi, eax,offset nwritten, ebx
add edi,[nwritten]
mov byte ptr [edi],0
call write_stdout, hMem
call write_stdout, offset end_html
call VirtualFree,hMem
call ExitProcess,-1

write_stdout proc bufOffs:dword
call lstrlen,bufOffs
call WriteFile,[hStdout],bufOffs,eax,offset nwritten,0
ret
write_stdout endp
extrn GetEnvironmentStringsA:near
extrn GetStdHandle:near
extrn ReadFile:near
extrn WriteFile:near
extrn GetFileSize:near
extrn VirtualAlloc:near
extrn VirtualFree:near
extrn ExitProcess:near
extrn lstrlen:near
ends
end _start


実行可能ファイルは、次のコマンドによって構築されます。
tasm32.exe / ml test.asm
tlink32.exe / Tpe / ap / o test.obj
プログラムがコンソールであることを忘れないでください。
上記のhtmlフォームを使用してこのプログラムを呼び出すことができます。フォームのtest.batという名前をtest.exeに変更し、それぞれ/ cgi-bin /にコピーするだけで、リクエストメソッドでPOSTを設定し、プログラムで処理できます。
また、別の方法でプログラムを呼び出すことができます。cgi-binディレクトリにファイルを作成し、たとえば「#!C:/ _ path_ / test.exe」という1行でtest.cgiを作成し、リクエストでサーバーを呼び出します。次に、最初の行を読み取ってexeファイルを実行します。このため、* .cgi拡張子が、スクリプトの拡張子としてhttp-serverの設定に書き込まれている必要があります。 このアプローチでは、サーバーはコマンドライン「test.exe path_to_test.exe」でプログラムを起動します。これにはいくつかの利点があります-最初にスクリプトを実行する人はスクリプトが何に書かれているかさえ知らないということです。たとえば、スクリプト用にこのファイルに行のファイル名を追加すると、すべてのインタープリターがこのように動作するため、デバッグが簡単になります-すべてのperl / php / etcプログラムに、チームインターン自体に 通訳。 したがって、サーバーは、cgi-programを起動するときに、プログラム拡張子が設定でスクリプトとして書き込まれている場合、ファイルの最初の行を読み取り、上記の形式であることが判明した場合、スペースを介してこのファイルの名前の行に示されているプログラムを起動します行は真珠通訳者を示しています;そのような贈り物を受け取ると、その実行を開始します、なぜなら 真珠のコメントは「#」記号であり、最初の行をスキップし、スクリプトをさらに実行します。一般に、物事は便利です。

Source: https://habr.com/ru/post/J111131/


All Articles