main()
C 또는 C ++ 응용 프로그램에서 인수를 전달할 때 argv[0]
항상 실행 파일의 이름이됩니까? 아니면 이것은 일반적인 관례 일 뿐이며 100 % 진실이라고 보장되지 않습니까?
답변:
추측 (교육을받은 추측조차도)은 재미 있지만 확실히하기 위해서는 표준 문서로 가야합니다. 예를 들어 ISO C11은 다음과 같이 말합니다 (내 강조).
의 값
argc
이 0보다 크면로 가리키는 문자열 은 프로그램 이름 을argv[0]
나타냅니다 .argv[0][0]
호스트 환경에서 프로그램 이름을 사용할 수없는 경우 널 문자가됩니다.
따라서 해당 이름을 사용할 수있는 경우에만 프로그램 이름 입니다. 그리고 그것은 프로그램 이름을 "나타내고" , 반드시 프로그램 이름 일 필요 는 없습니다 . 그 앞의 섹션은 다음과 같습니다.
의 값
argc
이 0보다 크면 inclusive를argv[0]
통한 배열 구성원argv[argc-1]
은 프로그램 시작 전에 호스트 환경에서 구현 정의 값을 제공하는 문자열에 대한 포인터를 포함해야합니다.
이것은 이전 표준 인 C99에서 변경되지 않았으며, 값 조차도 표준에 의해 지시되지 않는다는 것을 의미합니다. 이는 전적으로 구현에 달려 있습니다.
호스트 환경이 경우 수단은 프로그램 이름이 비어있을 수 없는 호스트 환경이 경우를 제공하고, 아무것도 하지 "무엇은"어떻게 든 프로그램 이름을 나타내는 제공을 제공합니다. 더 가학적인 순간에 스와힐리어로 번역하고 대체 암호를 통해 실행 한 다음 역 바이트 순서로 저장하는 것을 고려할 것입니다 :-).
그러나 구현 정의 는 ISO 표준에서 특정 의미를 갖습니다. 구현시 작동 방식을 문서화해야합니다. 따라서 호출 계열 argv[0]
과 함께 원하는 것을 넣을 수있는 UNIX조차도이를 exec
문서화해야합니다.
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
이 0보다 크면로 가리키는 문자열은 프로그램 이름을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
심볼릭 링크는 솔라리스 10 및 최대에 사용할 수 있습니다.
GetModuleFileNameW
에서는 모든 경로를 검색 할 수 있어야하지만 코드의 존재만으로 좋은 지침이 됨).
argv[0] !=
실행 가능한 이름 을 갖는 응용 프로그램
많은 쉘이를 확인하여 로그인 쉘인지 판별합니다 argv[0][0] == '-'
. 로그인 셸은 다른 속성을 가지고 있으며 특히 /etc/profile
.
일반적으로 init 자체이거나 getty
선행을 추가합니다 -
. /unix/299408/how-to-login-automatically-without-typing-the-root-username-or-password 도 참조하십시오. -인-빌드 / 300152 # 300152
다중 호출 바이너리, 아마도 가장 주목할만한 것은 Busybox 입니다. 이 심볼릭 링크 여러 이름은 예 /bin/sh
와 /bin/ls
단일 exebutable에 /bin/busybox
에서 사용하는 도구를 인식하고,argv[0]
.
이를 통해 여러 도구를 나타내는 하나의 작은 정적으로 연결된 실행 파일을 가질 수 있으며 기본적으로 모든 Linux 환경에서 작동합니다.
참조 : /unix/315812/why-does-argv-include-the-program-name/315817
실행 가능한 POSIX execve
예에서 argv[0] !=
실행 파일 이름
언급 된 기타 exec
했지만 여기에 실행 가능한 예가 있습니다.
ac
#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에서 테스트되었습니다.
이 페이지 는 다음을 설명합니다.
argv [0] 요소는 일반적으로 프로그램의 이름을 포함하지만, 이것은 의존해서는 안됩니다. 어쨌든 프로그램이 자신의 이름을 알지 못하는 것은 드문 일입니다!
그러나 다른 페이지는 항상 실행 파일의 이름이라는 사실을 백업하는 것처럼 보입니다. 이것은 다음과 같이 말합니다.
argv [0]이 프로그램 자체의 경로와 이름임을 알 수 있습니다. 이를 통해 프로그램은 자신에 대한 정보를 검색 할 수 있습니다. 또한 프로그램 인수 배열에 하나를 더 추가하므로 명령 줄 인수를 가져올 때 흔히 발생하는 오류는 argv [1]을 원할 때 argv [0]을 가져 오는 것입니다.
argv[0]="-/bin/sh"
했습니까? 어쨌든 내가 사용한 모든 기계의 경우입니다.
거의 보편적 인 관습인지 표준인지는 잘 모르겠지만 어느 쪽이든 따라야합니다. 나는 그것이 유닉스와 유닉스 계열 시스템 밖에서 악용되는 것을 본 적이 없다. 유닉스 환경에서, 특히 예전에는 프로그램이 호출되는 이름에 따라 상당히 다른 동작을 보일 수 있습니다.
편집 됨 : 다른 게시물에서 누군가가 특정 표준에서 나온 것으로 식별 한 것을 동시에 다른 게시물에서 볼 수 있지만,이 협약이 표준보다 오래 전부터 있다고 확신합니다.
execl("/home/hacker/.hidden/malicious", "/bin/ls", "-s", (char *)0);
.. 실행 파일의 이름은의 값과 관련이 없습니다argv[0]
.