Skip to content

Instantly share code, notes, and snippets.

@gynvael
Created January 23, 2019 11:20
Show Gist options
  • Save gynvael/772301c0924f8db4d2a050e9d772da3c to your computer and use it in GitHub Desktop.
Save gynvael/772301c0924f8db4d2a050e9d772da3c to your computer and use it in GitHub Desktop.
32-bit PE loader from OSAmber (part of bootloader)
[bits 16]
[org 0x0]
%define SEGMENT_PHYSICAL_ADDR 0x20000
%define SEGNO(segno,ti,rpl) (segno*8+ti*4+rpl)
%define PADDR(a) (a+SEGMENT_PHYSICAL_ADDR)
%define PEIMAGE_PADDR 0x20200
%define IDOSH_LFANEW 0x3C
%define IOPTH_IMGSIZE 0x50
%define IOPTH_IMGBASE 0x34
%define IOPTH_ENTRYPOINT 0x28
; Assumptions:
; cs == 0x2000
; ip == 0
start:
; Set ds same to cs
mov ax, cs
mov ds, ax
; Switch to protected mode
; Block interrupts
cli
; Load the GDT address into GDTR
lgdt [initial_gdt_table_desc]
; Set protected mode flag
mov eax, cr0
or al, 1
; Enter the flag and jump
mov cr0, eax
jmp dword SEGNO(1,0,0):PADDR(pmode_start) ; first segment,
; Yep, we are in the protected mode
[bits 32]
pmode_start:
; Re set the other segment regs
; fs and gs will not be used for now
mov ax, SEGNO(2,0,0)
mov ds, ax
mov es, ax
mov ss, ax
; Set the stack somewhere
mov esp, 0x800000 ; For now it will be enough (from 8MB down)
;
; Mini PE Loader
; Load the PE image and jump to EP
;
; Get the IMAGE_DOS_HEADER.e_lfanew
mov ebx, [PEIMAGE_PADDR+IDOSH_LFANEW]
add ebx, PEIMAGE_PADDR
; Get the IMAGE_NT_HEADERS.SizeOfImage
mov ecx, [ebx+IOPTH_IMGSIZE]
; Get the IMAGE_NT_HEADERS.ImageBase
mov edi, [ebx+IOPTH_IMGBASE]
; Setup esi
mov esi, PEIMAGE_PADDR
; Start to copy
shr ecx, 2
rep movsd
; Get the EP, add ImageBase
mov eax, [ebx+IOPTH_ENTRYPOINT]
add eax, [ebx+IOPTH_IMGBASE]
; Well, thats it, time to say goodbye
; And jump to the PE image
jmp eax
; Make sure this address is aligned to 0x20 ;>
times (0x20-(($-start)% 0x20)) db 0
initial_gdt_table:
; Null entry
dd 0
dd 0
; Code section
dw 0xffff ; Lower limit
dw 0x0000 ; Lower base
db 00000000b ; Mid base
db 10011010b ; Type = 1010 (Code, Execute/Read)
; S (Desc Type) = 1 (code or data)
; DPL (Priv lvl) = 0 (one ring to rule them all)
; P (Present) = 1 (yep)
db 11001111b ; Mid limit = 0xf
; AVL = 0 (nope)
; L (64-bit) = 0 (nope)
; D/B (16/32?) = 1 (32-bit)
; Granularity = 1 (4KB)
db 00000000b ; High base
; Data section
dw 0xffff ; Lower limit
dw 0x0000 ; Lower base
db 00000000b ; Mid base
db 10010010b ; Type = 0010 (Data, Read/Write)
; S (Desc Type) = 1 (code or data)
; DPL (Priv lvl) = 0 (one ring to rule them all)
; P (Present) = 1 (yep)
db 11001111b ; Mid limit = 0xf
; AVL = 0 (nope)
; L (64-bit) = 0 (nope)
; D/B (16/32?) = 1 (32-bit)
; Granularity = 1 (4KB)
db 00000000b ; High base
; Another null entry
dd 0
dd 0
initial_gdt_table_end:
initial_gdt_table_desc:
; There are 4 entries, 8 bytes each
; 4*8 = 20h
; So, the mask is 20h-1 -> 1Fh -> 0000000000011111
dw 0000000000011111b
dd PADDR(initial_gdt_table) ;
; Padding
times (0x200-($-start)) db 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment