从零实现一个安全沙箱:文件行为分析系统

前言

你有没有想过:杀毒软件是怎么判断一个未知程序是病毒还是正常软件的?它不只是查特征码,还会让程序在"沙箱"里先跑一遍,看看它做了什么。

沙箱是一个隔离的执行环境,让可疑程序在里面运行,观察它的行为------是否修改注册表、是否连接外网、是否加密文件。

今天我们从零实现一个安全沙箱的核心功能:

· 进程隔离(轻量级)

· 系统调用钩子(行为监控)

· 文件操作监控

· 网络行为监控

· 进程行为分析

· 威胁评分


一、沙箱核心原理

  1. 沙箱架构

```

┌─────────────────────────────────────────────────────────────┐

│ 待分析程序 │

│ (可疑样本) │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 钩子层 │

│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │

│ │ 文件操作 │ │ 注册表操作 │ │ 网络操作 │ │

│ │ 钩子 │ │ 钩子 │ │ 钩子 │ │

│ └─────────────┘ └─────────────┘ └─────────────┘ │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 行为日志 │

│ 时间 | 进程 | 操作 | 目标 | 结果 | 风险等级 │

└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐

│ 威胁评分引擎 │

│ 可疑行为加权累加 → 判定恶意/可疑/安全 │

└─────────────────────────────────────────────────────────────┘

```

  1. 行为分析维度

行为类别 可疑操作 风险分数

文件操作 批量加密/删除/改写系统文件 30-50

注册表 修改启动项、关联程序 20-40

网络 连接C2服务器、异常外联 30-60

进程 注入、创建远程线程、修改内存 20-50

系统 关机/重启/修改系统时间 10-30


二、完整代码实现

  1. 基础数据结构

```c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <pthread.h>

#include <time.h>

#include <errno.h>

#include <signal.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <dirent.h>

#include <arpa/inet.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#define MAX_PROCESSES 100

#define MAX_OPERATIONS 10000

#define MAX_PATH_LEN 512

#define MAX_CMD_LEN 256

#define HIGH_RISK_THRESHOLD 80

#define MEDIUM_RISK_THRESHOLD 40

// 操作类型

typedef enum {

OP_FILE_READ = 0,

OP_FILE_WRITE,

OP_FILE_DELETE,

OP_FILE_RENAME,

OP_FILE_CREATE,

OP_REG_READ,

OP_REG_WRITE,

OP_REG_DELETE,

OP_NET_CONNECT,

OP_NET_SEND,

OP_NET_LISTEN,

OP_PROC_CREATE,

OP_PROC_INJECT,

OP_PROC_TERMINATE,

OP_SYSTEM_EXEC

} operation_type_t;

// 操作记录

typedef struct operation_record {

time_t timestamp;

pid_t pid;

char process_name64;

operation_type_t op_type;

char targetMAX_PATH_LEN;

char detail256;

int risk_score;

int is_suspicious;

struct operation_record *next;

} operation_record_t;

// 进程记录

typedef struct process_record {

pid_t pid;

char name64;

char pathMAX_PATH_LEN;

time_t start_time;

time_t end_time;

int suspicious_count;

int operation_count;

int risk_score_total;

struct process_record *next;

} process_record_t;

// 沙箱环境

typedef struct sandbox {

process_record_t *processes;

operation_record_t *operations;

int op_count;

int max_ops;

int high_risk_count;

pthread_mutex_t mutex;

int running;

int monitor_all_pids;

} sandbox_t;

```

  1. 沙箱初始化

```c

// 创建沙箱

sandbox_t *sandbox_create(int max_ops) {

sandbox_t *sb = malloc(sizeof(sandbox_t));

memset(sb, 0, sizeof(sandbox_t));

sb->max_ops = max_ops;

sb->running = 1;

sb->monitor_all_pids = 1;

pthread_mutex_init(&sb->mutex, NULL);

printf("沙箱 初始化完成,最大操作记录: %d\n", max_ops);

return sb;

}

// 查找或创建进程记录

process_record_t *sandbox_get_process(sandbox_t *sb, pid_t pid) {

pthread_mutex_lock(&sb->mutex);

process_record_t *p = sb->processes;

while (p) {

if (p->pid == pid) {

pthread_mutex_unlock(&sb->mutex);

return p;

}

p = p->next;

}

// 创建新进程记录

p = malloc(sizeof(process_record_t));

p->pid = pid;

p->name0 = '\0';

p->path0 = '\0';

p->start_time = time(NULL);

p->end_time = 0;

p->suspicious_count = 0;

p->operation_count = 0;

p->risk_score_total = 0;

p->next = sb->processes;

sb->processes = p;

pthread_mutex_unlock(&sb->mutex);

return p;

}

```

  1. 操作记录

```c

// 获取操作类型名称

const char *op_type_name(operation_type_t type) {

switch (type) {

case OP_FILE_READ: return "FILE_READ";

case OP_FILE_WRITE: return "FILE_WRITE";

case OP_FILE_DELETE: return "FILE_DELETE";

case OP_FILE_RENAME: return "FILE_RENAME";

case OP_FILE_CREATE: return "FILE_CREATE";

case OP_REG_READ: return "REG_READ";

case OP_REG_WRITE: return "REG_WRITE";

case OP_REG_DELETE: return "REG_DELETE";

case OP_NET_CONNECT: return "NET_CONNECT";

case OP_NET_SEND: return "NET_SEND";

case OP_NET_LISTEN: return "NET_LISTEN";

case OP_PROC_CREATE: return "PROC_CREATE";

case OP_PROC_INJECT: return "PROC_INJECT";

case OP_PROC_TERMINATE: return "PROC_TERMINATE";

case OP_SYSTEM_EXEC: return "SYSTEM_EXEC";

default: return "UNKNOWN";

}

}

// 计算操作风险分数

int calculate_risk_score(operation_type_t type, const char *target) {

int score = 0;

switch (type) {

case OP_FILE_DELETE:

score = 15;

// 删除系统关键文件:加分

if (strstr(target, "/etc/") || strstr(target, "/bin/") ||

strstr(target, "/System/") || strstr(target, "\\Windows\\")) {

score += 25;

}

break;

case OP_FILE_WRITE:

score = 10;

// 写入系统目录

if (strstr(target, "/etc/") || strstr(target, "/bin/") ||

strstr(target, "\\Windows\\System32\\")) {

score += 20;

}

break;

case OP_FILE_RENAME:

score = 10;

break;

case OP_NET_CONNECT:

score = 20;

break;

case OP_NET_SEND:

score = 15;

break;

case OP_PROC_INJECT:

score = 30;

break;

case OP_SYSTEM_EXEC:

score = 25;

// 执行敏感命令

if (strstr(target, "rm -rf") || strstr(target, "del /f") ||

strstr(target, "format")) {

score += 30;

}

break;

case OP_REG_WRITE:

score = 15;

// 修改启动项

if (strstr(target, "run") || strstr(target, "Run") ||

strstr(target, "Startup") || strstr(target, "CurrentVersion")) {

score += 20;

}

break;

default:

score = 5;

}

return score;

}

// 记录操作

void sandbox_log_operation(sandbox_t *sb, pid_t pid, operation_type_t type,

const char *target, const char *detail, int force_high) {

pthread_mutex_lock(&sb->mutex);

// 如果记录满了,删除最旧的

if (sb->op_count >= sb->max_ops) {

operation_record_t *old = sb->operations;

sb->operations = old->next;

free(old);

sb->op_count--;

}

// 创建新记录

operation_record_t *op = malloc(sizeof(operation_record_t));

op->timestamp = time(NULL);

op->pid = pid;

op->op_type = type;

strncpy(op->target, target, MAX_PATH_LEN - 1);

op->targetMAX_PATH_LEN - 1 = '\0';

if (detail) {

strncpy(op->detail, detail, 255);

op->detail255 = '\0';

} else {

op->detail0 = '\0';

}

op->risk_score = force_high ? 50 : calculate_risk_score(type, target);

op->is_suspicious = op->risk_score > 20;

op->next = sb->operations;

sb->operations = op;

sb->op_count++;

// 更新进程统计

process_record_t *proc = sandbox_get_process(sb, pid);

if (proc) {

proc->operation_count++;

proc->risk_score_total += op->risk_score;

if (op->is_suspicious) {

proc->suspicious_count++;

}

}

pthread_mutex_unlock(&sb->mutex);

}

```

  1. 系统调用钩子(模拟)

```c

// 模拟的文件操作钩子

int sandbox_file_read(sandbox_t *sb, pid_t pid, const char *filename) {

printf("钩子 进程 %d 读取文件: %s\n", pid, filename);

sandbox_log_operation(sb, pid, OP_FILE_READ, filename, "文件读取", 0);

return 0;

}

int sandbox_file_write(sandbox_t *sb, pid_t pid, const char *filename) {

printf("钩子 进程 %d 写入文件: %s\n", pid, filename);

sandbox_log_operation(sb, pid, OP_FILE_WRITE, filename, "文件写入", 0);

return 0;

}

int sandbox_file_delete(sandbox_t *sb, pid_t pid, const char *filename) {

printf("钩子 进程 %d 删除文件: %s\n", pid, filename);

sandbox_log_operation(sb, pid, OP_FILE_DELETE, filename, "文件删除", 0);

return 0;

}

// 模拟的网络钩子

int sandbox_net_connect(sandbox_t *sb, pid_t pid, const char *host, int port) {

printf("钩子 进程 %d 连接网络: %s:%d\n", pid, host, port);

char detail128;

snprintf(detail, sizeof(detail), "连接 %s:%d", host, port);

sandbox_log_operation(sb, pid, OP_NET_CONNECT, host, detail, 0);

return 0;

}

// 模拟的进程操作钩子

int sandbox_proc_create(sandbox_t *sb, pid_t pid, const char *cmd) {

printf("钩子 进程 %d 创建子进程: %s\n", pid, cmd);

sandbox_log_operation(sb, pid, OP_PROC_CREATE, cmd, "进程创建", 0);

return 0;

}

// 模拟的系统执行钩子

int sandbox_system_exec(sandbox_t *sb, pid_t pid, const char *cmd) {

printf("钩子 进程 %d 执行系统命令: %s\n", pid, cmd);

sandbox_log_operation(sb, pid, OP_SYSTEM_EXEC, cmd, "系统命令执行", 0);

return 0;

}

```

  1. 威胁评分

```c

// 威胁等级

typedef enum {

THREAT_SAFE = 0,

THREAT_SUSPICIOUS,

THREAT_MALICIOUS,

THREAT_CRITICAL

} threat_level_t;

// 威胁结果

typedef struct threat_result {

threat_level_t level;

char description256;

int score;

int suspicious_count;

int total_ops;

char top_risks10128;

} threat_result_t;

// 分析进程行为

threat_result_t sandbox_analyze_process(sandbox_t *sb, pid_t pid) {

threat_result_t result = {0};

result.level = THREAT_SAFE;

result.score = 0;

result.suspicious_count = 0;

result.total_ops = 0;

pthread_mutex_lock(&sb->mutex);

process_record_t *proc = sb->processes;

while (proc) {

if (proc->pid == pid) {

result.score = proc->risk_score_total;

result.suspicious_count = proc->suspicious_count;

result.total_ops = proc->operation_count;

// 收集高风险操作

operation_record_t *op = sb->operations;

int risk_idx = 0;

while (op && risk_idx < 10) {

if (op->pid == pid && op->risk_score >= 30) {

snprintf(result.top_risksrisk_idx, 128,

"%s: %s", op_type_name(op->op_type), op->target);

risk_idx++;

}

op = op->next;

}

break;

}

proc = proc->next;

}

pthread_mutex_unlock(&sb->mutex);

// 判定威胁等级

if (result.score >= HIGH_RISK_THRESHOLD) {

result.level = THREAT_CRITICAL;

strcpy(result.description, "高危恶意行为检测");

} else if (result.score >= MEDIUM_RISK_THRESHOLD) {

result.level = THREAT_MALICIOUS;

strcpy(result.description, "恶意行为检测");

} else if (result.suspicious_count >= 3) {

result.level = THREAT_SUSPICIOUS;

strcpy(result.description, "可疑行为检测");

} else {

strcpy(result.description, "无明显恶意行为");

}

return result;

}

// 生成分析报告

void sandbox_print_report(sandbox_t *sb, pid_t pid) {

threat_result_t result = sandbox_analyze_process(sb, pid);

printf("\n=== 沙箱分析报告 ===\n");

printf("进程PID: %d\n", pid);

printf("威胁等级: ");

switch (result.level) {

case THREAT_SAFE: printf("✅ 安全\n"); break;

case THREAT_SUSPICIOUS: printf("⚠️ 可疑\n"); break;

case THREAT_MALICIOUS: printf("❌ 恶意\n"); break;

case THREAT_CRITICAL: printf("🚨 高危\n"); break;

}

printf("描述: %s\n", result.description);

printf("风险总分: %d\n", result.score);

printf("可疑操作: %d\n", result.suspicious_count);

printf("总操作数: %d\n", result.total_ops);

printf("\n高风险操作:\n");

for (int i = 0; i < 10 && result.top_risksi0; i++) {

printf(" - %s\n", result.top_risksi);

}

}

```

  1. 测试代码

```c

void test_sandbox() {

printf("=== 安全沙箱测试 ===\n\n");

sandbox_t *sb = sandbox_create(1000);

pid_t test_pid = 12345;

// 记录进程信息

process_record_t *proc = sandbox_get_process(sb, test_pid);

strcpy(proc->name, "test.exe");

printf("模拟 开始分析进程 %d\n\n", test_pid);

// 模拟正常行为

sandbox_file_read(sb, test_pid, "C:\\Users\\test\\document.txt");

sandbox_file_read(sb, test_pid, "C:\\Program Files\\app\\config.ini");

sandbox_net_connect(sb, test_pid, "api.example.com", 443);

// 模拟可疑行为

printf("\n--- 检测到可疑行为 ---\n");

sandbox_file_write(sb, test_pid, "C:\\Windows\\System32\\malware.dll");

sandbox_file_delete(sb, test_pid, "C:\\Windows\\System32\\important.sys");

sandbox_system_exec(sb, test_pid, "net user admin password /add");

sandbox_system_exec(sb, test_pid, "reg add HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run /v Malware /d malware.exe");

sandbox_net_connect(sb, test_pid, "192.168.1.100", 4444);

sandbox_net_connect(sb, test_pid, "c2-server.com", 8080);

sandbox_proc_create(sb, test_pid, "cmd.exe /c ransomware.exe");

// 生成报告

sandbox_print_report(sb, test_pid);

printf("\n所有操作记录: %d 条\n", sb->op_count);

printf("可疑操作: ");

int suspicious = 0;

operation_record_t *op = sb->operations;

while (op) {

if (op->is_suspicious) suspicious++;

op = op->next;

}

printf("%d 条\n", suspicious);

free(sb);

}

int main() {

test_sandbox();

return 0;

}

```


三、编译和运行

```bash

gcc -o sandbox sandbox.c -lpthread

./sandbox

```


四、沙箱 vs 传统杀毒

特性 沙箱分析 特征码查杀

检测未知威胁 ✅ 强 ❌ 弱

误报率 中 低

分析时间 秒到分钟 毫秒

资源消耗 高 低

对抗变种 好 差

适用场景 深度分析 实时防护


五、总结

通过这篇文章,你学会了:

· 沙箱的核心原理(隔离执行、行为监控)

· 系统调用钩子的实现

· 操作记录和风险评分

· 威胁等级判定

· 行为分析报告生成

安全沙箱是恶意软件分析的核心工具。掌握它,你就理解了动态分析系统的底层设计。

下一篇预告:《从零实现一个安全扫描器:端口扫描与漏洞检测》


评论区分享一下你遇到过的最复杂的恶意软件行为~

相关推荐
拳里剑气2 小时前
C++算法:队列与BFS
c++·算法·bfs·宽度优先·队列
aaPIXa6222 小时前
C++模板元编程:在编译期完成计算,实现零运行时开销
java·开发语言·c++
郝学胜-神的一滴2 小时前
CMake 038:OBJECT目标复用编译+Linux动态库版本自动化管理
linux·c++·程序人生·软件工程·软件构建·cmake·工程配置
Sylvia-girl3 小时前
第八站:vector及其常用操作【上】
c++
Sunsets_Red3 小时前
浅谈博弈论
c++·学习·编程·博弈论·信息学竞赛·巴巴博弈
ALex_zry4 小时前
C++26 std::inplace_vector 详解:零堆分配的定容向量
开发语言·c++
卷无止境4 小时前
C++ 类型转换变迁之路:从隐式转换到 static_cast
c++·后端
h_a_o777oah4 小时前
【动态规划】区间 DP :三层循环逻辑与模板实现细节(洛谷 P1880)
c++·算法·动态规划·acm·区间dp·化环为链·石子合并
QiLinkOS5 小时前
第三视觉理解徐玉生与他的商业活动(32)
大数据·c++·人工智能·算法·开源协议