make your executable bootable

Started by ggnfs000, January 06, 2017, 06:02:05 PM

Previous topic - Next topic

ggnfs000

make your executable bootable

The generated executable file I build was DOS executable with MZ header. Did some analyze today at two executable file I generate: PMSW.EXE and EXP.EXE
PMSW.EXE - is a supposedly be a basis of kernel (long way to go)
EXP.EXE - to throw in any code experiment.

With hiew32 disassembler, did some quick analysis on two files using following link at hand:
http://www.delorie.com/djgpp/doc/exe/

PMSW.EXE
file offset 00: MZ signature (as expected)
file offset 08h(No. of paragraph) * 10h(paragraph) = offset to start of file, this was pointer to first segment in the program:
STACK.
file offset 14h = initial value of IP which is 0000h
file offset 16h = initial value of CS which is 09dch
file offset 800h was STACK with size 200h
file offset a00h was DATA segment which immediately follows STACK.
file offset a5c3 was code segment.

Obviously once this is run, it should start execute from a5c3h where code segment starts. But CS:IP was 09dc:0000h. This confused me initially but after some looking around:
a5c3 - 800 = 
CODE SEGMENT START - 1ST SEGMENT START (FILE START) = 
9dc3h which is almost 09dc:0000h but not quite, off by 3 bytes. I see at the 9dc:0000 there is following opcode present: B82000h, i did not write this code for sure but for some reason compiler inserted it. I decided to not bother with this since B82000h was a legitimate instruction, by quickly trying with hiew32:



The same analyz with EXP.EXE was pretty much same consistent. Decided to stop at this for today, here are the plan for next few days:

- defined bootstrap function. The function body must be less than 512 to fit into 0th sector of disk.
- with MBR legacy boot, the 0th sector of HDD is loaded into 0000:7c00h, the bootstrap code will create DAP (disk access packet) area at 0000:7e00h right after 0th sector load area. Once it creates DAP, it call INT13H BIOS 42H Extended Read to load the rest of program (I just hardcoded 64K for now) into 0000:8000h area and jumps directly to it. Haven't tested the following code but I will give it a try and see what happens.

Also, will need to create small program (linux equivalent of dd?) to do a raw copy of PMSW.EXE to sector 1 and so on and body of function bootStrap into sector 0 of HDD. Here is the bootstrap function (untested):

bootStrap   proc    far
    mov     dl, 80h             ; disk 0

    mov     si, 7e00h           ;
    mov     ds, si
    sub     si, si              ; (DS:SI) = 0000:7e00h = DAP area.

    mov     byte ptr ds:[si+DAP_OFFSET_SIZE], 10h
    mov     byte ptr ds:[si+DAP_OFFSET_UNUSED], 00h
    mov     word ptr ds:[si+DAP_OFFSET_NO_SECTORS], (400h * 64) ; copy 64k

    mov     word ptr ds:[si+DAP_OFFSET_BUFFER_PTR], 0
    mov     word ptr ds:[si+DAP_OFFSET_BUFFER_PTR+2], 8000h

    mov     dword ptr ds:[si+DAP_OFFSET_SECTOR_START], eax
    mov     dword ptr ds:[si+DAP_OFFSET_SECTOR_START+4], 0h ; set starting sector No for upper 48 lba.

    mov     ah, 42h             ; (AH) = fcn No. for extended disk read.
    int     13h

    sub     ax, ax
    mov     ds, ax
    mov     di, 8000h

    jmp     word ptr ds:[si]


2/1/2016
Lot of enhancement and testing after that, came up with following executables:
copyraw.exe - will copy bootable code to MBR (sector 0) and rest of code to Sector 1 and on.

Upon test with hyper-v, all images are copied to bootable vFDD and created 1GB HDD (vhd).
Noticed I can not write past sector 1 on this drive.

I setup virtual box on my workstation, with 512MB HDD with *.vdi extension, it worked.
The sector write function is using BIOS INT13h 43h (extended write call) and it performs readback from same sector after each sector write to verify. There is something about hyperv vhd that is not working well with BIOS INT13h 43h call.
Sector write with vbox with HDD with *.vdi extension

Sector write with vboc with HDD with *.vhd

*.vdi file - virtual box disk image with fixed size option.
*.vhd - hyper-v disk image that supports up to 2TB (2040GB) in size with fixed size option.

...
Decided to continue further with vbox for now. After finding couple of defects, I have found finally the raw copy works. I have decided to do a raw copy exp.exe code area to HDD starting from sector 1. Sector 0 contains boot code which copies the sector 1 and past data into memory and jumps to it.

The exp.exe executable is DOS and file offset 08h has the offset of end of the DOS header and beginning of actually file. The trouble is I organized the segments as STACK, DATA and CODE so CODE segment to jump into was harder to find. I re-ordered the segments as CODE, STACK and DATA, at which point, it is evident that it is compiled in a way that file offset 08h has direct offset into beginning of CODE which is at 40h in terms of number of paragraphs, therefore the byte offset is actually 400h.

In the copyraw.asm, I modified the code such that, during the read EXP.EXE and copy to HDD loop, it will ignore first 512 bytes of read (400h bytes) to zero into code segment and that will be written to starting from sector 1. After that it finally appeared to do a right raw copy:

Left: Using RW everything tool to check the HDD sectors (currently displaying sector 1)
Right: Using hiew32.exe disassembly tool to offset into 400h which is beginning of code segment of EXP.EXE


For next step, fired up the VM to boot from the HDD, however boot still failed.


I was not sure why it did cause this to happen, however I did one thing to make boot code to execute successfully. The partition table on legacy MBR is located on last 64-bytes (4 x 16 bytes entries per entry) of MBR (sector 0). I decided to save this area by first reading sector 0 (MBR) into memory buffer and overwrite up to fisrt 200h - 64 bytes and write back to MBR, thus saving partition table area. Therefore the boot code has to fit within 200h - 64 bytes within the MBR. After that, there is no longer boot error message above, but system was still hanging with blank screen with cursor at the beginning of screen. This means sector 1 area definitely not being loaded since it starts with PRINT statement. I decided to put loop print statement that writes directly to video buffer, once this is done, I can see the loop prints displayed upon boot, meaning the MBR code was executed successfully but jump to sector 1 did not succeed.














Source: make your executable bootable