回答:
推測作業(教育を受けた推測作業でも)は楽しいですが、確実に標準のドキュメントにアクセスする必要があります。たとえば、ISO C11は次のように述べています(私の強調):
の値が
argc
ゼロより大きい場合、が指す文字列はプログラム名をargv[0]
表します。argv[0][0]
ホスト環境からプログラム名を取得できない場合は、ヌル文字になります。
そのため、いいえ、その名前が利用可能な場合、それはプログラム名だけです。そして、それはプログラム名を「表す」ものであり、必ずしもプログラム名であるとは限りません。その前のセクションは次のように述べています:
の値が
argc
ゼロより大きい場合、配列のメンバーargv[0]
はargv[argc-1]
包括的に、文字列へのポインターが含まれます。これには、プログラムの起動前にホスト環境によって実装定義の値が与えられます。
これは、以前の標準であるC99から変更されておらず、値されておらずによっても標準によって規定されていない。完全に実装次第です。
ホスト環境があれば、プログラム名を空にすることができることをこれ意味しないホスト環境があればそれを提供し、他に何もありません「何か」が何らかの形でプログラム名を表していることを提供し、それを提供します。私のよりサディスティックな瞬間には、それをスワヒリ語に変換し、置換暗号を実行してから、逆のバイト順で格納することを検討します:-)。
ただし、実装定義は ISO標準で特定の意味を持っています-実装はそれがどのように機能するかを文書化する必要があります。したがって、呼び出しargv[0]
のexec
ファミリで好きなものを入れることができるUNIXでさえ、それを文書化する必要があります(実際に文書化します)。
argv[0]
、現実の世界でのプログラミングには適切だと思います。
以下の下*nix
でのタイプのシステムexec*()
コール、argv[0]
だろうに何でも発信者プットargv0
のスポットexec*()
コール。
シェルはこれがプログラム名であるという規則を使用し、他のほとんどのプログラムは同じ規則に従います。 argv[0]
、通常はプログラム名です。
しかし、悪意のあるUnixプログラムは好きなものを呼び出しexec()
て作成できるargv[0]
ので、C標準が何と言っても、この100%の時間を当てにすることはできません。
C ++標準に従って、セクション3.6.1:
argv [0]は、プログラムの呼び出しに使用された名前または ""を表すNTMBSの最初の文字へのポインターです
ですから、少なくとも標準では保証されていません。
ISO-IEC 9899は次のように述べています。
5.1.2.2.1プログラムの起動
の値が
argc
ゼロより大きい場合、が指す文字列argv[0]
はプログラム名を表します。argv[0][0]
ホスト環境からプログラム名を取得できない場合は、ヌル文字になります。の値がargc
1より大きい場合、argv[1]
throughが指す文字列argv[argc-1]
はプログラムパラメータを表します。
私も使用しました:
#if defined(_WIN32)
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
return GetModuleFileNameA(NULL, pathName, (DWORD)pathNameCapacity);
}
#elif defined(__linux__) /* elif of: #if defined(_WIN32) */
#include <unistd.h>
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
size_t pathNameSize = readlink("/proc/self/exe", pathName, pathNameCapacity - 1);
pathName[pathNameSize] = '\0';
return pathNameSize;
}
#elif defined(__APPLE__) /* elif of: #elif defined(__linux__) */
#include <mach-o/dyld.h>
static size_t getExecutablePathName(char* pathName, size_t pathNameCapacity)
{
uint32_t pathNameSize = 0;
_NSGetExecutablePath(NULL, &pathNameSize);
if (pathNameSize > pathNameCapacity)
pathNameSize = pathNameCapacity;
if (!_NSGetExecutablePath(pathName, &pathNameSize))
{
char real[PATH_MAX];
if (realpath(pathName, real) != NULL)
{
pathNameSize = strlen(real);
strncpy(pathName, real, pathNameSize);
}
return pathNameSize;
}
return 0;
}
#else /* else of: #elif defined(__APPLE__) */
#error provide your own implementation
#endif /* end of: #if defined(_WIN32) */
次に、文字列を解析して、パスから実行可能ファイル名を抽出する必要があります。
/proc/self/path/a.out
シンボリックリンクは、Solaris 10とアップに使用可能であってもよいです。
GetModuleFileNameW
、任意のパスを取得できるようにするために使用する必要がありますが、コードの存在のみが適切なガイダンスを構成します)。
このページは述べています:
要素argv [0]には通常、プログラムの名前が含まれていますが、これに依存しないでください-とにかく、プログラムが自分の名前を知らないのは珍しいことです!
ただし、他のページは、それが常に実行可能ファイルの名前であるという事実を裏付けているようです。これは述べています:
argv [0]はプログラム自体のパスと名前です。これにより、プログラムはそれ自体に関する情報を発見できます。また、プログラムの引数の配列にもう1つ追加するため、コマンドライン引数をフェッチするときの一般的なエラーは、argv [1]が必要なときにargv [0]を取得することです。
argv[0]="-/bin/sh"
?とにかく、私が使用したすべてのマシンに当てはまります。
argv[0] !=
実行可能名を持つアプリケーション
多くのシェルは、をチェックすることで、それらがログインシェルかどうかを判断しますargv[0][0] == '-'
。ログインシェルにはさまざまなプロパティがあります。特に、次のようないくつかのデフォルトファイルをソースとしています。/etc/profile
。
通常は、それ自体がinitであるかgetty
、先頭-
にが追加されます。https://unix.stackexchange.com/questions/299408/how-to-login-automatically-without-typing-the-root-username-or-password -in-build / 300152#300152
マルチコールバイナリ、おそらく最も顕著なのはBusyboxです。これらのシンボリックリンクは複数の名前を含み、たとえば/bin/sh
、使用するツールを認識する/bin/ls
単一の実行可能ファイル/bin/busybox
にシンボリックリンクしますargv[0]
。
これにより、複数のツールを表す静的にリンクされた単一の実行ファイルを作成することが可能になり、基本的にどのLinux環境でも機能します。
参照:https : //unix.stackexchange.com/questions/315812/why-does-argv-include-the-program-name/315817
実行可能な名前の実行可能なPOSIXのexecve
例argv[0] !=
その他の言及 exec
しましたが、ここでは実行可能な例です。
交流
#define _XOPEN_SOURCE 700
#include <unistd.h>
int main(void) {
char *argv[] = {"yada yada", NULL};
char *envp[] = {NULL};
execve("b.out", argv, envp);
}
紀元前
#include <stdio.h>
int main(int argc, char **argv) {
puts(argv[0]);
}
次に:
gcc a.c -o a.out
gcc b.c -o b.out
./a.out
与える:
yada yada
はい、またargv[0]
可能性があります:
Ubuntu 16.10でテスト済み。
それがほぼ普遍的な慣習であるか標準であるかはわかりませんが、どちらの方法でも遵守する必要があります。ただし、UnixおよびUnixライクなシステム以外で悪用されることはありません。Unix環境では(おそらくおそらく昔は)、プログラムは呼び出された名前によって動作が大幅に異なる可能性があります。
編集済み:他の投稿と同時に、誰かが特定の規格に由来するものであると特定したことを確認しましたが、この規約はその規格よりもずっと前から存在していると思います。
execl("/home/hacker/.hidden/malicious", "/bin/ls", "-s", (char *)0);
。実行可能ファイルの名前は、の値とは関係ありませんargv[0]
。