Linux内核(x86)入口代码模糊测试指南Part 2 (上篇)

本文深入探讨Linux内核(x86)模糊测试,关注标志寄存器中的陷阱和对齐检查标志,堆栈指针的影响,以及段寄存器的使用。通过修改这些关键元素,以发现潜在的内核漏洞。
摘要由CSDN通过智能技术生成

在本系列的第一篇文章中,我们介绍了Linux内核入口代码的作用,以及如何进行JIT汇编和调用系统调用。在本文中,我们将为读者更进一步介绍标志寄存器、堆栈指针、段寄存器、调试寄存器以及进入内核的不同方法。

更多标志(%rflags)

方向标志只是我们众多感兴趣的标志之一。维基百科上关于%rflags的文章列出了我们感兴趣的其他一些标志

· bit 8:陷阱标志(用于单步调试)

· bit 18:对齐检查

大多数与算术相关的标志(进位标志等)并不是我们感兴趣的对象,因为它们在普通代码的正常运行过程中变化较大,这意味着内核对这些标志的处理很可能已经过了充分的测试。而另外一些标志(如中断启用标志)可能无法被用户空间修改,所以即使尝试也没什么用。

我们需要重点关注陷阱标志,因为设置该标志后,CPU在每条指令后都会传递一个调试异常,自然也会干扰输入代码的正常运行。

对齐检查标志也应当重点关注,因为当一个错误对齐的指针被解除引用时,它会使CPU传递一个对齐检查异常。虽然CPU在0环中执行时不应该执行对齐检查,但是检查是否存在因为对齐检查异常而进入内核的相关漏洞还是很有意思的(我们稍后再谈)。

维基百科的文章给出了修改这些标志的程序,但我们可以做得更好一点。

0:   9c                              pushfq
1:   48 81 34 24 00 01 00 00         xorq   $0x100,(%rsp)
9:   48 81 34 24 00 04 00 00         xorq   $0x400,(%rsp)
11:   48 81 34 24 00 00 04 00         xorq   $0x40000,(%rsp)
19:   9d                              popfq

 

这段代码将%rflags的内容压入堆栈上,然后直接修改堆栈上的标志值,再将该值弹出到%rflags中。实际上,我们在这里可以选择使用orq或者xorq指令;我选择xorq,因为它可以切换寄存器中的任何值。这样一来,如果我们连续进行多次系统调用(或内核入口),我们可以随机切换标志,而不必关心现有的值是什么。

既然我们无论如何都要修改%rflags寄存器,那么我们不妨把方向标志的修改纳入进去,把三个标志的修改合并到一条指令中。虽然这是一个很小的优化,但没有理由不这么做,奇热最后的结果如下所示

// pushfq
*out++ = 0x9c;
 
uint32_t mask = 0;
 
// trap flag
mask |= std::uniform_int_distribution
 
// direction flag
mask |= std::uniform_int_distribution
 
// alignment check
mask |= std::uniform_int_distribution
 
// xorq $mask, 0(%rsp)
*out++ = 0x48;
*out++ = 0x81;
*out++ = 0x34;
*out++ = 0x24;
*out++ = mask;
*out++ = mask >> 8;
*out++ = mask >> 16;
*out++ = mask >> 24;
 
// popfq
*out++ = 0x9d;

如果我们不希望进程在设置陷阱标志时立即被SIGTRAP杀死,我们需要注册一个信号处理程序来有效地忽略这个信号(显然使用SIG_IGN是不够的)

static void handle_child_sigtrap(int signum, siginfo_t *siginfo, void *ucontext)
{  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值