1. 程式人生 > 其它 >《三十天自制作業系統》虛擬機器0x1b異常bug修復與中文顯示

《三十天自制作業系統》虛擬機器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
0x40
View Code

順便一提,由於這裡使用的是第三十天的程式轉載的,作者的ipl10.nas並不能把該程式全部載入記憶體,所以建議把它改為ipl20;

對於該程式的說明只一處,注意第12行,即:JMP0x999999;

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