拦截 open调用 (进程白名单,文件白名单)

拦截 open

文章目录

      • 拦截 open
      • 第一个需求
      • 文件结构
        • 进程白名单
        • 文件白名单
      • 测试代码
      • 第一个版本
      • 版本二
        • 代码演示
      • 增加一个日志记录
      • 代码解释

gcc -shared -fPIC -o libintercept.so intercept.c -ldl
LD_PRELOAD=./libintercept.so ./processA
在Linux中,我们可以使用LD_PRELOAD环境变量来拦截并替换系统调用,如open函数。这是一个简单的示例,展示了如何创建一个新的open函数来替换系统的open函数:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>// 定义原始的open函数
static int (*original_open)(const char*, int, ...);// 我们的新open函数
int open(const char *pathname, int flags, ...) {printf("Intercepted open call for %s\n", pathname);// 获取原始的open函数original_open = dlsym(RTLD_NEXT, "open");// 调用原始的open函数return original_open(pathname, flags);
}~~~

你可以将这段代码保存为一个.c文件,然后使用以下命令编译为共享库:

gcc -shared -fPIC -o libintercept.so intercept.c -ldl


然后,你可以使用LD_PRELOAD环境变量来运行你的程序,如下所示:```bash
LD_PRELOAD=./libintercept.so your_program

这样,每当你的程序调用open函数时,都会调用我们的新open函数,而不是系统的open函数。

请注意,这只是一个基本的示例,你可能需要根据你的具体需求来修改这个新的open函数。此外,使用LD_PRELOAD拦截系统调用应该谨慎进行,因为它可能会影响到其他库的行为。


第一个需求

第一个需求
1.白名单进程 保存在 进程白名单文件 , 受保护文件的文件名保存在 文件白名单文件 中,
2.白名单 进程 能访问 所有文件(受保护文件和非保护文件)
3.对所有进程访问文件的 过程进行日志记录.(进程名,文件名,访问时间,成功与否)

在这里插入图片描述

文件结构

.
├── Files
│   ├── t1
│   ├── t2
│   ├── t3
│   ├── t4
│   ├── t5
│   ├── t6
│   ├── t7
│   ├── t8
│   └── t9
├── WHITELIST
│   ├── file_whitelist
│   ├── file_whitelist_backup
│   └── process_whitelist
├── intercept.c
├── libintercept.so
├── log.txt
├── p1
└── p1.c
进程白名单

白名单文件的路径名是/home/xxx/Test/WHITELIST/process_whitelist

/home/xxx/Test/p1
/home/xxx/Test/p2
/home/xxx/Test/p3
/home/xxx/Test/p4
/home/xxx/Test/p5
文件白名单

非白名单文件的路径名是/home/xxx/Test/WHITELIST/file_whitelist

/home/xxx/Test/Files/t1
/home/xxx/Test/Files/t2
/home/xxx/Test/Files/t3
/home/xxx/Test/Files/t4
/home/xxx/Test/Files/t5

测试代码

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>int main() {DIR *dir;struct dirent *entry;int fd;// 打开目录dir = opendir("/home/xxx/Test/Files");if (dir == NULL) {perror("无法打开目录");return 1;}// 遍历目录中的每个文件while ((entry = readdir(dir)) != NULL) {// 检查文件名是否以"t"开头if (strncmp(entry->d_name, "t", 1) == 0) {char filepath[1024];// 构造文件路径snprintf(filepath, sizeof(filepath), "/home/xxx/Test/Files/%s", entry->d_name);// 使用open函数打开文件fd = open(filepath, O_RDWR);if (fd == -1) {perror("无法打开文件");continue;}printf("打开文件: %s\n", filepath);// 写入文件const char *message = "我访问了这个文件\n";if (write(fd, message, strlen(message)) == -1) {perror("无法写入文件");}// 关闭文件if (close(fd) == -1) {perror("无法关闭文件");}}}// 关闭目录if (closedir(dir) == -1) {perror("无法关闭目录");}return 0;
}

第一个版本

gcc -shared -fPIC -o libintercept.so intercept.c -ldl

当然,这是修改后的完整代码:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>// 定义原始的open函数
static int (*original_open)(const char*, int, ...);// 根据进程ID获取进程名
char *get_process_name(pid_t pid) {char path[256];static char name[256];snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);FILE *file = fopen(path, "r");if (file == NULL) {return NULL;}if (fgets(name, sizeof(name), file) == NULL) {fclose(file);return NULL;}fclose(file);// 将程序名称转换为绝对路径char *absolute_path = realpath(name, NULL);if (absolute_path != NULL) {strncpy(name, absolute_path, sizeof(name));free(absolute_path);}return name;
}// 检查进程是否在白名单中
int is_whitelisted_process(const char *whitelist) {FILE *file = fopen(whitelist, "r");if (file == NULL) {return 0;}char *process_name = get_process_name(getpid());if (process_name == NULL) {fclose(file);return 0;}char line[256];while (fgets(line, sizeof(line), file)) {line[strcspn(line, "\n")] = '\0';  // 去掉换行符if (strcmp(line, process_name) == 0) {printf("匹配进程白名单成功,进程名为%s\n",process_name);fclose(file);return 1;}}fclose(file);return 0;
}// 检查文件是否在白名单中
int is_whitelisted_file(const char *whitelist, const char *filename) {FILE *file = fopen(whitelist, "r");if (file == NULL) {return 0;}char line[256];while (fgets(line, sizeof(line), file)) {line[strcspn(line, "\n")] = '\0';  // 去掉换行符if (strcmp(line, filename) == 0) {printf("匹配文件白名单成功,访问文件名为%s\n",filename);fclose(file);return 1;}}fclose(file);return 0;
}// 我们的新open函数
int open(const char *pathname, int flags, ...) {   //pathname 是打开的文件地址// 获取原始的open函数original_open = dlsym(RTLD_NEXT, "open");char real_path[PATH_MAX];realpath(pathname, real_path); // 将打开的文件路径转换为绝对路径// 检查进程是否在白名单中if (is_whitelisted_process("/home/xxx/Test/WHITELIST/process_whitelist")) {   // 传入的是进程白名单列表的绝对地址// 白名单进程可以访问所有文件return original_open(real_path, flags);}// 检查文件是否在白名单中,  传入文件白名单的绝对地址,和要访问文件的绝对地址if (!is_whitelisted_file("/home/xxx/Test/WHITELIST/file_whitelist", real_path)) {printf("非白名单文件的路径名是%s\n",real_path);// 非白名单进程可以访问非白名单文件return original_open(real_path, flags);}// 非白名单进程不能访问白名单文件fprintf(stderr, "拒绝访问: %s\n", real_path);return -1;
}

这段代码首先获取进程名,并将其转换为绝对路径。然后,它将这个绝对路径与进程白名单进行比较。如果进程在白名单中,它就可以访问所有文件。如果进程不在白名单中,但要访问的文件也不在白名单中,那么进程仍然可以访问该文件。如果进程和文件都不在白名单中,那么访问将被拒绝。

之前的版本一没有获取进程名绝对值

版本二

  1. 使用哈希表存储白名单:每次检查文件或进程是否在白名单中时,都需要打开白名单文件并逐行读取。这在白名单很大时会非常低效。相反,可以在程序启动时将白名单读入内存中的哈希表。这样,检查一个文件或进程是否在白名单中只需要在哈希表中查找,这将大大提高效率。
  2. 避免重复计算is_whitelisted_processis_whitelisted_file函数都调用了get_process_name函数来获取进程名。这意味着在一次open调用中,可能会多次计算同一个进程的名字。可以通过将进程名缓存到全局变量中来避免这种重复计算。
  3. 减少内存分配:在get_process_name函数中,每次调用都会分配一个新的字符串来存储进程名。这可能会导致大量的内存分配和释放。可以考虑使用静态缓冲区来存储进程名,从而避免频繁的内存分配。
  4. 关闭文件描述符:在is_whitelisted_processis_whitelisted_file函数中,如果在打开文件后发生错误,函数会直接返回,可能会导致文件描述符泄漏。应确保在所有可能的代码路径上都正确关闭了文件描述符。
gcc -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -shared -fPIC -o libintercept.so intercept.c -ldl -lglib-2.0
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>#include <glib.h>  // 需要安装glib库// 定义原始的open函数
static int (*original_open)(const char*, int, ...);// 进程名和白名单的全局变量
static char process_name[256] = {0};
static GHashTable *process_whitelist = NULL;
static GHashTable *file_whitelist = NULL;// 根据进程ID获取进程名
char *get_process_name(pid_t pid) {if (process_name[0] == '\0') {char path[256];snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);FILE *file = fopen(path, "r");if (file == NULL) {return NULL;}if (fgets(process_name, sizeof(process_name), file) == NULL) {fclose(file);return NULL;}fclose(file);}// 将程序名称转换为绝对路径char *absolute_path = realpath(process_name, NULL);if (absolute_path != NULL) {strncpy(process_name, absolute_path, sizeof(process_name));free(absolute_path);// printf("绝对路径不为空");
//      printf("进程绝对路径为 %s",process_name);}else{printf("进程名 %s 绝对路径为空\n",process_name);}return process_name;
}// 从文件中加载白名单到哈希表
void load_whitelist(const char *filename, GHashTable **whitelist) {FILE *file = fopen(filename, "r");if (file == NULL) {return;}char line[256];while (fgets(line, sizeof(line), file)) {line[strcspn(line, "\n")] = '\0';  // 去掉换行符g_hash_table_insert(*whitelist, g_strdup(line), NULL);}fclose(file);
}// 检查进程是否在白名单中
int is_whitelisted_process() {if (process_whitelist == NULL) {process_whitelist = g_hash_table_new(g_str_hash, g_str_equal);load_whitelist("/home/xxx/Test/WHITELIST/process_whitelist", &process_whitelist);}return g_hash_table_contains(process_whitelist, get_process_name(getpid()));
}// 检查文件是否在白名单中
int is_whitelisted_file(const char *filename) {if (file_whitelist == NULL) {file_whitelist = g_hash_table_new(g_str_hash, g_str_equal);load_whitelist("/home/xxx/Test/WHITELIST/file_whitelist", &file_whitelist);}return g_hash_table_contains(file_whitelist, filename);
}// 我们的新open函数
int open(const char *pathname, int flags, ...) {// 获取原始的open函数original_open = dlsym(RTLD_NEXT, "open");char real_path[PATH_MAX];realpath(pathname, real_path); // 将打开的文件路径转换为绝对路径// 检查进程是否在白名单中if (is_whitelisted_process()) {// 白名单进程可以访问所有文件printf("白名单进程访问%s 访问文件%s\n",get_process_name(getpid()),real_path);return original_open(real_path, flags);}// 检查文件是否在白名单中if (!is_whitelisted_file(real_path)) {// 非白名单进程可以访问非白名单文件printf("非白名单进程访问%s 访问 非白名单文件%s\n",get_process_name(getpid()),real_path);return original_open(real_path, flags);}printf("非白名单进程访问%s 访问 白名单文件%s\n",get_process_name(getpid()),real_path);// 非白名单进程不能访问白名单文件fprintf(stderr, "拒绝访问: %s\n", real_path);return -1;
}

这个代码使用了glib库的哈希表实现。在程序启动时,它会将白名单文件读入内存中的哈希表。然后,检查一个文件或进程是否在白名单中只需要在哈希表中查找,这将大大提高效率。此外,它还缓存了进程名,避免了重复计算。请注意,这个代码需要安装glib库才能编译和运行。

代码演示

白名单进程

能访问所有文件

在这里插入图片描述
在这里插入图片描述

非白名单进程

只能访问非白名单文件

在这里插入图片描述
在这里插入图片描述

增加一个日志记录


#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <time.h>#include <glib.h>  // 需要安装glib库// 定义原始的open函数
static int (*original_open)(const char*, int, ...);// 进程名和白名单的全局变量
static char process_name[256] = {0};
static GHashTable *process_whitelist = NULL;
static GHashTable *file_whitelist = NULL;// 日志文件名
static const char *log_filename = "/home/xxx/Test/LOG";// 根据进程ID获取进程名
char *get_process_name(pid_t pid) {if (process_name[0] == '\0') {char path[256];snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);FILE *file = fopen(path, "r");if (file == NULL) {return NULL;}if (fgets(process_name, sizeof(process_name), file) == NULL) {fclose(file);return NULL;}fclose(file);}// 将程序名称转换为绝对路径char *absolute_path = realpath(process_name, NULL);if (absolute_path != NULL) {strncpy(process_name, absolute_path, sizeof(process_name));free(absolute_path);// printf("绝对路径不为空");
//      printf("进程绝对路径为 %s",process_name);}else{printf("进程名 %s 绝对路径为空\n",process_name);}return process_name;
}// 从文件中加载白名单到哈希表
void load_whitelist(const char *filename, GHashTable **whitelist) {FILE *file = fopen(filename, "r");if (file == NULL) {return;}char line[256];while (fgets(line, sizeof(line), file)) {line[strcspn(line, "\n")] = '\0';  // 去掉换行符g_hash_table_insert(*whitelist, g_strdup(line), NULL);}fclose(file);
}// 检查进程是否在白名单中
int is_whitelisted_process() {if (process_whitelist == NULL) {process_whitelist = g_hash_table_new(g_str_hash, g_str_equal);load_whitelist("/home/xxx/Test/WHITELIST/process_whitelist", &process_whitelist);}return g_hash_table_contains(process_whitelist, get_process_name(getpid()));
}// 检查文件是否在白名单中
int is_whitelisted_file(const char *filename) {if (file_whitelist == NULL) {file_whitelist = g_hash_table_new(g_str_hash, g_str_equal);load_whitelist("/home/xxx/Test/WHITELIST/file_whitelist", &file_whitelist);}return g_hash_table_contains(file_whitelist, filename);
}// 记录日志
void log_access(const char *process, const char *file, int success) {FILE *log_file = fopen(log_filename, "a");if (log_file == NULL) {return;}time_t now = time(NULL);char *time_str = ctime(&now);time_str[strlen(time_str) - 1] = '\0';  // 去掉换行符fprintf(log_file, "[%s] Process: %s, File: %s, Access: %s\n",time_str, process, file, success ? "SUCCESS" : "FAILURE");fclose(log_file);
}// 我们的新open函数
int open(const char *pathname, int flags, ...) {// 获取原始的open函数original_open = dlsym(RTLD_NEXT, "open");char real_path[PATH_MAX];realpath(pathname, real_path); // 将打开的文件路径转换为绝对路径// 检查进程是否在白名单中if (is_whitelisted_process()) {// 白名单进程可以访问所有文件if (is_whitelisted_file(real_path)) {// 记录白名单进程访问白名单文件的日志log_access(get_process_name(getpid()), real_path, 1);}return original_open(real_path, flags);}// 检查文件是否在白名单中if (is_whitelisted_file(real_path)) {// 记录非白名单进程访问白名单文件的日志log_access(get_process_name(getpid()), real_path, 0);fprintf(stderr, "拒绝访问: %s\n", real_path);return -1;}// 非白名单进程可以访问非白名单文件return original_open(real_path, flags);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码解释

这段代码主要包含以下几个函数:

  1. get_process_name(pid_t pid):此函数根据进程ID获取进程名。它首先检查全局变量process_name是否已经被设置。如果没有,它会打开/proc/<pid>/cmdline文件并读取第一行,这就是进程名。然后,它会将进程名转换为绝对路径。
  2. load_whitelist(const char *filename, GHashTable **whitelist):此函数从指定的文件中加载白名单,并将其存储在一个哈希表中。每一行都被视为一个独立的条目。
  3. is_whitelisted_process()is_whitelisted_file(const char *filename):这两个函数检查给定的进程或文件是否在相应的白名单中。如果白名单哈希表尚未创建,它们会首先调用load_whitelist函数来加载白名单。
  4. log_access(const char *process, const char *file, int success):此函数将访问记录写入日志文件。每条记录包含时间戳、进程名、文件名和访问结果(成功或失败)。
  5. open(const char *pathname, int flags, ...):这是一个拦截open系统调用的函数。它首先检查调用进程是否在进程白名单中。如果在,那么它可以打开任何文件。否则,它只能打开文件白名单中的文件。如果一个非白名单进程试图打开一个白名单文件,访问将被拒绝,并记录一条失败的访问记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。

这段代码是一个Linux系统调用拦截器,它拦截了open系统调用。这个拦截器的目的是限制某些进程访问特定的文件。它的工作原理如下:

  1. 获取进程名get_process_name函数通过读取/proc/<pid>/cmdline文件来获取进程名。这个文件包含了启动该进程的命令行参数。
  2. 加载白名单load_whitelist函数从指定的文件中读取白名单,并将其存储在一个哈希表中。白名单中的每一行都被视为一个独立的条目。
  3. 检查白名单is_whitelisted_processis_whitelisted_file函数检查给定的进程或文件是否在相应的白名单中。
  4. 记录日志log_access函数将访问记录写入日志文件。每条记录包含时间戳、进程名、文件名和访问结果(成功或失败)。
  5. 拦截open系统调用:新的open函数首先检查调用进程是否在进程白名单中。如果在,那么它可以打开任何文件。否则,它只能打开文件白名单中的文件。如果一个非白名单进程试图打开一个白名单文件,访问将被拒绝,并记录一条失败的访问记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。

记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。

这段代码是一个Linux系统调用拦截器,它拦截了open系统调用。这个拦截器的目的是限制某些进程访问特定的文件。它的工作原理如下:

  1. 获取进程名get_process_name函数通过读取/proc/<pid>/cmdline文件来获取进程名。这个文件包含了启动该进程的命令行参数。
  2. 加载白名单load_whitelist函数从指定的文件中读取白名单,并将其存储在一个哈希表中。白名单中的每一行都被视为一个独立的条目。
  3. 检查白名单is_whitelisted_processis_whitelisted_file函数检查给定的进程或文件是否在相应的白名单中。
  4. 记录日志log_access函数将访问记录写入日志文件。每条记录包含时间戳、进程名、文件名和访问结果(成功或失败)。
  5. 拦截open系统调用:新的open函数首先检查调用进程是否在进程白名单中。如果在,那么它可以打开任何文件。否则,它只能打开文件白名单中的文件。如果一个非白名单进程试图打开一个白名单文件,访问将被拒绝,并记录一条失败的访问记录。

这个拦截器可以用来限制某些进程访问敏感文件,或者跟踪某些进程的文件访问行为。但是,它也可能被用于恶意目的,比如阻止某些进程正常工作。因此,使用这种拦截器需要谨慎。


待改进之处
程序一开始就应该加载白名单文件,而不是在open函数调用一次就加载一次。但是如果一开始就加载文件白名单,之后如果对白名单文件进行修改,就要将 该so 库文件重新编译一次。 如果能监控白名单文件是否修改,如果修改了就再加载白名单文件 就好了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/208781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

12.Mysql 多表数据横向合并和纵向合并

Mysql 函数参考和扩展&#xff1a;Mysql 常用函数和基础查询、 Mysql 官网 Mysql 语法执行顺序如下&#xff0c;一定要清楚&#xff01;&#xff01;&#xff01;运算符相关&#xff0c;可前往 Mysql 基础语法和执行顺序扩展。 (8) select (9) distinct (11)<columns_name…

【力扣热题100】287. 寻找重复数(弗洛伊德的乌龟和兔子方法)

【力扣热题100】287. 寻找重复数 写在最前面理解解决 "寻找重复数" 问题的算法问题描述弗洛伊德的乌龟和兔子方法为什么这个方法有效&#xff1f; 代码复杂度 总结回顾 写在最前面 刷一道力扣热题100吧 难度中等 https://leetcode.cn/problems/find-the-duplicate-…

Java Web应用小案例 - 实现用户登录功能

文章目录 一、使用纯JSP方式实现用户登录功能&#xff08;一&#xff09;项目概述&#xff08;二&#xff09;实现步骤1、创建Web项目2、创建登录页面 二、使用JSPServlet方式实现用户登录功能三、使用JSPServletDB方式实现用户登录功能 一、使用纯JSP方式实现用户登录功能 &a…

ubuntu22.04安装 nvidia-cudnn

nvidia-cudnn 是 NVIDIA CUDA 深度神经网络库&#xff08;CUDA Deep Neural Network library&#xff09;的缩写。这是一个由 NVIDIA 提供的库&#xff0c;用于加速深度学习应用程序。它包含了针对深度神经网络中常用操作&#xff08;如卷积、池化、归一化、激活层等&#xff0…

【Linux】如何清空某个文件的内容

cat /dev/null > file1 清空某个文件的内容使用cat /dev/null > file1&#xff0c;它将 /dev/null 的内容&#xff08;空内容&#xff09;重定向到 file1。 如下所示&#xff0c;file1文件里的内容被清空。 错误写法 错误写法是&#xff1a;cat file1 > /dev/null&…

持续集成交付CICD:CentOS 7 安装 Nexus 3.63

目录 一、实验 1.CentOS 7 安装Nexus3.63 二、问题 1.安装Nexus报错 2.Nexus启动停止相关命令 一、实验 1.CentOS 7 安装Nexus3.63 &#xff08;1&#xff09;当前操作系统版本&JDK版本 cat /etc/redhat-releasejava -version&#xff08;2&#xff09;下载Nexus新…

int 和 Integer 有什么区别,还有 Integer 缓存的实现

✨前言✨   Java本文主要介绍Java int 和 Integer的区别以及Integer 缓存的实现 &#x1f352;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f352;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评论区留言 文章目…

用C++实现队列顺序结构的基本操作

//队列顺序结构的基本操作&#xff1a; #include"stdio.h" #include"String" #define QueueSize 100 typedef char ElemType; typedef struct { ElemType data[QueueSize]; /*保存队中元素*/int front,rear; /*队头和队尾指针*/ } SqQueue; void Init…

使用STM32定时器实现精确的时间测量和延时

✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进&#xff0c; 代码获取、问题探讨及文章转载可私信。 ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。 &#x1f34e;获取更多嵌入式资料可点击链接进群领取&#xff0c;谢谢支持&#xff01;…

大数据技术4:Lambda和Kappa架构区别

前言&#xff1a;在大数据处理领域&#xff0c;两种突出的数据架构已成为处理大量数据的流行选择&#xff1a;Lambda 架构和 Kappa 架构。这些架构为实时处理和批处理提供了强大的技术解决方案&#xff0c;使组织能够从其数据中获得有价值的见解。随着互联网时代来临&#xff0…

Python VSCode 配置固定的脚本入口

Python VSCode 配置固定的脚本入口 打开或者新建一个启动配置 选择 .vscode目录下 launch.json文件 将 “program”: “${file}” 替换成 “program”: “mian.py”, //完成你自己的入口.py文件名即可 json启动配置文件 {// Use IntelliSense to learn about possible attrib…

面向对象中的单例模式

1、什么是设计模式 设计模式就是前人根据实际的问题提出的问题解决方案&#xff0c;我们把这种就称之为设计模式。 2、单例模式 单例模式是一种常见的设计模式&#xff01; 所谓的设计模式&#xff0c;不是一种新的语法&#xff0c;而是人们在实际的应用中&#xff0c;面对…

【银行测试】金融项目+测试方法范围分析,功能/接口/性能/安全...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、金融行业软件特…

3GPP标准查看、下载和几个UE相关系列标准

由于一直做终端侧协议。最近以UE为核心重新下载了一系列文档。 总结并举例一下分类标准。 如何查看3GPP标准列表 实际上在3GPP网站如下链接&#xff1a;Specifications by Series&#xff0c;每个系列以及分类都说的很清楚。 几个系列分类举例 和终端协议层工作比较关系密切…

ModuleNotFoundError: No module named ‘dlib‘

解决&#xff1a;ModuleNotFoundError: No module named ‘dlib’ 文章目录 解决&#xff1a;ModuleNotFoundError: No module named dlib背景报错问题报错翻译报错位置代码报错原因解决方法方法一&#xff0c;直接安装方法二&#xff0c;手动下载安装方法三&#xff0c;编译安…

SD之lora训练

目录 为什么要训练自己的模型 SD模型微调方法 准备素材 1 确定要训练的LoRA类型 2 图片收集 3 图片预处理 4 图片标注 安装Koyha_ss 训练lora 1.准备参数和环境 2.启动训练 使用模型 1 拷贝训练过的lora模型 2 启动SD WebUI进行图像生成 为什么要训练自己的模型 …

webpack该如何打包

1.我们先创建一个空的大文件夹 2.打开该文件夹的终端 输入npm init -y 2.1.打开该文件夹的终端 2.2在该终端运行 npm init -y 3.安装webpack 3.1打开webpack网址 点击“中文文档” 3.2点击“指南”在点击“起步” 3.3复制基本安装图片画线的代码 4.在一开始的文件夹下在创建一…

案例061:基于微信小程序的互助学习系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

django与数据库交互关于当前时间的坑

背景 在线上服务中使用时间进行数据库操作时发现异常&#xff0c;而在本地环境无法成功复现此问题&#xff0c;导致难以进行故障排查。 核心问题 view.py class XxxViewSet(viewsets.ModelViewSet):queryset Xxx.objects.with_status().order_by("status", &quo…

【数据结构】插入排序,希尔排序,选择排序,堆排序,冒泡排序

1.插入排序 思路&#xff1a;插入排序将一个数插入一个有序的数组里面&#xff0c;将这个数和数组元素挨着比较&#xff0c;直到他插入到合适的位置。 动画演示&#xff1a; 步骤&#xff1a;1.定义一个变量tmp保存要插入的数据 2.在循环中用tmp和有序数组中的元素比较&#…