【技巧沙龙】AI开辟者拭魅战营-7分钟打造1个定制技能。7月22号,我们等你一路!
为了保护体系内核不受恶意法度榜样的破坏,我们本来的做法是专门为应用法度榜样分派零丁应用的内存,使得应用法度榜样对数据的读写都限制在内核给他分派的内存段内。法度榜样对内存段的读写,美满是由DS存放器指向的全局描述符决定的,如不雅恶意法度榜样经由过程修改DS存放器的值,使得它在运行时,让DS存放器指向内核数据段的全局描述符,那么恶意法度榜样就可以读写内核的数据了,为了防备出现这种情况,我们要做的是让应用法度榜样没有读写段存放器的权力,是以我们就必须设定应有法度榜样的优先级。
在X86架构下,法度榜样可以分为4个等级,分别是0,1,2,3.级别数越低,它的权限就越高,体系内核是权限最高的,是以它运行的优先级为0,为了防止应用法度榜样作乱,我们在启动它之前,必须把它的优先级设定为最初级,也就是3.
为了让应用法度榜样运行在低特权级上,内核在启动应用法度榜样前,必须把应用法度榜样代码地点的内存段的级别设置为3,在一个级别为3的代码段上运行指令时,如不雅指令的优先级高于3,例如读写段存放器等,那么就会触发CPU缺点,根据上篇文┞仿讲过的内核异常处理机制,内核就会把应用法度榜样的杀掉落。于是我们修改内核启动应用法度榜样的相干代码,在write_vga_desktop.c中:
void cmd_hlt() {file_loadfile("abc.exe", &buffer); struct SEGMENT_DESCRIPTOR *gdt =(struct SEGMENT_DESCRIPTOR *)get_addr_gdt(); set_segmdesc(gdt+11, 0xfffff, buffer.pBuffer, 0x409a + 0x60); //new memory char *q = memman_alloc_4k(memman, 64*1024); set_segmdesc(gdt+12, 64 * 1024 - 1, q ,0x4092 + 0x60); struct TASK *task = task_now(); start_app(0, 11*8,64*1024, 12*8, &(task->tss.esp0)); memman_free_4k(memman, buffer.pBuffer, buffer.length); memman_free_4k(memman, q, 64 * 1024);}膳绫擎代码跟以前比拟,差别在于set_segmdesc调用中,设置内存段属性时,我们多加了0x60,加上0x60的目标是,把该描述符所指向的内存其优先级设置为3.如许一来,应用法度榜样一旦指向高优先级的CPU指令,例如move ds, ax这种读写段存放器的指令时,就会激发CPU异常。
同时我们经由过程调用task_now()获合适前正在运行的过程对象,每个过程对象都含有一个TSS数据构造,其内容如下(在multi_task.h中):
struct TSS32 { int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3; int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi; int es, cs, ss, ds, fs, gs; int ldtr, iomap;};TSS构造我们在早前讲到过程切换的┞仿节里有过对它的具体解读,这里我们须要留意它的几个变量:esp0, ss0, esp1, ss1, esp2, ss2。一个过程在运行时,它可以运行在不合优先级下,在不合优先级下运行时,它必须应用不合的客栈,这些变量就是用于存储不合优先级下对应的客栈段和客栈指针的。如不雅过程要切换到优先级0,那么CPU会主动大年夜esp0和ss0中攫取客栈指针和客栈内存段的全局描述符,如不雅过程要大年夜优先级0切换到优先级1,那么我们内核须要本身把对应优先级0的客栈指针和客栈段描述符的值存入到esp0和ss0。也就是说如不雅过程大年夜低优先级切换到高优先级时,CPU会主动帮我们大年夜TSS中攫取对应的客栈段全局描述符和客栈指针,实现响应的客栈切换。如不雅过程大年夜高优先级切换到低优先级时,须要过程本身把高优先级的客栈段描述符和客栈指针存储到TSS中的响应地位。
这也是为何我们调用start_app时,要把TSS对应的esp0变量的地址传入,因为start_app要启动一个优先级为3的应用法度榜样,一旦应用法度榜样运行起来时,过程的优先级会大年夜0变为3,是以我们须要把切换前的客栈指针和客栈段存储到TSS构造的esp0和ss0中。我们再看看start_app的实现:
start_app: ;void start_app(int eip, int cs,int esp, int ds, &(task->tss.esp0)) pushad mov eax, [esp+52] mov [eax], esp mov [eax+4], ss mov eax, [esp+36] ;eip mov ecx, [esp+40] ;cs mov edx, [esp+44] ;esp mov ebx, [esp+48] ;ds mov ds, bx mov es, bx or ecx,3 or ebx, 3 push ebx push edx push ecx push eax retf
esp+52对应的┞俘好是start_app的最后一个参数,也就是&(task->tss.esp0),也就是当前过程含有的TSS构造中,esp0变量的地址。我们把它的地址赋值给存放器eax, 指令mov [eax], esp 它的感化就是把当前客栈指针存入TSS构造里的esp0变量,指令mov [eax+4], ss, 它的感化是把当前客栈段描述符存储到TSS构造的ss0变量。
膳绫擎代铝闼楝有两条指令特别值得我们留意,他们是:
or ecx, 3or ebx, 3
00000001 -> 00001000
左移三位后会在右边空出3个0,这三个0是有专门感化的,前两个0用于表示对应内存段的优先级,也叫请求优先级,当内核要运行应用法度榜样的代码时,我们须要把应用法度榜样代码段赋值给存放器cs,把应用法度榜样的内存段赋值给ds,如不雅要把优先级大年夜0切换成3时,我们须要把请求优先级也设置为3,这就是前面两条指令的感化:
or ecx, 3or ebx, 3
ecx存放器存储的是应用法度榜样的代码段,ebx存放器存储的是应有法度榜样的内存段。我们以前讲过,在把全局描述符赋值给段存放器时,须要把该描述符对应在全局描述符表中的下标乘以8后再传给段存放器,为何要乘以8呢?假设某个全局描述符它的下标是1,乘以8相当于左移三位:
膳绫擎两条指令运行后,最右边的两个0都邑变成1,也就是把请求优先级设置成了3。还值得留意的是,以前我们把CPU控制器交给应用法度榜样时,应用的指令是call far,但如不雅跳转时带有优先级切换,那么CPU就不许可应用call far 或者是jmp far 这两种指令,我也不知道英特尔为何这么设计,要实现大年夜优先级0跳转到优先级3,必须先把优先级3对应的客栈和客栈指针压入当前客栈,然后把优先级3的代码段描述符和IP指针压入客栈,然后再履行retf敕令,这几个步调对应的┞俘好是最后几条指令:
推荐阅读
【技巧沙龙】AI开辟者拭魅战营-7分钟打造1个定制技能。7月22号,我们等你一路!无论是生活在一线都会,照样栖身在偏远山村,今天中国的绝大年夜多半处所,互联网都已经如同水与电一样,渗入渗出进人们的>>>详细阅读
地址:http://www.17bianji.com/lsqh/36255.html
1/2 1

网友点评
精彩导读
科技快报
品牌展示