• 自制操作系统日志——第二十七天


    自制操作系统日志——第二十七天

    今天主要的内容是LDT与库的制作。加油加油😊



    一、应用程序运行时,可以关闭命令行窗口

    我们接下来进行修改bootpack.c程序。我们需要修改两个地方,第一个就是当我们按下X按钮后,就先隐藏起命令行的窗口,之所以这样子做是因为由于关闭的一整个命令行窗口的步骤比较多,因此还需要花费一点时间去处理,这样子可能会让用户觉得有点久,所以如果我们直接隐藏起来,这样子就可以让用户觉得我们已经关闭成功了!!

    				if(i == 256 + 0x3b && key_shift != 0 && key_win != 0){//shift + F1强制关闭
    				    task = key_win->task; //获取当前处于的图层
    					if(task != 0 && task->tss.ss0 != 0)
    					{
    					    cons_putstr0(task->cons, "\nBreak(key):\n");
    					    io_cli();//不能再改变寄存器的值时候进行切换
    						task->tss.eax = (int) &(task->tss.esp0);
    						task->tss.eip = (int) asm_end_app;
    						io_sti();
    						task_run(task, -1, 0);//为了确实执行结束处理,需要把处于休眠状态的这个任务唤醒
    					}
    				}else if (2024 <= i && i <= 2279){
    				sht2 = shtctl->sheets0 + (i -2024);
    				memman_free_4k(memman, (int) sht2->buf, 256 * 165);
    				sheet_free(sht2);
    			}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后,我们还要修改console.c这个程序,以便对接收fifo缓冲区发来的数据进行进一步的处理:
    在这个 console_task函数里,主要我们就是将sheet换成cons.sheet。对于平常情况下两者没有太大差别,但是当我们的命令行窗口关闭后cons.sht会被置为0,而sheet则不变!

    然后,还要修改键盘里的API:
    等待键盘输入的过程中,如果FIFO缓冲区接收到4,则表示关闭命令行窗口的信号,此时取消定时器,并发出清理图层的信息,然后将sht->cons置为0!

    主要思路就是,我们利用命令行打开了一个程序后,此时我们对于该命令行的键盘输入都会由该程序进行接收,因此,当该程序接收到鼠标点击的关闭按钮后,系统就会像程序的fifo缓冲区发送4,然后调用API 15 进行接收处理,然后再向主函数发送对应的关闭命令行的fifo缓冲数据。

    int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
    {struct FIFO32 *sys_fifo = (struct FIFO32 *) *((int *) 0xfec);else if (edx == 15){
    		for(;;){if(i == 4){//只关闭命令行窗口
    				timer_cancel(cons->timer);
    				io_cli();
    				fifo32_put(sys_fifo, cons->sht - shtctl->sheets0 + 20240);
    				cons->sht = 0;
    				io_sti();
    			}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    运行,看看:
    在这里插入图片描述

    二、应用程序的保护

    我们前面已经做了一个操作系统的保护功能了,那么试想一下,如果我们呢利用应用程序访问应用程序段,并向里面写入奇怪的数据的话是不是也会发生异常?(毕竟我们制作了不能越权访问操作系统段的程序而已)
    我们制作下面这个程序:

    [FORMAT "WCOFF"]
    [INSTRSET "i486p"]
    [BITS 32]
    [FILE "crack7.nas"]
    
    		GLOBAL	_HariMain
    
    [SECTION .text]
    
    _HariMain:
    		MOV		AX,1005*8
    		MOV		DS,AX
    		CMP		DWORD [DS:0x0004],'Hari'
    		JNE		fin					; 不是应用程序,因此不执行任何操作
    
    		MOV		ECX,[DS:0x0000]		; 读取该应用程序的段
    		MOV		AX,2005*8
    		MOV		DS,AX
    
    crackloop:							; 填入数据
    		ADD		ECX,-1
    		MOV		BYTE [DS:ECX],123
    		CMP		ECX,0
    		JNE		crackloop
    
    fin:								; 结束
    		MOV		EDX,4
    		INT		0x40
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    然后,我们打开系统,先运行一个程序,然后再运行我们的破坏程序,最后移动一下鼠标就会出现下图:

    在这里插入图片描述
    以下呢,让我们进行分析一下:
    首先呢,我们所分配的段是按顺序进行分配的,也就是说:

    • 1003 : task_a
    • 1004 : idel 哨兵任务
    • 1005: 第一个应用程序的应用程序代码段(也就是图中的color2)
    • 1006: 第二个应用程序的代码段(也就是我们的破坏程序)

    当然数据也是类似的,从2003 ~ 2006号段这样子。 因此,我们的破坏程序,一开始就先越权读取了color2的代码段,检查是否是程序(即有无hari)。然后检测到以后,就设置将随意的数据写入到color2的数据段里也就是2005中,以此我们就可以进行覆盖了原来的数据内容了。这样子当然就可以搞破坏了!

    那么我们想要解决的思路起始就很简单,只要将我们运行的应用程序段进行隔离,不允许其他应用程序越权访问即可。 好在cpu已经为我们提供了一个较好的解决方案,即LDT ( 局部段管理表)。与GDT不同的是,GDT是全局的,其设置的段是所有任务通用的;但是LDT所设置的段只对某个程序有用而已。因此,我们将某个应用程序段设置再LDT中,其他任务就无法使用该LDT段了。

    LDT的内存地址是通过我们再GDT中设置的LDT段来告知cpu的。那么以下我们先进行设置LDT的段属性编号:
    bootpack.h:

    /* dsctbl.c */
    #define AR_LDT			0x0082
    
    /* mtask.c */
    struct TASK
    {
    	int sel, flags; //sel用于存放GDT编号
    	int level, priority; //设置优先级
    	struct FIFO32 fifo;
    	struct TSS32 tss;
    	struct SEGMENT_DESCRIPTOR ldt[2];
    	struct CONSOLE *cons;
    	int ds_base, cons_stack;//数据段地址;栈的地址
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    接下来,我们修改mtask.c来设置LDT。我们只需将LDT编号写入tss.ldtr,这样子创建TSS的过程中就会自动再GDT中设置对应的ldt了。

    struct TASK *task_init(struct MEMMAN *memman)
    {for(i = 0; i < MAX_TASKS; i++)
        {
            taskctl->tasks0[i].flags = 0;
            taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;
            taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8;
            set_segmdesc(gdt + TASK_GDT0  i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);
            set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS +i, 15, (int) taskctl->tasks0[i].ldt, AR_LDT);
        }}
     struct TASK *task_alloc(void)
    {
    略
    			task->tss.fs = 0;
    			task->tss.gs = 0;
    			task->tss.iomap = 0x40000000; //删掉原来的ldtr = 0
           task->tss.ss0 = 0 ;
           return task;//找到就返回一个!}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    接下来,还需要修改一下console.c函数:

    
    int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
    {set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);
    		    set_segmdesc(task->ldt + 1,      segsiz - 1, (int) q, AR_DATA32_RW + 0x60);start_app(0x1b,0 * 8 +4, esp, 1 * 8 + 4, &(task->tss.esp0));}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    首先,在start这里我们+4是为了告诉cpu我们这里不是GDT中段号,而是使用的LDT的段号。其次,由于每个任务的LDT都不一样因此这里不用担心会出现多个程序共用一段内存的情况!

    接着,我们make run:
    在这里插入图片描述

    看吧,这里直接就出现异常了!!因为此时的1005不再是应用程序的段了,使用操作系统默认该段是操作系统内的段,因此出现了访问异常的。

    那么,如果我们将段改成我们设置的4 和 12的话会发生什么? 不用想这肯定是自己破坏自己,因为应用程序的ldr仅有自己而已:
    在这里插入图片描述
    在这里插入图片描述
    看,确实没啥影响了吧!

    下面我们进行优化程序大小

    在前面我们制作的任何程序,都是直接与a_nask进行相连的,但是我们可能程序并不会全部用到这里面所有存储的api,这就会使得整个程序异常的臃肿,于是乎我们接下来打算将所有api都单独进行存储拆分:
    在这里插入图片描述
    即,一个API单独成一个函数!! 然后由于bim2hrb这个连接器有着筛选功能(也就是说其连接的所有.OBJ文件里如果本应用程序并没有使用到该OBJ文件里的任一函数就会直接丢弃,不进行连接) ,因此我们就可以利用这个极大的简化了我们程序的大小。(makeflie文件里的内容就自行查看了,这里难度不大,就是普通的连接而已)
    在这里插入图片描述

    现在让我们看看未简化前的程序大小:
    在这里插入图片描述

    在这里插入图片描述

    看到了吧,差距还挺明显的!

    这里为了以后方便进行统一的管理以及调用,我们这里将使用库 .lib 的文件将这些.obj文件进行打包成一个文件进行统一的管理。:
    makeflie:

    GOLIB    = $(TOOLPATH)golib00.exe 
    
    apilib.lib : Makefile $(OBJS_API)
    	$(GOLIB) $(OBJS_API) out:apilib.lib
    
    • 1
    • 2
    • 3
    • 4

    然后,我们就可以吧这些api全部放入库函数中!!程序连接时只需与库函数进行连接即可:
    在这里插入图片描述

    除此,之外为了方便调用函数,我们还制作了一个头文件:
    apilin.h:

    void api_putchar(int c);
    void api_putstr0(char *s);
    void api_putstr1(char *s, int l);
    void api_end(void);
    int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
    void api_putstrwin(int win, int x, int y, int col, int len, char *str);
    void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);
    void api_initmalloc(void);
    char *api_malloc(int size);
    void api_free(char *addr, int size);
    void api_point(int win, int x, int y, int col);
    void api_refreshwin(int win, int x0, int y0, int x1, int y1);
    void api_linewin(int win, int x0, int y0, int x1, int y1, int col);
    void api_closewin(int win);
    int api_getkey(int mode);
    int api_alloctimer(void);
    void api_inittimer(int timer, int data);
    void api_settimer(int timer, int time);
    void api_freetimer(int timer);
    void api_beep(int tone);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    这样子,我们的应用程序只需写一个include就足以了:
    在这里插入图片描述后续的make整理就参考源文件吧,以及书本上的没啥好说的。

    唯一要注意的是,这里我们将操作系统的内核和程序的makfile分开了,因此以后就不用每新增一个应用程序就重新生成以便了。其中app_make.txt 就是控制应用程序的生成的。

    最后,我们做完后直接在day27的文件夹下,打开运行的窗口,然后先src_only_full 全部清理一下后,在run_full 全部重新生成一下就好了。那么下面看看我们制作的程序的小全家福吧:
    在这里插入图片描述


    总结

    以上呢,就是今天关于LDT和库的所有内容,明天将进行很难的文字显示部分的内容啊,搞完明天我们的任务也就差不多完成了!!!!

  • 相关阅读:
    【Java】泛型通配符
    基于SpringBoot使用MyBatisX插件
    【C++】继承
    Python实现SSA智能麻雀搜索算法优化LightGBM回归模型(LGBMRegressor算法)项目实战
    嵌入式开发:清理可重用软件的API
    elasticsearch完整学习
    安装 Windows Server 2019 VM虚拟机
    7.2配置系统与ASP.NET Core集成
    nginx服务器
    角度回归(复数与欧拉公式,L1,L2)
  • 原文地址:https://blog.csdn.net/qq_43696276/article/details/126274388