bin2yx 发表于 2017-6-1 17:39:44

反汇编Bios中断例程的方法求教

反汇编Bios中断例程的方法求教
       
思路:

1        电脑启动后,会进入实模式,从0000:0000处创建中断向量表;
2        BIOS中断程序被加载到了内存中;
3        CPU跳至0000:7c00处执行引导程序。

        因此,我用汇编写好引导程序,加入写软盘功能,将0000:0000~FFFF:FFFF的内存全部写入到软盘,然后利用反汇编工具对其反汇编以得到BIOS中断程序的汇编代码。
       
       
行动步骤:

1        用虚拟机(VirtualBox)创建一台电脑;
2        虚拟两个软驱;
3        在linux下利用nasm编译引导程序(boot),生成.bin文件,然后使用linux的dd命令(如dd if=boot.bin of=boot.img)将其虚拟成软盘镜像。
4        继续使用dd命令创建一个空白软盘镜像(dd if=/dev/zero of=blank.img bs=1474560 count=1)。bs的作用是限制大小,1474560=1.44m软盘(不知道对不对)
5        分别将两个镜像装进软驱,从0号软盘启动虚拟电脑。出现问候后按回车执行写软盘程序。
6        将0000:0000~FFFF:FFFF的内存全部写入到1号软盘。

进行到这里,问题来了:
1        内存中的数据有一部分成功写入到了空白软盘,内存F000:0000以后应该有数据的,可是软盘里没有,连0000:FC00的数据都没有写入软盘,应该是我的 写软盘代码 有问题。
2        上述思路和步骤是否存在问题,大神们能否指点一下。

3        读软盘的程序也有问题,本想把软盘内容读到0000:7e00处,可直接将es=0000h,bx=7e00h的话程序会卡死,将es=07e0h,bp=0的话可以读,但是读到的内存位置变成了07e0:000a
3        代码附后,因为是刚刚从MASM转入学习NASM,代码可能不太好读,请大神包涵。


org 07c00h       

        mov ax,cs                        ;显示问候
        mov es,ax
        mov ax,BootMessage
        mov bp,ax
        mov cx,6
        mov dx,0
        call showgreen               

        mov ch,00000000b        ;设置光标形状
        mov cl,00010000b
        mov ah,01h                        ;中断入口
        int 10h
       
       
        call newline                ;换行

       
r16h:       
        mov ah,0                        ;等待键盘输入
        int 16h
        mov ah,0eh                        ;将输入输出至屏幕
        mov bx,00001010b
        mov cx,1
        int 10h
       
        cmp al,0dh                        ;回车键结束输入
        je COPY
        jne r16h

COPY:                                        ;写软盘程序,第一段写一个柱面
        push es                               
        mov si,0                        ;计数器
        mov ax,0h
        mov es,ax                        ;内存基地址
        mov bx,0h                        ;内存偏移地址
        mov ah,03h                        ;int13h 写扇区入口
        mov al,18                        ;写扇区的数量
        mov ch,0                        ;柱面 或者说 磁道
        mov cl,1                        ;第一个扇区开始
        mov dh,0                        ;驱动号 或者说 盘面号
        mov dl,1                        ;驱动器号 0~7f h 软盘
        int 13h
       
go:        push ax                                ;储存参数,以便开始写第二个柱面
        mov ax,es                       
        add ax,240h                        ;下一个内存基地址
        mov es,ax
        mov bx,0
        pop ax
        inc ch                                ;下一个柱面或者说磁道
        inc si                                ;计数器加1
        cmp si,80                        ;如果写够了80个磁道,就需要换盘面了                               
        je C_1
        int 13h
        jmp go
C_1:                                        ;写软盘第二盘面
        mov si,0                        ;计数器重新清零
        push ax
        mov ax,es                       
        add ax,240h
        mov es,ax                        ;内存基地址
        mov bx,0                        ;内存偏移地址
        pop ax
        mov ch,0                        ;柱面 或者说 磁道
        mov cl,1                        ;第一个扇区开始
        mov dh,1                        ;驱动号 或者说 盘面号
        mov dl,1                        ;驱动器号 0~7f h 软盘
        int 13h
       
go1:       
        push ax                                ;储存参数
        mov ax,es                       
        add ax,240h                        ;下一个内存基地址
        mov es,ax
        mov bx,0
        pop ax
        inc ch                                ;下一个磁道
        inc si                                ;计数器加1
        cmp si,33                        ;如果写够了113个磁道,就写了FE400个数据了       
                                                ;如果直接写114个磁道,es=FE40 + 240 =10080将产生溢出
        je C_end
        int 13h
        jmp go1
       
C_end:       
        mov bx,2400h                ;继续多写入一个磁道,写够100800 h个数据
        inc ch
        int 13h
       
        mov al,'o'                        ;显示一个o,表示程序可以执行到这一步
        mov ah,0eh
        mov bx,00001010b
        mov cx,1
        int 10h
        pop es
        jmp r16h                        ;跳回等待输入

showgreen:                                ;以绿色显示指定位置的字符串,需要设置es,bp,cx,dx
        mov ax,01301h
        mov bx,00001010b
        int 10h
        ret

loadf:                                        ;读软盘子程序
                                                ;读取软盘1至7e00 可软盘内容是复制到了7e0a 前9个位置留空了,为什么?
        push es
        mov ax,07e0h
        mov es,ax
        mov bp,0h
        mov ah,2                        ;int13 入口参数
        mov al,2                        ;读取两个扇区
        mov cx,0001h                ;从第一扇区开始
        mov dx,0001h                ;1号驱动器(0~80为软驱
        int 13h
        pop es
        ret
       
       
newline:
        mov        ah,03h                        ;获取光标位置
        int 10h       
        inc dh                                ;设置光标位置,换行
        mov dl,0                        ;行首
        mov ah,02h                        ;
        int 10h
        ret
       
BootMessage:        db "Hello!"                                ; 6byte
Smessage:                db "Well come to Buu"        ; 16byte
Load:        db "Load successfully..."
                db 0ah
                db "Do you want to continue? "        ; System-Load byte
                db "Press ENTER"
System:        dw 0h,07e1h                ; 系统入口地址       

times 510-($-$)        db 0
dw 0xaa55
       
       
       

人造人 发表于 2017-6-1 20:59:46

这个问题有意思,我感兴趣,我找个时间给你试一下
^_^

bin2yx 发表于 2017-6-2 21:04:10

人造人 发表于 2017-6-1 20:59
这个问题有意思,我感兴趣,我找个时间给你试一下
^_^

又麻烦你了哈哈~!
我已经解决了大部分问题了。原代码的COPY~C_end段代码有问题。
1、linux生成的软盘镜像不是18个扇区每道,而是36扇区每道。
2、我原来忽略了第一次写软盘后的ah、al返回值,导致第二次写软盘入口错误。
正确的代码如下:

COPY:                                                ;写入磁盘程序
        push es                               
        mov si,0                        ;计数器
        mov ax,0
        mov es,ax                        ;内存基地址
        mov bx,0                        ;内存偏移地址
        mov ah,03h                        ;int13h 写扇区入口
        mov al,36                        ;写扇区的数量 *** 这里必须星标一下 软盘镜像 居然不是18个扇区每道的。。。
        mov ch,0                        ;柱面 或者说 磁道
        mov cl,1                        ;第一个扇区开始
        mov dh,0                        ;驱动号 或者说 盘面号
        mov dl,0                        ;驱动器号 0~7f h 软盘
        int 13h
       
go:       
        mov ax,es                       
        add ax,480h                        ;下一个内存基地址
        mov es,ax
        mov ah,03h
        mov al,36
        inc ch                                ;下一个磁道
        inc si                                ;计数器加1
        cmp si,56                        ;如果写够了56个磁道,就需要换盘面了        ,但这里不需要换面,镜像也好像没有第二面                       
        je C_end
        int 13h
        jmp go
C_end:       
        mov bx,4800h                ;因为此时es=fc00,不能再加480h了,加了=10080h 会溢出 所以直接修改偏移地址
        inc ch
        mov ah,03h
        mov al,18                        ;暂定写18个扇区 此时已经超过1m数据了
        int 13h
       
        mov al,'o'
        mov ah,0eh
        mov bx,00001010b
        mov cx,1
        int 10h
        pop es
        jmp r16h

bin2yx 发表于 2017-6-2 21:13:42

自己解答一下,附虚拟机的1M内存数据,里边包含了中断向量表以及应该包含了BIOS中断例程,如果有兴趣的朋友了自己反汇编看看。我如果弄懂了也会把每个中断的学习情况慢慢发上来。

bin2yx 发表于 2017-6-2 21:22:12

人造人 发表于 2017-6-1 20:59
这个问题有意思,我感兴趣,我找个时间给你试一下
^_^

有没有好用的反汇编工具? 能够输入地址如 f000:efee 直接定位到该地址的? 我现在在用W32dsm 好像不是很方便,因为他的地址是1.ffff 这样的 不是基地址加偏移 ,而是一个10进制数 加后边一个16进制地址

人造人 发表于 2017-6-2 21:37:54

bin2yx 发表于 2017-6-2 21:22
有没有好用的反汇编工具? 能够输入地址如 f000:efee 直接定位到该地址的? 我现在在用W32dsm 好像不是很 ...

ndisasm

这是nasm 文件夹下的一个小工具
http://www.nasm.us/

人造人 发表于 2017-6-3 18:26:57


bin2yx 发表于 2017-6-4 22:23:03

人造人 发表于 2017-6-3 18:26


谢谢你的文件,我自己也能弄出来了。
还有个问题,我写的将内存0000:0000~FFFF:FFFF全部拷入软盘的代码还是有问题,虽然能拷贝大部分内存,但是每完成拷贝两个或者三个磁道后就会出一次错误,int13h的 ah返回值是 09H — DMA超过64K界限,出错以后的下几次循环又能成功,这就导致了小部分内存没有拷入软盘。我目前正在试着解决,可是很难。

人造人 发表于 2017-6-4 22:39:30

bin2yx 发表于 2017-6-4 22:23
谢谢你的文件,我自己也能弄出来了。
还有个问题,我写的将内存0000:0000~FFFF:FFFF全部拷入软盘的代码 ...

我正在从另一个角度解决这个问题,你的程序中是使用BIOS中断写软盘,BIOS中断的程序也在0000:0000~FFFF:FFFF
会不会是拿它本身拷贝它,出了问题?
因为我并不清楚BIOS中断是如何写的软盘,如果要用它来复制它本身,是否可以?
页: [1]
查看完整版本: 反汇编Bios中断例程的方法求教