最后的话
最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!
资料预览
给大家整理的视频资料:
给大家整理的电子书资料:
如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
// linux-3.10/include/linux/module.h
static inline int within_module_core(unsigned long addr, const struct module *mod)
{
return (unsigned long)mod->module_core <= addr &&
addr < (unsigned long)mod->module_core + mod->core_size;
}
static inline int within_module_init(unsigned long addr, const struct module *mod)
{
return (unsigned long)mod->module_init <= addr &&
addr < (unsigned long)mod->module_init + mod->init_size;
}
within\_module\_core判断地址addr是否在模块的module\_core地址区间。
within\_module\_init判断地址addr是否在模块的module\_init 地址区间。
// linux-3.10/include/linux/rculist.h
/**
* list_for_each_entry_rcu - iterate over rcu list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as list_add_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
#define list_for_each_entry_rcu(pos, head, member)
for (pos = list_entry_rcu((head)->next, typeof(*pos), member);
&pos->member != (head);
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
该函数逻辑非常简单,遍历内核模块链表,如果给定的地址在一个内核模块的module\_init和module\_core的范围之间,则找到所在地址属于该模块。
为了防止模块被释放,使用该函数时必须禁止内核抢占,或者加锁访问。注意禁止内核抢占或加锁是保护的struct module结构体数据。
### 1.2 is\_module\_address
is\_module\_address是对\_\_module\_address函数的一个简单封装,用来判断一个地址是否在模块内。宏preempt\_disable( )和preempt\_enable( )分别用来实现禁止内核抢占和允许内核抢占。
/*
* is_module_address - is this address inside a module?
* @addr: the address to check.
*
* See is_module_text_address() if you simply want to see if the address
* is code (not data).
*/
bool is_module_address(unsigned long addr)
{
bool ret;
preempt\_disable();
ret = \_\_module\_address(addr) != NULL;
preempt\_enable();
return ret;
}
## 二、使用例程
include <linux/init.h>
include <linux/kernel.h>
include <linux/module.h>
int test_module(void)
{
return 0;
}
//内核模块初始化函数
static int __init lkm_init(void)
{
struct module *mod;
unsigned long addr = (unsigned long)test_module;
preempt_disable();
mod = __module_address(addr);
preempt_enable();
if(mod){
printk(“module name = %s\n”, mod->name);
printk(“module core_size = %d\n”, mod->core_size);
printk(“module refcount = %ld\n”, module_refcount(mod));
}
return 0;
}
//内核模块退出函数
static void __exit lkm_exit(void)
{
}
module_init(lkm_init);
module_exit(lkm_exit);
MODULE_LICENSE(“GPL”);
test\_module函数的地址在该函数模块内,通过\_\_module\_address找到该模块,结果如下:
![在这里插入图片描述](https://img-blog.csdnimg.cn/285ad5f67ef54d0f93e3e5d101ff2354.png)
## 三、其它类似函数
### 3.1 \_\_module\_text\_address
/*
* is_module_text_address - is this address inside module code?
* @addr: the address to check.
*
* See is_module_address() if you simply want to see if the address is
* anywhere in a module. See kernel_text_address() for testing if an
* address corresponds to kernel or module code.
*/
bool is_module_text_address(unsigned long addr)
{
bool ret;
preempt\_disable();
ret = \_\_module\_text\_address(addr) != NULL;
preempt\_enable();
return ret;
}
/*
* __module_text_address - get the module whose code contains an address.
* @addr: the address.
*
* Must be called with preempt disabled or module mutex held so that
* module doesn’t get freed during this.
*/
struct module *__module_text_address(unsigned long addr)
{
struct module *mod = __module_address(addr);
if (mod) {
/* Make sure it’s within the text section. */
if (!within(addr, mod->module_init, mod->init_text_size)
&& !within(addr, mod->module_core, mod->core_text_size))
mod = NULL;
}
return mod;
}
EXPORT_SYMBOL_GPL(__module_text_address);
\_\_module\_text\_address返回值是一个struct module类型的指针,如果内存地址addr在某一模块的代码段内,则返回指向该模块的指针,如果addr不在模块的代码段内,则返回NULL。
init\_text\_size是内核模块初始化部分代码段大小。
core\_text\_size是内核模块核心部分代码段大小。
### 3.2 is\_module\_percpu\_address
/**
* is_module_percpu_address - test whether address is from module static percpu
* @addr: address to test
*
* Test whether @addr belongs to module static percpu area.
*
* RETURNS:
* %true if @addr is from module static percpu area
*/
bool is_module_percpu_address(unsigned long addr)
{
struct module *mod;
unsigned int cpu;
preempt\_disable();
list\_for\_each\_entry\_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED)
continue;
if (!mod->percpu_size)
continue;
for\_each\_possible\_cpu(cpu) {
void \*start = per\_cpu\_ptr(mod->percpu, cpu);
if ((void \*)addr >= start &&
(void \*)addr < start + mod->percpu_size) {
preempt\_enable();
return true;
}
}
}
preempt\_enable();
return false;
}
struct module
{
#ifdef CONFIG_SMP
/* Per-cpu data. */
void __percpu *percpu;
unsigned int percpu_size;
#endif
}
percpu指向该内核模块的percpu数据,在模块加载时初始化。
percpu\_size是percpu数据大小。
## 总结
通过判断全局内核链表modules下的每一个模块,判断该地址是否在模块的内存范围内。
该函数可在安全领域中用来检测内核关键点是否被hook,可参考开源项目:
<https://github.com/bytedance/Elkeid/blob/main/driver/LKM/src/anti_rootkit.c>
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
nti_rootkit.c>
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/forums/4f45ff00ff254613a03fab5e56a57acb)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**