nasm : UltraIso制作的MBR的逆向整理

来源:互联网 发布:mssql数据库管理工具 编辑:程序博客网 时间:2024/06/05 07:55

整理了UltraIso制作的MBR,整理为一个mbr.asm.

int 13h, ah = 42h和int 13h, ah = 2h 均可以读出扇区到内存.

做了一些修改

* 使0x7c00直接执行,不拷贝自己到0x600.  对于我自己做bootloader实验没有帮助

* mbr执行时,拷贝1#扇区到0x7e00, 然后跳到0x7e00.

todo list:

* 做bootloader实验时, 用的是FTA32格式化好的U盘, 1#扇区是分区表信息, 要改变载入的扇扇区为不用的扇区.

* 0x7e00为载入后续模块的Loader模块, 应该载入连续的几块扇区,视Loader模块的大小来确定. 而不应该只载入1块扇区.

这是初步整理的结果, 后续会完善. 这个初步的整理成果,是可以跑的~

 

; /// @file ls-boot-loader/mbr_made_in_ultraios_0x7c00_0x7dff.asm; /// @brief 逆向ultraIso的MBR, 去掉多于代码, 加上可以更换的分区表信息; /// @note 编译命令行 ; /// cd D:\prj\nasm_prj\boot\ls-boot-loader; /// d:; /// C:\nasm\nasm.exe mbr_made_in_ultraios_0x7c00_0x7dff.asm -o mbr_made_in_ultraios_0x7c00_0x7dff.bin -l mbr_made_in_ultraios_0x7c00_0x7dff.list; /// @note 将 mbr_made_in_ultraios_0x7c00_0x7dff.bin 写到U盘0扇区; /// 变量命名约定; /// label_x 为标签, 供跳转指令使用; /// addr_x 为地址, 供内存操作指令使用; /// byte_x word_x 为全局变量, 供程序流程内使用, 在使用前需要初始化; /// fn_x 为函数入口地址, 供 call 指令使用; /// XXX 为宏, 必须全大写, 单词之间用'_'连接;--------------------------------------------------------------------------------; /// 宏定义;--------------------------------------------------------------------------------; /// 如果没定义 SWITCH_USE_CHS_READ_SECTOR_TO_MEMORY, 就优先执行 int 13h ah = 42h, 扩展读扇区到内存, ; /// 如果失败, 才执行int 13h ah = 2h, 根据CHS读扇区到内存; /// 等调试完成, 请注释掉 SWITCH_USE_CHS_READ_SECTOR_TO_MEMORY%define SWITCH_USE_CHS_READ_SECTOR_TO_MEMORY ; ///< 使用 int 13h ah = 2h 的CHS接口读扇区到内存MEMORY_ADDR_BOOT_CODE_ORG_ENTRY equ 0x7c00 ; ///< MBR程序入口地址MEMORY_ADDDR_LOADER_MODULE equ 0x7e00; ///< "载入"模块地址MEMORY_ADDR_STACK_TOP equ 0x7c00 ; ///< 栈顶地址MEMORY_ADDR_SECTOR_NEED_COPY_TO_DEST equ MEMORY_ADDDR_LOADER_MODULE ; ///< 新扇区要拷贝到的内存地址CNT_PARTITION_ENTRY equ 4 ; ///< 分区表入口总数量BYTE_FLAG_PARTITION_ACTIVE equ 0x80 ; ///< 分区激活标志字节内容LEN_PARTITION_ENTRY equ 0x10 ; ///< 分区表入口长度为16BytesPARTITION_TYPE_FAT32_WITH_CHS_ADDRESSING equ 0x0b ; ///< 分区类型为FAT32+CHSPARTITION_TYPE_FAT32_WITH_LBA equ 0x0c ; ///< 分区类型为FAT32+LBA; /// byte_status字节状态位定义; /// 状态位 : 分区校验是否有效. 1 = 有效, 0 = 无效BIT_VALID_PARTITION_SET equ 00000001b ; ///< 设置分区有效位标志, 用OR方法, TEST位时,也用这个值BIT_VALID_PARTITION_CLR equ 11111110b ; ///< 清除分区有效位标志, 用AND方法bits 16 ; ///< 16位汇编;--------------------------------------------------------------------------------; /// MBR程序入口;--------------------------------------------------------------------------------org MEMORY_ADDR_BOOT_CODE_ORG_ENTRYclixor ax, axmov ds, axmov es, axmov ss, axmov sp, MEMORY_ADDR_STACK_TOP; /// 全局变量初始化mov byte[byte_status], al ; ///< 状态字节,初始化为FALSEmov byte[byte_udisk_sn], al; mov word[word_disk_head_number], axmov word[word_disk_sector_number], axsticldmov si, sp; /// 直接在0x7c00操作, 不拷贝到其他扇区再操作, 我们拷贝U盘1#扇区到MEMORY_ADDDR_LOADER_MODULEmov [byte_udisk_sn], dl ; ///< 保存U盘号码0x80; /// 显示信息 - 从U盘启动mov si, str_start_boot_from_usb_devicecall fn_disp_str; /// 校验分区表-查找有效的分区表入口mov si, addr_partition_tablexor ax, axmov cx, CNT_PARTITION_ENTRY ; 分区入口(partition entry)共4条label_verify_partition_entry_do_once:test byte [si], BYTE_FLAG_PARTITION_ACTIVE ; 判断该分区入口是否为激活jz label_verify_partition_entry_next ; ///< 如果分区表入口无效, 找下一个分区表入口inc ax ; ///< 保存-有效分区入口数量; /// bp为最后一个有效分区入口, 因为4个分区入口只有一个是激活的; /// 所以 bp 中保存的是唯一个被激活的分区入口mov bp, silabel_verify_partition_entry_next:add si, LEN_PARTITION_ENTRY ; ///< 切到下一个分区表入口loop label_verify_partition_entry_do_once ; ///< 判断该分区入口是否为激活dec axjz label_proc_valid_partition_table ; ///< 如果激活的分区表入口数量为1, 转有效处理; /// 如果分区表入口校验无效(没有唯一激活的分区表入口), 就不搞了, 报错(无效分区表)后,死循环mov si, str_invalid_partition_tablejmp label_show_msg_and_loop_dead;--------------------------------------------------------------------------------; /// 校验分区表;--------------------------------------------------------------------------------label_proc_valid_partition_table:pushamov dl, [byte_udisk_sn]     ; restore dl from bk_byte_dlmov ah, 41h ; 'A'mov bx, 55AAhint 13h             ; DISK - Check for INT 13h Extensions; BX = 55AAh, DL = drive number; Return: CF set if not supported; AH = extensions version; BX = AA55h; CX = Interface support bit mapjb short not_support_int_13h_extensions ; when return, flag CF must be zerocmp bx, 0AA55h      ; confirm that the extensions are presentjnz not_support_int_13h_extensions ; (9)、功能 08H; 功能描述:读取驱动器参数; 入口参数:AH=08H; DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘; 出口参数:CF=1——操作失败,AH=状态代码,参见功能号 01H 中的说明,否则, BL=01H; — 360K; =02H — 1.2M; =03H — 720K; =04H — 1.44M; CH=柱面数的低 8 位; CL 的位 7-6=柱面数的高 2 位; CL 的位 5-0=扇区数; DH=磁头数; DL=驱动器数; ES:DI=磁盘驱动器参数表地址test cl, 1 ; extended disk access functions (AH=42h-44h,47h,48h) supportedjz not_support_int_13h_extensions ; (9)、功能 08H; 功能描述:读取驱动器参数; 入口参数:AH=08H; DL=驱动器,00H~7FH:软盘;80H~0FFH:硬盘; 出口参数:CF=1——操作失败,AH=状态代码,参见功能号 01H 中的说明,否则, BL=01H; — 360K; =02H — 1.2M; =03H — 720K; =04H — 1.44M; CH=柱面数的低 8 位; CL 的位 7-6=柱面数的高 2 位; CL 的位 5-0=扇区数; DH=磁头数; DL=驱动器数; ES:DI=磁盘驱动器参数表地址; /// 如果支持 int13h 磁盘扩展, 做标志, 跳到 用磁盘扩展方法去读扇区到内存; /// 不用动态修改代码的方式,太不正规了. 如果做补丁,可以这样动态修改代码.%ifdef SWITCH_USE_CHS_READ_SECTOR_TO_MEMORYjmp not_support_int_13h_extensions%else; /// 设置分区校验有效位标志mov al, [byte_status];or al , BIT_VALID_PARTITION_SETmov byte[byte_status], aljmp label_read_sectors_into_memory%endif;--------------------------------------------------------------------------------not_support_int_13h_extensions:; int 13h, ah = 08h;; parameter IN;; AH = 08h; DL = drive (bit 7 set for hard disk); ES:DI = 0000h:0000h to guard against BIOS bugs;; parameter OUT;; CF set on error; AH = status (07h) (see #00234); ; CF clear if successful; AH = 00h; AL = 00h on at least some BIOSes; BL = drive type (AT/PS2 floppies only) (see #00242); CH = low eight bits of maximum cylinder number; CL = maximum sector number (bits 5-0); high two bits of maximum cylinder number (bits 7-6); DH = maximum head number; DL = number of drives; ES:DI -> drive parameter table (floppies only)mov dl, [byte_udisk_sn]mov di, 0 ; ///< ES:DI = 0000h:0000h to guard against BIOS bugsmov ah, 8stcint 13h;<bochs:74> r;rax: 00000000_00000000 rcx: 00000000_0009aeff;rdx: 00000000_0000fe01 rbx: 00000000_0000aa55;rsp: 00000000_00007bf0 rbp: 00000000_00007dbe;rsi: 00000000_000e7dfe rdi: 00000000_00000000;r8 : 00000000_00000000 r9 : 00000000_00000000;r10: 00000000_00000000 r11: 00000000_00000000;r12: 00000000_00000000 r13: 00000000_00000000;r14: 00000000_00000000 r15: 00000000_00000000;rip: 00000000_00007c73;eflags 0x00000202: id vip vif ac vm rf nt IOPL=0 of df IF tf sf zf af pf cfjb label_cant_get_chs ; ///< flag CF must be zeroand ah, ahjnz label_cant_get_chs ; ///< ah must be 0x00mov al, dh ; ///< maximum head number, now dh = 0xfe = 254inc aljz label_cant_get_chs ; ///< maximum head number is 255, head number range(1 ~ 255); /// now ax = 0ffand cx, 3Fh ; /// < now cx = 0xaeffjz label_cant_get_chs ; ///< sector number must > 0, now sector number = 0x3f = 63jmp label_save_chs; /// 原版在执行完(int 13h, ah = 8)后,有逻辑错误; /// 如果查询CHS失败, 就无法继续强制执行了; /// 因为得不到CHS, 按照CHS读取磁盘扇区到内存,一定会失败的...label_cant_get_chs:mov si, str_error_cant_get_chscall label_show_msg_and_loop_deadlabel_save_chs:; 校验通过, 保存要用到的参数mov [word_disk_head_number], ax ; ///< head number now onlymov [word_disk_sector_number], cx ; ///< sector number onlylabel_read_sectors_into_memory:popaxor cx, cx  ; count to copy; /// bp 中保存的是唯一个被激活的分区入口mov ax, [bp+8] ; first disk sector index - low bitsmov dx, [bp+0Ah] ; first disk sector index - high bitsmov bx, MEMORY_ADDR_SECTOR_NEED_COPY_TO_DEST ; dest addr copy tocall fn_read_sectors_into_memoryjnb ok_proc_read_sectors_into_memory ; addr_word_boot_signatureretry_proc_read_sectors_into_memory:; /// 这里是按照给定的分区表入口信息读取第一个扇区失败后的容错处理. 一般不可能进这里.; /// 分区表入口地址 + 4 为 Partition type, cmp byte [bp+4], PARTITION_TYPE_FAT32_WITH_CHS_ADDRESSING ; ///< FAT32 with CHS addressingjz loc_B3cmp byte [bp+4], PARTITION_TYPE_FAT32_WITH_LBA ; ///< FAT32 with LBAjz loc_B3jmp err_loading_operating_system ; str_error_loading_operating_system;--------------------------------------------------------------------------------loc_B3:inc cxadd ax, 6 ; ///< 这个开始扇区是咋算出来的,还不知道, 是兼容性的处理. 以后再研究.adc dx, 0call fn_read_sectors_into_memoryjnb ok_proc_read_sectors_into_memory ; addr_word_boot_signatureerr_loading_operating_system:mov si, str_error_loading_operating_system ; show str_error_loading_operating_systemjmp label_show_msg_and_loop_dead;--------------------------------------------------------------------------------ok_proc_read_sectors_into_memory:mov ax, [ds:7DFEh]    ; addr_word_boot_signaturecmp ax, 0AA55hjz ok_boot_signatureor cx, cxjz retry_proc_read_sectors_into_memoryjmp err_loading_operating_system ; str_error_loading_operating_system;--------------------------------------------------------------------------------ok_boot_signature:mov dl, [byte_udisk_sn]mov si, bpclijmp MEMORY_ADDR_SECTOR_NEED_COPY_TO_DESTlabel_show_msg_and_loop_dead:call fn_disp_strjmp $; =============== S U B R O U T I N E =======================================fn_disp_str:lodsband al, aljz fn_disp_str_endmov ah, 0Ehmov bx, 7int 10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE); AL = character, BH = display page (alpha modes); BL = foreground color (graphics modes)jmp fn_disp_strfn_disp_str_end:ret; =============== S U B R O U T I N E =======================================; /// @fn fn_read_sectors_into_memory; /// @brief 读扇区到内存; /// @param bp 被激活的分区表入口地址; /// @param cx 要拷贝的扇区数量; /// @param dx 激活的分区表入口中指定第一个扇区索引的高8位; /// @param ax 激活的分区表入口中指定第一个扇区索引的低8位; /// @param bx 扇区读取后,要拷贝到目的内存地址fn_read_sectors_into_memory:push dimov di, 5 ; ///< 读取扇区到内存失败时的重试次数fn_read_sectors_into_memory_retry:pusha;Format of disk address packet:;Offset  Size    Description     (Table 00272);10h    QWORD   (EDD-3.0, optional) 64-bit flat address of transfer buffer;;used if DWORD at 04h is FFFFh:FFFFh;08h    QWORD   starting absolute block number;(for non-LBA devices, compute as;(Cylinder*NumHeads + SelectedHead) * SectorPerTrack +;SelectedSector - 1;04h    DWORD   -> transfer buffer;02h    WORD    number of blocks to transfer (max 007Fh for Phoenix EDD);01h    BYTE    reserved (0);;00h    BYTE    size of packet (10h or 18h); /// 压入 disk address packet, 并将栈顶给si,供 int 13h, ah = 0x42 使用; /// 这么搞确实省空间,不过很容易填错参数, 分析者也容易看错参数xor cx, cx; /// 开始的绝对块号 = 1; /// 此时 cx == 0, dx:ax = 0000,0001push cx ;08h    QWORD   starting absolute block numberpush cxpush dxpush ax; /// 此时, cx:bx = 0000,7e00push cx ;04h    DWORD   -> transfer bufferpush bx; /// 此时 cx = 0inc cx ; ///< 此时, cx = 1, 说明要传送的块数为1push cx ;02h    WORD    number of blocks to transfer (max 007Fh for Phoenix EDD)push 0010h ;00h    BYTE    size of packet (10h or 18h)   ;01h    BYTE    reserved (0); ; /// DS:SI -> disk address packetmov si, sp; /// 根据分区表是否有效, 选择使用int 13h ah = 42h 扩展读扇区,还是使用int 13h ah = 2 根据CHS来读扇区test byte[byte_status], BIT_VALID_PARTITION_SETjz label_read_disk_to_memory_by_chs ; ///< 不是TRUE(分区校验无效), 转 int13h, ah = 2 读扇区; /// 分区表有效的处理; /// 使用 int13h, ah = 0x42 读扇区mov ah, 0x42mov dl, [byte_udisk_sn]     ; DL = drive; /// DS:SI -> disk address packet, 已经由函数入口处压入了 disk address packet, 压入时,已经填好了参数, 并将 sp => sijmp label_read_disk_to_memory_by_int_13h; /// 否则顺序执行下列代码label_read_disk_to_memory_by_chs:; /// ax 激活的分区表入口中指定第一个扇区索引的低8位div word [word_disk_sector_number]inc dxmov cx, dxxor dx, dxdiv word [word_disk_head_number]mov ch, al          ; CH = trackshr ax, 2and al, 0C0hor cl, al          ; CL = sectormov dh, dl          ; DH = headmov dl, [byte_udisk_sn]mov ax, 201h;AH = 02h;AL = number of sectors to read (must be nonzero);CH = low eight bits of cylinder number;CL = sector number 1-63 (bits 0-5);high two bits of cylinder (bits 6-7, hard disk only);DH = head number;DL = drive number (bit 7 set for hard disk);ES:BX -> data buffer;Return:;;CF set on error;if AH = 11h (corrected ECC error), AL = burst length;;CF clear if successful;AH = status (see #00234), 00h = successful completion;AL = number of sectors transferred (only valid if CF set for some BIOSes) now al = 1label_read_disk_to_memory_by_int_13h:int 13h             ; DISK - READ SECTORS INTO MEMORYlea sp, [si+10h] ; ///< 堆栈平衡popajb fn_read_sectors_into_memory_endcmp ah, 0x00 ; ///< AH = status (see #00234), 00h = successful completionjz fn_read_sectors_into_memory_ok; /// 失败重试, 这里的重试,感觉没用, 成功只有一种结果,失败有好多种原因; /// 如果要重试,也要先Sleep啊dec di; /// 重试之前, 将磁盘重置 pushaxor ah, ahmov dl, [byte_udisk_sn]int 13h             ; DISK - RESET DISK SYSTEM; DL = drive (if bit 7 is set both hard disks and floppy disks reset)popajmp fn_read_sectors_into_memory_retryfn_read_sectors_into_memory_ok:clc ; ///< 清除进位标记,代表成功fn_read_sectors_into_memory_end:pop diret;--------------------------------------------------------------------------------; /// 字符串定义;--------------------------------------------------------------------------------str_start_boot_from_usb_device:; db 0x0d, 0x0a, "start boot from usb device", 0x0d, 0x0a, 0db 0x0d, 0x0a, "start boot", 0x0d, 0x0a, 0str_invalid_partition_table:; db 'error : Invalid partition table', 0x0d, 0x0a, 0db 'error Invalid partition table', 0x0d, 0x0a, 0str_mbr_code_execute_over:; db "mbr code execute over", 0x0d, 0x0a, 0db "mbr end", 0x0d, 0x0a, 0str_error_loading_operating_system:; db 'error loading operating system', 0x0d, 0x0a, 0db 'error loading OS', 0x0d, 0x0a, 0str_error_cant_get_chs:; db 'error cant get CHS', 0x0d, 0x0a, 0db 'cant get CHS', 0x0d, 0x0a, 0;--------------------------------------------------------------------------------; /// 临时变量;--------------------------------------------------------------------------------; /// 状态字节, 每一位代表一个状态; /// bit 0 分区是否有效, 1 = 分区有效, 0 = 分区无效byte_status:db 0xcdbyte_udisk_sn: ; ///< 进入MBR代码时, DL中存放的是硬盘号码, 0x80代表第一块硬盘(即U盘)db 0xcd; /// int 13h, ah = 8h 时,取到的磁盘头数word_disk_head_number:dw 0xcdcd; /// int 13h, ah = 8h 时,取到的磁盘扇区数word_disk_sector_number:dw 0xcdcd;--------------------------------------------------------------------------------; 填充区;--------------------------------------------------------------------------------times 512 - ($ - $$) - 2 - (16 * 4) db 0; /// 对于不同的U盘分区size, 这里的值是不同的, partition_entry = 16, 共4个; /// 所以,使用不同的U盘做实验时, 格式化U盘后, 需要将U盘主分区的分区表入口抄下来,设置成下面的4个分区表入口; /// 这样才能将这512字节写入U盘0#扇区, 作为可用的MBR代码; /// 逆向UltraIos格式化U盘,写入的MBR代码, 可以看到代码中对此主分区分区表入口表, 做了校验.; /// 如果通不过校验, 不会加载后续的扇区到内存, 会跳到出错处理, 或走硬盘上的引导代码;Offset       0  1  2  3  4  5  6  7   8  9  A  B  C  D  E  F;0000001B0                                              80 00;0000001C0   02 00 0C FE FF AF 01 00  00 00 FF 3F E7 00;--------------------------------------------------------------------------------; /// Partition Table;--------------------------------------------------------------------------------addr_partition_table:db 0x80, 0x00, 0x02, 0x00, 0x0c, 0xfe, 0xff, 0xaf, 0x01, 0x00, 0x00, 0x00, 0xff, 0x3f, 0xe7, 0x00db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00;--------------------------------------------------------------------------------; /// Boot signature;--------------------------------------------------------------------------------addr_word_boot_signature:db 0x55, 0xaa

0 0
原创粉丝点击