实现电脑MBR保护锁

admin 2024年7月20日23:53:42评论39 views字数 7167阅读23分53秒阅读模式

实现电脑MBR保护锁

每个想要深入了解计算机低级工作规则原理的程序员都会考虑编写自己的操作系统。无论您的操作系统有多复杂,您需要做的第一件事就是实现主引导记录 (MBR)。MBR 是 BIOS 在可启动设备上执行的第一个程序。该文章介绍了如何实现使用密码保护的自定义 MBR。

操作系统加载理论,以及为什么我们需要 MBR

如第一段所述,MBR 是 BIOS 在可启动设备(硬盘驱动器、软盘或 USB 驱动器)上加载和执行的第一个程序。BIOS 执行以下步骤:

  • 读取我们从中启动的设备的前 512 个字节(第一个扇区);

  • 放入内存的 512 个字节,从0x7c00地址开始;

  • BIOS跳转到读取代码的0x7c00(第一条指令);

  • 之后,将执行 MBR(它可以检查分区表、加载操作系统内核或加载另一个引导加载程序)。

MBR结构式

实现电脑MBR保护锁

MBR包含:

linux

实现电脑MBR保护锁

  • 实现电脑MBR保护锁

  • 实现电脑MBR保护锁

  • windows

  • 实现电脑MBR保护锁

  • windows()

  • 实现电脑MBR保护锁

  • USB()

  • 实现电脑MBR保护锁

  • ()

  • 实现电脑MBR保护锁

  • ios

  • 实现电脑MBR保护锁

  • windbg

  • 实现电脑MBR保护锁

  • ()

  • 实现电脑MBR保护锁实现电脑MBR保护锁实现电脑MBR保护锁

  • 实现电脑MBR保护锁

  • 实现电脑MBR保护锁

  • 实现电脑MBR保护锁

  • 启动代码(可由 CPU 直接执行)

  • 分区表

  • 启动签名(两个字节0x55、0xAA),每个 MBR 都必须以这两个字节结尾。

通常,MBR 会检查分区表,找到活动分区并开始分区加载。

实现电脑MBR保护锁

在我们的例子中,我们希望使用密码保护我们的 MBR。为了简化我们的任务,我们将设置限制:

  • 我们的 MBR 将从软盘驱动器加载(因为我们不想损坏我们的“真实”MBR)

  • 密码将直接放入MBR

  • 计算机从软盘执行启动,要求用户输入密码,如果用户提供的密码与代码中的密码匹配,MBR 将从硬盘驱动器加载并执行“真正的”MBR。

我们需要哪些仪器:

  • 平面汇编机(FASM);

  • 模拟器(您可以尝试在 emu8086–8086 处理器模拟器中执行代码,它能够模拟从软盘加载,但不能模拟硬盘驱动器,或者您可以使用 Bochs 模拟器,它更接近真实计算机,但它的速度比 VirtualBox 或其他虚拟机管理程序慢得多)。

第一步

首先,我们将创建一个示例项目并编写以下代码:

org 7c00huse16
password_str db ‘Enter password:’, 0password db 6 dup(0)original_password db ‘OtUs77’, 0db 510-($-$$) dup(0), 0x55, 0xaabuf:

组织 7c00h 是一个指令,它告诉 FASM“我们的代码将在地址 7c00h(或0x7c00 - 它是一样的)加载。该指令很重要,因为没有它,FASM 就无法正确定义子程序的偏移量,并且可能会跳转到内存中的错误地址。

use16 告诉 FASM 生成 16 位代码。

password_str、password 和 original_password 是用于存储“输入密码:”的字符串,用户将输入的密码,以及保护我们的 MBR 免受未经身份验证的用户的密码。

最后两个字符串只是将字节0x55 0xAA放在 MBR 的末尾。

该代码不会执行任何操作,因为它没有定义任何操作,但现在我们有一个“样板”。让我们尝试向用户显示字符串“输入密码:”。

在屏幕上打印

为了在屏幕上打印任何 ASCII 字符,我们有一个中断 int10h。这个中断有几个功能,但我们只需要在屏幕上打印,所以我们使用这个中断的 0Eh 功能。

按如下方式使用 int10h

  • 将值 0Eh 放入 AH 寄存器;

  • 将打印字符的 ASCII 代码放入 AL 寄存器中;

  • 调用中断。

为了打印我们的字符串,我们将使用循环。

一点免责声明:在本文中,我们将实现一些过程,因此我们将使用调用约定 stdcall。这意味着可调用过程的参数将从右到左放入堆栈中(最后一个参数是第一个参数)。

org 7c00huse16; Load the “Enter password:” string address into AXlea ax, [password_str]; Push it to the stackpush ax; Call “print” subprogramcall print; Print functionprint:; Prologue. Save original BP value to the stackpush bp; Copy SP value to BP register, next time we will use BP instead of SP; Because we don’t need to corrupt its valuemov bp, sp; Set the CX register to zero, assembler’s loop uses CX as a loop counter, but we will print the characters, while we don’t get zero, means the end of the string (null-terminated strings indicate the end of the string by appending zero bytes)xor cx, cx; Copy the first argument — password_str address from the stack to the SI registermov si, [bp+4]; Printing looploop_print:; lodsb loads a byte from the address that is placed into the SI register and increments the SI value to the next byte. Byte, loaded by lodsb, is placed into AL registerlodsb; Check AL for the string terminatortest al, al; If we get the end of the string — loop endsjz end_print; If not, we call the int10h with 0Eh function to print the character from ALmov ah, 0Ehint 10hloop loop_print; Epilogue — restore original BP value and returnend_print:mov sp, bppop bpretpassword_str db ‘Enter password:’, 0password db 6 dup(0)original_password db ‘OtUs77’, 0db 510-($-$$) dup(0), 0x55, 0xaabuf:

尝试编译它并在任何模拟器中运行它。您将在屏幕上看到“输入密码:”字符串!那要好得多,你不觉得吗?

读取用户输入

我们已经成功处理了打印,现在我们需要读取用户的密码。如果我们有要打印的中断,我们就有要读取的中断。Int16h 及其 00h 函数执行键盘输入的读取。我们需要读取输入并将值存储到密码字符串中。

org 7c00huse16jmp loop_protectlea ax, [password_str]push axcall print; Save the address of the memory area, used to store the user’s inputlea di, 
		
输入密码查看隐藏内容

; Push it to the stack as the argument to the functionpush di; Call read functioncall readprint:push bpmov bp, spxor cx, cxmov si, [bp+4]loop_print:lodsbtest al, aljz end_printmov ah, 0Ehint 10hloop loop_printend_print:mov sp, bppop bpretread:; Prologue. Save BP and copy SP to BPpush bpmov bp, sp; We suppose that our password contains 6 characters or less, so users can input up to 6 characters, but not more. CX is used as the loop counter.mov cx, 6; Copy the password’s memory area address to the DI register. DI is used by the stosb command that saves byte from AH to the memory block, addressed by DI, and increases DI valuemov di, [bp+4]loop_read:; Input interrupt, we wait for the user’s inputmov ah, 0int 16h; Check the value, if the user presses Enter (1Ch code) — it is the end of the inputcmp ah, 1Ch; If input ends we don’t need to read moreje end_read; Save byte from AH to memory (address stored into DI)stosb; Print ‘*’ to the screen so that the user may see the keyboard works :)mov ah, 0Ehmov al, 2Ahint 10hloop loop_readend_read:mov sp, bppop bpretpassword_str db ‘Enter password:’, 0password db 6 dup(0)original_password db ‘OtUs77’, 0db 510-($-$$) dup(0), 0x55, 0xaabuf:

结束我们的打印-读取周期,我们有“输入密码:”输出和用户输入处理。接下来,我们需要比较密码。因此,我们将实现“check_password”功能。

org 7c00huse16lea ax, [password_str]push axcall printlea di, 
		
输入密码查看隐藏内容

push dicall read; Load user input to DI and push it to the stacklea di,
输入密码查看隐藏内容

push di; Load the original password to DI and push it to the stacklea di, [original_password]push di; Call checkcall check_passwordprint:; Printread:; Readcheck_password:push bpmov bp, sp; First of all, we need to clear registers AX, BX, and DX.; We will use only the lodsb command that loads a byte into the AL register, so we need to load a byte of the user’s input, and original password, and compare them. DX will be used as temp SI value, because lodsb increases SI, but we have two different memory areas, from which we load bytes.xor ax, axxor bx, bxxor dx, dx; Only 6 charactersmov cx, 6; Load the first argument from the stackmov si, [bp+4]; Load the second argument from the stackmov dx, [bp+6]; Loop for checking bytes equality one-by-oneloop_check:; Load the first byte of the original passwordlodsb; Move it to BX, because the next lodsb will change the AL valuemov bx, ax; Save SI — memory address of original password byte, that will be read next time we call lodsbpush si; Restore user’s password memory address from DX and read byte to ALmov si, dxlodsb; compare AX with BX. CMP will set ZF flag if AX and BX are equalcmp bx, ax; If the bytes are not equal ZF will be 0 and we will end the checkjz end_check; Move to the next bytes, save SI for the user’s password to DX, and restore SI value of the original password from the stack. The check will go to compare the next bytes and stop when CX becomes zero (all bytes are checked), or when the unequal bytes were found.mov dx, sipop siloop loop_checkend_check:mov sp, bppop bpretpassword_str db ‘Enter password:’, 0password db 6 dup(0)original_password db ‘OtUs77’, 0db 510-($-$$) dup(0), 0x55, 0xaabuf:

好吧!现在我们可以:

  • 向用户显示“输入密码:”字符串;

  • 读取密码;

  • 比较密码。

我们所需要的只是实现原始的 MBR 加载和执行。为此,我们需要执行以下步骤:

  • 将我们当前的MBR代码备份到不同的内存位置;

  • 将控制权传递给我们的 MBR 副本;

  • 将原始 MBR 代码加载到 0x7c00;

  • 跳转到0x7c00

org 7c00huse16; While users are not passing the correct password we will ask them to inputjmp loop_protectloop_protect:lea ax, [password_str]push axcall printlea di, 
		
输入密码查看隐藏内容

push dicall readlea di,
输入密码查看隐藏内容

push dilea di, [original_password]push dicall check_password; Clear the screenmov ax, 0int 10h; If check_password doesn’t clear the ZF flag — passwords are equal, we can proceedjnz load_mbrloop loop_protect; Save our custom MBR and do a different locationload_mbr:; Clear interruptscli; Clear the registers and save the original MBR entry point to the stackMOV SP, 0x7c00XOR AX, AXMOV SS, AXMOV ES, AXMOV DS, AXPUSH DX; From which memory address we will get bytesmov si, 0x7c00; Where we will store bytesmov di, 0x0600; How many bytes to copy (0x200 = 512)mov cx, 0x200; Clear direction flagcld; Repeatedly copy bytes from DI to SI memory addresses while CX is not zerorep movsb; Jump to stage2 — executing of our original MBR (i used constant addresses because FASM calculates offsets from 0x7c00)jmp near stage2 — $$ + 0x0600 ; calc right offset to jump; load the original MBRstage2:; Enable interruptssti; Prepare to read, BX indicates the original MBR location because int13h will load sectors to ES:BX addressmov bx, 0x7c00; Read the first sector from the hard drive by int13h interrupt; AH = 02h means “read sector” functionmov ah, 02h; Sectors countmov al, 1; HDD number (80h means the first HDD)mov dl, 80h; Track numbermov ch, 0; Head numbermov dh, 0; Sector numbermov cl, 1; Call the interruptint 13h; Jump to original MBR code, loaded to 0x7c00jmp $$ + 0x7600 ; in case of jmp problemsprint:; printread:; readcheck_password:; check passwordpassword_str db ‘Enter password:’, 0password db 6 dup(0)original_password db ‘OtUs77’, 0db 510-($-$$) dup(0), 0x55, 0xaabuf:

现在,您可以生成并执行代码。

原文始发于微信公众号(安全狗的自我修养):实现电脑MBR保护锁

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年7月20日23:53:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   实现电脑MBR保护锁https://cn-sec.com/archives/2776885.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息