如何在C#中向MBR写入消息且不破坏其初始化功能
问题:修改MBR显示自定义消息导致无法引导
我正在研究Windows的MBR(主引导记录),想通过修改它来显示类似“Hello, world!”的自定义消息。在GitHub上找到SyfuMBR和Fuc.MBR,但它们都是直接破坏MBR的,不符合我的需求。我改编了SyfuMBR的代码,结果重启后出现“FATAL: No bootable medium found! System halted.”错误。
我的改编代码如下:
[DllImport("kernel32")] private static extern IntPtr CreateFile( string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32")] private static extern bool WriteFile( IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped); private const uint GenericRead = 0x80000000; private const uint GenericWrite = 0x40000000; private const uint GenericExecute = 0x20000000; private const uint GenericAll = 0x10000000; private const uint FileShareRead = 0x1; private const uint FileShareWrite = 0x2; private const uint OpenExisting = 0x3; private const uint FileFlagDeleteOnClose = 0x4000000; private const uint MbrSize = 512u; public void Main() { var mbrData = Encoding.ASCII.GetBytes("Your computer has been Salatched :)"); var mbr = CreateFile("\\\\.\\PhysicalDrive0", GenericAll, FileShareRead | FileShareWrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero); try { WriteFile(mbr, mbrData, MbrSize, out uint lpNumberofBytesWritten, IntPtr.Zero); } catch { } }
调用代码:
MBR mbr = new MBR(); mbr.Main();
问题原因分析
你的代码直接用ASCII字符串覆盖了整个512字节的MBR,彻底破坏了MBR的核心结构:
- MBR前446字节是引导加载程序代码,负责初始化硬件并加载操作系统
- 接下来64字节是分区表,记录磁盘的分区信息
- 最后2字节是引导签名0xAA55,BIOS靠这个识别磁盘是否可引导
覆盖后,BIOS找不到合法的引导签名和分区表,自然会提示找不到可引导介质。
正确实现思路
要在MBR中显示自定义消息,必须保留MBR的原有结构,仅修改引导代码部分,添加显示字符串的汇编指令:
- 先读取原MBR的全部512字节数据,保留分区表(446-509字节)和引导签名(510-511字节)
- 将前446字节替换为包含显示消息功能的引导汇编代码(编译成机器码)
- 把修改后的完整512字节数据写回MBR
示例引导汇编代码(实现显示"Hello, world!")
org 0x7c00 ; BIOS加载MBR到内存0x7c00位置 mov ah, 0x0E ; BIOS中断:Teletype输出 mov bh, 0x00 ; 页码 mov bl, 0x07 ; 文本属性(白色黑底) ; 逐个字符输出字符串 mov al, 'H' int 0x10 mov al, 'e' int 0x10 mov al, 'l' int 0x10 mov al, 'l' int 0x10 mov al, 'o' int 0x10 mov al, ',' int 0x10 mov al, ' ' int 0x10 mov al, 'w' int 0x10 mov al, 'o' int 0x10 mov al, 'r' int 0x10 mov al, 'l' int 0x10 mov al, 'd' int 0x10 mov al, '!' int 0x10 jmp $ ; 无限循环,停留在当前画面 times 446-($-$$) db 0 ; 填充到446字节,预留分区表位置
将这段代码用NASM编译成二进制机器码(nasm -f bin mbr_msg.asm -o mbr_msg.bin),然后和原MBR的分区表、引导签名拼接成完整的512字节数据,再写入MBR。
修改后的C#代码思路
[DllImport("kernel32")] private static extern bool ReadFile( IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped); [DllImport("kernel32")] private static extern uint SetFilePointer( IntPtr hFile, int lDistanceToMove, IntPtr lpDistanceToMoveHigh, uint dwMoveMethod); public void ModifyMbrWithMessage() { // 1. 读取原MBR数据 var mbrHandle = CreateFile("\\\\.\\PhysicalDrive0", GenericRead | GenericWrite, FileShareRead | FileShareWrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero); if (mbrHandle == IntPtr.Zero) return; byte[] originalMbr = new byte[512]; ReadFile(mbrHandle, originalMbr, 512, out uint bytesRead, IntPtr.Zero); // 2. 加载编译好的引导代码(前446字节) byte[] bootCode = File.ReadAllBytes("mbr_msg.bin"); if (bootCode.Length > 446) throw new Exception("引导代码过长"); // 3. 拼接新MBR:引导代码 + 原分区表 + 原引导签名 byte[] newMbr = new byte[512]; Array.Copy(bootCode, newMbr, bootCode.Length); Array.Copy(originalMbr, 446, newMbr, 446, 66); // 分区表64字节+签名2字节 // 4. 写回MBR SetFilePointer(mbrHandle, 0, IntPtr.Zero, 0); // 定位到磁盘开头 WriteFile(mbrHandle, newMbr, 512, out uint bytesWritten, IntPtr.Zero); }
注意:修改MBR存在极高风险,操作前务必备份原MBR数据,并且在测试环境中操作,避免破坏正常系统。
内容的提问来源于stack exchange,提问作者Junior Plays
相关产品推荐
相关产品推荐

