Suterusu源码阅读和分析(1)

suterusu是一款跨多个Linux平台的rootkit,打入目标系统后能够完成文件隐藏、进程隐藏、端口隐藏、目录隐藏、文件下载、控制系统读写、远程交互等功能,是初学rootkit的必看材料,附上作者对suterusu的分析blog

除去主模块之外,还可以选择性编译6个扩展模块

  • keylogger
  • unlock 锁屏,必须输入指定密码
  • logfile 键盘记录到指定文件
  • hookrw 钩住系统读写
  • dlexec 事件驱动下载or执行二进制
  • icmp 监控含有特殊字节的icmp

目录结构

1
2
3
4
5
6
7
8
9
10
11
├── common.h	# 宏、函数声明
├── dlexec.c # 维护下载任务队列
├── hookrw.c # hook到系统读写
├── icmp.c # icmp队列处理
├── keylogger.c # 键盘记录 or 锁屏
├── keylog.h # 键盘宏
├── main.c # mod主逻辑
├── module.c # 阻止后续模块加入
├── serve.c # tcp server,让受害机通过dlexec下载我们的恶意文件
├── sock.c # 命令通道,和rootkit交互
└── util.c # hook函数实现(根基)

util

主要功能:

  • 定义了系统函数hook结构体,以链表的形式保存
  • 定义了四个hook操作函数
    • start:hook对应函数,保存至hook结构体
    • pause:暂时归还hook,即归还原函数
    • resume:重新hook,即再用我们的新函数替换系统函数
    • stop:删除当前hook函数,归还原函数
  • 开启/关闭写保护操作(在四个hook操作函数中用到)
  • 查找当前函数地址(配合main中查询到的symbol_table使用)

data_struct

1
2
3
4
5
6
struct sym_hook {
void *addr; // 当前函数位置
unsigned char o_code[HIJACK_SIZE]; // original 旧函数汇编
unsigned char n_code[HIJACK_SIZE]; // new 新函数汇编
struct list_head list; // 侵入式链表,让sym_hook形成链表结构
};

api

1
2
3
4
5
6
7
8
9
write_cr0(unsigned long)
read_cr0()
barrier()
preempt_enable()

void list_add ( struct list_head * new, struct list_head * head);
void list_del (struct list_head * entry);

int kallsyms_on_each_symbol (int(*fn)(void *, const char *, struct module *, unsigned long), void *data)

module

主要功能:函数挂入消息通知队列,当有新模块打入时,将新模块的init和exit函数替换为我们的空函数,达到防止后续模块加入的效果

data_struct

1
struct notifier_block

api

1
2
3
4
5
6
7
8
9
10
11
register_module_notifier(struct notifier_block *)
unregister_module_notifier(struct notifier_block *)


宏DEFINE_SPINLOCK,定义并初始化spinlock
用法:DEFINE_SPINLOCK(TEST);

spin_lock_irqsave
用法:spin_lock_irqsave(&TEST, flags<long int>);
spin_unlock_irqrestore
用法:spin_unlock_irqrestore(&TEST, flags<long int>);

内核通知链

Notifier链分析和使用

dlexec

主要功能:维护全局工作队列,将文件下载任务添入队列,文件下载后将文件权限改为777,配合icmp模块使用

data_struct

api

1
2
3
4
5
6
7
8
9
10
create_workqueue()
flush_workqueue()
destroy_workqueue()

queue_work()

sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, struct sock **)
inet_stream_connect(struct sock *, struct sockaddr *, int addr_len, int flags)
sock_recvmsg(struct sock *, struct msghdr *, size_t, int flags)
inet_release(struct sock *)

keylogger

主要功能:锁屏和记录按键

这里的密码很有趣,音量升键 上箭头 上箭头 音量降键 ??键 ??键 x 2

data_struct

1
2
3
task_struct
keyboard_notifier_param
loff_t

api

1
2
3
4
5
6
7
8
9
10
11
12
register_keyboard_notifier(struct notifier_block *)
unregister_keyboard_notifier(struct notifier_block *)

DECLARE_WAIT_QUEUE_HEAD

wait_event_interruptible()
wake_up_interruptible()
vfs_write

kthread_run
kthread_should_stop
kthread_stop

sock

主要功能:通过ioctl和mod进行交互,选择不同的接口,传入对应的参数

data_struct

1
struct ifconf

api

1
int ioctl(int fd, unsigned long request, ...);

icmp

主要功能:通过netfilter判断操作系统接收到的icmp报文,若icmp报文的magic字段同内置相符,则调用dlexec将对应ip和port挂入下载队列,完成文件传输和执行

data_struct

http://staff.ustc.edu.cn/~james/linux/netfilter-4.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
netfilter的钩子操作结构体

struct nf_hook_ops
{

struct list_head list; //链表成员
/* User fills in from here down. */
nf_hookfn *hook; //钩子函数指针
struct module *owner;
int pf; //协议簇,对于ipv4而言,是PF_INET
int hooknum; //hook类型
/* Hooks are ordered in ascending priority. */
int priority; //优先级
};

上面的nf_hookfn函数参数如下
unsigned int watch_icmp ( unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *) )

api

1
2
nf_register_hook
nf_unregister_hook