Correct x86 segment selector and descriptor bits

This commit is contained in:
elicn
2023-05-24 20:47:43 +03:00
parent 734e23023d
commit cf61fe6805
4 changed files with 39 additions and 37 deletions
+27 -25
View File
@@ -5,34 +5,38 @@
from unicorn.x86_const import *
QL_X86_F_GRANULARITY = 0x8
QL_X86_F_PROT_32 = 0x4
QL_X86_F_LONG = 0x2
QL_X86_F_AVAILABLE = 0x1
# segment descriptor bits [47:40]
QL_X86_A_DATA_A = (1 << 0)
QL_X86_A_DATA_W = (1 << 1)
QL_X86_A_DATA_E = (1 << 2)
QL_X86_A_DATA = (0 << 3)
QL_X86_A_PRESENT = 0x80
QL_X86_A_CODE_A = (1 << 0)
QL_X86_A_CODE_R = (1 << 1)
QL_X86_A_CODE_C = (1 << 2)
QL_X86_A_CODE = (1 << 3)
QL_X86_A_PRIV_3 = 0x60
QL_X86_A_PRIV_2 = 0x40
QL_X86_A_PRIV_1 = 0x20
QL_X86_A_PRIV_0 = 0x0
QL_X86_A_DESC_SYSTEM = (0 << 4) # S
QL_X86_A_DESC_CODE = (1 << 4)
QL_X86_A_DESC_DATA = (1 << 4)
QL_X86_A_CODE = 0x10
QL_X86_A_DATA = 0x10
QL_X86_A_TSS = 0x0
QL_X86_A_GATE = 0x0
QL_X86_A_EXEC = 0x8
QL_X86_A_PRIV_0 = (0b00 << 5) # DPL
QL_X86_A_PRIV_1 = (0b01 << 5)
QL_X86_A_PRIV_2 = (0b10 << 5)
QL_X86_A_PRIV_3 = (0b11 << 5)
QL_X86_A_DATA_WRITABLE = 0x2
QL_X86_A_CODE_READABLE = 0x2
QL_X86_A_DIR_CON_BIT = 0x4
QL_X86_A_PRESENT = (1 << 7)
QL_X86_S_GDT = 0x0
QL_X86_S_LDT = 0x4
QL_X86_S_PRIV_3 = 0x3
QL_X86_S_PRIV_2 = 0x2
QL_X86_S_PRIV_1 = 0x1
QL_X86_S_PRIV_0 = 0x0
# segment descriptor bits [55:52]
QL_X86_F_AVAILABLE = (1 << 0) # AVL
QL_X86_F_LONG = (1 << 1) # L
QL_X86_F_OPSIZE_32 = (1 << 2) # D/B
QL_X86_F_GRANULARITY = (1 << 3) # G
# segment selector bits
QL_X86_SEGSEL_RPL_MASK = 0b11
QL_X86_SEGSEL_TI_GDT = (0 << 2)
QL_X86_SEGSEL_TI_LDT = (1 << 2)
QL_X86_GDT_ADDR = 0x30000
QL_X86_GDT_LIMIT = 0x1000
@@ -43,8 +47,6 @@ IA32_FS_BASE_MSR = 0xC0000100
IA32_GS_BASE_MSR = 0xC0000101
IA32_APIC_BASE_MSR = 0x1B
# WINDOWS SETUP VALUE
# Linux also needs these
GS_SEGMENT_ADDR = 0x6000000
GS_SEGMENT_SIZE = (20 << 20) # 20 MB
+9 -9
View File
@@ -88,12 +88,12 @@ class GDTManager:
@staticmethod
def make_selector(idx: int, rpl: int) -> int:
assert rpl & ~0b11 == 0
assert rpl & ~QL_X86_SEGSEL_RPL_MASK == 0
return (idx << 3) | QL_X86_S_GDT | rpl
return (idx << 3) | QL_X86_SEGSEL_TI_GDT | rpl
def register_gdt_segment(self, index: int, seg_base: int, seg_limit: int, access: int) -> int:
flags = QL_X86_F_PROT_32
flags = QL_X86_F_OPSIZE_32
# is this a huge segment?
if seg_limit > (1 << 16):
@@ -139,7 +139,7 @@ class SegmentManager:
class SegmentManager86(SegmentManager):
def setup_cs_ds_ss_es(self, base: int, size: int) -> None:
# While debugging the linux kernel segment, the cs segment was found on the third segment of gdt.
access = QL_X86_A_PRESENT | QL_X86_A_CODE | QL_X86_A_CODE_READABLE | QL_X86_A_PRIV_3 | QL_X86_A_EXEC | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_CODE | QL_X86_A_CODE | QL_X86_A_CODE_C | QL_X86_A_CODE_R
selector = self.gdtm.register_gdt_segment(3, base, size - 1, access)
self.arch.regs.cs = selector
@@ -147,7 +147,7 @@ class SegmentManager86(SegmentManager):
# TODO : The section permission here should be QL_X86_A_PRIV_3, but I do n’t know why it can only be set to QL_X86_A_PRIV_0.
# While debugging the Linux kernel segment, I found that the three segments DS, SS, and ES all point to the same location in the GDT table.
# This position is the fifth segment table of GDT.
access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_0 | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_0 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W
selector = self.gdtm.register_gdt_segment(5, base, size - 1, access)
self.arch.regs.ds = selector
@@ -155,13 +155,13 @@ class SegmentManager86(SegmentManager):
self.arch.regs.es = selector
def setup_fs(self, base: int, size: int) -> None:
access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W
selector = self.gdtm.register_gdt_segment(14, base, size - 1, access)
self.arch.regs.fs = selector
def setup_gs(self, base: int, size: int) -> None:
access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W
selector = self.gdtm.register_gdt_segment(15, base, size - 1, access)
self.arch.regs.gs = selector
@@ -170,14 +170,14 @@ class SegmentManager86(SegmentManager):
class SegmentManager64(SegmentManager):
def setup_cs_ds_ss_es(self, base: int, size: int) -> None:
# While debugging the linux kernel segment, the cs segment was found on the sixth segment of gdt.
access = QL_X86_A_PRESENT | QL_X86_A_CODE | QL_X86_A_CODE_READABLE | QL_X86_A_PRIV_3 | QL_X86_A_EXEC | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_CODE | QL_X86_A_CODE | QL_X86_A_CODE_C | QL_X86_A_CODE_R
selector = self.gdtm.register_gdt_segment(6, base, size - 1, access)
self.arch.regs.cs = selector
# TODO : The section permission here should be QL_X86_A_PRIV_3, but I do n’t know why it can only be set to QL_X86_A_PRIV_0.
# When I debug the Linux kernel, I find that only the SS is set to the fifth segment table, and the rest are not set.
access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_0 | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_0 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W
selector = self.gdtm.register_gdt_segment(5, base, size - 1, access)
# self.arch.regs.ds = selector
+2 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
#
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
@@ -48,7 +48,7 @@ def ql_syscall_set_thread_area(ql: Qiling, u_info_addr: int):
index = ql.os.gdtm.get_free_idx(12)
if index in (12, 13, 14):
access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W
ql.os.gdtm.register_gdt_segment(index, base, limit, access)
ql.mem.write_ptr(u_info_addr, index, 4)
+1 -1
View File
@@ -383,7 +383,7 @@ class QlLinuxX86Thread(QlLinuxThread):
index = self.ql.os.gdtm.get_free_idx(12)
if index in (12, 13, 14):
access = QL_X86_A_PRESENT | QL_X86_A_DATA | QL_X86_A_DATA_WRITABLE | QL_X86_A_PRIV_3 | QL_X86_A_DIR_CON_BIT
access = QL_X86_A_PRESENT | QL_X86_A_PRIV_3 | QL_X86_A_DESC_DATA | QL_X86_A_DATA | QL_X86_A_DATA_E | QL_X86_A_DATA_W
self.ql.os.gdtm.register_gdt_segment(index, base, limit, access)
self.ql.mem.write_ptr(tls_addr, index, 4)