当前位置: 首页 > java >正文

Day21 保护操作系统

文章目录

      • 1. 保护操作系统1(harib18c)
      • 2. 保护操作系统2(harib18d)
      • 3. 对异常的支持(harib18e)
      • 4. 保护操作系统4(harib18g)

1. 保护操作系统1(harib18c)

先假设我们可以使用C语言编写应用程序,然后做了一个这样的应用程序,直接往0x00102600地址写0。这就是一个很强的破坏操作系统的应用软件,所以需要对操作系统加保护,即防止应用软件访问由操作系统管理的内存空间。

void HariMain(void)
{*((char *) 0x00102600) = 0;return;
}

2. 保护操作系统2(harib18d)

为应用程序提供专用的内存空间,并告诉应用程序“此处以外不可访问”。因此需要创建应用程序专用数据段,并在应用程序运行期间,将DS(数据段寄存器)和SS(栈段寄存器)指向该段地址。
在这里插入图片描述

// console.c 文件
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{/* 省略 */char *p, *q;/* 省略 */if (finfo != 0) {/* 找到该文件 */p = (char *) memman_alloc_4k(memman, finfo->size);q = (char *) memman_alloc_4k(memman, 64 * 1024);	// 应用程序专用64K空间*((int *) 0xfe8) = (int) p;file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);set_segmdesc(gdt + 1004, 64 * 1024 - 1,   (int) q, AR_DATA32_RW);	// 应用程序专用64K空间if (finfo->size >= 8 && strncmp(p + 4, "Hari", 4) == 0) {// 修改应用程序可执行文件的前6字节p[0] = 0xe8;p[1] = 0x16;p[2] = 0x00;p[3] = 0x00;p[4] = 0x00;p[5] = 0xcb;}start_app(0, 1003 * 8, 64 * 1024, 1004 * 8);	// 之前只是调用了far-CALLmemman_free_4k(memman, (int) p, finfo->size);memman_free_4k(memman, (int) q, 64 * 1024);cons_newline(cons);return 1;
}
# naskfunc.nas 文件
_start_app:		# void start_app(int eip, int cs, int esp, int ds);PUSHAD		# 将32位寄存器的值全部保存(共8个),所以取函数传参需要ESP多加32MOV		EAX,[ESP+36]	# 应用程序用EIPMOV		ECX,[ESP+40]	# 应用程序用CSMOV		EDX,[ESP+44]	# 应用程序用ESPMOV		EBX,[ESP+48]	# 应用程序用DS/SSMOV		[0xfe4],ESP		# 操作系统用ESPCLI			# 在切换过程到应用程序中禁止中断请求MOV		ES,BX	# 把ES,SS,DS,FS,GS都赋值为应用程序的DS/SSMOV		SS,BXMOV		DS,BXMOV		FS,BXMOV		GS,BXMOV		ESP,EDX		# 将应用函数栈顶赋值给ESPSTI			# 切换完恢复中断请求PUSH	ECX				# 用于far-CALL的PUSH(cs)PUSH	EAX				# 用于far-CALL的PUSH(eip)CALL	FAR [ESP]		# 调用应用程序,跳到[cs:eip]位置,应用程序的代码段# 应用程序结束后返回此处MOV		EAX,1*8			# 操作系统用DS/SSCLI			# 切换回操作系统用DS/SS,禁止中断请求MOV		ES,AXMOV		SS,AXMOV		DS,AXMOV		FS,AXMOV		GS,AXMOV		ESP,[0xfe4]STI			# 切换完恢复中断请求POPAD	# 恢复函数最初保存的寄存器值RET

PUSHAD之后的栈空间:
高地址
±----------+
| 参数 ds | ← ESP + 16 (调用前)
±----------+
| 参数 esp | ← ESP + 12
±----------+
| 参数 cs | ← ESP + 8
±----------+
| 参数 eip | ← ESP + 4
±----------+
| 返回地址 | ← ESP (调用前) ← call 指令压入
±----------+
| 旧 EAX | ← ESP - 4 ← PUSHAD 压入
±----------+
| 旧 ECX | ← ESP - 8
±----------+
| 旧 EDX | ← ESP - 12
±----------+
| 旧 EBX | ← ESP - 16
±----------+
| 旧 ESP (快照) | ← ESP - 20
±----------+
| 旧 EBP | ← ESP - 24
±----------+
| 旧 ESI | ← ESP - 28
±----------+
| 旧 EDI | ← ESP - 32 ← 当前 ESP 位置
±----------+
低地址

hrb_api函数是C语言编写的操作系统内部函数,因此如果不将段地址设回操作系统用的段就无法正常工作,于是修改_asm_hrb_api

# naskfunc.nas 文件
# 中断40时,会调用到 asm_hrb_api
_asm_hrb_api:PUSH	DSPUSH	ESPUSHADMOV		EAX,1*8MOV		DS,AX			# 先仅将DS设定位操作系统用MOV		ECX,[0xfe4]		# 操作系统的ESPADD		ECX,-40MOV		[ECX+32],ESP	# 保存应用程序的ESPMOV		[ECX+36],SS		# 保存应用程序的SS# 将PUSHAD的值复制到系统栈MOV		EDX,[ESP   ]MOV		EBX,[ESP+ 4]MOV		[ECX   ],EDX	# 复制传递给hrb_apiMOV		[ECX+ 4],EBX	# 复制传递给hrb_apiMOV		EDX,[ESP+ 8]MOV		EBX,[ESP+12]MOV		[ECX+ 8],EDX	# 复制传递给hrb_apiMOV		[ECX+12],EBX	# 复制传递给hrb_apiMOV		EDX,[ESP+16]MOV		EBX,[ESP+20]MOV		[ECX+16],EDX	# 复制传递给hrb_apiMOV		[ECX+20],EBX	# 复制传递给hrb_apiMOV		EDX,[ESP+24]MOV		EBX,[ESP+28]MOV		[ECX+24],EDX	# 复制传递给hrb_apiMOV		[ECX+28],EBX	# 复制传递给hrb_apiMOV		ES,AX			# 将剩余的段寄存器也设为操作系统用MOV		SS,AXMOV		ESP,ECXSTI			# 恢复中断请求CALL	_hrb_api	# 调用hrb_apiMOV		ECX,[ESP+32]	# 取出应用程序的ESPMOV		EAX,[ESP+36]	# 取出应用程序的SSCLIMOV		SS,AXMOV		ESP,ECXPOPADPOP		ESPOP		DSIRETD		# 自动执行STI,恢复中断请求

类似的需要修改每一个中断的汇编函数(_asm_inthandler20,_asm_inthandler21等),因为中断产生后会调用_inthandler20等操作系统内部的C语言函数,因此也需要对DS和SS进程切换。
其实CPU本身就具有自动进行复杂段切换的功能,最终并不会像本节这样对中断产生时调用到的函数做手动的DS/SS切换。

3. 对异常的支持(harib18e)

在x86架构规范中,当应用程序试图破坏操作系统,或者试图违背操作系统的设置时,就会产生0x0d中断,因此该中断也被称为“异常”。

# naskfunc.nas 文件
_asm_inthandler0d:STIPUSH	ESPUSH	DSPUSHADMOV		AX,SSCMP		AX,1*8JNE		.from_app
# 当操作系统活动时,产生中断的情况和之前类似MOV		EAX,ESPPUSH	SS				# 保存中断时的SSPUSH	EAX				# 保存中断时的ESPMOV		AX,SSMOV		DS,AXMOV		ES,AXCALL	_inthandler0dADD		ESP,8POPADPOP		DSPOP		ESADD		ESP,4			# INT 0x0d 中需要使用的IRETD
.from_app:
# 当应用程序活动时产生中断CLIMOV		EAX,1*8MOV		DS,AX			# 先仅将DS设定为操作系统用MOV		ECX,[0xfe4]		# 操作系统的ESPADD		ECX,-8MOV		[ECX+4],SS		# 保存产生中断时的SSMOV		[ECX  ],ESP		# 保存产生中断时的ESPMOV		SS,AXMOV		ES,AXMOV		ESP,ECXSTICALL	_inthandler0dCLICMP		EAX,0JNE		.killPOP		ECXPOP		EAXMOV		SS,AX			# 将SS恢复为应用程序用MOV		ESP,ECX			# 将ESP恢复为应用程序用POPADPOP		DSPOP		ESADD		ESP,4			# INT 0x0d 需要使用IRETD
.kill:
# 将应用程序强制结束MOV		EAX,1*8			# 操作系统用的DS/SSMOV		ES,AXMOV		SS,AXMOV		DS,AXMOV		FS,AXMOV		GS,AXMOV		ESP,[0xfe4]		# 强制返回到start_app时的ESPSTI			# 切换完成后恢复中断请求POPAD		# 恢复事先保存的寄存器值RET
// console.c 文件
int inthandler0d(int *esp)
{struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n");	// 一般保护异常return 1; /* 强制结束程序 */
}

该函数类似于_asm_inthandler20,主要在于其添加了STI/CLI这样的控制中断请求禁止和恢复的指令,和根据inthandler0d的执行结果来强制结束应用程序的操作。0x0d对应的中断其实就是一般保护异常,还有一些特殊的异常是由0x0d以外的中断处理。

// dsctbl.c 文件
void init_gdtidt(void)
{/* IDT的设置 */set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32);
}

现在在命令行执行crack1应该会爆出“General Protected Exception.”错误。

4. 保护操作系统4(harib18g)

当前可以防止C语言应用程序恶意访问操作系统的段内存,但是还不能防止汇编程序直接直接向DS存入操作系统的段地址。如下:

# crack2.nas 文件
[INSTRSET "i486p"]
[BITS 32]MOV		EAX,1*8				# 操作系统用的段号MOV		DS,AX				# 将其存入DSMOV		BYTE [0x102600],0RETF

x86存在一个功能,在段定义的地方,如果将访问权限加上0x60,就可以将段设置为应用程序用。当CS的段地址为应用程序用段地址时,CPU会认为“当前正在运行应用程序”,这是如果存入操作系统用段地址的话,就会产生异常。

int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{char *p, *q;struct TASK *task = task_now();/* 省略 */set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);set_segmdesc(gdt + 1004, 64 * 1024 - 1,   (int) q, AR_DATA32_RW + 0x60);/* 省略 */start_app(0, 1003 * 8, 64 * 1024, 1004 * 8, &(task->tss.esp0));/* 省略 */
}

参考之前的方法,需要在start_app的函数定义中far-CALL应用程序的段,但是x86中禁止操作系统far-CALL或far-JMP应用程序。此时可以使用RETF,就像是被CALL过一样,先将地址PUSH到栈中,然后执行RETF,就可以成功启动应用程序了。

RETF的本质就是从栈中将地址POP出来,并JMP到该地址,因此可以用RETF代替far-JMP功能。

# naskfunc.nas 文件
_start_app:		; void start_app(int eip, int cs, int esp, int ds, int *tss_esp0);PUSHAD		# 将32位寄存器的值全部保存MOV		EAX,[ESP+36]	# 应用程序用EIPMOV		ECX,[ESP+40]	# 应用程序用CSMOV		EDX,[ESP+44]	# 应用程序用ESPMOV		EBX,[ESP+48]	# 应用程序用DS/SSMOV		EBP,[ESP+52]	# tss.esp0的地址MOV		[EBP  ],ESP		# 保存操作系统的ESPMOV		[EBP+4],SS		# 保存操作系统的SSMOV		ES,BXMOV		DS,BXMOV		FS,BXMOV		GS,BX
# 调整栈,以免用RETF跳转到应用程序OR		ECX,3			# ECX是应用程序段号OR		EBX,3			# EBX是应用程序段号PUSH	EBX				# 应用程序用的SSPUSH	EDX				# 应用程序用的ESPPUSH	ECX				# 应用程序用的CSPUSH	EAX				# 应用程序用的EIPRETF
# 应用程序结束后不会回到这里

由于并不是通过far-CALL调用应用程序,因此应用程序执行完成之后无法用RETF的方式结束并返回。

# naskfunc.nas 文件
_asm_hrb_api:STIPUSH	DSPUSH	ESPUSHAD		# 用于保存PUSHAD		# 向hrb_api传值MOV		AX,SSMOV		DS,AX		# 将操作系统段地址存入DS和ESMOV		ES,AXCALL	_hrb_apiCMP		EAX,0		# 当EAX不为0时调用end_app,结束程序JNE		end_appADD		ESP,32POPADPOP		ESPOP		DSIRETD
end_app:
#	EAX为tss.esp0的地址MOV		ESP,[EAX]POPADRET					# 返回cmd_app

当_hrb_api返回0时,继续运行程序;返回非0值时,则把返回值当作tss.esp0处理,JNE end_app强制结束应用程序。所以需要修改hrb_api函数,配置当EDX为4时结束程序。

// console.c 文件
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{struct TASK *task = task_now();/* 省略 */if (edx == 4) {return &(task->tss.esp0);}return 0;
}

同时修改异常中断0x0d:

// console.c 文件
int *inthandler0d(int *esp)
{struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);struct TASK *task = task_now();cons_putstr0(cons, "\nINT 0D :\n General Protected Exception.\n");return &(task->tss.esp0);	/* 让程序强制结束 */
}

由于把麻烦的栈切换全部由CPU处理了,因此_asm_inthandler20,_asm_inthandler21,_asm_inthandler2c等系列的函数也都需要恢复原来的样子。但是处理异常中断的_asm_inthandler0d恢复为原来的样子之外还需要关注EAX的值(类似_asm_hrb_api中当EAX不等于0的时候需要调用end_app)。
配置asm_hrb_api作为0x40中断时也需要声明“其可用于应用程序作为API来调用”。

// dsctbl.c 文件
void init_gdtidt(void)
{/* 省略 */set_gatedesc(idt + 0x40, (int) asm_hrb_api,      2 * 8, AR_INTGATE32 + 0x60);/* 省略 */
}

在应用程序中(hello.nas, hello2.nas, crack2.nas)则需要在结束时添加程序退出:

MOV EDX, 4
INT 0x40

对于c语言写的应用程序(a.c, crack1.c, hello3.c),则需要在最后调用定义在a_nask.nas文件中的汇编代码函数api_end

# a_nask.nas 文件
_api_end:	# void api_end(void);MOV		EDX,4INT		0x40
http://www.xdnf.cn/news/20466.html

相关文章:

  • 【01背包问题变体】P1282 多米诺骨牌
  • MySQL集群高可用架构之组复制 (MGR)
  • 校园洒水车cad+三维图+设计说书
  • 金属也有“记忆力”?—聊聊二合一玛哈特矫平机如何“消除”金属的记忆
  • 修复存在坏块或05、C4、C5 S.M.A.R.T错误的硬盘
  • Spring Cloud Alibaba快速入门02-Nacos
  • FRCNet
  • Fab资源快速导入UE
  • Shell 脚本实现系统监控与告警
  • Spring Boot中MyBatis的定义与使用
  • IOC为什么交由spring容器管理?
  • 操作系统研发工作心得体会 - 于复杂性中构建秩序
  • 每日一题(2)
  • MySQL学习记录-索引
  • 携程社招前端面经
  • pthread_detach函数
  • 2025最新超详细FreeRTOS入门教程:第二章 FreeRTOS任务创建
  • 设计一个 AB 测试平台
  • 实例和对象的区别
  • 【目录-单选】鸿蒙HarmonyOS开发者基础
  • 自适应滤波器:Ch4 最小均方(LMS)算法
  • [光学原理与应用-433]:晶体光学 - 晶体光学是研究光在单晶体中传播规律及其伴随现象的分支学科,聚焦于各向异性光学媒质的光学特性
  • 上海“我店”模式:消费增值新玩法及其隐忧
  • 论文阅读:VGGT Visual Geometry Grounded Transformer
  • 【C++】引用的本质与高效应用
  • 【高等数学】第十一章 曲线积分与曲面积分——第三节 格林公式及其应用
  • javascript 国际化方法
  • AI 生成式艺术重塑动漫角色创作:从技术逻辑到多元可能性(一)
  • GPT-5发布:统一智能体时代的开启——从“工具”到“协作者”的范式跃迁
  • 详解MySQL环境变量配置及其在备份中的应用