1 攻克难题——字符串显示API(harib18a)

早安,大家精神还好吗?笔者有点没睡够,不过今天我们要继续加油哦。

先总结一下昨天最后遇到的情况:hello.hrb运行正常,但hello2.hrb却出现异常。为什么会这样呢?想了一下,应该是内存段惹的祸。

显示单个字符时,我们用[CS:ECX]的方式特意指定了CS(代码段寄存器),因此可以成功读取msg的内容。但在显示字符串时,由于无法指定段地址,程序误以为是DS而从完全错误的内存地址中读取了内容,碰巧读出的内容是0,于是就什么都没有显示出来。

因此,我们需要在API中做个改动,使其能够将应用程序传递的地址解释为代码段内的地址。

■■■■■

hrb_api并不知道代码段的起始位置位于内存的哪个地址,但cmd_app应该知道,因为当初设置这个代码段的正是cmd_app。

由于我们没有办法从cmd_app向hrb_api直接传递数据,因此只好又在内存里找个地方存放一下了。0xfec这个位置之前已经用过了,这次我们放在它前面的0xfe8好了。

  1. int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline)
  2. {
  3. (中略)
  4. if (finfo != 0) {
  5. /*找到文件的情况*/
  6. p = (char *) memman_alloc_4k(memman, finfo->size);
  7. *((int *) 0xfe8) = (int) p; /*这里! */
  8. file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
  9. set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
  10. farcall(0, 1003 * 8);
  11. memman_free_4k(memman, (int) p, finfo->size);
  12. cons_newline(cons);
  13. return 1;
  14. }
  15. /*没有找到文件的情况*/
  16. return 0;
  17. }
  18. void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
  19. {
  20. int cs_base = *((int *) 0xfe8); /*这里!*/
  21. struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);
  22. if (edx == 1) {
  23. cons_putchar(cons, eax & 0xff, 1);
  24. } else if (edx == 2) {
  25. cons_putstr0(cons, (char *) ebx + cs_base); /*这里!*/
  26. } else if (edx == 3) {
  27. cons_putstr1(cons, (char *) ebx + cs_base, ecx); /*这里!*/
  28. }
  29. return;
  30. }

就是这个样子,应该没有什么难点,所以就不讲解了。

好了,赶紧试验一下,看看只有19个字节的hello2能不能成功显示出字符串。

1 攻克难题——字符串显示API(harib18a) - 图1

显示出来了!

成功了,看来果然是内存段搞的鬼,问题解决!