【问题标题】:Linux Kernel code in memory check with sha256 sum使用 sha256 和检查内存中的 Linux 内核代码
【发布时间】:2018-08-10 10:57:27
【问题描述】:

有没有办法在内存中找到加载的内核代码?我的意思是引导加载程序加载内核并执行它。内核提取自身并开始初始化硬件并运行 init。据我了解,内核是从磁盘的 (b)zImage 保存和加载的。我想在系统内存中找到这个未更改的代码并检查它。

我有以下增强功能:

为加载的内核代码创建一个 sha256 哈希,并将其与定义的值进行比较,以审计系统的安全性。因此,我加载了一个模块,该模块试图在内存中找到内核代码并从中计算出 sha256 和。

我试图像这样在内存中找到内核代码:

static struct resource *adhoc_next_resource(struct resource *p, bool sibling_only)
{
  if (sibling_only)
    return p->sibling;

  if (p->child)
    return p->child;
  while (!p->sibling && p->parent)
    p = p->parent;
  return p->sibling;
}

static struct resource *get_kernel_code (void) {
    struct resource *kern_code = &iomem_resource;

    while (kern_code && strcmp(kern_code->name ? kern_code->name : "","Kernel code") != 0) {
        kern_code = adhoc_next_resource(kern_code, false);
    }

    return kern_code;
}

int init_module(void)
{
    void *start,*end;
    size_t length;
    SHA256_CTX sha256;
    u32 *hash;
    struct resource *kern_code;

    kern_code = get_kernel_code();
    if ( IS_ERR(kern_code) )
        return -EINVAL;

    start = (void*)phys_to_virt(kern_code->start);
    end = (void*)phys_to_virt(kern_code->end);
    length = kern_code->end -  kern_code->start;

    printk("%s[%s]:%s address: %0*llx-%0*llx \n", MODULE_NAME, __FUNCTION__, kern_code->name ? kern_code->name : "", 4, start, 4, end );

    printk("%s[%s]: length: %lu \n", MODULE_NAME, __FUNCTION__, length);


    printk ( KERN_INFO "%s[%s]: Init sha256\n", MODULE_NAME, __FUNCTION__ );
    sha256_init(&sha256);

    printk ( KERN_INFO "%s[%s]: Give kernel code to sha256\n", MODULE_NAME, __FUNCTION__ );
    sha256_update ( &sha256, start, length );

    hash = kmalloc ( 4 * sizeof(u32), GFP_KERNEL );

    printk ( KERN_INFO "%s[%s]: Finalize sha256\n", MODULE_NAME, __FUNCTION__ );
    sha256_final ( &sha256, (BYTE*)hash );

    printk ( KERN_INFO "%s[%s]: Hash value of kernel code: %x - %x - %x - %x \n", MODULE_NAME, __FUNCTION__, hash[0], hash[1], hash[2], hash[3] );

    kfree(hash);

    return 0;
}

但是,每次重新启动时,我都会得到不同的 sha256 总和。

  1. 请解释发生了什么?内核代码内存中的某些内容发生了变化。但它会是什么?
  2. 这个概念可行吗?或者不是每次都在内存中加载相同的代码。

【问题讨论】:

  • “将加载的内核代码放入内存”是什么意思?如果您加载代码,它就在内存中。我的意思是您将代码加载到内存中,对吧?
  • 系统启动时。引导加载程序以某种方式将内核映像加载到内存中并开始执行代码。如果它是 (b)zImage,则内核运行并提取自身。内核代码的加载与我的代码无关。我想在系统内存中找到提取的内核代码(如您在我的代码中所见)并从中创建一个 sha256 和以检查它是否已更改(有人替换了内核映像中的一些代码)。我希望这现在清楚了吗?
  • 好的,我明白你的意思。我写的有点混乱。我不想加载它。我想在内存中找到加载的代码。我更新了文本。
  • 您在上面的代码中所做的是找到一个名称为“内核代码”的iomem结构。你可以从/proc/iomem 看到。那么“内核代码”是什么意思?您在寻找代码的文本部分吗?你有嵌入式裸 CPU 背景吗?
  • 顺便说一句,更改内核地址的功能称为地址空间布局随机化(ASLR)。你可以阅读它here

标签: linux memory linux-kernel kernel


【解决方案1】:

我自己找到了这个问题的答案:

  1. 我对内核的内存位置等进行了更多研究。我发现在运行时内核“.text”部分(提取的 bzImage)没有存储在 iomem_resource 列表中。我检查了“内核代码”资源中的地址范围(参见我之前发布的代码),发现大部分位都是 0。只有在开头和结尾处有一些代码。但这不是“内核代码”我没有找到答案这个“内核代码”部分的破解是什么。也许它必须是内核映像的“.text”部分,但不是在我的系统上(ARM 32bit & yocto-linux 4.10.17)。

  2. Yasushi 发布的 KASLR 功能 (info here) 不是 ARM 32 位架构的问题。我发现内核内部定义了这种类型的系统上没有启用此功能。但这是一个非常有趣的功能。

  3. 为了获取“.text”部分的内核地址,我现在使用 kallsysm 功能。这是所有地址和导出变量的大列表。有两个变量定义开始和结束。我使用以下代码:

    开始 = (void*)kallsyms_lookup_name("_stext"); end = (void*)kallsyms_lookup_name("_etext");

注意:注意虚拟内存与物理内存位置。 Kallsysm 输出是虚拟内存位置。 (如有错误请指正)

最后:对于相同的内核代码,每次启动时我都会得到相同的校验和,我可以继续完成我的审计模块:-)。

【讨论】:

    猜你喜欢
    • 2014-06-01
    • 1970-01-01
    • 2013-05-05
    • 2012-11-15
    • 1970-01-01
    • 2013-03-24
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多