《三十天自制操作系统》虚拟机0x1b异常bug修复与中文显示
作者:互联网
gitee传送门:进入下载
Bug修复
只需把代码段的合法地址修改成下图这样即可:
bug原因分析:
1、错误示例:在QEMU中是可以正常运行的,但一把软盘挪到虚拟机中运行就会报:
2、原因:finfo是经过压缩的文件,而appsize是解压缩后的文件,所以当指向0x1b时,指令硬编码为E9XXXXXXXX,而跳转的地址超过了finfo的size,所以虚拟机报了上图的错误,至于QEMU未报错的原因就不得而知了;
下面使用lines进行说明,下图是压缩过后的lines.hrb
未压缩的大小为642字节
而E9的地址为:
翻译为汇编就是:
计算如上指令:
0x257与0x252相差正好是该指令长度0x5,意思计算往后跳了0x257的长度,十进制就是(599),再看压缩过的hrb文件大小,310字节,目标地址为0x1b + 599字节,自然会触发0x0d保护异常;
这是验证该想法的程序:
1 [FORMAT "WCOFF"] 2 [INSTRSET "i486p"] 3 [BITS 32] 4 [FILE "crack.nas"] 5 6 GLOBAL _HariMain 7 8 [SECTION .text] 9 10 _HariMain: 11 MOV EAX, 0x999999 12 JMP EAX 13 MOV AX, 1005 * 8 14 MOV DS, AX 15 CMP DWORD [DS:0X4], 'Hari' ;这里获得的就是代码段数据,使用cs寻址的原因是因为若改变的cs数据 16 ;会改变CPU指令寻址,导致执行到不可知区域 17 18 JNE fin 19 20 MOV ECX, [DS:0] 21 MOV AX, 2005 * 8 22 MOV DS, AX 23 24 crack_loop: 25 ADD ECX, -1 26 MOV BYTE [DS:ECX], 123 27 CMP ECX, 0 28 JNE crack_loop 29 30 fin: 31 MOV EDX, 0X4 32 INT 0x40View Code
顺便一提,由于这里使用的是第三十天的程序转载的,作者的ipl10.nas并不能把该程序全部载入内存,所以建议把它改为ipl20;
对于该程序的说明只一处,注意第12行,即:JMP 0x999999;
QEMU上就别试了,结果就是直接死机,然后退出QEMU。虚拟机上是这样报异常的:
这里大体也就可以猜出EIP=0x29处就是第十二行,有图有真相,所以直接上图:
所以就像之前说的那样,压缩的错误,所以改个数值即可;
汉字显示
直接上成果:
要注意的是你获得的字模显示的格式,书本上作者是前16个字节显示前半部分,后16个自然是后半部分,而这里的字模则是单数显示前半部分,双数就是后半部分,所以针对此情况,就需要重写字符显示的方法;
注意事项说完了就说说为了显示汉字添加了哪些吧:
在haribote文件夹中添加language.c来管理各种语言,有了这个函数,就不能像作者那样把某种语言地址写入诸如(0xfe8)这样的地址了,由于考虑到对各种语言的支持;不过问题也不大,把这些语言的地址作为变量存放,一来代码引用可读性增强了,二来判断该语言是否成功载入也不用看第一面第一区第一点的数值是不是0xff了,只需判断代表该语种的变量值是否不为0,而且若没有该语种,为该语种留下的空间也省去了,总之好处多多,该方法只需在bootpack.c中替换原本加载文字的的代码即可,往后就无需引用;
1 #include "bootpack.h" 2 3 int languages[MAX_LANGUAGE_NUMBER]; 4 5 void language_init(void) 6 { 7 const static char* language_name[MAX_LANGUAGE_NUMBER] = { 8 "hankaku", 9 "chinese", 10 "nihongo" 11 }; 12 13 extern char hankaku[4096]; 14 struct MEMMAN* memman = (struct MEMMAN*)MEMMAN_ADDR; 15 int* fat; 16 struct FILEINFO* finfo; 17 int i, siz; 18 for (i = 0; i < MAX_LANGUAGE_NUMBER; i++)languages[i] = 0;//首先置零 19 languages[0] = hankaku; 20 21 /* 载入nihongo.fnt */ 22 fat = (int*)memman_alloc_4k(memman, 4 * 2880); 23 file_readfat(fat, (unsigned char*)(ADR_DISKIMG + 0x000200)); 24 25 for (i = 1; i < LANGUAGE_NUMBER_NOW; i++) 26 { 27 char* now = 0; 28 finfo = file_search(language_name[i], (struct FILEINFO*)(ADR_DISKIMG + 0x002600), 224); 29 if (finfo != 0) {//找到了 30 siz = finfo->size; 31 now = file_loadfile2(finfo->clustno, &siz, fat); 32 } 33 else 34 { 35 //加上.fnt继续找 36 char new_name[100];//转载新名字 37 int j = 0; 38 while (*(language_name[i] + j))new_name[j] = *(language_name[i] + j++); 39 int cnt = 4; 40 static const char* hind = ".fnt"; 41 while (cnt)new_name[j++] = hind[4 - cnt--]; 42 new_name[j] = 0;//加上.fnt后缀继续找 43 44 //sprintf(s, "%d %d %d", languages[ASCLL], languages[CHINESE], languages[2]); 45 putfonts8_asc_sht(sht_back, 10, 216, COL8_FFFFFF, COL8_008484, new_name, 100); 46 47 finfo = file_search(new_name, (struct FILEINFO*)(ADR_DISKIMG + 0x002600), 224); 48 if (finfo != 0) {//找到了 49 siz = finfo->size; 50 now = file_loadfile2(finfo->clustno, &siz, fat); 51 } 52 } 53 languages[i] = now;//找到赋值该地址,未找到赋值为初值0,用处见graphic.c 54 } 55 memman_free_4k(memman, (int)fat, 4 * 2880); 56 57 }language.c
重写过后的文字显示方法:(用于中文)
1 void putfont_len16_height16_chinese(char* vram, int xsize, int x, int y, char c, char* font, char right) 2 { 3 int i; 4 char* p, d /* data */; 5 6 for (i = 0; i < 16; i++) { 7 p = vram + (y + i) * xsize + x; 8 d = font[(i << 1) + right]; 9 if ((d & 0x80) != 0) { p[0] = c; } 10 if ((d & 0x40) != 0) { p[1] = c; } 11 if ((d & 0x20) != 0) { p[2] = c; } 12 if ((d & 0x10) != 0) { p[3] = c; } 13 if ((d & 0x08) != 0) { p[4] = c; } 14 if ((d & 0x04) != 0) { p[5] = c; } 15 if ((d & 0x02) != 0) { p[6] = c; } 16 if ((d & 0x01) != 0) { p[7] = c; } 17 } 18 return; 19 }putfont_len16_height16_chinese
最后就是重写后的putfonts8_asc,用于配合language.c实现各种语言的显示;
1 void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s) 2 { 3 extern char hankaku[4096]; 4 struct TASK *task = task_now(); 5 char* languageNow, * font; 6 int k, t; 7 8 if (ASCLL == task->langmode)languageNow = hankaku; 9 else 10 { 11 if (!languages[task->langmode])languageNow = hankaku;//该语言模块未导入,选择默认ascll 12 else languageNow = languages[task->langmode];//该语言模块导入 13 } 14 15 if (task->langmode == ASCLL) {//ascll 16 for (; *s != 0x00; s++) { 17 putfont8(vram, xsize, x, y, c, languageNow + *s * 16); 18 x += 8; 19 } 20 } 21 22 if (task->langmode == CHINESE) {//中文 23 for (; *s != 0x00; s++) { 24 if (task->langbyte1 == 0) { 25 if (0x81 <= *s && *s <= 0xfe) { 26 task->langbyte1 = *s; 27 } 28 else { 29 putfont8(vram, xsize, x, y, c, hankaku + *s * 16); 30 } 31 } 32 else { 33 k = task->langbyte1 - 0xa1; 34 t = *s - 0xa1; 35 task->langbyte1 = 0; 36 font = languageNow + (k * 94 + t) * 32;//+ 256 * 16 37 putfont_len16_height16_chinese(vram, xsize, x - 8, y, c, font, 0); /* 左半部分 */ 38 putfont_len16_height16_chinese(vram, xsize, x, y, c, font, 1); /* 右半部分 */ 39 } 40 x += 8; 41 } 42 } 43 44 if (task->langmode == 2) {//日文 jis 45 for (; *s != 0x00; s++) { 46 if (task->langbyte1 == 0) { 47 if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) { 48 task->langbyte1 = *s; 49 } else { 50 putfont8(vram, xsize, x, y, c, languageNow + *s * 16); 51 } 52 } else { 53 if (0x81 <= task->langbyte1 && task->langbyte1 <= 0x9f) { 54 k = (task->langbyte1 - 0x81) * 2; 55 } else { 56 k = (task->langbyte1 - 0xe0) * 2 + 62; 57 } 58 if (0x40 <= *s && *s <= 0x7e) { 59 t = *s - 0x40; 60 } else if (0x80 <= *s && *s <= 0x9e) { 61 t = *s - 0x80 + 63; 62 } else { 63 t = *s - 0x9f; 64 k++; 65 } 66 task->langbyte1 = 0; 67 font = languageNow + 256 * 16 + (k * 94 + t) * 32; 68 putfont8(vram, xsize, x - 8, y, c, font); /* 左半部分 */ 69 putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ 70 } 71 x += 8; 72 } 73 } 74 75 if (task->langmode == 3) {//日文 edu 76 for (; *s != 0x00; s++) { 77 if (task->langbyte1 == 0) { 78 if (0x81 <= *s && *s <= 0xfe) { 79 task->langbyte1 = *s; 80 } else { 81 putfont8(vram, xsize, x, y, c, hankaku + *s * 16); 82 } 83 } else { 84 k = task->langbyte1 - 0xa1; 85 t = *s - 0xa1; 86 task->langbyte1 = 0; 87 font = languageNow + 256 * 16 + (k * 94 + t) * 32; 88 putfont8(vram, xsize, x - 8, y, c, font); /* 左半部分 */ 89 putfont8(vram, xsize, x , y, c, font + 16); /* 右半部分 */ 90 } 91 x += 8; 92 } 93 } 94 return; 95 }putfonts8_asc
标签:task,16,int,虚拟机,0x1b,char,xsize,bug,langbyte1 来源: https://www.cnblogs.com/ILXYR/p/15367409.html