使用有趣的 Linux 病毒程序解释基本 Linux 系统调用
【摘要】 如果你对编写 Linux 系统编程感兴趣,你应该学习所有基本的库/系统调用。本文有一个示例 C 程序,其中包含一组系统调用,可帮助您了解这些基本库调用的用法。
如果你对编写 Linux 系统编程感兴趣,你应该学习所有基本的库/系统调用。本文有一个示例 C 程序,其中包含一组系统调用,可帮助您了解这些基本库调用的用法。
下面给出的示例 C 代码执行以下操作:
- 自动打开一些终端
- 显示会话以 root 或非 root 身份运行的消息
- 在所有打开的终端上显示上述消息
以下是以下示例代码中涵盖的 13 个重要的库或系统调用。
- memset() :此函数用常量字节 c 填充 s 指向的内存区域的前 n 个字节。
- fopen() :此函数打开文件,其名称是其第一个参数指向的字符串,并将流与它相关联。
- getcwd() :此函数返回一个以 null 结尾的字符串,其中包含一个绝对路径名,该路径名是调用进程的当前工作目录
- getuid() :该函数返回调用进程的真实用户ID
- snprintf() :此函数根据格式生成输出并将输出写入缓冲区。
- fwrite() :此函数用于将数据写入流
- fflush() :此函数强制将所有用户空间缓冲数据写入特定流
- fclose() :此函数刷新关联的流并关闭底层文件描述符。
- system() : 这个函数执行一个命令
- sleep() :此函数使调用进程休眠,直到经过指定的秒数或没有忽略的信号到达。
- opendir() : 这个函数打开一个目录流
- readdir() :此函数读取作为流打开的目录
- atoi() :此函数将 ascii 参数转换为整数。
以下是显示如何使用上述所有 13 个系统调用的 C 代码。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<dirent.h>
#include<sys/types.h>
#include<pwd.h>
// A buffer to hold current working directory
char cwd[512];
void inform(char *path, char *binary_name)
{
// Declare variables for file operations
FILE *fp = NULL;
// A counter to be used in loop
unsigned int counter = 0;
// A buffer to hold the information message
char msg[1024];
// memset function initializes the bytes
// in the buffer 'msg' with NULL characters
memset(msg, '\0', sizeof(msg));
memset(cwd, '\0', sizeof(cwd));
// Check for the path to be non NULL
if(NULL== path)
{
printf("\n NULL path detected\n");
return;
}
// fopen will open the file represented
// by 'path' in read write mode.
fp = fopen(path,"r+");
if(!fp)
{
printf("\n Failed to open %s\n",path);
return;
}
else
{
printf("\n Successfully opened %s\n",path);
}
// getcwd() gives us the current working directory
// of the environemt from which this binary was
// executed
if(NULL == getcwd(cwd,sizeof(cwd)))
{
printf("\n Failed to get current directory\n");
return;
}
// getuid() returns the real user ID of the calling
// process.
// getuid() returns 0 for root and non zero for
// any other user.
if( 0 != getuid())
{
// This functions fills the buffer 'msg' with the formatted string by replacing %s in the harcoded string with the appropriate values
snprintf(msg,sizeof(msg),"\n\n\nYOU ARE NOT ROOT!!!!!");
}
else
{
snprintf(msg, sizeof(msg),"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nYOU ARE ROOT!!!!!!!!!!!!!!");
}
// Make sure the information8 is printed 25 times on each
// open terminal
for(counter=0;counter<25;counter++)
{
printf("\n fwrite()\n");
// Write the information message on to the terminal
fwrite(msg, strlen(msg), 1, fp);
// Flush the message to the stdout of the terminal
fflush(fp);
// Wait for one second.
sleep(1);
}
// close the file representing the terminal
fclose(fp);
}
int main(int argc, char *argv[])
{
// Since we will do some directory operations
// So declare some variables for it.
DIR *dp = NULL;
struct dirent *ptr = NULL;
// This variable will contain the path to
// terminal
char *path = NULL;
// Used as a counter in loops
int i =0;
// Step1 :
// Open 5 terminals each after 2 seconds
// of delay.
for(;i<5;i++)
{
// The system API executes a shell command
// We try to execute two commands here
// Both of these commands will open up
// a terminal. We have used two commands
// just in case one of them fails.
system("gnome-terminal");
system("/usr/bin/xterm");
// This call is used to cause a delay in
// program execution. The argument to this
// function is the number of seconds for
// which the delay is required
sleep(2);
}
// Give user some 60 seconds before issuing
// a information message.
sleep(60);
// Now, open the directory /dev/pts which
// corresponds to the open command terminals.
dp = opendir("/dev/pts");
if(NULL == dp)
{
printf("\n Failed to open /dev/pts\n");
return 0;
}
// Now iterate over each element in the
// directory untill all the elements are
// iterated upon.
while ( NULL != (ptr = readdir(dp)) )
{
// ptr->d_name gives the current device
// name or the terminal name as a device.
// All the numeric names correspond to
// open terminals.
// To check the numeric values we use
// atoi().
// Function atoi() converts the ascii
// value into integer
switch(atoi(ptr->d_name))
{
// Initialize 'path' accordingly
case 0:path = "/dev/pts/0";
break;
case 1:
path = "/dev/pts/1";
break;
case 2:
path = "/dev/pts/2";
break;
case 3:
path = "/dev/pts/3";
break;
case 4:
path = "/dev/pts/4";
break;
case 5:
path = "/dev/pts/5";
break;
case 6:
path = "/dev/pts/6";
break;
case 7:
path = "/dev/pts/8";
break;
case 9:
path = "/dev/pts/9";
break;
default:
break;
}
if(path)
{
// Call this function to throw some information.
// Pass the path to terminal where the information
// is to be sent and the binary name of this
// program
inform(path, argv[0]);
// Before next iteration, make path point to
// NULL
path = NULL;
}
}
sleep(60);
return 0;
}
上面的代码本身是不言自明的,因为它包含足够的注释来解释这些系统调用的作用。如果您是 Linux 系统编程的新手,这段代码足以让您充分了解所有这些重要功能的用法。有关更多详细信息和高级用法,请仔细阅读他们的手册页。
这段代码是一个有趣的基本病毒程序的模拟。编译并执行上述 c 程序后,它将执行以下操作。此代码在 Linux mint 上进行了测试。但是,它应该适用于所有 ubuntu 衍生产品。
- 用户将在 1 秒后看到 5 个终端一个接一个地打开。
- 虽然用户会想知道刚刚发生了什么,但他所有打开的终端都会慢慢开始重复获取有关登录是 root 还是非 root 的信息。
- 请注意,为了您的学习目的,代码中启用了调试日志记录,如果您想玩得开心,请注释掉调试 printf,然后执行它。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)