利用LDT(本地描述符表)

Bri*_*ian 8 c x86 assembly

我试图使用除默认代码和数据用户和内核段之外的不同段进行一些实验.我希望通过使用本地描述符表和modify_ldt系统调用来实现这一点.通过系统调用,我在LDT中创建了一个新条目,它是一个段描述符,其基地址是我要"隔离"的全局变量,限制为4个字节.

我尝试通过C程序中的内联汇编将数据段寄存器与我的自定义LDT条目的段选择器一起加载,但是当我尝试访问变量时,我收到了分段错误.

我的怀疑是我的全局变量的偏移存在问题,并且当计算地址时,它超出了我的自定义段的限制,因此导致seg错误.

有谁知道这种情况的工作?

哦,顺便说一句,这是在Linux的x86架构上.这是我第一次在论坛上提出这样的问题,所以如果有任何其他信息可以证明是有用的,请告诉我.

先感谢您.

编辑:我意识到我可能应该包含源代码:)

struct user_desc* table_entry_ptr = NULL;

/* Allocates memory for a user_desc struct */
table_entry_ptr = (struct user_desc*)malloc(sizeof(struct user_desc));

/* Fills the user_desc struct which represents the segment for mx */
table_entry_ptr->entry_number = 0;
table_entry_ptr->base_addr = ((unsigned long)&mx);
table_entry_ptr->limit = 0x4;
table_entry_ptr->seg_32bit = 0x1;
table_entry_ptr->contents = 0x0;
table_entry_ptr->read_exec_only = 0x0;
table_entry_ptr->limit_in_pages = 0x0;
table_entry_ptr->seg_not_present = 0x0;
table_entry_ptr->useable = 0x1;

/* Writes a user_desc struct to the ldt */
num_bytes = syscall( __NR_modify_ldt,
                   LDT_WRITE, // 1
                   table_entry_ptr,
                   sizeof(struct user_desc)
                   );

asm("pushl %eax");
asm("movl $0x7, %eax"); /* 0111: 0-Index 1-Using the LDT table 11-RPL of 3 */
asm("movl %eax, %ds");
asm("popl %eax");

mx = 0x407CAFE;
Run Code Online (Sandbox Code Playgroud)

seg故障发生在最后一条指令处.

Nat*_*man 6

我只能猜测,因为我没有可用的装配.

我猜你得到段错误的行编译成如下:

mov ds:[offset mx], 0x407cafe
Run Code Online (Sandbox Code Playgroud)

其中offset mx被所述偏移到mx在程序的数据段(如果它是一个静态变量)或在堆栈(如果它是一个自动可变的).无论哪种方式,这个偏移量都是在编译时计算出来的,无论DS指向什么点,它都将被使用.

现在你在这里所做的是创建一个新的段,其基数位于地址,mx并且其限制是0x4或者0x4fff(取决于G-bit你没有指定的那个).

如果G-bit为0,则限制为0x4,并且由于mx位于地址0x00x4原始位置之间的可能性极小,因此DS当您访问mx新段内的偏移时,您将超过限制.

如果G-bit是1,那么限制是0x4fff.现在只有当原件mx位于上方时才会出现段错误0x4fff.

考虑到新细分市场的基础mx,您可以mx通过以下方式访问:

mov ds:[0], 0x407cafe
Run Code Online (Sandbox Code Playgroud)

不过,我不知道如何在C中写这个.