114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
import zlib
|
|
import time
|
|
import socket
|
|
import struct
|
|
from loguru import logger
|
|
import mss
|
|
import mss.tools
|
|
import pyautogui
|
|
import configparser
|
|
from Crypto.Cipher import AES
|
|
import base64
|
|
import ssl
|
|
|
|
class RemoteClient:
|
|
def __init__(self, host='127.0.0.1', port=5000):
|
|
config = configparser.ConfigParser()
|
|
config.read('config.ini')
|
|
|
|
self.host = config['Server']['host']
|
|
self.port = int(config['Server']['port'])
|
|
self.client_id = config['Authentication']['client_id']
|
|
|
|
# 初始化加密组件
|
|
self.cipher = AES.new(
|
|
base64.b64decode(config['Security']['encryption_key']),
|
|
AES.MODE_CBC,
|
|
base64.b64decode(config['Security']['encryption_salt'])
|
|
)
|
|
|
|
# 创建SSL上下文
|
|
self.context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
|
|
self.context.load_cert_chain(config['Authentication']['cert_file'])
|
|
self.context.check_hostname = False
|
|
|
|
self.sock = self.context.wrap_socket(
|
|
socket.socket(socket.AF_INET, socket.SOCK_STREAM),
|
|
server_hostname=config['Server']['host']
|
|
)
|
|
self.prev_hash = None
|
|
self.prev_mouse = (0, 0)
|
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
logger.add('remote_client.log',
|
|
rotation='10 MB',
|
|
retention='7 days',
|
|
format='{time:YYYY-MM-DD HH:mm:ss} | {level} | {module}:{function} - {message}')
|
|
|
|
def connect(self):
|
|
try:
|
|
self.sock.connect((self.host, self.port))
|
|
logger.info(f'成功连接到服务器 {self.host}:{self.port}')
|
|
except Exception as e:
|
|
logger.error(f'连接错误: {e}')
|
|
|
|
def capture_screen(self):
|
|
with mss.mss() as sct:
|
|
screenshot = sct.grab(sct.monitors[0])
|
|
raw_bytes = mss.tools.to_png(sct.grab(sct.monitors[0]), (0, 0, screenshot.width, screenshot.height))
|
|
current_hash = zlib.crc32(raw_bytes)
|
|
|
|
if current_hash != self.prev_hash:
|
|
original_size = len(raw_bytes)
|
|
compressed = zlib.compress(raw_bytes, level=9)
|
|
compressed_size = len(compressed)
|
|
ratio = (1 - compressed_size/original_size) * 100
|
|
logger.debug(f'屏幕变化检测 [尺寸: ({screenshot.width},{screenshot.height})] [压缩率: {ratio:.1f}%]')
|
|
self.prev_hash = current_hash
|
|
return ('screen', compressed, (screenshot.width, screenshot.height))
|
|
return None
|
|
|
|
def get_mouse_data(self):
|
|
x, y = pyautogui.position()
|
|
buttons = pyautogui.mouseDown()
|
|
|
|
if (x, y) != self.prev_mouse or buttons:
|
|
logger.info(f'鼠标事件 [坐标: ({x},{y})] [按键: {buttons}]')
|
|
data = struct.pack('!II?', x, y, buttons)
|
|
self.prev_mouse = (x, y)
|
|
return ('mouse', data)
|
|
return None
|
|
|
|
def send_data(self, data_type, payload, size=None):
|
|
header = struct.pack('!4sI', data_type.encode(), len(payload))
|
|
if size:
|
|
header += struct.pack('!II', *size)
|
|
try:
|
|
self.sock.sendall(header + payload)
|
|
logger.trace(f'发送{data_type}数据 [大小: {len(payload)}字节]')
|
|
except Exception as e:
|
|
logger.warning(f'发送错误: {e}')
|
|
self.connect()
|
|
|
|
def run(self):
|
|
self.connect()
|
|
while True:
|
|
start_time = time.time()
|
|
|
|
# 捕获屏幕差异
|
|
screen_data = self.capture_screen()
|
|
if screen_data:
|
|
self.send_data(*screen_data)
|
|
|
|
# 捕获鼠标状态
|
|
mouse_data = self.get_mouse_data()
|
|
if mouse_data:
|
|
self.send_data(*mouse_data)
|
|
|
|
# 保持2秒间隔
|
|
elapsed = time.time() - start_time
|
|
if elapsed < 2:
|
|
time.sleep(2 - elapsed)
|
|
|
|
if __name__ == '__main__':
|
|
client = RemoteClient()
|
|
client.run() |