;---------------------->8-------------- biosscan.nfo ; biosscan v2 secure boot Master Boot Record (MBR) ; copyright (c)2013 olivier.poudade.free.fr ; protects againts modifications of : vme, cpu, rom, nvr, mbr, chs, ivt, rst and kvm ; os compatibility : macosx, windows8, windows7, windows xp, windows vista, windows7, ubuntu, linux and all x86 architecture ; bios compatibility : Award 4.51PG, 6.00PG, AMI PnP 2.53, Microids and SeaBIOS ; size : 366 bytes ; test with boch, assemble with fasm ;---------------------->8-------------- biosscan.bat ; SET BXSHARE=c:\sourcecode\env ; SET ENVDEV=c:\sourcecode\env ; DEL %ENVDEV%\BIOSSCAN.BIN ; %ENVDEV%\FASM.EXE BIOSSCAN.ASM ; %ENVDEV%\VFD.EXE INSTALL VFD.SYS /A > NUL ; %ENVDEV%\VFD.EXE START > NUL ; %ENVDEV%\VFD.EXE CONFIG /M > NUL ; %ENVDEV%\VFD.EXE LINK 0 A > NUL ; %ENVDEV%\VFD.EXE OPEN A: /RAM /W /144 > NUL ; %ENVDEV%\VFD.EXE FORMAT A: /F > NUL ; %ENVDEV%\FASM.EXE BIOSSCAN.ASM ; %ENVDEV%\PARTCOPY.EXE BIOSSCAN.BIN 0 200 -f0 ; %ENVDEV%\BOCHS.EXE -q ; : %ENVDEV%\bochsdbg.exe ; %ENVDEV%\VFD.EXE STOP /F > NUL ; %ENVDEV%\VFD.EXE STOP /F > NUL ; %ENVDEV%\VFD.EXE STOP /F > NUL ; %ENVDEV%\VFD.EXE STOP /F > NUL ; %ENVDEV%\VFD.EXE REMOVE /F > NUL ;---------------------->8-------------- bochsrc.txt ;megs: 32 ;romimage: file=$BXSHARE/BIOS-bochs-latest ;vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest ;vga: extension=vbe ;floppya: 1_44=a:, status=inserted ;floppyb: 1_44=b.img, status=ejected ;ata0-master: type=disk, mode=flat, path="c.img" ;boot: floppy ;log: bochsout.txt ;mouse: enabled=0 ;cpu: ips=15000000 ;vga_update_interval: 150000 ;pci: enabled=1, chipset=i440fx # default if compiled with PCI support ;---------------------->8-------------- use16 ; vs. nasm [BITS 16] ; 16-bit mode VSCROLP equ 3363 ; number of on-screen pages (shadow segment+ivt)/(lines*len(ASCIIZ)=int(66560/24*59)+1=57 VSCROLL equ 24 ; 24 bytes per lines (here 59 lines) org 7c00h ; vs nasm [ORG 7c00h] ; add to offsets voodoo: mov di,0cf92h ; arbitrary location suitable for size optimization - cf. hereunder mov dword [di],0cf980010h ;60060010h ; [6002h]=6006h : gdt descriptor gdt address & [6000h]=10h : gdt descriptor gdt size nb:00*=base a00-a15,base a16-a23,segment access rights,limit 19:16+flags,base a24-a31 not word [di+14] ; mov word [600eh],0ffffh ; gdt descriptor segment limit mov word [di+19],di ;0cf92h ; gdt descriptor cf=present,ring 0 DPL,data,expand-up,writable 92h=32-bit page-granularity lgdt [di] ; load gdt table mov cr0,eax ; set control register 0 LSb push word 0008h ; select descriptor 1 pop ds ; 8h = 1000b push ds ; select descriptor 1 pop es ; 8h = 1000b dec ax ; back to realmode 1 byte shorter than and al,0feh / salc also less safe mov cr0,eax ; toggle LSbit back again dec dx ; cf. db 0eah,0f0h,0ffh,0,0f0h ; opcode "jmp far f000:fff0" (f000h:fff0h=Power On Reset Vector) -> SOFT RESET REBOOT push dx ; ie. push word 0ffffh push ax ; ie. push word 00h mov word [467h],porvent ; reentrant porvent ; 0fffbh;mbrbeg ; 40h:67h=POST real mode re-entry point offset in 256-byte BDA mov al,0fh ; 0fh=Shutdown Status Byte out 70h,al ; 70h=RTC/CMOS NVR chip index register mov al,0ah ; possible values : 05h=flush kbd+jmp[40h:67h] with EOI;0ah=jmp[40h:67h] without EOI;0bh=iret[40h:67h];0ch=retf[40h:67h] out 71h,al ; 71h=RTC/CMOS NVR chip data register payload:retf ; jmp far ffff:0000 or jmp far f000:fff0 blackholed here VME db "lels" ; "Parallels Software International" : 6ch,65h,6ch,73h db "inno" ; "innotek VirtualBox BIOS" : 69h,6eh,6eh,6fh db "VMwa" ; "VMware, Inc." : 56h,4dh,77h,61h db "al M" ; "Virtual Machine" (Sun Virtual PC) : 61h,6ch,20h,4dh db "imic" ; "Simics" (Virtual Simics) : 69h,6dh,69h,63h db "noch" ; "Bochs BIOS" : ??h,6fh,63h,68h db "QEMU" ; "QEMU BIOS" : 51h,45h,4dh,55h db 12h,11h,2h,31h ; FUN Load and Activate ROM 8x8 Character Set (ax=1112h bl=font block to load) ; mov ah,8 ; FUN read drive parameters porvent:mov edi,0fbfffh ; edi-> top of shadow rom bios scanvme:mov esi,VME ; esi-> VME signatures table mov cx,8 ; 7 VME signatures to test mov eax,cr4 ; get control register 4 LSw ; V86 flag=0 @ boot <- back to realmode 1 byte shorter than and al,0feh test ax,0100000000000000b ; test VMX enable flag jnz payload ; exit to blackhole testvme:db 67h ; 32-bit override lodsd ; mov eax,[esi] & add esi,4 cmp dword [edi],eax ; test this VME signature presence jz payload ; VME detected loop testvme ; repeat for all VME signatures scasb ; shorter than inc di bug? needs db 67h ? jnz scanvme ; if di=ffffh => rollover di=0000h genuine:int 10h ; VME not detected (native/genuine host); API BIOS video services xor ah,ah ; FUN set video mode (al=12h=video mode 640x480) int 10h ; API BIOS video services bswap eax ; i.e : mov ah,2 ; FUN read drive parameters al=nb of sectors to read mov esi,ebx ; save start of scanning address inc cx ; i.e. : mov cx,1 ch=track number=0 ; cl=start sector=1 (also LBA 64) but can be LBA 17 for CDs and DVDs int 13h ; API BIOS disk services : dh=head number=0 ; dl=drive number=80h mov cl,128 ; 40h-7H=ESCD extended system configuration data 7fh from CMOS reference moon.inf.uji.es/docs/interr/cmos/cmost.htm addcmos:mov al,cl ; index of nvr byte to read (NB : INTs and NMIs !=disabled) out 70h,al ; output the byte address to CMOS in al,71h ; read the CMOS byte mov byte [bx],al ; al contains cmos byte inc bx ; fill up overlay loop addcmos ; up to end of ESCD aad ; was xor ah,ah ; debug : ? need ah=0 for car color mov cx,VSCROLP-1 ; VSCROLP-1 pages to process because code will fall through below function one last time at the end mov fs,si bioscan:pushad ; save CX=on-screen page number ESI=start of window address call outbuff ; Registre à décalage à rétroaction linéaire - output 59x80 byte buffer to screen (omit top line) pointing to esi: start address of 4736-byte memory dump popad ; restore CX=on-screen page number ESI=start of window address sub esi,VSCROLL ; 24 chars x 59 lines loop bioscan ; repeat until all ivt+segment processed outbuff:mov cx,36;29;59 ; save one byte here if vscollp<256 with mov cl,59 59/60 lines to dump ; cursor y position=bottom (59 lines*24 bytes=1416 bytes/page) format : 60 lignes dont 59 utilisées : 4 octets adresse + 48 octets hexadecimal + 24 octets ASCIIZ allines:xor bx,bx ; 80 columns on each line ; cursor x position=right mov edx,esi ; read memory address printip:rol edx,4 ; get hexadecimal nibble in LSN position mov al,dl ; al=char=LSN call putchar ; put LSN binary nibble on screen test bl,8 ; test if column 4 reached yet jz printip ; else continue to print ip mov dl,56 ; set second column (ascii str) index mov bp,fs ; lfsr point base to 16-byte buffer start address oneline:call readout ; read one byte and output to screen 2 hexadecimal ascii nibbles push bx ; save 1st column column index mov bl,dl ; print one of 32 ascii bytes jp $+2 ; lfsr test odd parity of column number if even then do not store yet inc bp ; lfsr else store xor [bp],al ; lfsr xor 2 nibble of a byte call outchar ; start=68+(col-1(parity)-4)/2 inc dx ; bx starts at 68 and ends at 100 pop bx ; restort 1st column column index cmp bl,56 ; test if EOL reached : alternate cmp dl,maxchar jnz oneline ; repeat for all columns lfsrcrc:pushad ; save all 32-bit registers cmpxchg8b [bp-28] ;cmp 64 bit val EDX:EAX and destination operand : puts memory in EDX:EAX mov esi,edx ; 63-bit linear feedback shift register data integrity test xor cl,cl ; x = (x>>31)^(x>>30)^(x<<32) (mod 2^63) shld edx,eax,1 ; L1 = (b1<<1)|(b0>>31) shld esi,eax,2 ; L2 = (b1<<2)|(b0>>30); adc cl,cl ; H1 = (b1>>31) adc cl,cl smaller than adc cl,0 xor edx,esi ; H2 = (b1>>30) xchg eax,edx ; b1 = H1^H2^b0 &0x7FFFFFFF xor dl,cl ; b0 = L1^L2 xor [bp+2-28],eax ; i.e. : xor [6020h],eax store new lfsr64 MSDword as input xor [bp+6-28],edx ; i.e. : xor [6024h],edx store new lfsr64 LSDword as input popad ; restore all 32-bit registers loop allines ; decrement row number/test if top of page reached /repeat for all rows pushad ; save all 32-bit registers mov dx,16 ; 32 nibbles to print (old+new lfsr) mov esi,fs;0cf92h;6018h ; point to 16-byte buffer start address @here->cx=0 bx=68 outlfsr:call readout ; read one byte and output to screen 2 hexadecimal ascii nibbles dec dx ; test if all 32 nibbles have been printed jnz outlfsr ; if not then repeat until popad ; restore all 32-bit registers putchar:and al,0fh ; get LSN binary nibble in al cmp al,0ah ; bin2hex put binary nibble on screen/al=binary nibble sbb al,69h ; bin2hex 0-9: 96h .. 9Fh A-F: A1h..A6h das ; bin2hex 0-9: 66h -> 30h...39h A-F: 60h -> 41h...46h outchar:pushad ; save all 32-bit registers on stack (32 vs. 16 : need: Esi) lea esi,[0ffa6eh+8*eax] ; movcurs 0f000:0fa6e->IBM BIOS 128 character 8x8 rom fonts (8 bits x 8 bytes) lea edi,[0a2300h+1*ebx] ; movcurs 0a000+640*14lines:00000->start @ of vga mode 6eh/vesa mode 102h ; add 8 pixels (1 bytes) per column lea di,[di+640] ; movcurs loop : 3 bytes shorter than "add edi,imm16" ; 320h=1 480 pixel bitplane scanline loop $-4 ; movcurs loop number of rows times to previous line mov cl,8;7 ; outchar 8=font height -1 (inutile de recopier interligne) bitmask:db 67h ; outchar address size override prefix (db 067h) for code is 16-bit ; spares an "inc si" below movsb ; was mov byte [edi],al lea di,[di+79] ; outchar 1 byte shorter than "add di,imm16" loop bitmask ; outchar repeat for all height bitmasks popad ; restore all 32-bit registers on stack (32 vs. 16 : need: Esi) inc bx ; increment column number ret ; aka c3h readout:db 67h ; outchar address size override prefix (db 067h) for code is 16-bit ; spares an "inc si" below lodsb ; read MSN & LSN byte call nibbles ; display one nibble at at time nibbles:ror al,4 ; get MSN binary nibble in 4 LSb of al push ax ; save MSN & LSN byte call putchar ; put LSN binary nibble on screen pop ax ; restore MSN & LSN byte ret ; aka c3h lfsrsav db 0,0,0,0,0,0,0,0 ; saved lfsr times 510-($-$$) db 0 ; fill sector w/ 0's dw 0aa55h ; also 'push bp'/'stosb' opcodes but mostly unchecked because of 0aa55h vs. 055aah holly war