Boot Loader: boot0 | |
; | |
; A small boot sector program written in x86 assembly whose only | |
; responsibility is to locate the active partition, load the | |
; partition booter into memory, and jump to the booter's entry point. | |
; It leaves the boot drive in DL and a pointer to the partition entry in SI. | |
; | |
; This boot loader must be placed in the Master Boot Record. | |
; | |
; In order to coexist with a fdisk partition table (64 bytes), and | |
; leave room for a two byte signature (0xAA55) in the end, boot0 is | |
; restricted to 446 bytes (512 - 64 - 2). If boot0 did not have to | |
; live in the MBR, then we would have 510 bytes to work with. | |
; | |
; boot0 is always loaded by the BIOS or another booter to 0:7C00h. | |
; | |
; This code is written for the NASM assembler. | |
; nasm boot0.s -o boot0 | |
; | |
; This version of boot0 implements hybrid GUID/MBR partition scheme support | |
; | |
; Written by Tamás Kosárszky on 2008-03-10 and JrCs on 2013-05-08. | |
; | |
; Turbo added EFI System Partition boot support | |
; | |
; Added KillerJK's switchPass2 modifications | |
; | |
; JrCs added FAT32/exFAT System Partition boot support on GPT pure partition scheme | |
; | |
; | |
; boot0af and boot0ss share the same code except. | |
; The ACTIVEFIRST macro is used to select the right code | |
; boot0af - define ACTIVEFIRST | |
; boot0ss - do not define ACTIVEFIRST | |
; | |
; | |
; Set to 1 to enable obscure debug messages. | |
; | |
DEBUG EQU 0 | |
; | |
; Set to 1 to enable verbose mode | |
; | |
VERBOSE EQU 0 | |
; | |
; Various constants. | |
; | |
kBoot0Segment EQU 0x0000 | |
kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer | |
kBoot0LoadAddr EQU 0x7C00 ; boot0 load address | |
kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address | |
kMBRBuffer EQU 0x1000 ; MBR buffer address | |
kLBA1Buffer EQU 0x1200 ; LBA1 - GPT Partition Table Header buffer address | |
kGPTABuffer EQU 0x1400 ; GUID Partition Entry Array buffer address | |
kPartTableOffset EQU 0x1be | |
kMBRPartTable EQU kMBRBuffer + kPartTableOffset | |
kSectorBytes EQU 512 ; sector size in bytes | |
kBootSignature EQU 0xAA55 ; boot sector signature | |
kHFSPSignature EQU 'H+' ; HFS+ volume signature | |
kHFSPCaseSignature EQU 'HX' ; HFS+ volume case-sensitive signature | |
kEXFATSignature EQU 'EX' ; exFAT volume signature | |
kFAT32BootCodeOffset EQU 0x5a ; offset of boot code in FAT32 boot sector | |
kBoot1FAT32Magic EQU 'BO' ; Magic string to detect our boot1f32 code | |
kGPTSignatureLow EQU 'EFI ' ; GUID Partition Table Header Signature | |
kGPTSignatureHigh EQU 'PART' | |
kGUIDLastDwordOffs EQU 12 ; last 4 byte offset of a GUID | |
kPartCount EQU 4 ; number of paritions per table | |
kPartTypeEXFAT EQU 0x07 ; exFAT Filesystem type | |
kPartTypeFAT32 EQU 0x0c ; FAT32 Filesystem type | |
kPartTypeHFS EQU 0xaf ; HFS+ Filesystem type | |
kPartTypePMBR EQU 0xee ; On all GUID Partition Table disks a Protective MBR (PMBR) | |
; in LBA 0 (that is, the first block) precedes the | |
; GUID Partition Table Header to maintain compatibility | |
; with existing tools that do not understand GPT partition structures. | |
; The Protective MBR has the same format as a legacy MBR | |
; and contains one partition entry with an OSType set to 0xEE | |
; reserving the entire space used on the disk by the GPT partitions, | |
; including all headers. | |
kPartActive EQU 0x80 ; active flag enabled | |
kPartInactive EQU 0x00 ; active flag disabled | |
kAppleGUID EQU 0xACEC4365 ; last 4 bytes of Apple type GUIDs. | |
kEFISystemGUID EQU 0x3BC93EC9 ; last 4 bytes of EFI System Partition Type GUID: | |
; C12A7328-F81F-11D2-BA4B-00A0C93EC93B | |
kBasicDataGUID EQU 0xC79926B7 ; last 4 bytes of Basic Data System Partition Type GUID: | |
; EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 | |
%ifdef FLOPPY | |
kDriveNumber EQU 0x00 | |
%else | |
kDriveNumber EQU 0x80 | |
%endif | |
; | |
; Format of fdisk partition entry. | |
; | |
; The symbol 'part_size' is automatically defined as an `EQU' | |
; giving the size of the structure. | |
; | |
struc part | |
.bootid resb 1 ; bootable or not | |
.head resb 1 ; starting head, sector, cylinder | |
.sect resb 1 ; | |
.cyl resb 1 ; | |
.type resb 1 ; partition type | |
.endhead resb 1 ; ending head, sector, cylinder | |
.endsect resb 1 ; | |
.endcyl resb 1 ; | |
.lba resd 1 ; starting lba | |
.sectors resd 1 ; size in sectors | |
endstruc | |
; | |
; Format of GPT Partition Table Header | |
; | |
struc gpth | |
.Signature resb 8 | |
.Revision resb 4 | |
.HeaderSize resb 4 | |
.HeaderCRC32 resb 4 | |
.Reserved resb 4 | |
.MyLBA resb 8 | |
.AlternateLBA resb 8 | |
.FirstUsableLBA resb 8 | |
.LastUsableLBA resb 8 | |
.DiskGUID resb 16 | |
.PartitionEntryLBA resb 8 | |
.NumberOfPartitionEntries resb 4 | |
.SizeOfPartitionEntry resb 4 | |
.PartitionEntryArrayCRC32 resb 4 | |
endstruc | |
; | |
; Format of GUID Partition Entry Array | |
; | |
struc gpta | |
.PartitionTypeGUID resb 16 | |
.UniquePartitionGUID resb 16 | |
.StartingLBA resb 8 | |
.EndingLBA resb 8 | |
.Attributes resb 8 | |
.PartitionName resb 72 | |
endstruc | |
; | |
; Macros. | |
; | |
%macro DebugCharMacro 1 | |
mov al, %1 | |
call print_char | |
%endmacro | |
%macro LogString 1 | |
mov di, %1 | |
call log_string | |
%endmacro | |
%if DEBUG | |
%define DebugChar(x) DebugCharMacro x | |
%else | |
%define DebugChar(x) | |
%endif | |
;-------------------------------------------------------------------------- | |
; Start of text segment. | |
SEGMENT .text | |
ORG kBoot0RelocAddr | |
;-------------------------------------------------------------------------- | |
; Boot code is loaded at 0:7C00h. | |
; | |
start: | |
; | |
; Set up the stack to grow down from kBoot0Segment:kBoot0Stack. | |
; Interrupts should be off while the stack is being manipulated. | |
; | |
cli ; interrupts off | |
xor ax, ax ; zero ax | |
mov ss, ax ; ss <- 0="" span="">-> | |
mov sp, kBoot0Stack ; sp <- of="" span="" stack="" top="">-> | |
sti ; reenable interrupts | |
mov es, ax ; es <- 0="" span="">-> | |
mov ds, ax ; ds <- 0="" span="">-> | |
; | |
; Relocate boot0 code. | |
; | |
mov si, kBoot0LoadAddr ; si <- source="" span="">-> | |
mov di, kBoot0RelocAddr ; di <- destination="" span="">-> | |
cld ; auto-increment SI and/or DI registers | |
mov cx, kSectorBytes/2 ; copy 256 words | |
repnz movsw ; repeat string move (word) operation | |
; | |
; Code relocated, jump to start_reloc in relocated location. | |
; | |
jmp kBoot0Segment:start_reloc | |
;-------------------------------------------------------------------------- | |
; Start execution from the relocated location. | |
; | |
start_reloc: | |
DebugChar('>') | |
%if DEBUG | |
mov al, dl | |
call print_hex | |
%endif | |
; | |
; Since this code may not always reside in the MBR, always start by | |
; loading the MBR to kMBRBuffer and LBA1 to kGPTBuffer. | |
; | |
xor eax, eax | |
mov [my_lba], eax ; store LBA sector 0 for read_lba function | |
mov al, 2 ; load two sectors: MBR and LBA1 | |
mov bx, kMBRBuffer ; MBR load address | |
call load | |
jc error ; MBR load error | |
; | |
; Look for the booter partition in the MBR partition table, | |
; which is at offset kMBRPartTable. | |
; | |
mov si, kMBRPartTable ; pointer to partition table | |
call find_boot ; will not return on success | |
error: | |
LogString(boot_error_str) | |
hang: | |
hlt | |
jmp hang | |
;-------------------------------------------------------------------------- | |
; Find the active (boot) partition and load the booter from the partition. | |
; | |
; Arguments: | |
; DL = drive number (0x80 + unit number) | |
; SI = pointer to fdisk partition table. | |
; | |
; Clobber list: | |
; EAX, BX, EBP | |
; | |
find_boot: | |
; | |
; Check for boot block signature 0xAA55 following the 4 partition | |
; entries. | |
; | |
cmp WORD [si + part_size * kPartCount], kBootSignature | |
jne .exit ; boot signature not found. | |
xor bx, bx ; BL will be set to 1 later in case of | |
; Protective MBR has been found | |
inc bh ; BH = 1. Giving a chance for a second pass | |
; to boot an inactive but boot1h aware HFS+ partition | |
; by scanning the MBR partition entries again. | |
.start_scan: | |
mov cx, kPartCount ; number of partition entries per table | |
.loop: | |
; | |
; First scan through the partition table looking for the active | |
; partition. | |
; | |
%if DEBUG | |
mov al, [si + part.type] ; print partition type | |
call print_hex | |
%endif | |
mov eax, [si + part.lba] ; save starting LBA of current | |
mov [my_lba], eax ; MBR partition entry for read_lba function | |
cmp BYTE [si + part.type], 0 ; unused partition? | |
je .continue ; skip to next entry | |
cmp BYTE [si + part.type], kPartTypePMBR ; check for Protective MBR | |
jne .testPass | |
mov BYTE [si + part.bootid], kPartInactive ; found Protective MBR | |
; clear active flag to make sure this protective | |
; partition won't be used as a bootable partition. | |
mov bl, 1 ; Assume we can deal with GPT but try to scan | |
; later if not found any other bootable partitions. | |
.testPass: | |
cmp bh, 1 | |
jne .Pass2 | |
.Pass1: | |
%ifdef ACTIVEFIRST | |
jmp SHORT .tryToBootIfActive | |
%else | |
jmp SHORT .tryToBootSupportedFS | |
%endif | |
.Pass2: | |
%ifdef ACTIVEFIRST | |
jmp SHORT .tryToBootSupportedFS | |
%endif | |
.tryToBootIfActive: | |
; We're going to try to boot a partition if it is active | |
cmp BYTE [si + part.bootid], kPartActive | |
jne .continue | |
xor dh, dh ; Argument for loadBootSector to skip file system signature check. | |
jmp SHORT .tryToBoot | |
.tryToBootSupportedFS: | |
; We're going to try to boot a partition with a supported filesystem | |
; equipped with boot1x in its boot record regardless if it's active or not. | |
mov dh, 1 ; Argument for loadBootSector to check file system signature. | |
cmp BYTE [si + part.type], kPartTypeHFS | |
je .tryToBoot | |
cmp BYTE [si + part.type], kPartTypeFAT32 | |
je .tryToBoot | |
cmp BYTE [si + part.type], kPartTypeEXFAT | |
jne .continue | |
.tryToBoot: | |
; | |
; Found boot partition, read boot sector to memory. | |
; | |
call loadBootSector | |
jne .continue | |
jmp SHORT initBootLoader | |
.continue: | |
add si, BYTE part_size ; advance SI to next partition entry | |
loop .loop ; loop through all partition entries | |
; | |
; Scanned all partitions but not found any with active flag enabled | |
; Anyway if we found a protective MBR before we still have a chance | |
; for a possible GPT Header at LBA 1 | |
; | |
dec bl | |
jnz .switchPass2 ; didn't find Protective MBR before | |
call checkGPT | |
.switchPass2: | |
; | |
; Switching to Pass 2 | |
; try to find a boot1h aware HFS+ MBR partition | |
; | |
dec bh | |
mov si, kMBRPartTable ; set SI to first entry of MBR Partition table | |
jz .start_scan ; scan again | |
.exit: | |
ret ; Giving up. | |
; | |
; Jump to partition booter. The drive number is already in register DL. | |
; SI is pointing to the modified partition entry. | |
; | |
initBootLoader: | |
DebugChar('J') | |
%if VERBOSE | |
LogString(done_str) | |
%endif | |
jmp kBoot0LoadAddr | |
; | |
; Found Protective MBR Partition Type: 0xEE | |
; Check for 'EFI PART' string at the beginning | |
; of LBA1 for possible GPT Table Header | |
; | |
checkGPT: | |
push bx | |
mov di, kLBA1Buffer ; address of GUID Partition Table Header | |
cmp DWORD [di], kGPTSignatureLow ; looking for 'EFI ' | |
jne .exit ; not found. Giving up. | |
cmp DWORD [di + 4], kGPTSignatureHigh ; looking for 'PART' | |
jne .exit ; not found. Giving up indeed. | |
mov si, di | |
; | |
; Loading GUID Partition Table Array | |
; | |
mov eax, [si + gpth.PartitionEntryLBA] ; starting LBA of GPT Array | |
mov [my_lba], eax ; save starting LBA for read_lba function | |
mov cx, [si + gpth.NumberOfPartitionEntries] ; number of GUID Partition Array entries | |
mov bx, [si + gpth.SizeOfPartitionEntry] ; size of GUID Partition Array entry | |
push bx ; push size of GUID Partition entry | |
; | |
; Calculating number of sectors we need to read for loading a GPT Array | |
; | |
; push dx ; preserve DX (DL = BIOS drive unit number) | |
; mov ax, cx ; AX * BX = number of entries * size of one entry | |
; mul bx ; AX = total byte size of GPT Array | |
; pop dx ; restore DX | |
; shr ax, 9 ; convert to sectors | |
; | |
; ... or: | |
; Current GPT Arrays uses 128 partition entries each 128 bytes long | |
; 128 entries * 128 bytes long GPT Array entries / 512 bytes per sector = 32 sectors | |
; | |
mov al, 32 ; maximum sector size of GPT Array (hardcoded method) | |
mov bx, kGPTABuffer | |
push bx ; push address of GPT Array | |
call load ; read GPT Array | |
pop si ; SI = address of GPT Array | |
pop bx ; BX = size of GUID Partition Array entry | |
jc error | |
; | |
; Walk through GUID Partition Table Array | |
; and load boot record from first supported partition. | |
; | |
; If it has boot signature (0xAA55) then jump to it | |
; otherwise skip to next partition. | |
; | |
%if VERBOSE | |
LogString(gpt_str) | |
%endif | |
.gpt_loop: | |
mov eax, [si + gpta.PartitionTypeGUID + kGUIDLastDwordOffs] | |
cmp eax, kAppleGUID ; check current GUID Partition for Apple's GUID type | |
je .gpt_ok | |
; | |
; Turbo - also try EFI System Partition | |
; | |
cmp eax, kEFISystemGUID ; check current GUID Partition for EFI System Partition GUID type | |
je .gpt_ok | |
; | |
; JrCs - also try FAT2 System Partition | |
; | |
cmp eax, kBasicDataGUID ; check current GUID Partition for Basic Data Partition GUID type | |
jne .gpt_continue | |
.gpt_ok: | |
; | |
; Found a possible good partition try to boot it | |
; | |
mov eax, [si + gpta.StartingLBA] ; load boot sector from StartingLBA | |
mov [my_lba], eax | |
mov dh, 1 ; Argument for loadBootSector to check file system signature. | |
call loadBootSector | |
jne .gpt_continue ; no boot loader signature | |
mov si, kMBRPartTable ; fake the current GUID Partition | |
mov [si + part.lba], eax ; as MBR style partition for boot1h | |
mov BYTE [si + part.type], kPartTypeHFS ; with HFS+ filesystem type (0xAF) | |
jmp SHORT initBootLoader | |
.gpt_continue: | |
add si, bx ; advance SI to next partition entry | |
loop .gpt_loop ; loop through all partition entries | |
.exit: | |
pop bx | |
ret ; no more GUID partitions. Giving up. | |
;-------------------------------------------------------------------------- | |
; loadBootSector - Load boot sector | |
; | |
; Arguments: | |
; DL = drive number (0x80 + unit number) | |
; DH = 0 skip file system signature checking | |
; 1 enable file system signature checking | |
; [my_lba] = starting LBA. | |
; | |
; Returns: | |
; ZF = 0 if boot sector hasn't kBootSignature | |
; 1 if boot sector has kBootSignature | |
; | |
loadBootSector: | |
pusha | |
mov al, 3 | |
mov bx, kBoot0LoadAddr | |
call load | |
jc error | |
or dh, dh | |
jz .checkBootSignature | |
.checkHFSSignature: | |
%if VERBOSE | |
LogString(test_str) | |
%endif | |
; | |
; Looking for HFSPlus ('H+') or HFSPlus case-sensitive ('HX') signature. | |
; | |
mov ax, [kBoot0LoadAddr + 2 * kSectorBytes] | |
cmp ax, kHFSPSignature ; 'H+' | |
je .checkBootSignature | |
cmp ax, kHFSPCaseSignature ; 'HX' | |
je .checkBootSignature | |
; | |
; Looking for exFAT signature | |
; | |
mov ax, [kBoot0LoadAddr + 3] | |
cmp ax, kEXFATSignature ; 'EX' | |
je .checkBootSignature | |
; | |
; Looking for boot1f32 magic string. | |
; | |
mov ax, [kBoot0LoadAddr + kFAT32BootCodeOffset] | |
cmp ax, kBoot1FAT32Magic | |
jne .exit | |
.checkBootSignature: | |
; | |
; Check for boot block signature 0xAA55 | |
; | |
cmp WORD [kBoot0LoadAddr + kSectorBytes - 2], kBootSignature | |
.exit: | |
popa | |
ret | |
;-------------------------------------------------------------------------- | |
; load - Load one or more sectors from a partition. | |
; | |
; Arguments: | |
; AL = number of 512-byte sectors to read. | |
; ES:BX = pointer to where the sectors should be stored. | |
; DL = drive number (0x80 + unit number) | |
; [my_lba] = starting LBA. | |
; | |
; Returns: | |
; CF = 0 success | |
; 1 error | |
; | |
load: | |
push cx | |
.ebios: | |
mov cx, 5 ; load retry count | |
.ebios_loop: | |
call read_lba ; use INT13/F42 | |
jnc .exit | |
loop .ebios_loop | |
.exit: | |
pop cx | |
ret | |
;-------------------------------------------------------------------------- | |
; read_lba - Read sectors from a partition using LBA addressing. | |
; | |
; Arguments: | |
; AL = number of 512-byte sectors to read (valid from 1-127). | |
; ES:BX = pointer to where the sectors should be stored. | |
; DL = drive number (0x80 + unit number) | |
; [my_lba] = starting LBA. | |
; | |
; Returns: | |
; CF = 0 success | |
; 1 error | |
; | |
read_lba: | |
pushad ; save all registers | |
mov bp, sp ; save current SP | |
; | |
; Create the Disk Address Packet structure for the | |
; INT13/F42 (Extended Read Sectors) on the stack. | |
; | |
; push DWORD 0 ; offset 12, upper 32-bit LBA | |
push ds ; For sake of saving memory, | |
push ds ; push DS register, which is 0. | |
mov ecx, [my_lba] ; offset 8, lower 32-bit LBA | |
push ecx | |
push es ; offset 6, memory segment | |
push bx ; offset 4, memory offset | |
xor ah, ah ; offset 3, must be 0 | |
push ax ; offset 2, number of sectors | |
; It pushes 2 bytes with a smaller opcode than if WORD was used | |
push BYTE 16 ; offset 0-1, packet size | |
DebugChar('<') | |
%if DEBUG | |
mov eax, ecx | |
call print_hex | |
%endif | |
; | |
; INT13 Func 42 - Extended Read Sectors | |
; | |
; Arguments: | |
; AH = 0x42 | |
; DL = drive number (80h + drive unit) | |
; DS:SI = pointer to Disk Address Packet | |
; | |
; Returns: | |
; AH = return status (sucess is 0) | |
; carry = 0 success | |
; 1 error | |
; | |
; Packet offset 2 indicates the number of sectors read | |
; successfully. | |
; | |
mov si, sp | |
mov ah, 0x42 | |
int 0x13 | |
jnc .exit | |
DebugChar('R') ; indicate INT13/F42 error | |
; | |
; Issue a disk reset on error. | |
; Should this be changed to Func 0xD to skip the diskette controller | |
; reset? | |
; | |
xor ax, ax ; Func 0 | |
int 0x13 ; INT 13 | |
stc ; set carry to indicate error | |
.exit: | |
mov sp, bp ; restore SP | |
popad | |
ret | |
;-------------------------------------------------------------------------- | |
; Write a string with 'boot0: ' prefix to the console. | |
; | |
; Arguments: | |
; ES:DI pointer to a NULL terminated string. | |
; | |
; Clobber list: | |
; DI | |
; | |
log_string: | |
pusha | |
push di | |
mov si, log_title_str | |
call print_string | |
pop si | |
call print_string | |
popa | |
ret | |
;-------------------------------------------------------------------------- | |
; Write a string to the console. | |
; | |
; Arguments: | |
; DS:SI pointer to a NULL terminated string. | |
; | |
; Clobber list: | |
; AX, BX, SI | |
; | |
print_string: | |
mov bx, 1 ; BH=0, BL=1 (blue) | |
cld ; increment SI after each lodsb call | |
.loop: | |
lodsb ; load a byte from DS:SI into AL | |
cmp al, 0 ; Is it a NULL? | |
je .exit ; yes, all done | |
mov ah, 0xE ; INT10 Func 0xE | |
int 0x10 ; display byte in tty mode | |
jmp short .loop | |
.exit: | |
ret | |
%if DEBUG | |
;-------------------------------------------------------------------------- | |
; Write a ASCII character to the console. | |
; | |
; Arguments: | |
; AL = ASCII character. | |
; | |
print_char: | |
pusha | |
mov bx, 1 ; BH=0, BL=1 (blue) | |
mov ah, 0x0e ; bios INT 10, Function 0xE | |
int 0x10 ; display byte in tty mode | |
popa | |
ret | |
;-------------------------------------------------------------------------- | |
; Write the 4-byte value to the console in hex. | |
; | |
; Arguments: | |
; EAX = Value to be displayed in hex. | |
; | |
print_hex: | |
pushad | |
mov cx, WORD 4 | |
bswap eax | |
.loop: | |
push ax | |
ror al, 4 | |
call print_nibble ; display upper nibble | |
pop ax | |
call print_nibble ; display lower nibble | |
ror eax, 8 | |
loop .loop | |
mov al, 10 ; carriage return | |
call print_char | |
mov al, 13 | |
call print_char | |
popad | |
ret | |
print_nibble: | |
and al, 0x0f | |
add al, '0' | |
cmp al, '9' | |
jna .print_ascii | |
add al, 'A' - '9' - 1 | |
.print_ascii: | |
call print_char | |
ret | |
getc: | |
pusha | |
mov ah, 0 | |
int 0x16 | |
popa | |
ret | |
%endif ;DEBUG | |
;-------------------------------------------------------------------------- | |
; NULL terminated strings. | |
; | |
%if VERBOSE | |
gpt_str db 'GPT', 0 | |
test_str db 'test', 0 | |
done_str db 'done', 0 | |
%endif | |
boot_error_str db 'error', 0 | |
;-------------------------------------------------------------------------- | |
; Pad the rest of the 512 byte sized booter with zeroes. The last | |
; two bytes is the mandatory boot sector signature. | |
; | |
; If the booter code becomes too large, then nasm will complain | |
; that the 'times' argument is negative. | |
; | |
; According to EFI specification, maximum boot code size is 440 bytes | |
; | |
pad_boot: | |
times 428-($-$$) db 0 ; 428 = 440 - len(log_title_str) | |
log_title_str: | |
%ifdef ACTIVEFIRST | |
db 10, 13, 'boot0af: ', 0 ; can be use as signature | |
%else | |
db 10, 13, 'boot0ss: ', 0 ; can be use as signature | |
%endif | |
pad_table_and_sig: | |
times 510-($-$$) db 0 | |
dw kBootSignature | |
ABSOLUTE 0xE400 | |
; | |
; In memory variables. | |
; | |
my_lba resd 1 ; Starting LBA for read_lba function | |
; END https://github.com/Clover-EFI-Bootloader/clover/blob/master/BootHFS/boot0.s |
Friday, October 27, 2017
talking about "bad rabbit" or "petya" or MTR fake bootloader, here's the code
Ok, God damm it...how do they hide?
This guide explains how to change squid caching proxy server outgoing IP address either based on usernames / subnets or multiple IPs.
CYBERCITI.BIZ
Subscribe to:
Posts (Atom)
Hack mil elsa GET REQUEST special character defesa.pt
https://example.com/api/data?query=hello%20world https://example.com/api/data?search=rock%26roll%3Dawesome%23fun https://intranet.marinha....
