第22天 用C语言编写应用程序

这篇博客讲述了如何使用C语言编写应用程序时保护操作系统,避免恶意代码破坏。通过实例展示了如何通过改变定时器设置引起异常,以及如何利用CPU异常处理功能帮助发现程序中的bug。还介绍了强制结束应用程序的方法,以及如何通过快捷键结束运行中的程序。最后,讨论了如何显示字符串和创建窗口,并在窗口中描绘字符和方块的操作。
摘要由CSDN通过智能技术生成

第22天 用C语言编写应用程序

2020.4.26

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

  • 把OS的段地址存入DS和访问OS管理的内存空间这两招已经不能用了。

  • 试试在定时器上做手脚:这样,光标闪烁就会变得异常,任务切换的速度也会变慢。

  • 编写恶意应用程序crack3.nas:

    [INSTRSET "i486p"]
    [BITS 32]
            MOV		AL,0x34
            OUT		0x43,AL
            MOV		AL,0xff
            OUT		0x40,AL
            MOV		AL,0xff
            OUT		0x40,AL
    
    ; 	上述代码相当于
    ;	io_out8(PIT_CTRL, 0x34);
    ;	io_out8(PIT_CNT0, 0xff);
    ;	io_out8(PIT_CNT0, 0xff);
    
            MOV		EDX,4
            INT		0x40
    
    • 原本定时器的设定值是11932=0x2e9c:
      io_out8(PIT_CTRL, 0x34);
      io_out8(PIT_CNT0, 0x9c);
      io_out8(PIT_CNT0, 0x2e);
      
    • 现在设定值变成了0xffff=65535,显然,这样光标闪烁就会变慢。
  • make后用VMware运行:

    • 显示了一般保护性异常。
    • 当以应用程序模式运行时,执行IN指令和OUT指令都会产生一般保护性异常。当然,通过修改CPU设置,可以允许应用程序使用IN指令和OUT指令,但这样会留下隐患。
  • 继续编写恶意应用程序crack4.nas:

    [INSTRSET "i486p"]
    [BITS 32]
            CLI
    fin:
            HLT
            JMP		fin
    
    • 先CLI再HLT,这样电脑就死机了吧?
  • make后用VMware运行:

    • 再次显示了一般保护性异常。
    • 当以应用程序模式运行时,执行CLI、STI和HLT这些指令都会产生异常。因为中断是由OS来管理的,应用程序不可以随便进行控制。
    • 不能执行HLT,应用程序就无法省电,不过可以通过调用任务休眠的API来实现,而不能由应用程序自己来执行HLT。
    • 此外,在多任务下,调用休眠API还可以让OS将CPU时间分配给其他任务。
  • OS代码中有io_cli函数,如果应用程序far-CALL这个函数呢?找到bootpack.map文件中io_cli的地址:

    0x00000AC1 : _io_cli
    
  • 编写恶意应用程序crack5.nas:

    [INSTRSET "i486p"]
    [BITS 32]
            CALL	2*8:0xac1
            MOV		EDX,4
            INT		0x40
    
  • make后用VMware运行试试:

    • 再次产生一般保护性异常。
    • 如果应用程序可以CALL任何地址的话,那crack5.nas就成功了。因此,CPU规定除了设置好的地址以外,禁止应用程序CALL其他的地址。因此,此OS中应用程序调用OS只能采用INT 40的方法。
  • 既然应用程序只能调用API,那么把API修改一下:

    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,123456789
            INT		0x40
            MOV		EDX,4
            INT		0x40
    
  • make后用VMware运行:

    • OS崩溃了。
    • OS之所以崩溃是因为出现了“内鬼API”——123456789。

2. 帮助发现bug(harib19b)

  • CPU的异常处理功能,除了可以保护OS免遭应用程序的破坏,还可以帮助我们在编写应用程序时及早发现bug。

  • 编写有bug的应用程序bug1.c:

    void api_putchar(int c);
    void api_end(void);
    
    void HariMain(void)
    {
        char a[100];
        a[10] = 'A';		/* 这句代码没有问题 */
        api_putchar(a[10]);
        a[102] = 'B';		/* 这句代码有问题 */
        api_putchar(a[102]);
        a[123] = 'C';		/* 这句代码有问题 */
        api_putchar(a[123]);
        api_end();
    }
    
    • 这个应用程序有明显的bug,即超出数组边界。
  • make后用VMware运行试试:

    • 这应该是产生了没有设置过的异常所导致的。
  • 顺便提一下,保护OS暂时结束了,因而把“内鬼API”删掉,也把crack[1-6].[nas|c]删除

  • 由于a数组是保存在栈中的,因此数组越界产生了栈异常

    • 栈异常的中断号是0x0c
    • 根据CPU的说明书,从0x00到0x1f都是异常所使用的中断,所以,IRQ的中断号都是从0x20开始的。
    • 其他比较有用的异常有:
      • 0x00号:除零异常,当试图除以0时产生。
      • 0x06号:非法指令异常,当试图执行CPU无法理解的机器语言指令时产生,比如当试图执行一段数据时可能产生。
  • 编写asm_inthandler0c函数:

    _asm_inthandler0c:
            STI
            PUSH	ES
            PUSH	DS
            PUSHAD
            MOV		EAX,ESP
            PUSH	EAX
            MOV		AX,SS
            MOV		DS,AX
            MOV		ES,AX
            CALL	_inthandler0c
            CMP		EAX,0
            JNE		end_app
            POP		EAX
            POPAD
            POP		DS
            POP		ES
            ADD		ESP,4			; INT 0x0c 需要这句
            IRETD
    
    • 当产生0x0c号中断时,必须强制结束应用程序。
  • 编写inthandler0c函数(console.c文件中,inthandler0c和inthandler0d都在console.c中):

    int *inthandler0c(int *esp)
    {
        struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
        struct TASK *task = task_now();
        cons_putstr0(cons, "\nINT 0C :\n Stack Exception.\n");
        return &(task->tss.esp0);	/* 强制结束应用程序 */
    }
    
    • inthandler0c和inthandler0d函数的区别只是显示信息不同。
  • 在IDT中注册:

    void init_gdtidt(void)
    {
        ……
        /* IDT设置 */
        set_gatedesc(idt + 0x0c, (int) asm_inthandler0c, 2 * 8, AR_INTGATE32); /*注册0x0c号中断*/
        set_gatedesc(idt + 0x0d, (int) asm_inthandler0d, 2 * 8, AR_INTGATE32);
        set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
        set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
        set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
        set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
        set_gatedesc(idt + 0x40, (
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值