GDT: Jumps to wrong memory after reloading registers
Posted: Sat Nov 18, 2017 3:45 pm
Hello everyone,
after reading through a lot of the wiki pages/tutorials I decided to setup my own GDT, however as soon as I reload any of the registers ds, ss and cs there's a jump to a completely wrong address for some reason and that causes a crash.
To store the address and size used when executing "lgdt" i used this struct:
And to store a single gdt entry I used this struct:
Then I define an array of 3 of the structs containing the null descriptor, the kernel data segment and the kernel code segment:
With make_entry doing this:
I'm using following assembler functions to lgdt:
When stepping through this with GDB I checked if eax contained the correct address and it did, and the size and address of the GDT were also correct.
Now here comes the problematic code:
As soon as the jmp is executed the executions jumps to a seemingly random address in memory resulting, sooner or later, in a crash. I also tried swapping around the flushing of the CS register and the setting of ds and ss, but I still get the same Problem it jumps to a bogus address once reaching the first instructions that modifies any of cs, ds and ss.
While single stepping through GDB I also noticed that the "disassemble" command doesn't recognise the far jump, but instead displays (BAD).
I hope you can help me.
Regards,
Luca
after reading through a lot of the wiki pages/tutorials I decided to setup my own GDT, however as soon as I reload any of the registers ds, ss and cs there's a jump to a completely wrong address for some reason and that causes a crash.
To store the address and size used when executing "lgdt" i used this struct:
Code: Select all
struct gdt_info {
unsigned int address;
unsigned short size;
} __attribute__((packed));
Code: Select all
struct gdt_entry {
unsigned char upperBase; // Bits 24 to 31 of base address
unsigned char config; //Flags in the upper 4 bits and Limit from 16-19 in the lower four
unsigned char access; //Access byte
unsigned char middleBase; // Bits 16 to 23 of base address
unsigned short lowerBase; //Bits 0 to 15 of base address
unsigned short limit; //Lower limit(Bits 0 to 15)
} __attribute__((packed));
Code: Select all
struct gdt_entry nullDescriptor = {
.upperBase = 0,
.config = 0,
.access = 0,
.middleBase = 0,
.lowerBase = 0,
.limit = 0
};
gdt_entries[0] = nullDescriptor;
/* 0x9A = 10011010 0xC=1100 */
gdt_entries[1] = gdt_makeEntry(0, 0xFFFFF, 0x9A, 0xC);
/* 0x92 = 10010010 */
gdt_entries[2] = gdt_makeEntry(0, 0xFFFFF, 0x92, 0xC);
Code: Select all
struct gdt_entry gdt_makeEntry(unsigned int base, unsigned int limit, unsigned char access, unsigned char flags){
struct gdt_entry newEntry = {
.upperBase = (base & 0xFF000000) >> 24,
.config = ((flags & 0x0F) << 4) | ((limit & 0xF0000) >> 16),
.access = access,
.middleBase = (base & 0x00FF0000) >> 16,
.lowerBase = (base & 0x0000FFFF),
.limit = (limit & 0x0FFFF)
};
return newEntry;
}
Code: Select all
global load_gdt
;load_gdt Loads a GDT, with the first argument being the address to a gdt_info struct
;Stack: [esp+4] Address to gdt_info struct
; [esp] Return address
load_gdt:
mov eax, [esp+4]
lgdt [eax]
ret
Now here comes the problematic code:
Code: Select all
global gdt_setRegisters
;gdt_setRegisters Sets the required cs, ss and ds registers
;Stack:
; [esp] Return address
gdt_setRegisters:
jmp 0x08:flush_cs ;And then flush it
flush_cs:
; And we are with cs = [esp+2]
mov ax, 0x10
mov ds, ax
mov ss, ax
ret
While single stepping through GDB I also noticed that the "disassemble" command doesn't recognise the far jump, but instead displays (BAD).
I hope you can help me.
Regards,
Luca