我对修改内核内部结构、应用补丁、处理设备驱动程序和模块感兴趣,以获取我个人的乐趣。
是否有针对经验丰富的程序员的内核黑客攻击综合资源?
答案1
**TODO** +editPic: Linux Kernel Developer -> (Ring Layer 0)
+addSection: Kernel Virtualization Engine
KERN_WARN_CODING_STYLE: Do not Loop unless you absolutely have to.
推荐书籍未初始化
void *i
“人们只有在拥有一定的生命之后才能理解书籍,或者至少没有人能够理解一本深刻的书,直到他至少看到并经历了其中的一部分内容”。 ——埃兹拉·庞德
一千人的旅程代码里程必须从一步开始。如果您对从以下哪本书开始感到困惑,请不要担心,选择您喜欢的任何一本。并非所有徘徊的人都迷失了方向。作为所有道路最终都连接到高速公路,随着页面的进展,您将在内核之旅中探索新事物,不会遇到任何死胡同,并最终连接到code-set
.保持清醒的头脑阅读并记住:代码不是文学。
剩下的不是事物、情感、图像、心理图片、记忆,甚至不是想法。它是一个函数。某种过程。生命的一个方面,可以被描述为“更大”事物的功能。因此,它似乎并没有真正与其他东西“分离”。就像刀的功能——切割东西——实际上与刀本身并不分离。该功能目前可能正在使用,也可能没有使用,但它可能永远不会分离。
阅读不是为了反驳和反驳;也不相信并认为理所当然;也找不到谈话和话语;但要权衡和考虑。有的书是要浅尝的,有的书是要吞咽的,有的书是要咀嚼消化的:也就是说,有的书要读部分,有的书要读,但不要好奇,有的书要全读。 ,并勤奋和专注。
static void tasklet_hi_action(struct softirq_action *a)
{
struct tasklet_struct *list;
local_irq_disable();
list = __this_cpu_read(tasklet_hi_vec.head);
__this_cpu_write(tasklet_hi_vec.head, NULL);
__this_cpu_write(tasklet_hi_vec.tail, this_cpu_ptr(&tasklet_hi_vec.head));
local_irq_enable();
while (list) {
struct tasklet_struct *t = list;
list = list->next;
if (tasklet_trylock(t)) {
if (!atomic_read(&t->count)) {
if (!test_and_clear_bit(TASKLET_STATE_SCHED,
&t->state))
BUG();
t->func(t->data);
tasklet_unlock(t);
continue;
}
tasklet_unlock(t);
}
local_irq_disable();
t->next = NULL;
*__this_cpu_read(tasklet_hi_vec.tail) = t;
__this_cpu_write(tasklet_hi_vec.tail, &(t->next));
__raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_enable();
}
}
核心Linux( 5 -> 1 -> 3 -> 2 -> 7 -> 4 -> 6 )
“自然既没有内核,也没有外壳;她同时就是一切”——约翰·沃尔夫冈·冯·歌德
读者应该熟悉操作系统概念;对长时间运行的进程及其与短时间突发执行的进程的差异有一个公平的理解;容错同时满足软实时和硬实时约束。在阅读时,了解n/ack
Linux 内核源代码在核心子系统中所做的设计选择非常重要。
线程[和]信号是一条依赖于平台的痛苦、绝望、恐怖和疯狂的踪迹(~安东尼·巴克斯特)。话虽如此,在深入研究内核之前,您应该成为一名自我评估的 C 专家。您还应该对链表、堆栈、队列、红黑树、哈希函数等有良好的经验。
volatile int i;
int main(void)
{
int c;
for (i=0; i<3; i++) {
c = i&&&i;
printf("%d\n", c); /* find c */
}
return 0;
}
Linux 内核源代码的美丽和艺术在于所使用的有意的代码混淆。这通常是必要的,以便以干净而优雅的方式传达涉及两个或多个操作的计算含义。在为多核架构编写代码时尤其如此。
视频讲座论实时系统,任务调度,内存压缩,内存屏障,表面活性剂
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
- Linux内核开发-罗伯特·洛夫
- 了解 Linux 内核-丹尼尔·P·博维、马可·塞萨蒂
- Linux 内核设计的艺术-杨丽香
- 专业Linux内核架构-沃尔夫冈·毛雷尔
- UNIX 操作系统的设计-莫里斯·J·巴赫
- 了解 Linux 虚拟内存管理器-梅尔·戈尔曼
- Linux 内核内部结构-蒂格兰·艾瓦齐安
- 嵌入式 Linux 入门-克里斯托弗·哈利南
Linux 设备驱动程序( 1 -> 2 -> 4 -> 3 -> 8 -> ... )
“音乐不会陪伴你前进。你必须严格依靠你的能力来陪伴它,真正专注于情感或故事的那一小部分核心”。 ——黛比·哈利
您的任务基本上是在硬件设备和软件内核之间建立高速通信接口。您应该阅读硬件参考数据表/手册,以了解设备的行为及其控制和数据状态以及提供的物理通道。从长远来看,了解您特定架构的汇编知识以及对 VLSI 硬件描述语言(如 VHDL 或 Verilog)的了解将对您有所帮助。
问:但是,为什么我必须阅读硬件规格?
A:因为,“软件无法弥合碳和硅之间的鸿沟”——Rahul Sonnad
不过,以上内容并不构成问题计算算法(驱动程序代码-下半部处理),因为它可以在通用图灵机。如果计算结果在数学领域,可以肯定的是,在物理域。
视频讲座在 Linux 设备驱动程序上(讲义 17 和 18),嵌入式 KMS 驱动程序剖析,引脚控制和 GPIO 更新,通用时钟框架,编写真正的 Linux 驱动程序 - Greg KH
static irqreturn_t phy_interrupt(int irq, void *phy_dat)
{
struct phy_device *phydev = phy_dat;
if (PHY_HALTED == phydev->state)
return IRQ_NONE; /* It can't be ours. */
/* The MDIO bus is not allowed to be written in interrupt
* context, so we need to disable the irq here. A work
* queue will write the PHY to disable and clear the
* interrupt, and then reenable the irq line.
*/
disable_irq_nosync(irq);
atomic_inc(&phydev->irq_disable);
queue_work(system_power_efficient_wq, &phydev->phy_queue);
return IRQ_HANDLED;
}
- Linux 设备驱动程序-乔纳森·科贝特、亚历山德罗·鲁比尼和格雷格·克罗-哈特曼
- 基本 Linux 设备驱动程序-斯里克里希南·文卡特斯瓦兰
- 编写 Linux 设备驱动程序-杰里·库珀斯坦
- Linux 内核模块编程指南-彼得·杰伊·萨尔兹曼、迈克尔·布里安、奥里·波梅兰兹
- Linux PCMCIA 程序员指南-大卫·海因兹
- Linux SCSI 编程指南-海科·艾伯费尔特
- POSIX 操作系统串行编程指南-迈克尔·斯威特
- Linux 图形驱动程序:简介-史蒂芬·马尔切森
- Linux USB 设备驱动程序编程指南-德特勒夫·弗利格尔
- Linux 内核设备模型-帕特里克·莫切尔
内核网络( 1 -> 2 -> 3 -> ... )
“称其为氏族,称其为网络,称其为部落,称其为家庭:无论你如何称呼它,无论你是谁,你都需要一个。” - 简·霍华德
了解内核中的数据包遍历是理解内核网络的关键。如果我们想了解 Netfilter 或 IPSec 内部结构等,就必须了解它。 Linux内核网络层最重要的两个结构是:struct sk_buff
和struct net_device
static inline int sk_hashed(const struct sock *sk)
{
return !sk_unhashed(sk);
}
- 了解 Linux 网络内部结构-克里斯蒂安·本韦努蒂
- Linux 内核网络:实现和理论-拉米·罗森
- UNIX网络编程-W·理查德·史蒂文斯
- Linux 网络编程权威指南-凯尔·戴维斯、约翰·W·特纳、内森·约科姆
- Linux TCP/IP 堆栈:嵌入式系统网络-托马斯·F·赫伯特
- Linux Socket 编程示例-沃伦·盖伊
- Linux 高级路由和流量控制 HOWTO-伯特·休伯特
内核调试( 1 -> 4 -> 9 -> ... )
除非在与计算机交流时,人们能够准确地表达自己的意思,否则必然会产生麻烦。~艾伦·图灵,关于计算机
Brian W. Kernighan 在《Unix for Beginners》(1979)一文中说,“最有效的调试工具仍然是仔细的思考,加上明智地放置打印语句”。了解要收集的内容将帮助您快速获取正确的数据以进行快速诊断。伟大的计算机科学家 Edsger Dijkstra 曾经说过,测试可以证明错误的存在,但不能证明错误的不存在。良好的调查实践应该平衡快速解决问题的需要、培养技能的需要以及主题专家的有效利用。
有时候,当你跌入谷底时,似乎什么都不起作用,你也没有了所有的选择。然后才是真正的调试开始。错误可能会为您提供所需的休息时间,让您摆脱对无效解决方案的执着。
视频讲座关于内核调试和分析,核心转储分析,使用 GDB 进行多核调试,控制多核竞争条件,调试电子产品
/* Buggy Code -- Stack frame problem
* If you require information, do not free memory containing the information
*/
char *initialize() {
char string[80];
char* ptr = string;
return ptr;
}
int main() {
char *myval = initialize();
do_something_with(myval);
}
/* “When debugging, novices insert corrective code; experts remove defective code.”
* – Richard Pattis
#if DEBUG
printk("The above can be considered as Development and Review in Industrial Practises");
#endif
*/
- Linux 调试和性能调优-史蒂夫·贝斯特
- Linux应用程序调试技术-奥勒良·梅林特
- 使用 GDB 进行调试:GNU 源代码级调试器-罗兰·H·佩什
- 调试嵌入式Linux-克里斯托弗·哈利南
- 使用 GDB、DDD 和 Eclipse 进行调试的艺术-诺曼·马特洛夫
- 为什么程序失败:系统调试指南-安德烈亚斯·泽勒
- 软件驱魔:调试和优化遗留代码的手册-比尔·布伦登
- 调试:查找最难以捉摸的软件和硬件问题-大卫·J·阿甘斯
- 思维调试:多学科方法-罗伯特·查尔斯·梅茨格
- 查找错误:一本关于错误程序的书-亚当·巴尔
文件系统( 1 -> 2 -> 6 -> ... )
“我想要虚拟内存,至少因为它与文件系统结合在一起”。 ——肯·汤普森
在 UNIX 系统上,一切都是文件;如果某个东西不是文件,那么它就是一个进程,除了命名管道和套接字。在文件系统中,文件由 表示inode
,这是一种序列号,其中包含有关构成文件的实际数据的信息。 Linux 虚拟文件系统VFS
在安装和使用每个文件系统时将其信息缓存在内存中。必须非常小心地正确更新文件系统,因为这些缓存中的数据会随着文件和目录的创建、写入和删除而被修改。这些缓存中最重要的是缓冲区缓存,它集成到各个文件系统访问其底层块存储设备的方式中。
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
struct open_flags op;
int fd = build_open_flags(flags, mode, &op);
struct filename *tmp;
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fsnotify_open(f);
fd_install(fd, f);
}
}
putname(tmp);
return fd;
}
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
- Linux 文件系统-摩西酒吧
- Linux 文件系统-威廉·冯·哈根
- UNIX 文件系统:演变、设计和实现-史蒂夫·D·佩特
- 实用文件系统设计-多米尼克·詹保罗
- 文件系统取证分析-布赖恩·开利
- Linux 文件系统层次结构-平阮
- BTRFS:Linux B 树文件系统-奥哈德·罗德
- StegFS:Linux 的隐写文件系统-安德鲁·D·麦克唐纳、马库斯·G·库恩
安全( 1 -> 2 -> 8 -> 4 -> 3 -> ... )
“UNIX 的设计目的并不是为了阻止用户做愚蠢的事情,因为这也会阻止他们做聪明的事情”。 — 道格·格温
如果不使用,任何技术都无法发挥作用。道德随着技术的改变而改变。
”F × S = k“自由和安全的产物是一个常数。——尼文定律
密码学构成了在线信任的基础。黑客攻击是利用技术、物理或人为因素的安全控制。保护内核免受其他正在运行的程序的影响是迈向安全稳定系统的第一步,但这显然还不够:不同用户态应用程序之间也必须存在某种程度的保护。漏洞利用可以针对本地或远程服务。
“你无法用蛮力破解你的命运……你需要一个后门,一个进入生活的侧通道。” ——克莱德·杜苏扎
视频讲座密码学和网络安全,安全命名空间,防范远程攻击,安全嵌入式Linux
env x='() { :;}; echo vulnerable' bash -c "echo this is a test for Shellsock"
- 黑客:剥削的艺术-乔恩·埃里克森
- Rootkit 军械库:系统黑暗角落中的逃脱与躲避- 比尔·布伦登
- 黑客暴露:网络安全秘密-斯图尔特·麦克卢尔、乔尔·斯坎布雷、乔治·库尔茨
- 内核利用指南:攻击核心-恩里科·佩拉、马西米利亚诺·奥尔达尼
- 记忆取证的艺术-迈克尔·海尔·赖、安德鲁·凯斯、杰米·莱维、艾伦·沃尔特斯
- 实用逆向工程-Bruce Dang、Alexandre Gazet、Elias Bachaalany
- 实用恶意软件分析-迈克尔·西科尔斯基、安德鲁·霍尼格
- 最大程度的 Linux 安全性:保护 Linux 服务器的黑客指南-匿名的
- Linux安全-克雷格·亨特
- 现实世界的 Linux 安全-鲍勃·托克森
内核源码(0.11 -> 2.4 -> 2.6 -> 3.18)
“就像葡萄酒一样,对内核编程的掌握会随着时间的推移而成熟。但是,与葡萄酒不同的是,它在这个过程中变得更加甜蜜”。 ——劳伦斯·穆切卡
你可能不认为程序员是艺术家,但编程是一个极具创造性的职业。这是基于逻辑的创造力。计算机科学教育不能使任何人成为专家程序员,就像学习画笔和颜料不能使人成为专家画家一样。正如你已经知道的,知路和行路是有区别的。卷起袖子亲自动手研究内核源代码是至关重要的。最后,用你由此获得的内核知识,无论你走到哪里,你都会闪耀。
不成熟的程序员会模仿;成熟的程序员偷窃;糟糕的程序员会破坏他们所获得的东西,而优秀的程序员会将其变成更好的东西,或者至少是不同的东西。优秀的程序员将他的盗窃行为焊接成一种独特的整体感觉,与被撕裂的感觉完全不同。
linux-0.11
├── boot
│ ├── bootsect.s head.s setup.s
├── fs
│ ├── bitmap.c block_dev.c buffer.c char_dev.c exec.c
│ ├── fcntl.c file_dev.c file_table.c inode.c ioctl.c
│ ├── namei.c open.c pipe.c read_write.c
│ ├── stat.c super.c truncate.c
├── include
│ ├── a.out.h const.h ctype.h errno.h fcntl.h
│ ├── signal.h stdarg.h stddef.h string.h termios.h
│ ├── time.h unistd.h utime.h
│ ├── asm
│ │ ├── io.h memory.h segment.h system.h
│ ├── linux
│ │ ├── config.h fdreg.h fs.h hdreg.h head.h
│ │ ├── kernel.h mm.h sched.h sys.h tty.h
│ ├── sys
│ │ ├── stat.h times.h types.h utsname.h wait.h
├── init
│ └── main.c
├── kernel
│ ├── asm.s exit.c fork.c mktime.c panic.c
│ ├── printk.c sched.c signal.c sys.c system_calls.s
│ ├── traps.c vsprintf.c
│ ├── blk_drv
│ │ ├── blk.h floppy.c hd.c ll_rw_blk.c ramdisk.c
│ ├── chr_drv
│ │ ├── console.c keyboard.S rs_io.s
│ │ ├── serial.c tty_io.c tty_ioctl.c
│ ├── math
│ │ ├── math_emulate.c
├── lib
│ ├── close.c ctype.c dup.c errno.c execve.c _exit.c
│ ├── malloc.c open.c setsid.c string.c wait.c write.c
├── Makefile
├── mm
│ ├── memory.c page.s
└── tools
└── build.c
- 初学者从Linux 0.11 源码(源代码少于20,000行)。经过20年的发展,与Linux 0.11相比,Linux已经变得非常庞大、复杂、难学。但设计理念和主体结构没有根本性变化。学习Linux 0.11还是有重要的现实意义的。
- 内核黑客必读 =>
Linux_source_dir/Documentation/*
- 您应该订阅并活跃至少一个内核邮件列表。从...开始内核新手。
- 您不需要阅读完整的源代码。一旦熟悉了内核 API 及其用法,就可以直接从您感兴趣的子系统的源代码开始。您也可以从编写自己的即插即用模块开始对内核进行实验。
- 设备驱动程序编写者将受益于拥有自己的专用硬件。从...开始树莓派。
答案2
Linux 内核新手是一个很好的资源。
答案3
我建议你阅读“Linux 内核简述”,作者:Greg Kroah-Hartman 和“了解 Linux 内核”,作者:罗伯特·洛夫。必须阅读:)
答案4
参见Linux 文档项目。特别是“Linux内核模块指南”。