프로세스의 실행 환경 정보를 제공하는 간단한 C 프로그램을 만들어보자.
구현 옵션은 다음과 같으며, 각 옵션마다 해당되는 값을 출력하도록 작성되었다.
-e [이름] : 지정된 이름의 환경변수 값. 이름이 없을 땐 모든 환경변수들의 값
-u : 실행중인 프로세스의 실제 사용자 ID와 유효 사용자 ID
-g : 실행중인 프로세스의 실제 그룹 ID와 유효 그룹 ID
-i : 프로세스 ID
-p : 부모 프로세스 ID
- 명령줄 인자는 strcmp()를 사용하였음
- unistd.h, pwd.h, grp.h를 통해 시스템 정보를 조회한다.
각 옵션별 기능 설명
-e [이름] : 환경 변수 출력
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
extern char **environ;
int main(int argc, char *argv[]){
for (int i=1; i<argc; i++){
if (strcmp(argv[i], "-e") == 0){
// 다음 인자가 존재하고 && -로 시작하지 않는다면 -> 환경변수 이름으로 처리
if(i+1 < argc && argv[i+1][0]!='-'){
char *val = getenv(argv[i+1]);
if (val)
printf("%s=%s\n", argv[i+1], val);
else
printf("%s = (null)\n", argv[i+1]);
i++;
} else {
// 인자가 없거나 -옵션이 연이어 나오는 경우 -> 모든 환경변수 출력
char **env = environ;
while(*env){
printf("%s\n", *env);
env++;
}
}
-e 다음에 환경 변수 이름이 있으면 해당 환경 변수의 값을 출력하고, 이름이 없으면 시스템의 모든 환경변수를 출력한다.
getenv("변수명") : 해당 변수의 값을 가져옴
environ : 전체 환경변수들의 포인터 배열 (글로벌 변수)
1. argv[i]가 -e인지 확인
2. 다음 인자 argv[i+1]이 존재하고 -로 시작하지 않으면
=> getenv(argv[i+1])로 해당 환경변수의 값을 가져온다.
3. 그렇지 않으면 environ을 통해 전체 환경변수들을 순회하며 출력
코드에 사용된 기본 포인터 개념들을 간단히 정리해보면 다음과 같다.
char * | 하나의 문자열(문자 배열)을 가리키는 포인터 |
char ** | 문자열들의 배열(즉, 문자열 목록)을 가리키는 포인터 |
environ | 현재 프로세스의 모든 환경변수를 가리키는 이중 포인터 변수 |
즉 정리하자면 environ은 전역 변수이며, 운영체제가 프로세스를 실행할 때 다음과 같이 환경 변수들을 담아서 전달한다.
environ --> [0] --> "PATH=/usr/bin"
[1] --> "HOME=/home/user"
[2] --> "SHELL=/bin/bash"
...
[n] --> NULL
두 번째 else 문으로 예를 들어보자.
char **env = environ;
while (*env) {
printf("%s\n", *env);
env++;
}
env는 이중 포인터이고, 환경 변수 문자열 배열의 시작 주소를 가리킨다.
*env는 char *이다. (ex. "PATH=/usr/bin")
printf("%s\n", *env)로 문자열을 한 줄 출력하고,
env++; 을 통해 다음 문자열로 이동하는 원리이다. (environ[0] -> environ[1] -> environ[2] -> ...)
<출력 예시>
-u: 사용자 ID 출력
printf("나의 실제 사용자 ID: %d (%s)\n", getuid(), getpwuid(getuid())->pw_name);
printf("나의 유효 사용자 ID: %d (%s)\n", geteuid(), getpwuid(geteuid())->pw_name);
- getuid()와 geteuid()는 각각 실제 사용자 ID와 유효 사용자 ID를 반환
- getpwuid(uid)는 UID에 해당하는 사용자 정보 구조체를 반환
-g : 그룹 ID 출력
printf("나의 실제 그룹 ID: %d (%s)\n", getgid(), getgrgid(getgid())->gr_name);
printf("나의 유효 그룹 ID: %d (%s)\n", getegid(), getgrgid(getegid())->gr_name);
- getgid()와 getegid()는 각각 실제 그룹 ID와 유효 그룹 ID를 반환
- getgrgid(uid)는 GID에 해당하는 group 구조체를 반환하여 그룹 이름 조회 가능
-i: 현재 프로세스 ID 출력
printf("나의 프로세스 번호 : %d\n", getpid());
-p: 부모 프로세스 ID 출력
printf("부모 프로세스 번호 : %d\n", getppid());
<출력 예시>
전체 코드
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
extern char **environ;
int main(int argc, char *argv[]){
for (int i=1; i<argc; i++){
if (strcmp(argv[i], "-e") == 0){
if(i+1 < argc && argv[i+1][0]!='-'){
char *val = getenv(argv[i+1]);
if (val)
printf("%s=%s\n", argv[i+1], val);
else
printf("%s = (null)\n", argv[i+1]);
i++;
} else {
char **env = environ;
while(*env){
printf("%s\n", *env);
env++;
}
}
} else if (strcmp(argv[i], "-u") == 0){
printf("나의 실제 사용자 ID: %d (%s)\n", getuid(), getpwuid(getuid())->pw_name);
printf("나의 유효 사용자 ID: %d (%s)\n", geteuid(), getpwuid(geteuid())->pw_name);
} else if (strcmp(argv[i], "-g") == 0){
printf("나의 실제 그룹 ID: %d (%s)\n", getgid(), getgrgid(getgid())->gr_name);
printf("나의 유효 그룹 ID: %d (%s)\n", getegid(), getgrgid(getegid())->gr_name);
} else if (strcmp(argv[i], "-i") == 0){
printf("나의 프로세스 번호 : %s\n", getpid());
} else if (strcmp(argv[i], "-p") == 0){
printf("부모 프로세스 번호 : %s\n", getppid());
} else {
printf("Unknown option: %s\n", argv[i]);
}
}
return 0;
}
'System Hacking' 카테고리의 다른 글
[System] 텍스트 편집기 C 프로그램 만들기 - 줄 단위 출력/삭제/추가/대치 기능 구현 (0) | 2025.04.09 |
---|---|
[System] 버퍼 오버플로우 실습 예제 문제 풀이 (0) | 2024.11.25 |
[System] 버퍼 오버플로우 기본 개념 다지기 - Buffer Overflow 실습 예제 풀이 (0) | 2024.11.25 |