so_hook/hook.bin.cpp
dongl 64452a7aa7 main.cpp
g++ -Wall -fPIC -shared -o net_ip_hook.so main.cpp -ldl
sudo gedit /etc/environment

#LD_LIBRARY_PATH
#LD_PRELOAD
LD_PRELOAD="/home/dongl/code/safe_test/hook.so"
#LD_PRELOAD="/home/dongl/code/safe_test/net_ip_hook.so"
2023-07-10 13:22:50 +08:00

273 lines
9.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by dongl on 23-7-10.
//
#include <dlfcn.h>
#include <fcntl.h>
#include <cstring>
#include <string>
#include <set>
#include <unistd.h>
#include <algorithm>
#include <arpa/inet.h>
#define ACCEPT 9999
#define CONNECT 19999
// 定义指向原始open函数的函数指针
typedef int (*file_open_func_t)(const char *pathname, int flags, ...);
static file_open_func_t original_file_open = nullptr;
static file_open_func_t file_open = nullptr;
//read
typedef ssize_t (*file_read_func_t)(int fd, void *buf, size_t nbytes);
static file_read_func_t original_file_read = nullptr;
static file_read_func_t file_read = nullptr;
// connect
typedef int (*ip_connect_fun_t)(int, const struct sockaddr *, socklen_t);
static ip_connect_fun_t original_file_connect = nullptr;
static ip_connect_fun_t file_connect = nullptr;
// accept
typedef int (*ip_accept_fun_t)(int, struct sockaddr *, socklen_t *);
static ip_accept_fun_t original_file_accept = nullptr;
static ip_accept_fun_t file_accept = nullptr;
// 定义原始的do_sys_open()函数指针
//static long (*real_do_sys_open)(int dfd, const char __user *filename, int flags, umode_t mode) = nullptr;
// 定义日志文件路径和配置文件路径的环境变量
const char *LOG_FILE_PATH = "/home/dongl/code/safe_test/log";
const char *CONFIG_FILE_PATH = "/home/dongl/code/safe_test/config.txt";
const char *LOG_NET_IP_PATH = "/home/dongl/code/safe_test/net-log";
const char *CONFIG_NET_IP_PATH = "/home/dongl/code/safe_test/net-config.txt";
// 将时间戳转换为字符串
std::string Time_t2String(time_t t) {
char tmp[64] = {0};
strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S", localtime(&t));
return tmp;
}
// 获取当前进程的可执行文件路径和名称
size_t get_executable_path(char *processdir, char *processname, size_t len) {
char *path_end;
if (readlink("/proc/self/exe", processdir, len) <= 0)
return -1;
path_end = strrchr(processdir, '/');
if (path_end == nullptr)
return -1;
++path_end;
strcpy(processname, path_end);
*path_end = '\0';
return (size_t) (path_end - processdir);
}
// 读取配置文件并填充文件和进程集合
void read_config_file(std::set<std::string>& file_set, std::set<std::string>& process_set, const char* config_name) {
// 打开配置文件
int config_fd = original_file_open(config_name, O_RDONLY);
if (config_fd < 0)
return;
// 读取配置文件
char buff[4096];
std::string data;
bool state = true;
while (original_file_read(config_fd, buff, sizeof(buff)) > 0) {
for (const auto &item: buff) {
if (item != '\n') {
data.push_back(item);
} else if (item == '\n') {
// 检查行是文件部分还是进程部分
std::string temp = config_name == CONFIG_FILE_PATH ? "[safe_file]" : "[black_ip]";
if (data == temp) {
state = true;
data.clear();
continue;
} else if (data == "[safe_process]") {
state = false;
data.clear();
continue;
}
// 将文件或进程添加到相应的集合中
if (state) {
file_set.insert(data);
data.clear();
} else {
process_set.insert(data);
data.clear();
}
}
}
}
// 关闭配置文件
close(config_fd);
}
// 将文件访问日志写入日志文件
void write_log(const std::string &pathname, int mode, const std::string &result, const char* log_name) {
char run_path[40960] = {0};
char process_name[10240] = {0};
get_executable_path(run_path, process_name, sizeof(run_path));
std::string access_mode;
if (mode == O_RDONLY)
access_mode = "读取";
else if (mode == ACCEPT)
access_mode = "ACCEPT";
else if (mode == CONNECT)
access_mode = "CONNECT";
else if (mode == O_WRONLY)
access_mode = "写入";
else if (mode == O_RDWR)
access_mode = "读写";
else if (mode == (O_WRONLY | O_APPEND))
access_mode = "追加";
std::string log = "[" + Time_t2String(time(nullptr)) + "] " +
"<" + pathname + "> " + access_mode + " {" + process_name + ":" + run_path + "} " + result + "\n";
int log_fd = original_file_open(log_name, O_WRONLY | O_CREAT | O_APPEND, 0644);
if (log_fd > 0) {
write(log_fd, log.c_str(), log.size());
close(log_fd);
}
}
//
ssize_t read(int fd, void *buf, size_t nbytes) {
std::set<std::string> file_set;
std::set<std::string> process_set;
read_config_file(file_set, process_set, CONFIG_FILE_PATH);
// 查进程名 及 运行路径
char run_path[4096] = {0};
char process_name[1024] = {0};
get_executable_path(run_path, process_name, sizeof(run_path));
// 根据fd取文件名
char file_name[4096] = {'\0'};
char file_path[4096] = {'\0'};
snprintf(file_name, sizeof(file_name), "/proc/%d/fd/%d", getpid(), fd);
ssize_t ret = readlink(file_name, file_path, sizeof(file_path) - 1);
if (ret == -1) {
return original_file_read(fd, buf, nbytes);
}
// 检查
auto safe_file = file_set.find(file_path);
auto safe_process = process_set.find(process_name);
// 校验
if (safe_file != file_set.end()) {
if (safe_process != process_set.end()) {
write_log(file_path, O_RDONLY, "正常访问", LOG_FILE_PATH);
} else {
write_log(file_path, O_RDONLY, "拒绝访问", LOG_FILE_PATH);
errno = EACCES;
return original_file_read(fd, buf, 0);
}
}
return original_file_read(fd, buf, nbytes);
}
// 判断接入的网络是否为过滤IP如果是则提前返回
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
// 获取链接ip
char ip[128];
memset(ip, 0, sizeof(ip)); // ip地址
int port = -1; // 端口号
if (AF_INET == addr->sa_family) {
auto *sa4 = (struct sockaddr_in *) addr;
inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip));
port = ntohs(sa4->sin_port);
printf("\nAF_INET IP===%s:%d\n", ip, port);
}
// 查进程名 及 运行路径
char run_path[4096] = {0};
char process_name[1024] = {0};
get_executable_path(run_path, process_name, sizeof(run_path));
// 获取黑名单ip
std::set<std::string> ip_set;
std::set<std::string> process_set;
read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH);
auto black_ip = ip_set.find(ip);
auto safe_process = process_set.find(process_name);
// 比较IP 是黑名单ip
if (black_ip != ip_set.end()) {
// log ip
std::string temp;
temp.append(ip);
temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">");
if (safe_process != process_set.end()) {
write_log(temp, CONNECT, "允许访问", LOG_NET_IP_PATH);
return original_file_connect(sockfd, addr, addrlen);
} else {
write_log(temp, CONNECT, "拒绝访问", LOG_NET_IP_PATH);
return -1;
}
}
return original_file_connect(sockfd, addr, addrlen);
}
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
// 获取链接ip
char ip[128];
memset(ip, 0, sizeof(ip)); // ip地址
int port = -1; // 端口号
if (AF_INET == addr->sa_family) {
auto *sa4 = (struct sockaddr_in *) addr;
inet_ntop(AF_INET, (void *) (struct sockaddr *) &sa4->sin_addr, ip, sizeof(ip));
port = ntohs(sa4->sin_port);
printf("\nAF_INET IP===%s:%d\n", ip, port);
}
// 查进程名 及 运行路径
char run_path[4096] = {0};
char process_name[1024] = {0};
get_executable_path(run_path, process_name, sizeof(run_path));
// 获取黑名单ip
std::set<std::string> ip_set;
std::set<std::string> process_set;
read_config_file(ip_set, process_set, CONFIG_NET_IP_PATH);
auto black_ip = ip_set.find(ip);
auto safe_process = process_set.find(process_name);
// log ip
std::string temp;
temp.append(ip);
temp.append(":"+std::to_string(port)+"<"+std::to_string(sockfd)+">");
// 比较IP 是黑名单ip
if (black_ip != ip_set.end()) {
if (safe_process != process_set.end()) {
write_log(temp, ACCEPT, "允许访问",LOG_NET_IP_PATH);
return original_file_accept(sockfd, addr, addrlen);
} else {
write_log(temp, ACCEPT, "拒绝访问", LOG_NET_IP_PATH);
return -1;
}
}
// 放行
return original_file_accept(sockfd, addr, addrlen);
}
// 初始化函数,获取原始文件访问函数的地址并替换为拦截函数
int main() {
original_file_open = (file_open_func_t) dlsym(RTLD_NEXT, "open");
original_file_read = (file_read_func_t) dlsym(RTLD_NEXT, "read");
original_file_connect = (ip_connect_fun_t) dlsym(RTLD_NEXT, "connect");
original_file_accept = (ip_accept_fun_t) dlsym(RTLD_NEXT, "accept");
}