mirror of
https://github.com/qilingframework/qiling.git
synced 2026-10-12 02:21:40 +00:00
Correct x86 segment selector and descriptor bits
This commit is contained in:
+27
-25
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user