简介:本资源为开源远程访问工具(RAT)「终结者源码」的完整工程代码包,面向网络安全研究人员、逆向分析学习者及系统安全方向的中高级开发者,用于深入理解远程控制软件的核心机制与攻防对抗技术。压缩包大小约3MB,为RAR格式,虽未提供具体文件总数与类型明细,但根据描述可知其包含可编译的多平台源码主体、网络通信模块、加密传输逻辑、持久化后门实现、权限提升组件及命令控制框架等关键部分,覆盖TCP/IP连接建立、SSL/TLS加解密、注册表/启动项注入、进程遍历与UI交互等典型功能模块。已有690人学习下载,适合开展恶意软件行为分析、安全工具开发实践或红队技术原理研究。读者可基于该源码完成编译调试、协议逆向、反检测策略复现及防御方案验证,是理解RAT底层运作与提升实战安全能力的重要技术样本。
1. 这不是电影彩蛋,而是一个可运行的终端交互式AI代理框架:本地化部署、命令行驱动、支持插件扩展的“终结者”风格智能体系统
你有没有试过在终端里输入agent --task "整理Downloads文件夹里近3天的PDF,按作者名归类到子目录",然后看着它自动调用find、file、pdfinfo、mkdir、mv,甚至调用本地Python脚本提取元数据?这不是科幻——“终结者源码”项目就是这样一个不依赖云端API、纯本地运行、以Shell为入口、用Python为骨架、带状态记忆与任务拆解能力的CLI智能体框架。它不生成诗歌,不画猫图,专攻“让Linux命令更懂人话”。适合运维工程师写自动化巡检脚本、数据工程师快速清洗杂乱日志、嵌入式开发者在无GUI设备上构建语音指令后端。项目命名虽带戏剧张力,但代码极其务实:没有Web界面、不连Redis集群、不抽象成微服务,所有逻辑压进一个agent.py主入口+若干plugins/模块中。我第一次跑通时,它用ps aux | grep nginx查出进程后,自动补全了sudo systemctl restart nginx——那一刻我才意识到,所谓“终结者”,不过是把subprocess.run()和re.search()用对了地方。
2. 环境准备与最小可运行验证:从克隆到执行一条真实命令的完整链路
2.1 依赖解析与Python环境隔离策略
项目采用标准pyproject.toml管理依赖,核心要求明确:Python ≥ 3.9(因使用typing.Union新语法)、rich用于终端渲染、typer构建CLI、watchdog监听文件变化(用于后续热重载插件)。关键点在于:它刻意避开了LLM大模型依赖——所有“智能”行为均来自规则引擎+正则匹配+预置动作模板,因此无需CUDA、不占显存、树莓派4B也能满速运行。
提示:不要用
pip install -r requirements.txt——项目已弃用requirements.txt,所有依赖必须通过pip install -e .安装,否则typer命令注册会失效。
# 推荐做法:创建干净虚拟环境 python -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate.bat # Windows # 安装项目(-e 表示可编辑模式,修改代码立即生效) pip install -e .安装后,终端应能直接调用agent命令:
$ agent --help Usage: agent [OPTIONS] COMMAND [ARGS]... 终结者智能体:本地化终端任务代理 Options: --debug / --no-debug 启用调试日志 --help Show this message and exit. Commands: exec 执行自然语言任务(如:重启nginx服务) list 列出可用插件 status 显示当前代理状态2.2 第一条命令实测:agent exec "检查磁盘空间并告警"
这是项目文档中默认演示任务,也是验证整个链路是否打通的黄金用例。执行后,你会看到三阶段输出:
①意图识别:[INFO] 意图解析为: disk_usage_check
②动作编排:[DEBUG] 计划执行: ['df -h', 'awk '/\/$/ {print $5}'']
③结果反馈:[SUCCESS] 根分区使用率:82% —— 超过阈值80%,触发告警
背后逻辑藏在src/agent/core/executor.py中:
# src/agent/core/executor.py def execute_disk_usage_check(self) -> Dict[str, Any]: # 步骤1:获取所有挂载点使用率 result = subprocess.run( ["df", "-h"], capture_output=True, text=True, check=True ) # 步骤2:提取根分区(/)使用率百分比 root_line = [line for line in result.stdout.splitlines() if line.startswith("/dev/") and " / " in line] if not root_line: raise RuntimeError("未找到根分区信息") usage_percent = re.search(r'(\d+)%', root_line[0]) if not usage_percent: raise RuntimeError("无法解析使用率") usage = int(usage_percent.group(1)) # 步骤3:阈值判断与告警(阈值硬编码在config.yaml中) threshold = self.config.get("disk_alert_threshold", 80) if usage > threshold: self._trigger_alert(f"根分区使用率{usage}%,超过阈值{threshold}%") return {"usage_percent": usage, "alert_triggered": usage > threshold}这段代码的价值不在复杂度,而在于结构清晰:每个execute_*方法对应一个原子任务,返回结构化字典供上层组合。self._trigger_alert()是可覆盖方法——你完全可以把它改成发邮件、写入InfluxDB或调用企业微信机器人hook。
2.3 配置文件加载机制:config.yaml如何控制行为边界
项目不写死任何路径或阈值,全部交由config.yaml驱动。默认配置位于src/agent/config.yaml,关键字段如下:
# src/agent/config.yaml disk_alert_threshold: 80 log_level: INFO plugins: - name: "disk_monitor" enabled: true priority: 10 - name: "file_cleaner" enabled: false priority: 5 command_timeout: 30 # 所有shell命令超时秒数注意:
plugins列表决定哪些功能模块被加载。enabled: false的插件不会被导入,priority值越小越早执行(用于任务前置校验)。这个设计让运维同学能一键禁用高风险插件(如system_reboot),而不必删代码。
验证配置生效的方法很简单:临时修改disk_alert_threshold: 10,再执行agent exec "检查磁盘空间并告警"——你会立刻看到告警被触发,证明配置热加载有效(项目启动时读取一次,后续不重载)。
3. 核心模块拆解:一个请求从进入到返回的完整链路
3.1 CLI入口:typer.Typer如何将自然语言映射到函数
整个系统的门面是src/agent/cli.py,它用typer构建了极简但健壮的命令路由:
# src/agent/cli.py import typer from src.agent.core.executor import Executor app = typer.Typer(help="终结者智能体:本地化终端任务代理") @app.command() def exec( task: str = typer.Argument(..., help="自然语言描述的任务,如 '重启nginx'"), debug: bool = typer.Option(False, "--debug", help="启用调试日志"), ): """执行自然语言任务""" executor = Executor(debug=debug) try: result = executor.run(task) typer.echo(f"[SUCCESS] {result.get('message', '任务完成')}") except Exception as e: typer.echo(f"[ERROR] {str(e)}") raise typer.Exit(code=1)关键洞察:typer.Argument(...)强制要求用户必须输入任务描述,避免空命令;executor.run(task)是真正干活的入口,它内部做了三件事:
- 分词与关键词提取(非BERT,而是
jieba+预置词典,如["重启","start","restart"]→action_restart) - 意图匹配(查
src/agent/intents/下的YAML规则文件,例如restart_service.yaml定义了匹配正则与对应执行函数) - 参数抽取(用
spacy轻量模型提取实体,如"nginx"作为服务名传给execute_restart_service(service_name="nginx"))
提示:
intents/目录是业务逻辑中枢。新增一个意图只需:① 写YAML规则 ② 在executor.py中实现对应函数 ③ 重启agent。无需改CLI层。
3.2 意图识别引擎:intents/service_restart.yaml规则文件详解
以重启服务为例,规则文件src/agent/intents/service_restart.yaml长这样:
intent: service_restart description: 重启指定系统服务 patterns: - "重启(.+?)服务" - "start (.+?) service" - "restart (.+?)" - "让(.+?)重新运行" entities: - name: service_name type: string required: true extractor: "regex_group_1" # 取第一个括号匹配内容 actions: - function: execute_restart_service args: service_name: "{service_name}"当用户输入agent exec "重启mysql服务"时:
patterns中第一条正则"重启(.+?)服务"匹配成功regex_group_1提取出"mysql"赋值给service_nameactions调用execute_restart_service(service_name="mysql")
这个YAML驱动的设计,让产品经理能直接改规则而不动Python代码——我们某客户就用此机制,在30分钟内上线了“重启docker容器”新功能。
3.3 插件系统:plugins/file_cleaner.py如何实现热插拔
插件是项目扩展性的基石。所有插件必须继承src/agent/plugins/base.py中的BasePlugin类,并实现register()方法:
# src/agent/plugins/file_cleaner.py from src.agent.plugins.base import BasePlugin class FileCleanerPlugin(BasePlugin): def register(self): # 声明本插件提供的能力 return { "name": "file_cleaner", "description": "清理指定目录下过期文件", "triggers": ["clean", "delete old", "remove outdated"], "functions": { "clean_old_files": self.clean_old_files } } def clean_old_files(self, path: str, days: int = 7) -> Dict[str, Any]: """删除path下修改时间超过days天的文件""" cmd = f"find {shlex.quote(path)} -type f -mtime +{days} -delete" result = subprocess.run( cmd, shell=True, capture_output=True, text=True ) return { "deleted_count": len(result.stdout.strip().split("\n")) if result.stdout.strip() else 0, "error": result.stderr }插件启用方式:在config.yaml中添加- name: "file_cleaner",并在plugins/目录下存在该文件。无需import、无需注册装饰器——框架启动时自动扫描plugins/下所有.py文件并调用其register()方法。这种约定优于配置的设计,让插件开发像写脚本一样简单。
4. 避坑指南:5个新手必踩的血泪问题与解决方案
4.1 现象:执行agent exec "重启nginx"报错Command 'systemctl restart nginx' returned non-zero exit status 1
原因:当前用户无sudo权限,且systemctl命令未配置免密。项目默认不加sudo前缀,认为安全第一。
解决:
① 临时方案:sudo agent exec "重启nginx"(不推荐长期使用)
② 正规方案:在/etc/sudoers中添加youruser ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx
③ 开发方案:修改execute_restart_service()函数,在subprocess.run()中显式加sudo并处理密码提示(需用pexpect库)
4.2 现象:中文分词失败,"重启mysql服务"被识别为intent: unknown
原因:jieba未加载自定义词典,"mysql"被切分为"my" + "sql"导致正则匹配失败。
解决:
① 编辑src/agent/intents/custom_dict.txt,添加一行mysql 100 n(词、词频、词性)
② 在src/agent/intents/__init__.py中加入:
import jieba jieba.load_userdict("src/agent/intents/custom_dict.txt")4.3 现象:修改intents/下YAML后,重启agent仍不生效
原因:YAML文件被缓存。框架首次加载后存入内存,未监听文件变更。
解决:
① 开发时加--debug参数,框架会自动重载YAML(仅debug模式)
② 生产环境需手动重启agent进程
③ 进阶方案:用watchdog监听intents/目录,触发reload_intents()方法(需自行实现)
4.4 现象:agent list显示插件但exec时提示Function 'xxx' not found
原因:插件register()返回的functions字典中,key名与intents/*.yaml中actions.function不一致。
解决:严格对照命名。例如插件返回{"clean_old_files": ...},则YAML中必须写:
actions: - function: clean_old_files # 必须完全一致,大小写敏感4.5 现象:df -h命令在某些Alpine镜像中不存在,导致磁盘检查失败
原因:df是GNU coreutils组件,但Alpine默认用busybox df,输出格式不同。
解决:
① 在Dockerfile中安装coreutils:apk add --no-cache coreutils
② 或修改execute_disk_usage_check(),兼容busybox版df:
# 兼容busybox df(无-h选项,单位为KB) if shutil.which("df") and "busybox" in subprocess.run(["df"], capture_output=True).stderr.decode(): cmd = ["df"] else: cmd = ["df", "-h"]5. 二次开发实战:为“终结者”添加SSH远程执行能力
5.1 需求场景与架构定位
某实验室需要批量管理20台边缘设备,每台设备运行轻量Agent,主控机通过agent exec "在设备A上重启采集服务"下发指令。原生框架只支持本地命令,必须扩展SSH通道。这不是加个paramiko就行——要保证:① 连接复用(避免每次新建TCP)② 错误透传(远程systemctl失败要原样返回)③ 权限隔离(不同设备用不同密钥)。
5.2 实现步骤:从连接池到意图绑定
步骤1:构建SSH连接池(src/agent/ssh/pool.py)
# src/agent/ssh/pool.py import paramiko from typing import Dict, Optional from src.agent.config import Config class SSHConnectionPool: _instances: Dict[str, "SSHConnectionPool"] = {} def __new__(cls, host: str): if host not in cls._instances: cls._instances[host] = super().__new__(cls) return cls._instances[host] def __init__(self, host: str): if hasattr(self, '_initialized') and self._initialized: return self.host = host self.client = paramiko.SSHClient() self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 从config.yaml读取设备配置 config = Config() device_cfg = config.get("devices", {}).get(host, {}) self.client.connect( hostname=host, username=device_cfg.get("user", "root"), key_filename=device_cfg.get("key_path"), timeout=10 ) self._initialized = True def run(self, command: str) -> Dict[str, str]: stdin, stdout, stderr = self.client.exec_command(command, timeout=30) return { "stdout": stdout.read().decode(), "stderr": stderr.read().decode(), "exit_code": stdout.channel.recv_exit_status() }关键设计:单例模式确保同一host只建一个连接;
Config()自动读取config.yaml中devices段落,示例:devices: edge-01: user: "pi" key_path: "/home/user/.ssh/edge_rsa" edge-02: user: "admin" key_path: "/home/user/.ssh/admin_rsa"
步骤2:注册新意图remote_exec.yaml
# src/agent/intents/remote_exec.yaml intent: remote_exec description: 在远程设备上执行命令 patterns: - "在(.+?)上(.+)" - "让(.+?)执行(.+)" entities: - name: target_host type: string required: true extractor: "regex_group_1" - name: remote_command type: string required: true extractor: "regex_group_2" actions: - function: execute_remote_command args: host: "{target_host}" command: "{remote_command}"步骤3:实现执行函数并注入Executor
# src/agent/core/executor.py from src.agent.ssh.pool import SSHConnectionPool class Executor: # ... 其他代码 ... def execute_remote_command(self, host: str, command: str) -> Dict[str, Any]: try: pool = SSHConnectionPool(host) result = pool.run(command) if result["exit_code"] != 0: raise RuntimeError(f"远程执行失败({result['exit_code']}): {result['stderr']}") return { "message": f"在{host}上成功执行: {command}", "stdout": result["stdout"], "exit_code": result["exit_code"] } except Exception as e: return {"error": str(e)}步骤4:验证与调试
# 先在config.yaml中配置设备 echo "devices: edge-01: user: pi key_path: /home/user/.ssh/id_rsa" >> src/agent/config.yaml # 执行远程命令 agent exec "在edge-01上 systemctl restart sensor-collector" # 输出应为: # [SUCCESS] 在edge-01上成功执行: systemctl restart sensor-collector5.3 验证技巧:用--debug看透数据流
加--debug参数后,你会看到每一层的日志:
[DEBUG] 意图匹配: remote_exec (置信度 0.92) [DEBUG] 实体抽取: {'target_host': 'edge-01', 'remote_command': 'systemctl restart sensor-collector'} [DEBUG] 调用函数: execute_remote_command(host='edge-01', command='systemctl restart sensor-collector') [DEBUG] SSH连接池: 复用现有连接到 edge-01 [DEBUG] 远程执行: systemctl restart sensor-collector → exit_code=0这种透明性让你在5分钟内定位是网络问题、密钥问题还是远程命令语法问题。
从那以后我每次加新功能,都强制走一遍--debug日志链路,再配合print()打点关键变量——不是信不过框架,而是信不过自己手抖敲错的hostnam。希望帮到你。
本文还有配套的精品资源,点击获取