0
点赞
收藏
分享

微信扫一扫

通过DevTools逃离Chrome沙盒(CVE-2024-6778和CVE-2024-5836)

伽马星系 2024-11-05 阅读 16

欢迎来到博主的专栏:从0开始Linux
博主ID:代码小豪

文章目录

bash

什么?我写bash?bash作为一个大型的shell程序,甚至已经成为一种语言。博主当然没能力复刻。

博主这里写了一个仿bash的shell程序。主要目的是仿制bash的命令行是如何执行命令的,但是bash的功能远超于此。相当于是博主在班门弄斧了。这里先带大家了解一下bash。

bash是linux系统下的默认shell程序。比如我们登录linux系统后,显示出来的命令行,其实就是bash程序的命令行模式
在这里插入图片描述
我们在命令行中写的指令,其实都是交给bash解析的。而且我们在命令行中启动的程序,其父进程都是bash。因此,我们打开linux系统所见的那个黑乎乎的命令行,其实就是bash,换句话说,我们在使用linux的时候,其实一直都在使用bash程序,只是我们对其不了解罢了。

myshell

博主将这个自己写的shell程序,命名为myshell,既然myshell要仿bash的命令行模式,首先我们要搞清楚bash的功能有什么。

首先是命令行,我们要先提示用户,当前我们处于命令行模式,请用户输入指令。因此,我们要先写出myshell的命令行提示符。为了和bash做出区分,因此命令行设计也要和bash不同才行。
在这里插入图片描述
其具体格式为[用户名@主机名 当前工作文件]:,而这些信息都在环境变量当中,因此需要用到getenv()函数获取这些数据。

//博主在文章末尾会附上完整代码,因此这里只展示部分,以提供思路参考

std::string getusr()//获取用户名
{
    std::string name=getenv("USER");
    return name.empty()?"None":name;
}

void  PrintCommandLine()//打印命令行提示符        
{                                                 
   char buf[BASE_SIZE]={0};                       
   snprintf(buf,BASE_SIZE,"[%s@%s %s]:"\          
            ,getusr().c_str(),gethost().c_str(),getcwd().c_str());//获取这些环境变量,并且将其输出到buf中
   fputs(buf,stdout);                             
   fflush(stdout);                               
}

接下来,命令行可以接收用户输入的命令,我们将其保存在一个字符数组当中。

int main()
{
    char commandbuf[BASE_SIZE];//保存用户命令
    EnvInit();//初始化环境变量
    while(true)
    {
     	//1. 命令行提示符
        PrintCommandLine();

        //2. 获取用户命令
        if(GetUsrCommand(commandbuf)==false)
        {
            continue;
        }

		//3. 解析用户命令
        ParseUsrCommand(commandbuf);

        //4. 执行用户命令
		ExecuteUsrCommand();
    }
    return 0;
}

第三步是解析用户命令行参数,比如ls -a -l --color,我们应该将每个单独的字符串(即空格隔开的字符串),按照顺序保存在一个字符型指针数组当中。
在这里插入图片描述
第四步是执行用户命令,在前面的进程章节中,博主提到,在命令行执行的程序,实际上都是bash创建的子进程,但是bash是如何创建的呢?其实原理很简单,bash使用fork函数,创建一个子进程,接着用execvpe函数,切换到用户想要启动的进程,比如bash执行ls指令,本质上就是bash先fork出一个子进程,接着execvpe("ls",gargv,environ)的方式创建的。具体的细节大家可以去看看博主前面写的,与进程相关的文章,实际上博主写这个myshell的本质是想让大家将进程系列的知识串联起来。

void ExecuteUsrCommand()//执行用户命令
{
    pid_t id=fork();//创建一个bash子进程
    if(id==0)
    {
        execvpe(gargv[0],gargv,env);//切换到用户的命令进程
        exit(1);
    }
    else if(id>0)
    {
        int status=0;
        waitpid(id,&status,0);//回收创建的子进程,避免产生僵尸进程                                                                                                                                        
        lastcode=WEXITSTATUS(status);                            
    }                                                            
}

但是有些命令,是不能通过创建子进程的方式执行的,比如cd指令,我使用这个指令是想让bash切换工作路径,而是让子进程切换路劲,因此如果解析出用户使用cd指令,我们应该让bash自己去执行,而非创建子进程执行,这种命令,我们称其为内建命令。bash的内建命令比较多,博主只写了其中几个。

bool CheckAndExecuteBulitCommand()//判断一下用户输入的是否是内建命令
{
    if(gargc==2&&strcmp(gargv[0],"cd")==0)//cd是内建命令
    {
     	if(chdir(gargv[1])==-1)//切换myshell的当前工作路径
        {
            printf("No such file of dirtory");
            lastcode=ERROR;
            return true;
        }
		lastcode=0;
        return true;

    }
    else if(strcmp(gargv[0],"export")==0)
    {
     	addenv(gargv[1]);
        return true;
    }
    else if(strcmp(gargv[0],"env")==0)//显示myshell当前的环境变量
    {
     	for(int i=0;env[i]!=nullptr;i++)
        {
            printf("env[%d]:%s\n",i,env[i]);
        }
	return true;
    }
    else if(gargc==2&&strcmp(gargv[0],"echo")==0)
    {
     	if(strcmp(gargv[1],"$?")==0)
        {
            printf("%d\n",lastcode);
        }
		else
		{
            printf("%s\n",gargv[1]);
        }
		lastcode=0;
		return true;
    }
    else if(strcmp(gargv[0],"exit")==0)
    {
     	printf("thank you for your using myshell\n");
        exit(0);
    }

    return false;
}


到此,一个简单的shell程序myshell就已经写好了,下面是实际使用的演示。

myshell

源码

点击下面链接获取源码与程序
简单的仿bash的shell程序

或:

#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/wait.h>


#define BASE_SIZE 256
//命令行参数与环境变量
char *gargv[BASE_SIZE];
int gargc;
char* env[BASE_SIZE];
extern char** environ;
//最近一次进程的运行结果
int lastcode=0;
#define ERROR 1

//当前文件路径
char cwd[BASE_SIZE];
char cwdenv[BASE_SIZE];
void EnvInit()
{
    int index=0;
    while(environ[index]!=nullptr)
    {
     	env[index]=(char*)malloc(strlen(environ[index])+1);
        strcpy(env[index],environ[index]);
        index++;
    }
    env[index]=nullptr;
}

void addenv(char* item)//增加环境变量
{
    int index=0;
    while(env[index]!=nullptr)
    {
     	index++;
    }
    env[index]=(char*)malloc(strlen(item)+1);
    strcpy(env[index],item);
    env[index+1]=nullptr;
}

std::string getusr()//获取用户名
{
    std::string name=getenv("USER");
    return name.empty()?"None":name;
}

std::string gethost()//获取主机名
{
    std::string hostname=getenv("HOSTNAME");
    return hostname.empty()?"None":hostname;
}

std::string getcwd()//获取当前工作文件
{
   if( getcwd(cwd,BASE_SIZE)==nullptr)
   {
       strcpy(cwd,"Node");
   }
   snprintf(cwdenv,BASE_SIZE,"PWD=%s",cwd);
   putenv(cwdenv);
    return cwd;
}
void  PrintCommandLine()//打印命令行提示符
{
   char buf[BASE_SIZE]={0};
   snprintf(buf,BASE_SIZE,"[%s@%s %s]:"\
           ,getusr().c_str(),gethost().c_str(),getcwd().c_str());//获取这些环境变量,并且将其输出到buf中
   fputs(buf,stdout);
   fflush(stdout);
}

bool GetUsrCommand(char commandbuf[])
{
    if(fgets(commandbuf,BASE_SIZE,stdin)==nullptr)
    {
     	return false;
    }
    commandbuf[strlen(commandbuf)-1]='\0';
    return true;

}

void ParseUsrCommand(char* commandbuf)
{
    memset(gargv,0,BASE_SIZE*sizeof(commandbuf[0]));
    gargc=0;
    gargv[gargc++]=strtok(commandbuf," ");
    while(bool(gargv[gargc]=strtok(nullptr," ")))
    {
     	gargc++;
    }
}

bool CheckAndExecuteBulitCommand()//判断一下用户输入的是否是内建命令
{
    if(gargc==2&&strcmp(gargv[0],"cd")==0)//cd是内建命令
    {
     	if(chdir(gargv[1])==-1)//切换myshell的当前工作路径
        {
            printf("No such file of dirtory");
            lastcode=ERROR;
            return true;
        }
		lastcode=0;
        return true;

    }
    else if(strcmp(gargv[0],"export")==0)
    {
     	addenv(gargv[1]);
        return true;
    }
    else if(strcmp(gargv[0],"env")==0)//显示myshell当前的环境变量
    {
     	for(int i=0;env[i]!=nullptr;i++)
        {
            printf("env[%d]:%s\n",i,env[i]);
        }
		return true;
    }
    else if(gargc==2&&strcmp(gargv[0],"echo")==0)
    {
     	if(strcmp(gargv[1],"$?")==0)
        {
            printf("%d\n",lastcode);
        }
		else
		{
            printf("%s\n",gargv[1]);
    	}
		lastcode=0;
        return true;
    }
    else if(strcmp(gargv[0],"exit")==0)
    {
     	printf("thank you for your using myshell\n");
        exit(0);
    }

    return false;
}

void ExecuteUsrCommand()//执行用户命令
{
    pid_t id=fork();//创建一个bash子进程
    if(id==0)
    {
     	execvpe(gargv[0],gargv,env);//切换到用户的命令进程
        exit(1);
    }
    else if(id>0)
    {
     	int status=0;
        waitpid(id,&status,0);//回收创建的子进程,避免产生僵尸进程
        lastcode=WEXITSTATUS(status);
    }
}

void debug()
{
    int i=0;
    while(gargv[i])
    {
     	printf("%s\n",gargv[i]);
        i++;
    }
    printf("%d\n",gargc);
}

int main()
{
    char commandbuf[BASE_SIZE];
    EnvInit();//初始化环境变量
    while(true)
    {
     	//1. 命令行提示符
        PrintCommandLine();

        //2. 获取用户命令
        if(GetUsrCommand(commandbuf)==false)
        {
            continue;
        }

		//3. 解析用户命令
    	ParseUsrCommand(commandbuf);

    	//4. 执行用户命令
   	 	if(CheckAndExecuteBulitCommand())//判断一下用户输入的是否是内建命令
    	{
        	continue;
    	}
		ExecuteUsrCommand();
    }
    return 0;
}



举报

相关推荐

0 条评论