利用LDT(本地描述符表)

时间:2009-11-20 15:17:57

标签: c assembly x86

我正在尝试使用除默认代码和数据用户和内核段之外的不同段进行一些实验。我希望通过使用本地描述符表和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;

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

1 个答案:

答案 0 :(得分:6)

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

我猜你得到段错误的行被编译为:

mov ds:[offset mx], 0x407cafe

其中offset mx是程序数据段中mx的偏移量(如果它是静态变量)或堆栈中的偏移量(如果它是自动变量)。无论哪种方式,此偏移量都是在编译时计算的,无论DS指向什么,都将使用该偏移量。

现在您在此处所做的是创建一个新的细分受众群,其基数位于mx的地址,其限制为0x40x4fff(取决于{{1}你没有指定的)。

如果G-bit为0,则限制为G-bit,因为0x4位于地址mx0x0之间的可能性极小原始0x4,当您访问新细分中的DS偏移量时,您将越过限制。

如果mx为1,则限制为G-bit。现在,只有当原0x4fff位于mx上方时才会出现段错误。

考虑到新细分的基数位于0x4fff,您可以通过以下方式访问mx

mx

我不知道如何在C中写这个。