Re-upload history
This commit is contained in:
1 parent
f28e26558d
commit
90916315b9
17 files changed
+817
-509
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,284 +4,205 @@
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <omp.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
|
||||
// 定义DLL导出宏
|
||||
#ifdef __cplusplus
|
||||
#define DLL_EXPORT extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define DLL_EXPORT __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
// 灰度图像结构体
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
unsigned char* data;
|
||||
} GrayImage;
|
||||
|
||||
// 点坐标结构体
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int error; // 0表示成功,非0表示错误码
|
||||
double confidence; // 匹配置信度
|
||||
int error;
|
||||
double confidence;
|
||||
} MatchResult;
|
||||
|
||||
// 屏幕截图并转换为灰度图像
|
||||
// 辅助:UTF8 → WCHAR
|
||||
static wchar_t* utf8_to_wchar(const char* utf8) {
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
|
||||
wchar_t* buf = (wchar_t*)malloc(sizeof(wchar_t) * len);
|
||||
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, buf, len);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// 修复1:支持中文/UTF8路径
|
||||
DLL_EXPORT GrayImage* LoadImageGray(const char* filename, int* errorCode) {
|
||||
*errorCode = 0;
|
||||
if (!filename) { *errorCode = 100; return NULL; }
|
||||
|
||||
wchar_t* wpath = utf8_to_wchar(filename);
|
||||
FILE* f = _wfopen(wpath, L"rb");
|
||||
free(wpath);
|
||||
|
||||
if (!f) { *errorCode = 100; return NULL; }
|
||||
|
||||
int w, h, ch;
|
||||
unsigned char* data = stbi_load_from_file(f, &w, &h, &ch, 1);
|
||||
fclose(f);
|
||||
|
||||
if (!data) { *errorCode = 100; return NULL; }
|
||||
|
||||
GrayImage* im = (GrayImage*)malloc(sizeof(GrayImage));
|
||||
if (!im) { stbi_image_free(data); *errorCode = 101; return NULL; }
|
||||
|
||||
im->width = w;
|
||||
im->height = h;
|
||||
im->data = data;
|
||||
return im;
|
||||
}
|
||||
|
||||
// 修复2:多显示器虚拟屏幕截图
|
||||
DLL_EXPORT GrayImage* CaptureScreenGray(int* errorCode) {
|
||||
*errorCode = 0;
|
||||
HDC hdcScreen = GetDC(NULL);
|
||||
if (!hdcScreen) {
|
||||
*errorCode = 1;
|
||||
return NULL;
|
||||
}
|
||||
int w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||||
int h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||||
int x0 = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||||
int y0 = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||||
|
||||
HDC hdcMem = CreateCompatibleDC(hdcScreen);
|
||||
if (!hdcMem) {
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
*errorCode = 2;
|
||||
return NULL;
|
||||
}
|
||||
HDC hdc = GetDC(NULL);
|
||||
HDC mem = CreateCompatibleDC(hdc);
|
||||
HBITMAP bmp = CreateCompatibleBitmap(hdc, w, h);
|
||||
SelectObject(mem, bmp);
|
||||
|
||||
int width = GetSystemMetrics(SM_CXSCREEN);
|
||||
int height = GetSystemMetrics(SM_CYSCREEN);
|
||||
if (!BitBlt(mem, 0, 0, w, h, hdc, x0, y0, SRCCOPY)) { *errorCode = 4; goto cleanup; }
|
||||
|
||||
HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
|
||||
if (!hBitmap) {
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
*errorCode = 3;
|
||||
return NULL;
|
||||
}
|
||||
BITMAPINFOHEADER bi = {0};
|
||||
bi.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bi.biWidth = w;
|
||||
bi.biHeight = -h;
|
||||
bi.biPlanes = 1;
|
||||
bi.biBitCount = 24;
|
||||
bi.biCompression = BI_RGB;
|
||||
|
||||
SelectObject(hdcMem, hBitmap);
|
||||
if (!BitBlt(hdcMem, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY)) {
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
*errorCode = 4;
|
||||
return NULL;
|
||||
}
|
||||
unsigned char* rgb = (unsigned char*)malloc(w * h * 3);
|
||||
if (!GetDIBits(hdc, bmp, 0, h, rgb, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) { *errorCode = 6; free(rgb); goto cleanup; }
|
||||
|
||||
BITMAPINFOHEADER bmi = {0};
|
||||
bmi.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.biWidth = width;
|
||||
bmi.biHeight = -height;
|
||||
bmi.biPlanes = 1;
|
||||
bmi.biBitCount = 24;
|
||||
bmi.biCompression = BI_RGB;
|
||||
|
||||
unsigned char* pixels = (unsigned char*)malloc(3 * width * height);
|
||||
if (!pixels) {
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
*errorCode = 5;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!GetDIBits(hdcScreen, hBitmap, 0, height, pixels, (BITMAPINFO*)&bmi, DIB_RGB_COLORS)) {
|
||||
free(pixels);
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
*errorCode = 6;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GrayImage* result = (GrayImage*)malloc(sizeof(GrayImage));
|
||||
if (!result) {
|
||||
free(pixels);
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
*errorCode = 7;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result->width = width;
|
||||
result->height = height;
|
||||
result->data = (unsigned char*)malloc(width * height);
|
||||
if (!result->data) {
|
||||
free(pixels);
|
||||
free(result);
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
*errorCode = 8;
|
||||
return NULL;
|
||||
}
|
||||
GrayImage* out = (GrayImage*)malloc(sizeof(GrayImage));
|
||||
out->width = w;
|
||||
out->height = h;
|
||||
out->data = (unsigned char*)malloc(w * h);
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int offset = y * width * 3 + x * 3;
|
||||
unsigned char r = pixels[offset + 2];
|
||||
unsigned char g = pixels[offset + 1];
|
||||
unsigned char b = pixels[offset];
|
||||
result->data[y * width + x] = (unsigned char)(0.299 * r + 0.587 * g + 0.114 * b);
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int off = y * w * 3 + x * 3;
|
||||
int r = rgb[off+2], g = rgb[off+1], b = rgb[off];
|
||||
out->data[y*w + x] = (unsigned char)(0.299*r + 0.587*g + 0.114*b);
|
||||
}
|
||||
}
|
||||
|
||||
free(pixels);
|
||||
ReleaseDC(NULL, hdcScreen);
|
||||
DeleteDC(hdcMem);
|
||||
DeleteObject(hBitmap);
|
||||
|
||||
return result;
|
||||
free(rgb);
|
||||
cleanup:
|
||||
DeleteObject(bmp);
|
||||
DeleteDC(mem);
|
||||
ReleaseDC(NULL, hdc);
|
||||
return *errorCode ? NULL : out;
|
||||
}
|
||||
|
||||
// 加载PNG图像并转为灰度
|
||||
DLL_EXPORT GrayImage* LoadImageGray(const char* filename, int* errorCode) {
|
||||
if (!errorCode) return NULL;
|
||||
*errorCode = 0;
|
||||
// 修复3:加入 SearchArea(x1,y1,x2,y2)
|
||||
DLL_EXPORT MatchResult FindTemplateOptimized(
|
||||
GrayImage* screen,
|
||||
GrayImage* target,
|
||||
double threshold,
|
||||
int searchX1, int searchY1, int searchX2, int searchY2
|
||||
) {
|
||||
MatchResult res = {-1, -1, 0, 0.0};
|
||||
double bestDiff = 1e18;
|
||||
|
||||
int width, height, channels;
|
||||
unsigned char* data = stbi_load(filename, &width, &height, &channels, 1);
|
||||
if (!data) {
|
||||
*errorCode = 100;
|
||||
return NULL;
|
||||
}
|
||||
if (!screen || !target || !screen->data || !target->data) { res.error = 200; return res; }
|
||||
int tw = target->width, th = target->height;
|
||||
int sw = screen->width, sh = screen->height;
|
||||
if (tw > sw || th > sh) { res.error = 201; return res; }
|
||||
|
||||
GrayImage* result = (GrayImage*)malloc(sizeof(GrayImage));
|
||||
if (!result) {
|
||||
stbi_image_free(data);
|
||||
*errorCode = 101;
|
||||
return NULL;
|
||||
}
|
||||
// 区域裁剪
|
||||
int x1 = (searchX1 >= 0) ? searchX1 : 0;
|
||||
int y1 = (searchY1 >= 0) ? searchY1 : 0;
|
||||
int x2 = (searchX2 > 0) ? searchX2 : sw;
|
||||
int y2 = (searchY2 > 0) ? searchY2 : sh;
|
||||
if (x2 - x1 < tw || y2 - y1 < th) { res.error = 201; return res; }
|
||||
|
||||
result->width = width;
|
||||
result->height = height;
|
||||
result->data = data;
|
||||
return result;
|
||||
}
|
||||
|
||||
// 带OpenMP加速和负载均衡的模板匹配
|
||||
DLL_EXPORT MatchResult FindTemplateOptimized(GrayImage* screen, GrayImage* target, double threshold) {
|
||||
MatchResult result = {-1, -1, 0, 0.0};
|
||||
|
||||
if (!screen || !target || !screen->data || !target->data) {
|
||||
result.error = 200;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (target->width > screen->width || target->height > screen->height) {
|
||||
result.error = 201;
|
||||
return result;
|
||||
}
|
||||
|
||||
double minDiff = INFINITY;
|
||||
const int targetPixels = target->width * target->height;
|
||||
const long maxPossibleDiff = 255 * 255 * targetPixels;
|
||||
const int chunk_size = (target->height > 100) ? 5 : 10;
|
||||
long maxDiff = 255LL * 255LL * tw * th;
|
||||
|
||||
#pragma omp parallel
|
||||
{
|
||||
double localMinDiff = INFINITY;
|
||||
int localBestX = -1;
|
||||
int localBestY = -1;
|
||||
double locBest = 1e18;
|
||||
int lx = -1, ly = -1;
|
||||
|
||||
#pragma omp for schedule(dynamic, chunk_size) nowait
|
||||
for (int y = 0; y <= screen->height - target->height; y++) {
|
||||
register long diff;
|
||||
register int screenPixel, targetPixel;
|
||||
|
||||
for (int x = 0; x <= screen->width - target->width; x++) {
|
||||
diff = 0;
|
||||
|
||||
for (int ty = 0; ty < target->height; ty++) {
|
||||
const int screenY = y + ty;
|
||||
const int targetYOffset = ty * target->width;
|
||||
int tx = 0;
|
||||
|
||||
for (; tx < target->width - 3; tx += 4) {
|
||||
screenPixel = screen->data[screenY * screen->width + x + tx];
|
||||
targetPixel = target->data[targetYOffset + tx];
|
||||
diff += (screenPixel - targetPixel) * (screenPixel - targetPixel);
|
||||
|
||||
screenPixel = screen->data[screenY * screen->width + x + tx + 1];
|
||||
targetPixel = target->data[targetYOffset + tx + 1];
|
||||
diff += (screenPixel - targetPixel) * (screenPixel - targetPixel);
|
||||
|
||||
screenPixel = screen->data[screenY * screen->width + x + tx + 2];
|
||||
targetPixel = target->data[targetYOffset + tx + 2];
|
||||
diff += (screenPixel - targetPixel) * (screenPixel - targetPixel);
|
||||
|
||||
screenPixel = screen->data[screenY * screen->width + x + tx + 3];
|
||||
targetPixel = target->data[targetYOffset + tx + 3];
|
||||
diff += (screenPixel - targetPixel) * (screenPixel - targetPixel);
|
||||
}
|
||||
|
||||
for (; tx < target->width; tx++) {
|
||||
screenPixel = screen->data[screenY * screen->width + x + tx];
|
||||
targetPixel = target->data[targetYOffset + tx];
|
||||
diff += (screenPixel - targetPixel) * (screenPixel - targetPixel);
|
||||
#pragma omp for schedule(dynamic, 4) nowait
|
||||
for (int y = y1; y <= y2 - th; y++) {
|
||||
for (int x = x1; x <= x2 - tw; x++) {
|
||||
long sum = 0;
|
||||
for (int dy = 0; dy < th; dy++) {
|
||||
for (int dx = 0; dx < tw; dx++) {
|
||||
int s = screen->data[(y+dy)*sw + (x+dx)];
|
||||
int t = target->data[dy*tw + dx];
|
||||
int d = s - t;
|
||||
sum += d * d;
|
||||
}
|
||||
}
|
||||
|
||||
if (diff < localMinDiff) {
|
||||
localMinDiff = diff;
|
||||
localBestX = x + target->width / 2;
|
||||
localBestY = y + target->height / 2;
|
||||
if (sum < locBest) {
|
||||
locBest = sum;
|
||||
lx = x + tw/2;
|
||||
ly = y + th/2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp critical
|
||||
{
|
||||
if (localMinDiff < minDiff) {
|
||||
minDiff = localMinDiff;
|
||||
result.x = localBestX;
|
||||
result.y = localBestY;
|
||||
}
|
||||
if (locBest < bestDiff) {
|
||||
bestDiff = locBest;
|
||||
res.x = lx;
|
||||
res.y = ly;
|
||||
}
|
||||
}
|
||||
|
||||
result.confidence = 1.0 - ((double)minDiff / maxPossibleDiff);
|
||||
if (result.confidence < threshold) {
|
||||
result.x = -1;
|
||||
result.y = -1;
|
||||
result.error = 202;
|
||||
res.confidence = 1.0 - (double)bestDiff / maxDiff;
|
||||
if (res.confidence < threshold) {
|
||||
res.x = res.y = -1;
|
||||
res.error = 202;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 鼠标点击
|
||||
// 修复4:绝对坐标鼠标点击
|
||||
DLL_EXPORT int ClickAt(int x, int y) {
|
||||
if (!SetCursorPos(x, y)) {
|
||||
return 300;
|
||||
}
|
||||
if (!SetCursorPos(x, y)) return 300;
|
||||
|
||||
INPUT inputs[2] = {{0}};
|
||||
inputs[0].type = INPUT_MOUSE;
|
||||
inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
|
||||
inputs[1].type = INPUT_MOUSE;
|
||||
inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;
|
||||
INPUT in[2] = {0};
|
||||
in[0].type = INPUT_MOUSE;
|
||||
in[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
|
||||
in[1].type = INPUT_MOUSE;
|
||||
in[1].mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE;
|
||||
|
||||
if (SendInput(2, inputs, sizeof(INPUT)) != 2) {
|
||||
return 301;
|
||||
}
|
||||
float fx = (float)x / GetSystemMetrics(SM_CXVIRTUALSCREEN) * 65535.0f;
|
||||
float fy = (float)y / GetSystemMetrics(SM_CYVIRTUALSCREEN) * 65535.0f;
|
||||
in[0].mi.dx = (LONG)fx;
|
||||
in[0].mi.dy = (LONG)fy;
|
||||
in[1].mi.dx = (LONG)fx;
|
||||
in[1].mi.dy = (LONG)fy;
|
||||
|
||||
if (SendInput(2, in, sizeof(INPUT)) != 2) return 301;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 释放图像内存
|
||||
DLL_EXPORT void FreeGrayImage(GrayImage* img) {
|
||||
if (img) {
|
||||
if (img->data) {
|
||||
free(img->data);
|
||||
}
|
||||
free(img);
|
||||
}
|
||||
DLL_EXPORT void FreeGrayImage(GrayImage* im) {
|
||||
if (im) { free(im->data); free(im); }
|
||||
}
|
||||
|
||||
// 初始化函数
|
||||
DLL_EXPORT int Initialize() {
|
||||
omp_set_num_threads(omp_get_num_procs() * 2);
|
||||
omp_set_num_threads(omp_get_num_procs());
|
||||
return 0;
|
||||
}
|
||||
@@ -1,145 +1,215 @@
|
||||
# Termination4
|
||||
|
||||
## 项目简介
|
||||
> **开源 · 大规模 APT 武器病毒 · 教学示范**
|
||||
>
|
||||
> 一个面向网络安全教学与攻防研究的大型 APT(高级持续性威胁)武器化病毒开源项目。
|
||||
> 原生基于 Python 实现,受限于 Python 运行效率,仅作为教学示范;
|
||||
> 经 **Viper** 工具链改装后,可提供更接近真实 APT 行为特性的高质量教学效果。
|
||||
|
||||
Termination4 是一个基于 Python 的网络测试与数据采集框架,用于内网环境中的大规模网络行为测试和数据收集。
|
||||
---
|
||||
|
||||
## 版本信息
|
||||
## 一、项目简介
|
||||
|
||||
- **当前版本**: 4.2.0
|
||||
- **编译版本**: 407
|
||||
- **作者**: Veyra
|
||||
### 1.1 项目定位
|
||||
|
||||
## 技术架构
|
||||
Termination4(全称 *Termination Generally Use Cyber Virus Puppet Weapons*)是一个**开源的大规模 APT 武器病毒**项目,目标是完整复现真实 APT 攻击链路,供安全研究人员、红蓝对抗学习者、高校网络安全教学使用。
|
||||
|
||||
### 核心技术栈
|
||||
项目覆盖 APT 杀伤链的全部核心阶段:
|
||||
|
||||
- **编程语言**: Python 3.12
|
||||
- **编译工具**: Nuitka / PyInstaller
|
||||
- **网络通信**: Socket.IO
|
||||
- **加密方式**: OpenSSL + 自定义加密
|
||||
- **系统接口**: C 扩展 (CDLL)
|
||||
- **初始投放与感染**(Initial Access & Infection)
|
||||
- **持久化驻留**(Persistence)
|
||||
- **命令与控制**(Command & Control, C2)
|
||||
- **横向移动与传播**(Lateral Movement & Propagation)
|
||||
- **信息收集与回传**(Collection & Exfiltration)
|
||||
- **反检测与对抗**(Defense Evasion)
|
||||
- **远程控制**(Remote Control)
|
||||
|
||||
### 主要组件
|
||||
### 1.2 为什么是"教学示范"
|
||||
|
||||
#### 1. 网络传输模块 (TWNT)
|
||||
本项目**完整实现了 APT 的行为模型与代码结构**,但存在一个根本性瓶颈:
|
||||
|
||||
- Socket.IO 客户端通信
|
||||
- WebSocket 加密传输
|
||||
- 自动重连机制
|
||||
- 远程命令执行
|
||||
> **Python 的运行效率不足以支撑真实大规模 APT 武器的实战需求。**
|
||||
|
||||
#### 2. 工作线程模块 (TWNTWork)
|
||||
具体表现为:
|
||||
|
||||
- **MonitorWorker**: 系统硬件监控
|
||||
- CPU 使用率
|
||||
- 内存使用情况
|
||||
- 网络流量统计
|
||||
| 瓶颈维度 | Python 原生实现的局限 |
|
||||
|:-|:-|
|
||||
| **执行效率** | 解释执行,CPU 密集型任务(加密、压缩、图像处理)吞吐量低 |
|
||||
| **内存占用** | 对象模型开销大,大规模并发感染时内存膨胀严重 |
|
||||
| **启动速度** | 解释器初始化 + 模块导入耗时,影响投递后的快速响应 |
|
||||
| **隐蔽性** | 进程特征明显,易于被 EDR 通过解释器特征识别 |
|
||||
| **分发体积** | 携带完整运行时,体积大、特征强 |
|
||||
|
||||
- **ListenKMWorker**: 输入设备监听
|
||||
- 键盘事件捕获
|
||||
- 鼠标事件捕获
|
||||
- 屏幕区域截图
|
||||
因此,**Python 原生版本仅适合作为静态代码阅读、行为分析、攻防原理教学使用**,不具备实战部署能力。这恰好满足"教学示范"的核心诉求:**结构清晰、可读性高、行为可追溯、便于在隔离环境中观察分析。**
|
||||
|
||||
- **TWNTProcessSynchronousWorker**: 进程同步
|
||||
- 线程状态监控
|
||||
- 进程状态监控
|
||||
### 1.3 Viper 改装:从教学示范到高质量教学
|
||||
|
||||
- **TWNTCoverScreen**: 屏幕监控
|
||||
- 定时截图上传
|
||||
- 图像压缩传输
|
||||
为弥补 Python 效率瓶颈,项目引入 **Viper** 工具链进行改装。Viper 是一套将 Python 源码编译为高效本地代码的工具链,改装后带来以下教学增益:
|
||||
|
||||
- **TWNETProcess**: 命令处理
|
||||
- Python 代码执行
|
||||
- CMD 命令执行
|
||||
- PowerShell 命令执行
|
||||
| 改装方向 | Viper 改装后的教学价值 |
|
||||
|:-|:-|
|
||||
| **性能接近真实 APT** | 本地编译执行,CPU/IO 吞吐量显著提升,使教学演示中的时序、规模更贴近实战 |
|
||||
| **行为时序还原** | 解决 Python 版因效率失真导致的"演示不像真 APT"问题,让学员观察到真实的感染速率、回传频率 |
|
||||
| **二进制分析教学** | 编译产物可作为逆向工程样本,支撑二进制静态分析、特征码识别教学 |
|
||||
| **反检测对抗教学** | 失去 Python 解释器特征后,可在受控环境中演示更真实的 EDR 对抗场景 |
|
||||
| **跨阶段联调** | 高效执行使全链路联动(感染 → 驻留 → C2 → 回传)成为可演示的整体 |
|
||||
|
||||
#### 3. 任务表模块 (LW3T)
|
||||
> **教学建议**:静态代码阅读与原理讲解使用 Python 原生源码;动态行为演示与时序分析使用 Viper 改装版本。两者配合可获得最佳教学效果。
|
||||
|
||||
- 本地任务管理
|
||||
- 定时任务调度
|
||||
- 任务执行回调
|
||||
---
|
||||
|
||||
#### 4. 感染模块 (InfectionWorker)
|
||||
## 二、版本信息
|
||||
|
||||
- 移动设备检测
|
||||
- 文件感染标记
|
||||
- 磁盘索引
|
||||
- **当前版本**:4.2.0
|
||||
- **编译版本**:407
|
||||
- **作者**:Veyra
|
||||
- **项目地址**:https://github.com/GVSADS/Termination4
|
||||
- **配套项目**:https://github.com/GVSADS/Termination(未完全同步)
|
||||
|
||||
#### 5. 辅助模块
|
||||
---
|
||||
|
||||
- **AntiVirusSoftware**: 安全软件检测
|
||||
- **AutoRun**: 自启动配置
|
||||
- **AdministratorMode**: 权限管理
|
||||
- **WorkSpaceDeployer**: 工作目录部署
|
||||
## 三、技术架构
|
||||
|
||||
## 项目结构
|
||||
### 3.1 核心技术栈
|
||||
|
||||
- **主语言**:Python 3.12
|
||||
- **改装工具链**:Viper(Python → 本地代码编译)
|
||||
- **打包编译**:Nuitka / PyInstaller
|
||||
- **C 扩展构建**:CMake + Ninja
|
||||
- **运行时 C 编译**:TinyCC(见 `TPcc/`,用于运行期快速编译 C 扩展)
|
||||
- **网络通信**:Socket.IO / WebSocket
|
||||
- **加密体系**:OpenSSL + 自研 GodKeys 弱对称加密
|
||||
- **系统接口**:C 扩展(CDLL 调用)
|
||||
|
||||
### 3.2 APT 杀伤链模块映射
|
||||
|
||||
| 杀伤链阶段 | 对应模块 | 说明 |
|
||||
|:-|:-|:-|
|
||||
| **初始投放** | `.inf/Install/`、`.inf/SubstituteExecution/` | 安装器、被感染文件代偿启动 |
|
||||
| **持久化** | `TLhread/Thread_AutoRun.py`、`.inf/Service/`、`.inf/RegistryOverride/` | 服务注册、注册表劫持、自启动 |
|
||||
| **C2 通信** | `TLhread/Thread_TWNT.py`、`TPLib/T_SSHServer/`、`TFrp/` | Socket.IO 主通道、SSH 备用通道、内网穿透 |
|
||||
| **横向传播** | `TLhread/Thread_InfectionWorker.py`、`.inf/TemplateMatcher/` | 移动设备感染、磁盘索引、快速模板匹配 |
|
||||
| **信息收集** | `TLib/T_KeMouse.py`、`TPLib/T_WMI/`、`TPLib/T_Browser/`、`TPLib/T_DOC/` | 键鼠监听、WMI 系统信息、浏览器数据、文档采集 |
|
||||
| **屏幕监控** | `TLhread/Thread_TWNTWork.py`(CoverScreen/ListenKM)、`T2SRFB/` | 截图回传、VNC 远程桌面 |
|
||||
| **凭证窃取** | `TPLib/T_SigThiever/` | 数字签名窃取(SigThief 技术) |
|
||||
| **反检测** | `TLhread/Thread_AntiVirusSoftware.py`、`TPLib/T_VMDISC/`、`ocr/` | 杀软识别、虚拟机检测、360 弹窗模板匹配 |
|
||||
| **任务调度** | `TLhread/Thread_LW3T.py`、`TLib/T_LW3T.py` | 本地与网络任务表、定时调度 |
|
||||
| **远程命令** | `TLhread/Thread_TWNTWork.py`(TWNETProcess) | Python / CMD / PowerShell 命令执行 |
|
||||
| **更新机制** | `.inf/Update/`、`TLib/T_Version.py` | SHA256 校验、自动更新分发 |
|
||||
|
||||
### 3.3 工作线程模型
|
||||
|
||||
`TLhread/Thread_TWNTWork.py` 中定义了核心工作线程群:
|
||||
|
||||
- **MonitorWorker**:CPU、内存、网络流量硬件监控
|
||||
- **ListenKMWorker**:键盘 / 鼠标事件捕获与屏幕区域截图
|
||||
- **TWNTProcessSynchronousWorker**:进程与线程状态同步
|
||||
- **TWNTCoverScreen**:定时截图与图像压缩上传
|
||||
- **TWNETProcess**:远程命令解析与执行(Python / CMD / PowerShell)
|
||||
|
||||
---
|
||||
|
||||
## 四、项目结构
|
||||
|
||||
```
|
||||
Termination4/
|
||||
├── Termination4.py # 主程序入口
|
||||
├── TerminationLib.py # 核心逻辑
|
||||
├── TLhread/ # 线程模块
|
||||
│ ├── Thread_TWNT.py # 网络传输
|
||||
│ ├── Thread_TWNTWork.py # 工作线程
|
||||
│ ├── Thread_LW3T.py # 任务表
|
||||
│ ├── Thread_InfectionWorker.py # 感染功能
|
||||
│ ├── Thread_AntiVirusSoftware.py # 安全检测
|
||||
│ └── Thread_AutoRun.py # 自启动
|
||||
├── TerminationLib.py # 核心逻辑(面向对象)
|
||||
├── TLhread/ # 线程 / 进程模块
|
||||
│ ├── Thread_TWNT.py # 网络传输主线程
|
||||
│ ├── Thread_TWNTWork.py # 工作线程群
|
||||
│ ├── Thread_LW3T.py # 任务表线程
|
||||
│ ├── Thread_InfectionWorker.py# 感染线程
|
||||
│ ├── Thread_AntiVirusSoftware.py # 杀软对抗
|
||||
│ ├── Thread_AutoRun.py # 自启动配置
|
||||
│ ├── Thread_Process.py # 进程线程
|
||||
│ ├── Thread_Web.py # 其他网络服务
|
||||
│ └── Thread_EasterEgg.py # 彩蛋
|
||||
├── TLib/ # 核心库
|
||||
│ ├── T_Process.py # 进程管理
|
||||
│ ├── T_Log.py # 日志系统
|
||||
│ ├── T_FIO.py # 文件操作
|
||||
│ ├── T_GodKeys.py # 加密模块
|
||||
│ ├── T_GodKeys.py # GodKeys 自研加密
|
||||
│ ├── T_FIO.py # 文件 I/O
|
||||
│ ├── T_Process.py # 进程 / 线程支持
|
||||
│ ├── T_KeMouse.py # 键鼠模拟
|
||||
│ ├── T_AdministratorMode.py # 提权
|
||||
│ ├── T_EXEConfig.py # 内嵌配置
|
||||
│ ├── T_Version.py # 版本与更新
|
||||
│ ├── T_WSD.py # WorkSpaceDeployer 工作目录部署
|
||||
│ └── ...
|
||||
├── TPLib/ # 扩展库
|
||||
│ ├── T_IndexEspionageProgram/ # 索引程序
|
||||
│ ├── T_SSHServer/ # SSH 服务
|
||||
│ └── T_Pyftpdlib/ # FTP 服务
|
||||
├── TPLib/ # 高级扩展库
|
||||
│ ├── T_SSHServer/ # SSH C2 通道
|
||||
│ ├── T_WMI/ # WMI 信息收集
|
||||
│ ├── T_VMDISC/ # 虚拟机检测
|
||||
│ ├── T_Browser/ # 浏览器数据采集
|
||||
│ ├── T_DOC/ # 文档采集
|
||||
│ ├── T_SigThiever/ # 数字签名窃取
|
||||
│ ├── T_Pyftpdlib/ # 内置 FTP 服务
|
||||
│ ├── T_IndexEspionageProgram/ # 索引间谍程序
|
||||
│ └── T_MCDrink/ # 扩展模块
|
||||
├── T2SRFB/ # VNC 远程桌面(C++ 实现)
|
||||
├── TFrp/ # 内网穿透(PyFrp)
|
||||
├── TPcc/ # TinyCC 运行时 C 编译器
|
||||
├── .inf/ # C 语言扩展
|
||||
│ ├── Install/ # 安装程序
|
||||
│ ├── Service/ # 服务程序
|
||||
│ ├── Service/ # 核心服务
|
||||
│ ├── Update/ # 更新程序
|
||||
│ └── Tools/ # 工具库
|
||||
├── T2SRFB/ # VNC 远程桌面
|
||||
├── TFrp/ # 内网穿透
|
||||
│ ├── RegistryOverride/ # 注册表重写
|
||||
│ ├── SubstituteExecution/ # 被感染代偿启动
|
||||
│ ├── TemplateMatcher/ # 快速模板比较
|
||||
│ ├── Tools/ # 工具库
|
||||
│ └── Test/ # 技术栈测试
|
||||
├── TConfig/ # 配置文件
|
||||
└── SSLib/ # SSL 库
|
||||
│ ├── version.ini # 版本信息
|
||||
│ ├── EXEConfig.bin # 加密内嵌配置
|
||||
│ └── EXEConfig.dict # 字典格式配置
|
||||
├── TLUI/ # 界面相关代码
|
||||
├── SSLib/ # OpenSSL 动态链接库
|
||||
├── static/ # 静态资源
|
||||
├── ocr/ # 360 杀软弹窗匹配模板
|
||||
├── Art/ # 美术资源
|
||||
├── Test/ # 技术栈测试
|
||||
├── Prompt/ # AI 提示词
|
||||
├── setup_nuitka.py # Nuitka 编译脚本
|
||||
├── setup_pack.py # PyInstaller 打包脚本
|
||||
└── script.spec # PyInstaller 清单
|
||||
```
|
||||
|
||||
## 编译方式
|
||||
---
|
||||
|
||||
### 使用 Nuitka 编译
|
||||
## 五、编译与运行
|
||||
|
||||
```bash
|
||||
python setup_nuitka.py
|
||||
```
|
||||
|
||||
### 使用 PyInstaller 打包
|
||||
|
||||
```bash
|
||||
python setup_pack.py
|
||||
```
|
||||
|
||||
## 运行方式
|
||||
|
||||
### Python 模式
|
||||
### 5.1 Python 原生模式(教学阅读用)
|
||||
|
||||
```bash
|
||||
python Termination4.py
|
||||
```
|
||||
|
||||
### 编译后的可执行文件
|
||||
> 仅推荐用于源码阅读、行为分析、隔离环境下的功能验证。
|
||||
|
||||
### 5.2 Nuitka 编译模式
|
||||
|
||||
```bash
|
||||
Termination4.exe
|
||||
python setup_nuitka.py
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
### 5.3 PyInstaller 打包模式
|
||||
|
||||
### 服务器配置
|
||||
```bash
|
||||
python setup_pack.py
|
||||
```
|
||||
|
||||
程序会从以下地址获取配置:
|
||||
### 5.4 Viper 改装模式(高质量教学用)
|
||||
|
||||
使用 Viper 工具链将 Python 源码编译为本地代码,具体使用方式参见 Viper 工具链文档。
|
||||
|
||||
> Viper 改装版本适合用于:动态行为演示、时序分析、二进制逆向教学、反检测对抗教学。
|
||||
|
||||
---
|
||||
|
||||
## 六、配置说明
|
||||
|
||||
### 6.1 服务器配置
|
||||
|
||||
程序启动时从以下地址拉取 C2 配置:
|
||||
|
||||
- `http://wytyh.space3v.work/T.json`
|
||||
- `https://raw.githubusercontent.com/GVSADS/Termination/refs/heads/main/T.json`
|
||||
@@ -154,90 +224,124 @@ Termination4.exe
|
||||
}
|
||||
```
|
||||
|
||||
### 本地配置
|
||||
### 6.2 本地配置
|
||||
|
||||
- `TConfig/version.ini` - 版本信息
|
||||
- `TConfig/EXEConfig.bin` - 程序配置(加密)
|
||||
| 文件 | 作用 |
|
||||
|:-|:-|
|
||||
| `TConfig/version.ini` | 版本信息 |
|
||||
| `TConfig/EXEConfig.bin` | 加密内嵌配置(GodKeys 序列化) |
|
||||
| `TConfig/EXEConfig.dict` | 字典格式配置 |
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 网络功能
|
||||
|
||||
- Socket.IO 实时通信
|
||||
- WebSocket 加密传输
|
||||
- 自动重连和故障恢复
|
||||
- 远程命令执行
|
||||
|
||||
### 监控功能
|
||||
|
||||
- 系统资源监控
|
||||
- 进程和线程监控
|
||||
- 屏幕截图
|
||||
- 输入设备监听
|
||||
|
||||
### 任务管理
|
||||
|
||||
- 本地任务表
|
||||
- 定时任务调度
|
||||
- 任务执行追踪
|
||||
|
||||
### 系统集成
|
||||
|
||||
- Windows 服务集成
|
||||
- 注册表操作
|
||||
- 进程权限管理
|
||||
- 文件系统操作
|
||||
|
||||
## 开发环境
|
||||
|
||||
### 系统要求
|
||||
|
||||
- **操作系统**: Windows 10/11
|
||||
- **Python 版本**: 3.12+
|
||||
- **权限要求**: 管理员权限
|
||||
|
||||
### 依赖库
|
||||
|
||||
主要依赖包括:
|
||||
|
||||
- `socketio-client`
|
||||
- `requests`
|
||||
- `psutil`
|
||||
- `pynput`
|
||||
- `cryptography`
|
||||
- `pillow`
|
||||
- `pywin32`
|
||||
|
||||
## 调试模式
|
||||
### 6.3 调试 REPL
|
||||
|
||||
程序内置 REPL 调试服务器:
|
||||
|
||||
- **地址**: localhost:12345
|
||||
- **功能**: 远程执行 Python 代码
|
||||
- **状态**: Python 模式下启用
|
||||
- **地址**:`localhost:12345`
|
||||
- **功能**:远程执行 Python 代码
|
||||
- **状态**:Python 模式下启用(编译版本默认关闭)
|
||||
|
||||
## 更新机制
|
||||
---
|
||||
|
||||
程序支持自动更新:
|
||||
## 七、功能特性
|
||||
|
||||
### 7.1 网络功能
|
||||
- Socket.IO 实时通信与自动重连
|
||||
- WebSocket 加密传输
|
||||
- SSH / FTP 备用通道
|
||||
- 内网穿透(PyFrp)
|
||||
|
||||
### 7.2 监控功能
|
||||
- 系统资源(CPU / 内存 / 网络)监控
|
||||
- 进程与线程状态监控
|
||||
- 屏幕截图与 VNC 远程桌面
|
||||
- 键鼠输入监听
|
||||
|
||||
### 7.3 任务管理
|
||||
- 本地与网络任务表(LW3T)
|
||||
- 定时任务调度
|
||||
- 任务执行回调与追踪
|
||||
|
||||
### 7.4 系统集成
|
||||
- Windows 服务集成
|
||||
- 注册表操作与劫持
|
||||
- 进程权限管理
|
||||
- 文件系统操作
|
||||
|
||||
### 7.5 对抗能力
|
||||
- 杀毒软件识别(含 360 弹窗模板匹配)
|
||||
- 虚拟机与沙箱检测
|
||||
- 数字签名窃取
|
||||
|
||||
---
|
||||
|
||||
## 八、开发环境
|
||||
|
||||
### 8.1 系统要求
|
||||
|
||||
- **操作系统**:Windows 10 / 11
|
||||
- **Python 版本**:3.12+(避免使用内置 3.10)
|
||||
- **权限要求**:管理员权限
|
||||
- **C 编译器**:MSVC / MinGW(用于 C 扩展)
|
||||
|
||||
### 8.2 主要依赖
|
||||
|
||||
- `socketio-client`:实时通信
|
||||
- `requests`:HTTP 客户端
|
||||
- `psutil`:系统监控
|
||||
- `pynput`:输入监听
|
||||
- `cryptography`:加密
|
||||
- `pillow`:图像处理
|
||||
- `pywin32`:Windows API
|
||||
|
||||
---
|
||||
|
||||
## 九、安全与法律声明
|
||||
|
||||
> **⚠️ 严肃警告**
|
||||
|
||||
1. **本项目仅用于网络安全教学、攻防研究与隔离环境测试。**
|
||||
2. **严禁将本项目用于任何未经授权的真实网络环境或真实目标。**
|
||||
3. **使用者须遵守所在国家 / 地区的网络安全法律法规。** 在中华人民共和国境内,未经授权传播、使用病毒木马程序违反《中华人民共和国网络安全法》《刑法》第二百八十五条、第二百八十六条等相关规定。
|
||||
4. **运行前必须在完全隔离的环境中部署**(独立虚拟机、断网、无敏感数据)。
|
||||
5. **作者不对任何违规使用后果承担责任。**
|
||||
|
||||
### 教学使用建议
|
||||
|
||||
- ✅ 在隔离虚拟机中观察 APT 行为链
|
||||
- ✅ 阅读源码理解各攻击阶段实现原理
|
||||
- ✅ 在红蓝对抗训练中作为红队道具(受控环境)
|
||||
- ✅ 作为逆向工程与特征识别的样本
|
||||
- ❌ 严禁连接公网或他人网络
|
||||
- ❌ 严禁投递至真实主机
|
||||
- ❌ 严禁用于勒索、破坏、窃密等违法目的
|
||||
|
||||
---
|
||||
|
||||
## 十、更新机制
|
||||
|
||||
1. 检查远程版本 SHA256
|
||||
2. 下载更新文件
|
||||
3. 验证文件完整性
|
||||
4. 执行更新程序
|
||||
4. 执行更新程序(`.inf/Update/`)
|
||||
|
||||
## 注意事项
|
||||
---
|
||||
|
||||
1. 本程序仅用于内网测试环境
|
||||
2. 需要管理员权限运行
|
||||
3. 建议在隔离环境中测试
|
||||
4. 使用前请配置正确的服务器地址
|
||||
## 十一、技术支持
|
||||
|
||||
## 技术支持
|
||||
- **项目地址**:https://github.com/GVSADS/Termination4
|
||||
- **配套仓库**:https://github.com/GVSADS/Termination
|
||||
- **版本**:4.2.0
|
||||
- **编译次数**:407
|
||||
- **作者**:Veyra
|
||||
|
||||
- **项目地址**: https://github.com/GVSADS/Termination4
|
||||
- **版本**: 4.2.0
|
||||
- **编译次数**: 407
|
||||
---
|
||||
|
||||
## 许可证
|
||||
## 十二、许可证
|
||||
|
||||
本项目仅供学习和研究使用。
|
||||
本项目仅供学习与研究使用,不得用于商业用途或任何违法违规用途。使用即代表您已阅读并同意上述安全与法律声明。
|
||||
|
||||
```
|
||||
本项目为教育用途开源项目
|
||||
Copyright (c) Veyra
|
||||
Educational Use Only
|
||||
```
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
import threading
|
||||
from pyftpdlib.authorizers import DummyAuthorizer
|
||||
from pyftpdlib.handlers import FTPHandler
|
||||
from pyftpdlib.servers import FTPServer
|
||||
|
||||
class Thread_FTP:
|
||||
def __init__(self,
|
||||
Welcome: str = "T_Pyftpdlib Based FTP Server Ready.",
|
||||
Port: int = 36667,
|
||||
Users: list = [{"UserName": "UserName", "Password": "Password", "Path": r"C:\\", "Perm": "elradfmwMT"}],
|
||||
max_cons: int = 256,
|
||||
max_cons_per_ip: int = 5):
|
||||
"""初始化FTP服务器配置"""
|
||||
self.Welcome: str = Welcome
|
||||
self.Port: int = Port
|
||||
self.lock: threading.Lock = threading.Lock()
|
||||
self.Users: list = Users # 注意这里原代码写的dict实际应该是list
|
||||
self.max_cons: int = max_cons
|
||||
self.max_cons_per_ip: int = max_cons_per_ip
|
||||
self.server = None
|
||||
self.authorizer = None
|
||||
self.handler = None
|
||||
self.address = None
|
||||
|
||||
# 初始化服务器
|
||||
self._SetupRoute()
|
||||
|
||||
def _SetupRoute(self):
|
||||
"""设置FTP服务器路由和权限"""
|
||||
self.authorizer = DummyAuthorizer()
|
||||
|
||||
# 添加用户
|
||||
for user in self.Users:
|
||||
username = user["UserName"]
|
||||
password = user["Password"]
|
||||
path = user["Path"]
|
||||
perm = user["Perm"]
|
||||
|
||||
if not username and not password:
|
||||
# 添加匿名用户
|
||||
self.authorizer.add_anonymous(path, perm=perm)
|
||||
else:
|
||||
# 添加普通用户
|
||||
self.authorizer.add_user(username, password, path, perm=perm)
|
||||
|
||||
# 配置FTP处理器
|
||||
self.handler = FTPHandler
|
||||
self.handler.authorizer = self.authorizer
|
||||
self.handler.banner = self.Welcome
|
||||
self.address = ('0.0.0.0', self.Port)
|
||||
|
||||
def _StartServer(self):
|
||||
"""启动FTP服务器"""
|
||||
if self.server is None:
|
||||
self.server = FTPServer(self.address, self.handler)
|
||||
self.server.max_cons = self.max_cons
|
||||
self.server.max_cons_per_ip = self.max_cons_per_ip
|
||||
|
||||
print(f"Starting FTP server on port {self.Port}...")
|
||||
print(f"Welcome message: {self.Welcome}")
|
||||
print(f"Max connections: {self.max_cons}, Max per IP: {self.max_cons_per_ip}")
|
||||
|
||||
try:
|
||||
self.server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print("\nServer is shutting down...")
|
||||
self.server.close_all()
|
||||
|
||||
def start(self):
|
||||
"""在新线程中启动服务器"""
|
||||
self.thread = threading.Thread(target=self._StartServer, daemon=True)
|
||||
self.thread.start()
|
||||
print("FTP server thread started")
|
||||
|
||||
def Handle_Welcome(self, Value):
|
||||
"""更新欢迎信息"""
|
||||
with self.lock:
|
||||
self.Welcome = Value
|
||||
# 注意:实时更新欢迎信息需要重新创建handler,这里仅更新存储的值
|
||||
|
||||
def Handle_Port(self, Value):
|
||||
"""更新端口(需要重启服务器才能生效)"""
|
||||
with self.lock:
|
||||
self.Port = Value
|
||||
self.address = ('0.0.0.0', self.Port)
|
||||
|
||||
def Handle_Users(self, Value):
|
||||
"""更新用户列表(需要重启服务器才能生效)"""
|
||||
with self.lock:
|
||||
self.Users = Value
|
||||
self._SetupRoute() # 重新设置权限
|
||||
|
||||
def Handle_max_cons(self, Value):
|
||||
"""更新最大连接数"""
|
||||
with self.lock:
|
||||
if self.server:
|
||||
self.server.max_cons = Value
|
||||
|
||||
def Handle_max_cons_per_ip(self, Value):
|
||||
"""更新每个IP的最大连接数"""
|
||||
with self.lock:
|
||||
if self.server:
|
||||
self.server.max_cons_per_ip = Value
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 示例配置
|
||||
ftp_server = Thread_FTP(
|
||||
Welcome="Welcome to My FTP Server!",
|
||||
Port=36667,
|
||||
Users=[
|
||||
{"UserName": "user1", "Password": "pass1", "Path": r"C:\\", "Perm": "elradfmwMT"},
|
||||
{"UserName": "", "Password": "", "Path": r"C:\\", "Perm": "elr"} # 匿名用户
|
||||
],
|
||||
max_cons=100,
|
||||
max_cons_per_ip=3
|
||||
)
|
||||
|
||||
# 启动服务器
|
||||
ftp_server.start()
|
||||
|
||||
# 保持主线程运行
|
||||
try:
|
||||
while True:
|
||||
threading.Event().wait(1)
|
||||
except KeyboardInterrupt:
|
||||
print("Main program exiting...")
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Galactic Vorpal Software Development Studio
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+388
@@ -0,0 +1,388 @@
|
||||
<p align="center">
|
||||
<img src="https://avatars.githubusercontent.com/u/193612261?v=4" width="270px" />
|
||||
<p align="center">PyFrp</p>
|
||||
<p align="center">Frp (Fast Reverse Proxy) implemented in Python</p>
|
||||
</p>
|
||||
|
||||

|
||||

|
||||
|
||||
---
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
---
|
||||
> **This project is only in its early stages, and the documentation is currently being improved. Thank you for using this project. If possible, please give it a star ♥**
|
||||
|
||||
# PyFrp
|
||||
|
||||
## 🗡 Brief Introduction
|
||||
The original Frp (https://github.com/Fatedier/frp/) is somewhat bloated in size, while PyFrp is a simplified Python-based implementation with a smaller footprint and fewer features.
|
||||
|
||||
### Comparison with the Original Frp
|
||||
| Feature| PyFrp | Frp|
|
||||
|:---------------:|:-----:|:----:|
|
||||
| Quick Setup| ✅| ✅|
|
||||
| Size| ✅| ❌|
|
||||
| SSL Support| ❌| ✅|
|
||||
| Embeddable| ✅| ⭕ |
|
||||
| Documentation| ✅| ✅|
|
||||
| TCP Support| ✅| ✅|
|
||||
| UDP Support| ❌| ✅|
|
||||
| HTTPS Support| ❌| ✅|
|
||||
|
||||
Choose based on your needs:
|
||||
- If you prioritize **quick setup, small size, simplicity, and embeddability** (e.g., integrating into your Python project), PyFrp is a great choice.
|
||||
- For **production deployments**, Frp remains the better option for now.
|
||||
|
||||
In the future, we aim to enhance PyFrp's functionality, add more configuration options, and potentially support additional protocols (e.g., HTTP/HTTPS).
|
||||
|
||||
We’re just getting started and would greatly appreciate your support—**a ⭐ Star** would mean a lot to us!
|
||||
|
||||
> Note: **HTTPS is not yet supported**. We may add this later, and contributions are welcome!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
The only third-party library you need is `pycryptodome`. Install it with:
|
||||
```bash
|
||||
pip install pycryptodome
|
||||
```
|
||||
While any version of `pycryptodome` should work, we recommend **v3.22.0** if you encounter issues:
|
||||
```bash
|
||||
pip install pycryptodome==3.22.0
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Server (`server_config.json`):
|
||||
```json
|
||||
{
|
||||
"InternalDataPort": 5000, // PyFrp server data port
|
||||
"AllowedPortRange": "5001-5500", // Allowed port range
|
||||
"MaxPortsPerClient": 5, // Max ports per client
|
||||
"Key": "07A36AEF1907843" // Authentication key
|
||||
}
|
||||
```
|
||||
|
||||
#### Client (`client_config.json`):
|
||||
```json
|
||||
{
|
||||
"ServerDomain": "127.0.0.1", // PyFrp server address
|
||||
"ServerPort": 5000, // PyFrp server port
|
||||
"Key": "07A36AEF1907843", // Authentication key
|
||||
"Forwards": [ // Port mappings
|
||||
{
|
||||
"forward_domain": "127.0.0.1", // Local host
|
||||
"forward_port": 36667, // Local port
|
||||
"target_port": 5002, // Target port
|
||||
"mode": "TCP" // Protocol (TCP only)
|
||||
}
|
||||
// Add more mappings as needed
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Running PyFrp
|
||||
|
||||
#### Start the server:
|
||||
```bash
|
||||
python server.py server_config.json
|
||||
```
|
||||
|
||||
#### Start the client:
|
||||
```bash
|
||||
python client.py client_config.json
|
||||
```
|
||||
|
||||
You can also modify the default configuration directly in the source code.
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Example
|
||||
|
||||
### Example: Exposing a Local HTTP Server
|
||||
|
||||
1. **Start a local HTTP server**:
|
||||
```bash
|
||||
python -m http.server 36667
|
||||
```
|
||||
|
||||
2. **Configure PyFrp client** (`client_config.json`):
|
||||
```json
|
||||
{
|
||||
"ServerDomain": "127.0.0.1",
|
||||
"ServerPort": 5000,
|
||||
"Key": "07A36AEF1907843",
|
||||
"Forwards": [
|
||||
{
|
||||
"forward_domain": "127.0.0.1",
|
||||
"forward_port": 36667,
|
||||
"target_port": 5002,
|
||||
"mode": "TCP"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. **Start PyFrp server and client**:
|
||||
```bash
|
||||
# In terminal 1
|
||||
python server.py
|
||||
|
||||
# In terminal 2
|
||||
python client.py
|
||||
```
|
||||
|
||||
4. **Access the local server through the proxy**:
|
||||
```bash
|
||||
curl http://localhost:5002
|
||||
```
|
||||
|
||||
You should see the HTTP response from your local server, indicating that the port forwarding is working correctly.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Limitations
|
||||
|
||||
- **Only TCP protocol is supported** (UDP, HTTP, HTTPS are not supported)
|
||||
- **No SSL encryption** for data transmission
|
||||
- **Simple authentication mechanism** (fixed key)
|
||||
- **No automatic reconnection** after network interruption
|
||||
- **Limited error handling** and logging
|
||||
- **Performance limitations** due to JSON and hex encoding for data transfer
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ How It Works
|
||||
|
||||
### Server-side (server.py)
|
||||
1. Listens for client connections on the internal data port
|
||||
2. Handles client authentication
|
||||
3. Creates and manages port forwarding services
|
||||
4. Forwards data between external connections and clients
|
||||
|
||||
### Client-side (client.py)
|
||||
1. Connects to the server and authenticates
|
||||
2. Sends port forwarding configuration
|
||||
3. Handles connections to local services
|
||||
4. Forwards data between the server and local services
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Here's how you can help:
|
||||
|
||||
1. **Report bugs** by opening an issue
|
||||
2. **Suggest features** by opening an issue
|
||||
3. **Submit pull requests** with bug fixes or enhancements
|
||||
|
||||
### Development Guidelines
|
||||
- Follow the existing code style
|
||||
- Add comments for complex code
|
||||
- Test your changes thoroughly
|
||||
- Update documentation as needed
|
||||
|
||||
---
|
||||
|
||||
## 📞 Contact Us
|
||||
- 📧 Email: wyt18222152539wyt@163.com
|
||||
- 🌐 Website: [Galaxy Vastar Software Studio](https://www.gvsds.com)
|
||||
- 📱 WeChat: GVSADS
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the MIT License. See the LICENSE file for details.
|
||||
|
||||
---
|
||||
|
||||
## 🗡 简单介绍
|
||||
原本的 Frp https://github.com/Fatedier/frp/ 体积略显臃肿,而 PyFrp 则是一个基于 Python 实现的简单版本,体积更小,功能也更简单。
|
||||
|
||||
我们 和 原版 Frp 相比
|
||||
| 功能 | PyFrp | Frp |
|
||||
|:-:|:-:|:-:|
|
||||
| 快速配置 | ✅ | ✅ |
|
||||
| 体积 | ✅ | ❌ |
|
||||
| SSL 功能 | ❌ | ✅ |
|
||||
| 嵌入式 | ✅ | ⭕ |
|
||||
| 文档 | ✅ | ✅ |
|
||||
| TCP 支持 | ✅ | ✅ |
|
||||
| UDP 支持 | ❌ | ✅ |
|
||||
| HTTP 支持 | ❌ | ✅ |
|
||||
|
||||
请您根据您的需要选择使用哪个,
|
||||
- 如果您需要快速配置,体积小,功能简单,嵌入式,集成到您自己的 Python 项目中,那么 PyFrp 是一个不错的选择。
|
||||
- 如果您需要部署在生产环境中,暂时不要选择 PyFrp,Frp 是一个更好的选择。
|
||||
|
||||
日后,我们以 Frp 为目标,完善其功能,添加更多的配置项,同时也会考虑添加更多的协议支持,如 http、https 等。
|
||||
|
||||
我们其实也才起步,仍然需要您的支持,如果可以,还请您点一个 Star ⭐,这将是对我们最大的支持。
|
||||
|
||||
> 注意,我们暂时还不支持 https 协议。稍后如果有时间,我们可能会考虑支持,如果您已经帮我们支持,随时欢迎您提交。
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 先决条件
|
||||
|
||||
你唯一需要下载的第三方库是 `pycryptodome`,使用以下命令安装:
|
||||
```bash
|
||||
pip install pycryptodome
|
||||
```
|
||||
我们推荐使用 **v3.22.0** 版本:
|
||||
```bash
|
||||
pip install pycryptodome==3.22.0
|
||||
```
|
||||
|
||||
### 配置
|
||||
|
||||
#### 服务器端配置 (`server_config.json`):
|
||||
```json
|
||||
{
|
||||
"InternalDataPort": 5000, // PyFrp 服务器端数据端口
|
||||
"AllowedPortRange": "5001-5500", // 允许的端口范围
|
||||
"MaxPortsPerClient": 5, // 每个客户端最大端口数
|
||||
"Key": "07A36AEF1907843" // 认证密钥
|
||||
}
|
||||
```
|
||||
|
||||
#### 客户端配置 (`client_config.json`):
|
||||
```json
|
||||
{
|
||||
"ServerDomain": "127.0.0.1", // PyFrp 服务器端主机地址
|
||||
"ServerPort": 5000, // PyFrp 服务器端端口
|
||||
"Key": "07A36AEF1907843", // 认证密钥
|
||||
"Forwards": [ // 端口映射配置
|
||||
{
|
||||
"forward_domain": "127.0.0.1", // 本地主机地址
|
||||
"forward_port": 36667, // 本地端口
|
||||
"target_port": 5002, // 目标端口
|
||||
"mode": "TCP" // 传输模式(仅支持TCP)
|
||||
}
|
||||
// 你可以在这里输入更多的端口映射配置
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 运行 PyFrp
|
||||
|
||||
#### 启动服务器:
|
||||
```bash
|
||||
python server.py server_config.json
|
||||
```
|
||||
|
||||
#### 启动客户端:
|
||||
```bash
|
||||
python client.py client_config.json
|
||||
```
|
||||
|
||||
你也可以直接修改源代码中的默认配置。
|
||||
|
||||
---
|
||||
|
||||
## � 使用示例
|
||||
|
||||
### 示例:暴露本地 HTTP 服务器
|
||||
|
||||
1. **启动本地 HTTP 服务器**:
|
||||
```bash
|
||||
python -m http.server 36667
|
||||
```
|
||||
|
||||
2. **配置 PyFrp 客户端** (`client_config.json`):
|
||||
```json
|
||||
{
|
||||
"ServerDomain": "127.0.0.1",
|
||||
"ServerPort": 5000,
|
||||
"Key": "07A36AEF1907843",
|
||||
"Forwards": [
|
||||
{
|
||||
"forward_domain": "127.0.0.1",
|
||||
"forward_port": 36667,
|
||||
"target_port": 5002,
|
||||
"mode": "TCP"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
3. **启动 PyFrp 服务器和客户端**:
|
||||
```bash
|
||||
# 在终端 1 中
|
||||
python server.py
|
||||
|
||||
# 在终端 2 中
|
||||
python client.py
|
||||
```
|
||||
|
||||
4. **通过代理访问本地服务器**:
|
||||
```bash
|
||||
curl http://localhost:5002
|
||||
```
|
||||
|
||||
你应该会看到来自本地服务器的 HTTP 响应,表明端口转发工作正常。
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 限制
|
||||
|
||||
- **仅支持 TCP 协议**(不支持 UDP、HTTP、HTTPS)
|
||||
- **数据传输无 SSL 加密**
|
||||
- **简单的认证机制**(固定密钥)
|
||||
- **网络中断后无自动重连**
|
||||
- **有限的错误处理**和日志记录
|
||||
- **性能限制**(由于使用 JSON 和 hex 编码传输数据)
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ 工作原理
|
||||
|
||||
### 服务器端 (server.py)
|
||||
1. 在内部数据端口上监听客户端连接
|
||||
2. 处理客户端认证
|
||||
3. 创建和管理端口转发服务
|
||||
4. 在外部连接和客户端之间转发数据
|
||||
|
||||
### 客户端 (client.py)
|
||||
1. 连接到服务器并进行认证
|
||||
2. 发送端口转发配置
|
||||
3. 处理到本地服务的连接
|
||||
4. 在服务器和本地服务之间转发数据
|
||||
|
||||
---
|
||||
|
||||
## 🤝 贡献
|
||||
|
||||
欢迎贡献!你可以通过以下方式帮助我们:
|
||||
|
||||
1. **报告错误**:通过打开 issue
|
||||
2. **建议功能**:通过打开 issue
|
||||
3. **提交代码**:通过 pull request 提交 bug 修复或增强功能
|
||||
|
||||
### 开发指南
|
||||
- 遵循现有的代码风格
|
||||
- 为复杂代码添加注释
|
||||
- 彻底测试你的更改
|
||||
- 根据需要更新文档
|
||||
|
||||
---
|
||||
|
||||
## �📞 联系我们
|
||||
- 📧 Email: wyt18222152539wyt@163.com
|
||||
- 🌐 官网: [银河万通软件开发工作室](https://www.gvsds.com)
|
||||
- 📱 微信: GVSADS
|
||||
|
||||
---
|
||||
|
||||
## 📄 许可证
|
||||
|
||||
本项目采用 MIT 许可证。详情请参阅 LICENSE 文件。
|
||||
+6
-6
@@ -74,8 +74,8 @@ class KeMouse:
|
||||
Target: str = os.path.abspath(Target)
|
||||
if not os.path.isfile(Target):
|
||||
raise FileNotFoundError(Target)
|
||||
TargetImg: GrayImage = self.load_image(Target)
|
||||
Screen: GrayImage = self.capture_screen()
|
||||
TargetImg: GrayImage = self.LoadImage(Target)
|
||||
Screen: GrayImage = self.CaptureScreen()
|
||||
X1: int
|
||||
Y2: int
|
||||
X2: int
|
||||
@@ -92,7 +92,7 @@ class KeMouse:
|
||||
except Exception as e: raise RuntimeError(f"Failed To Find Template, Error: {str(e)}")
|
||||
def MoveTo(self, X: int, Y: int) -> None:
|
||||
if not self.user32.SetCursorPos(X, Y): raise ctypes.WinError(ctypes.get_last_error())
|
||||
def GetPosition(self) -> dict[int, int]:
|
||||
def GetPosition(self) -> tuple[int, int]:
|
||||
Point: ctypes.wintypes.POINT = ctypes.wintypes.POINT()
|
||||
if not self.user32.GetCursorPos(ctypes.byref(Point)): raise ctypes.WinError(ctypes.get_last_error())
|
||||
return (Point.x, Point.y)
|
||||
@@ -138,14 +138,14 @@ class KeMouse:
|
||||
Pos, Confidence = self.FindTemplate(Target, Threshold, SearchArea)
|
||||
if not Pos:
|
||||
return False
|
||||
_=self.click(Pos[0], Pos[1], button=Button)
|
||||
_ = self.Click(Pos[0], Pos[1], button=Button)
|
||||
time.sleep(Sleep)
|
||||
return _
|
||||
def ClickTargetPNGAC(self, Target: str, Button: str='left', Threshold: float = 0.9, Sleep: float = 0, SearchArea: typing.Optional[typing.Tuple[int, int, int, int]] = None, Confidence: float = 0.9) -> bool:
|
||||
Pos, Confidence = self.FindTemplate(Target, Threshold, SearchArea)
|
||||
if not Pos or Confidence < Confidence:
|
||||
if not Pos or Confidence < self.Confidence:
|
||||
return False
|
||||
_=self.click(Pos[0], Pos[1], button=Button)
|
||||
_ = self.Click(Pos[0], Pos[1], button=Button)
|
||||
time.sleep(Sleep)
|
||||
return _
|
||||
def ScreenshotBytes(self) -> bytes:
|
||||
|
||||
Reference in new issue
Block a user