Day22 用C语言编译应用程序

文章目录

      • 1. 保护操作系统5(harib19a)
      • 2. 帮助发现bug(harib19b)
      • 3. 强制结束应用程序(harib19c)
      • 4. 用C语言显示字符串(harib19e)
      • 5. 显示窗口(harib19f)

1. 保护操作系统5(harib19a)

上一章节已经对“应用软件在系统内存上动手脚”这一case做了防护。不过定时器上还是存在安全漏洞的,接下来crack3的目的是使光标闪烁变慢,使任务切换的速度变慢。

# crack3.nas 文件
[INSTRSET "i486p"]
[BITS 32]MOV		AL,0x34OUT		0x43,ALMOV		AL,0xffOUT		0x40,ALMOV		AL,0xffOUT		0x40,AL# 	上述代码的功能与下列相当
#	io_out8(PIT_CTRL, 0x34);
#	io_out8(PIT_CNT0, 0xff);
#	io_out8(PIT_CNT0, 0xff);MOV		EDX,4INT		0x40

但这并不会针对性的影响到定时器,因为直接再应用程序中使用IN和OUT指令的话,会产生一般保护异常,然后就在屏幕上显示“General Protected Exception”。
简单粗暴的crack4,目的是直接禁止中断,那么就会不再产生定时器中断,任务切换也会停止,键盘鼠标中断也会停止。

# crack4.nas 文件
[INSTRSET "i486p"]
[BITS 32]CLI
fin:HLTJMP		fin

但其实,应用程序中也不能直接使用CLI, STI和HLT指令,这些也会产生一般保护异常。可以尝试CALL操作系统函数(_io_cli)的地址,通过查看map文件可以该函数地址。

# crack5.nas 文件
[INSTRSET "i486p"]
[BITS 32]CALL	2*8:0xac1MOV		EDX,4INT		0x40

但是还忽略了一点,应用程序的地址的CALL并不是任意的,只能CALL设置好的地址。所以crack5程序还是会产生一般保护异常。应用程序期望调用操作系统只能才做INT 0x40的方式。
临时修改hrb_api,使它可以处理一个临时的edx用于破坏操作系统,并在应用程序中INT 0x40,但是对定时器或键盘鼠标中断下手,确实并不简单。

// console.c 文件
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{int cs_base = *((int *) 0xfe8);struct TASK *task = task_now();struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);if (edx == 1) {cons_putchar(cons, eax & 0xff, 1);} else if (edx == 2) {cons_putstr0(cons, (char *) ebx + cs_base);} else if (edx == 3) {cons_putstr1(cons, (char *) ebx + cs_base, ecx);} else if (edx == 4) {return &(task->tss.esp0);} else if (edx == 123456789) {*((char *) 0x00102600) = 0;}return 0;
}
# crack6.nas 文件
[INSTRSET "i486p"]
[BITS 32]MOV		EDX,123456789INT		0x40MOV		EDX,4INT		0x40

2. 帮助发现bug(harib19b)

CPU的异常处理功能,除了可以保护操作系统免遭应用程序的破坏,还可以帮助在编写程序时及时发现bug,例如数组越界访问等。
当一个局部数组变量被越界访问时,就有可能产生栈异常。栈异常的中断号为0x0c。0x0c的中断函数类似0x0d,只是改一下异常时的信息打印就好。

# naskfunc.nas 文件
_asm_inthandler0c:STIPUSH	ESPUSH	DSPUSHADMOV		EAX,ESPPUSH	EAXMOV		AX,SSMOV		DS,AXMOV		ES,AXCALL	_inthandler0cCMP		EAX,0JNE		end_appPOP		EAXPOPADPOP		DSPOP		ESADD		ESP,4			# 类似 INT 0x0d IRETD
// console.c 文件
int *inthandler0c(int *esp)
{struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);struct TASK *task = task_now();char s[30];cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n");sprintf(s, "EIP = %08X\n", esp[11]);cons_putstr0(cons, s);return &(task->tss.esp0);	/* 强制结束程序 */
}
// dsctbl.c 文件
void init_gdtidt(void)
{set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);	// 注册给idt
}

在inthandler0c函数中,企图打印esp[11],即EIP,会将下一条将要被执行的指令在内存中的地址打印出来。因此inthandler0c的含义就是在发生异常时,把异常产生的指令地址打印出来。然后再根据.map文件和.lst文件就能定位到产生异常的具体位置。
在这里插入图片描述

3. 强制结束应用程序(harib19c)

如果一个应用程序中存在一个毫不间歇的死循环,那么系统整体的速度就会变慢。为了防止类似死循环这种程序,可以将某一个按键作为强制结束键,按一下就可以结束程序。
将强制结束任务写在bootpack.c文件的HariMain函数的键盘中断处理中:

// bootpack.c 文件
void HariMain(void)
{/* 省略 */i = fifo32_get(&fifo);io_sti();if (256 <= i && i <= 511){if (i == 256 + 0x3b && key_shift != 0 && task_cons->tss.ss0 != 0) {	/* Shift+F1 */cons = (struct CONSOLE *) *((int *) 0x0fec);cons_putstr0(cons, "\nBreak(key) :\n");io_cli();task_cons->tss.eax = (int) &(task_cons->tss.esp0);task_cons->tss.eip = (int) asm_end_app;io_sti();}}/* 省略 */
}
# naskfunc.nas 文件
# asm_end_app是end_app函数的修改
_asm_end_app:
#	EAX为tss.esp0的地址MOV		ESP,[EAX]MOV		DWORD [EAX+4],0POPADRET		# 返回cmd_app

当 按下强制结束键时,改写命令行窗口任务的寄存器值,并goto到asm_end_app函数,如此便可以强制结束程序。

// mtask.c 文件
struct TASK *task_alloc(void)
{/* 省略 */for (i = 0; i < MAX_TASKS; i++) {if (taskctl->tasks0[i].flags == 0) {task = &taskctl->tasks0[i];/* 省略 */task->tss.ss0 = 0;return task;}}return 0;
}

还需要确保task_cons->tss.ss0不为0时采取调用结束程序,为防止应用程序还未运行(task_cons->tss.ss0为0)进行调用。

4. 用C语言显示字符串(harib19e)

第一个供c语言调用的api:

# a_nask.nas 文件
_api_putstr0:	; void api_putstr0(char *s);PUSH	EBXMOV		EDX,2MOV		EBX,[ESP+8]		; sINT		0x40POP		EBXRET

但此时如果直接在c语言中调用api_putstr0函数,应该是无法在屏幕上显示参数s的。
调试api之前,先解释一下可执行程序.hrb文件的内容。可执行程序.hrb文件由两部分组成:代码部分和数据部分。其中,数据部分在位于代码部分的开头一块区域中。当应用程序启动时,数据部分被传送到应用程序使用的数据段中。
对于.hrb文件:
在这里插入图片描述
0x0000 存放的是应用程序启动后数据段的大小,当前固定大小为64KB。
0x0004 存放的是“Hari”这四个字符,读取文件的时候会先判断这四个字节,判断一致才会当作可执行程序处理。
0x0008 存放的是数据段预备空间的大小。暂时没有使用。
0x000c 存放的是应用程序启动时,ESP的初始值。也就是说,0x000c位置的内容表示栈指针,调用api_putstr0的时候所传入的参数s就会放在0x000c的内容所代表的内存地址处。例如,可执行程序hello4.hrb被执行时char *参数s的地址是0x0400,就是文件hello4.hrb的0x000c处写的0x0400。而这个值之前的部分会作为栈来使用,也就是1024字节(十六进制就是0x0400),这个值在编译的时候已经确定好了。

# Makefile 文件
hello4.bim : hello4.obj a_nask.obj Makefile$(OBJ2BIM) @$(RULEFILE) out:hello4.bim stack:1k map:hello4.map \hello4.obj a_nask.obj

0x0010和0x0014 的目的是当.hrb文件被加载时,告诉操作系统该可执行文件的数据大小和在文件中的位置。
0x0018 在内存中的放置应该是“00 00 00 E9”,其中E9是JMP指令的机器码,这就相当于在0x001b位置存放了一个JMP指令。
0x001c 的程序入口结合0x001b的JMP指令,就可以运行可执行文件了。(但是程序入口地址-0x20是为啥,不太清楚)
0x0020 存放对应用程序使用的malloc函数调用之后的返回地址。
根据以上内容需要修改console.c文件。

// console.c 文件
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
{/* 省略 */if (finfo != 0) {/* 找到文件 */p = (char *) memman_alloc_4k(memman, finfo->size);file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {segsiz = *((int *) (p + 0x0000));esp    = *((int *) (p + 0x000c));datsiz = *((int *) (p + 0x0010));	// 数据部分的大小dathrb = *((int *) (p + 0x0014));	// 数据部分在文件中的位置q = (char *) memman_alloc_4k(memman, segsiz);	// 根据hrb文件确定数据段大小*((int *) 0xfe8) = (int) q;set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60);set_segmdesc(gdt + 1004, segsiz - 1,      (int) q, AR_DATA32_RW + 0x60);for (i = 0; i < datsiz; i++) {// 执行程序前把数据部分拷贝到数据段q[esp + i] = p[dathrb + i];}start_app(0x1b, 1003 * 8, esp, 1004 * 8, &(task->tss.esp0));memman_free_4k(memman, (int) q, segsiz);} else {// 找不到Hari则报错cons_putstr0(cons, ".hrb file format error.\n");}memman_free_4k(memman, (int) p, finfo->size);cons_newline(cons);return 1;}/* 未找到文件 */return 0;
}

为啥将“Hari”字符放在文件的0x0004位置,而不是0x0000位置呢?
0x0000位置存放的是应用程序启动后数据段的大小,bim2hrb会自动将该内容调整为4KB的倍数,所以0x0000位置的字节必定是00。一个普通文件的0x0000位置却很小可能是00,但是却有可能是某个字母,所以将“Hari”字符放在文件的0x0004位置可以提高访问的安全性。

5. 显示窗口(harib19f)

现在期望实现一个用于显示窗口的api,暂时这样设计:
在这里插入图片描述
调用后返回值:
在这里插入图片描述
但是当前有个问题,如何将返回值传递给应用程序。中断服务函数会通过IRETD安全的返回应用程序,并且在返回之前会把8个32位寄存器POPAD出去,所以只能依赖POPAD和IRETD。
两次PUSHAD之后的栈是这样的:

[高地址]
EAX <— 1st
ECA
EDX
EBX
ESO
EBP
ESI
EDI
EAX <— 2nd, hrb_api使用到的就是这里及以下
ECA
EDX
EBX
ESO
EBP
ESI
EDI

// console.c 文件
int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{int ds_base = *((int *) 0xfe8);		// 来自于bootpack.c的HariMain函数中的shtctl变量struct TASK *task = task_now();struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);struct SHTCTL *shtctl = (struct SHTCTL *) *((int *) 0x0fe4);struct SHEET *sht;int *reg = &eax + 1;	/* 参照栈空间可知, &eax+1可以获取到系统EDI *//* reg[0] : EDI,   reg[1] : ESI,   reg[2] : EBP,   reg[3] : ESP *//* reg[4] : EBX,   reg[5] : EDX,   reg[6] : ECX,   reg[7] : EAX *//* 省略 */if (edx == 5) {sht = sheet_alloc(shtctl);sheet_setbuf(sht, (char *) ebx + ds_base, esi, edi, eax);make_window8((char *) ebx + ds_base, esi, edi, (char *) ecx + ds_base, 0);sheet_slide(sht, 100, 50);sheet_updown(sht, 3);	/* 背景层高度3,位于task_a之上 */reg[7] = (int) sht;	// 把sht赋值给EAX,_asm_hrb_api中POPAD的时候会弹出栈}return 0;
}

再写一个测试程序:

# a_nask.nas 文件
_api_openwin:	# int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);PUSH	EDIPUSH	ESIPUSH	EBXMOV		EDX,5MOV		EBX,[ESP+16]	# bufMOV		ESI,[ESP+20]	# xsizMOV		EDI,[ESP+24]	# ysizMOV		EAX,[ESP+28]	# col_invMOV		ECX,[ESP+32]	# titleINT		0x40	# 调用中断POP		EBXPOP		ESIPOP		EDIRET
// winhello.c 文件
int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);
void api_end(void);char buf[150 * 50];void HariMain(void)
{int win;win = api_openwin(buf, 150, 50, -1, "hello");api_end();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/96601.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/96601.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单学习HTML+CSS+JavaScript

一、HTML HTML被称为 超文本标记语言&#xff0c;是由一系列标签构成的语言。 下面介绍HTML中的标签&#xff1a; &#xff08;一&#xff09;HTML文件基本结构 <!DOCTYPE html><html><head><title>Document</title></head> <body&…

强化学习中重要性采样

PPO 中重要性采样 https://github.com/modelscope/ms-swift/blob/main/docs/source/Instruction/GRPO/GetStarted/GRPO.md乐&#xff0c;这个网页中是的groundtruth是错误的&#xff08;可能是为了防止抄袭&#xff09;。一些例子 0. 池塘养鱼的一个例子 想象一下&#xff0c;你…

《树与二叉树详解:概念、结构及应用》

目录 一. 树的概念和结构 1.1 树的基本概念 1.2 树的结构特点 二. 树的表示方法和实际运用 2.1 孩子 - 兄弟表示法&#xff08;Child-Sibling Representation&#xff09; 2.2 树的实际应用场景 三. 二叉树的概念 3.1 二叉树的核心定义 3.2 二叉树的基本分类 四. 二叉…

Qt/C++,windows多进程demo

1. 项目概述 最近研究了一下Qt/C框架下&#xff0c;windows版本的多进程编写方法&#xff0c;实现了一个小demo。下面详细介绍一下。 MultiProcessDemo是一个基于Qt框架实现的多进程应用程序示例&#xff0c;展示了如何在Windows平台上通过共享内存和事件机制实现进程间通信。该…

Android SystemServer 系列专题【篇五:UserController用户状态控制】

本篇接着SystemServer的启动流程&#xff0c;围绕SystemServer最后阶段关于主用户的启动和解锁的流程&#xff0c;作为切入点&#xff0c;来看看SystemServer是如何讲用户状态同步到所有的系统级服务中。ssm.onStartUserssm.onUnlockingUserssm.onUnlockedUser本篇先介绍UserCo…

推荐使用 pnpm 而不是 npm

npm 的局限性 磁盘空间浪费在 npm 早期版本中&#xff0c;每个项目的node_modules目录都会完整复制所有依赖包&#xff0c;即使多个项目依赖同一个包的相同版本&#xff0c;也会重复存储。这导致磁盘空间被大量占用&#xff0c;随着项目数量的增加&#xff0c;存储成本显著上升…

Transformer实战(18)——微调Transformer语言模型进行回归分析

Transformer实战&#xff08;18&#xff09;——微调Transformer语言模型进行回归分析0. 前言1. 回归模型2. 数据处理3. 模型构建与训练4. 模型推理小结系列链接0. 前言 在自然语言处理领域中&#xff0c;预训练 Transformer 模型不仅能胜任离散类别预测&#xff0c;也可用于连…

【Linux】【实战向】Linux 进程替换避坑指南:从理解 bash 阻塞等待,到亲手实现能执行 ls/cd 的 Shell

前言&#xff1a;欢迎各位光临本博客&#xff0c;这里小编带你直接手撕&#xff0c;文章并不复杂&#xff0c;愿诸君耐其心性&#xff0c;忘却杂尘&#xff0c;道有所长&#xff01;&#xff01;&#xff01;&#xff01; IF’Maxue&#xff1a;个人主页&#x1f525; 个人专栏…

linux常用命令 (3)——系统包管理

博客主页&#xff1a;christine-rr-CSDN博客 ​​​​​ ​​ hi&#xff0c;大家好&#xff0c;我是christine-rr ! 今天来分享一下linux常用命令——系统包管理 目录linux常用命令---系统包管理&#xff08;一&#xff09;Debian 系发行版&#xff08;Ubuntu、Debian、Linux …

YOLOv8 mac-intel芯片 部署指南

&#x1f680; 在 Jupyter Notebook 和 PyCharm 中使用 Conda 虚拟环境&#xff08;YOLOv8 部署指南&#xff0c;Python 3.9&#xff09; YOLOv8 是 Ultralytics 开源的最新目标检测模型&#xff0c;轻量高效&#xff0c;支持分类、检测、分割等多种任务。 在 Mac&#xff08;…

【高等数学】第十一章 曲线积分与曲面积分——第六节 高斯公式 通量与散度

上一节&#xff1a;【高等数学】第十一章 曲线积分与曲面积分——第五节 对坐标的曲面积分 总目录&#xff1a;【高等数学】 目录 文章目录1. 高斯公式2. 沿任意闭曲面的曲面积分为零的条件3. 通量与散度1. 高斯公式 设空间区域ΩΩΩ是由分片光滑的闭曲面ΣΣΣ所围成&#x…

IDEA试用过期,无法登录,重置方法

IDEA过期&#xff0c;重置方法: IntelliJ IDEA 2024.2.0.2 (亲测有效) 最新Idea重置办法!&#xff1a; 方法一&#xff1a; 1、删除C:\Users\{用户名}\AppData\Local\JetBrains\IntelliJIdea2024.2 下所有文件(注意&#xff1a;是子目录全部删除) 2、删除C:\Users\{用户名}\App…

创建用户自定义桥接网络并连接容器

1.创建用户自定义的 alpine-net 网络[roothost1 ~]# docker network create --driver bridge alpine-net 9f6d634e6bd7327163a9d83023e435da6d61bc6cf04c9d96001d1b64eefe4a712.列出 Docker 主机上的网络[roothost1 ~]# docker network ls NETWORK ID NAME DRIVER …

Vue3 + Vite + Element Plus web转为 Electron 应用,解决无法登录、隐藏自定义导航栏

如何在vue3 Vite Element Plus搭好的架构下转为 electron应用呢&#xff1f; https://www.electronjs.org/zh/docs/latest/官方文档 https://www.electronjs.org/zh/docs/latest/ 第一步&#xff1a;安装 electron相关依赖 npm install electron electron-builder concurr…

qt QAreaLegendMarker详解

1. 概述QAreaLegendMarker 是 Qt Charts 模块中的一部分&#xff0c;用于在图例&#xff08;Legend&#xff09;中表示 QAreaSeries 的标记。它负责显示区域图的图例项&#xff0c;通常包含区域颜色样例和对应的描述文字。图例标记和对应的区域图关联&#xff0c;显示区域的名称…

linux 函数 kstrtoul

kstrtoul 函数概述 kstrtoul 是 Linux 内核中的一个函数&#xff0c;用于将字符串转换为无符号长整型&#xff08;unsigned long&#xff09;。该函数定义在 <linux/kernel.h> 头文件中&#xff0c;常用于内核模块中解析用户空间传递的字符串参数。 函数原型 int kstrtou…

LLM(三)

一、人类反馈的强化学习&#xff08;RLHF&#xff09;微调的目标是通过指令&#xff0c;包括路径方法&#xff0c;进一步训练你的模型&#xff0c;使他们更好地理解人类的提示&#xff0c;并生成更像人类的回应。RLHF&#xff1a;使用人类反馈微调型语言模型&#xff0c;使用强…

DPO vs PPO,偏好优化的两条技术路径

1. 背景在大模型对齐&#xff08;alignment&#xff09;里&#xff0c;常见的两类方法是&#xff1a;PPO&#xff1a;强化学习经典算法&#xff0c;OpenAI 在 RLHF 里用它来“用奖励模型更新策略”。DPO&#xff1a;2023 年提出的新方法&#xff08;参考论文《Direct Preferenc…

BLE6.0信道探测,如何重构物联网设备的距离感知逻辑?

在物联网&#xff08;IoT&#xff09;无线通信技术快速渗透的当下&#xff0c;实现人与物、物与物之间对物理距离的感知响应能力已成为提升设备智能高度与人们交互体验的关键所在。当智能冰箱感知用户靠近而主动亮屏显示内部果蔬时、当门禁系统感知到授权人士靠近而主动开门时、…

【计算机 UTF-8 转换为本地编码的含义】

UTF-8 转换为本地编码的含义 详细解释一下"UTF-8转换为本地编码"的含义以及为什么在处理中文时这很重要。 基本概念 UTF-8 编码 国际标准&#xff1a;UTF-8 是一种能够表示世界上几乎所有字符的 Unicode 编码方式跨平台兼容&#xff1a;无论在哪里&#xff0c;UTF-8 …