1+ import os
2+ import sys
3+ import threading
4+ import queue
5+ import base64
6+ import time
7+ import argparse
8+ import psutil
9+ import pynvml
10+ from rich .live import Live
11+ from rich .table import Table
12+ from rich .console import Console
13+
14+ from numba import cuda
15+ import numpy as np
16+
17+ def check_system_limits ():
18+ max_ram_gb = 32
19+ max_vram_gb = 8
20+
21+ total_ram = psutil .virtual_memory ().total / (1024 ** 3 )
22+ if total_ram > max_ram_gb :
23+ print (f"[WARN] { total_ram :.1f} GB RAM - Not supported" )
24+
25+ try :
26+ pynvml .nvmlInit ()
27+ handle = pynvml .nvmlDeviceGetHandleByIndex (0 )
28+ mem_info = pynvml .nvmlDeviceGetMemoryInfo (handle )
29+ total_vram = mem_info .total / (1024 ** 3 )
30+ if total_vram > max_vram_gb :
31+ print (f"[WARN] { total_vram :.1f} GB VRAM - Not supported" )
32+ pynvml .nvmlShutdown ()
33+ except :
34+ print ("[INFO] Couldn’t check VRAM (no supported GPU or nvml issue)" )
35+
36+
37+ def main ():
38+ check_system_limits ()
39+ args = parse_args ()
40+
41+ def chunk_reader (fobj , chunk_size = 2 * 1024 * 1024 ):
42+ while True :
43+ data = fobj .read (chunk_size )
44+ if not data :
45+ break
46+ yield data
47+
48+ def is_system_folder (path ):
49+ sys_folders = ['AppData' , 'Local' , 'Microsoft' , 'Windows' , 'ProgramData' , 'Program Files' , 'Program Files (x86)' ]
50+ return any (part in path .split (os .sep ) for part in sys_folders )
51+
52+ @cuda .jit
53+ def cuda_search_kernel (data , pattern , result ):
54+ i = cuda .grid (1 )
55+ n = data .size
56+ m = pattern .size
57+ if i + m <= n :
58+ match = True
59+ for j in range (m ):
60+ if data [i + j ] != pattern [j ]:
61+ match = False
62+ break
63+ if match :
64+ result [0 ] = 1
65+
66+ def cuda_search (data_bytes , pattern_bytes ):
67+ data_np = np .frombuffer (data_bytes , dtype = np .uint8 )
68+ pattern_np = np .frombuffer (pattern_bytes , dtype = np .uint8 )
69+ result = np .zeros (1 , dtype = np .uint8 )
70+ threads_per_block = 256
71+ blocks = (len (data_np ) + threads_per_block - 1 ) // threads_per_block
72+ d_data = cuda .to_device (data_np )
73+ d_pattern = cuda .to_device (pattern_np )
74+ d_result = cuda .to_device (result )
75+ cuda_search_kernel [blocks , threads_per_block ](d_data , d_pattern , d_result )
76+ d_result .copy_to_host (result )
77+ return result [0 ] == 1
78+
79+ class SearchThread (threading .Thread ):
80+ def __init__ (self , tid , task_queue , results , args , status_dict , counter_lock , files_scanned ):
81+ super ().__init__ ()
82+ self .tid = tid
83+ self .task_queue = task_queue
84+ self .results = results
85+ self .args = args
86+ self .status_dict = status_dict
87+ self .daemon = True
88+ self .counter_lock = counter_lock
89+ self .files_scanned = files_scanned
90+ self .cuda_available = False
91+ try :
92+ cuda .select_device (0 )
93+ self .cuda_available = True
94+ except cuda .cudadrv .error .CudaSupportError :
95+ self .cuda_available = False
96+
97+ def run (self ):
98+ while True :
99+ try :
100+ path = self .task_queue .get (timeout = 1 )
101+ except queue .Empty :
102+ self .status_dict [self .tid ] = "> Idle"
103+ break
104+
105+ self .status_dict [self .tid ] = f"[INFO] Scanning { os .path .basename (path )} "
106+
107+ if self .args .skip_sys and is_system_folder (path ):
108+ self .status_dict [self .tid ] = "> Idle"
109+ self .task_queue .task_done ()
110+ continue
111+
112+ if os .path .isdir (path ):
113+ if not self .args .nosub :
114+ try :
115+ for entry in os .listdir (path ):
116+ full_path = os .path .join (path , entry )
117+ self .task_queue .put (full_path )
118+ except Exception as e :
119+ if self .args .errors :
120+ print (f"[ERROR] Cannot list { path } : { e } " )
121+ else :
122+ filename = os .path .basename (path )
123+
124+ if self .args .fc and filename != self .args .fc :
125+ self .status_dict [self .tid ] = "> Idle"
126+ self .task_queue .task_done ()
127+ continue
128+
129+ if self .args .ext and not filename .lower ().endswith (self .args .ext .lower ()):
130+ self .status_dict [self .tid ] = "> Idle"
131+ self .task_queue .task_done ()
132+ continue
133+
134+ try :
135+ fsize = os .path .getsize (path )
136+ if self .args .minsize and fsize < self .args .minsize :
137+ self .status_dict [self .tid ] = "> Idle"
138+ self .task_queue .task_done ()
139+ continue
140+ if self .args .maxsize and fsize > self .args .maxsize :
141+ self .status_dict [self .tid ] = "> Idle"
142+ self .task_queue .task_done ()
143+ continue
144+
145+ if self .args .amongus and fsize == 69420 :
146+ print (f"[?] Sus file found: { path } " )
147+
148+ except Exception as e :
149+ if self .args .errors :
150+ print (f"[ERROR] cannot get size { path } : { e } " )
151+ self .status_dict [self .tid ] = "> Idle"
152+ self .task_queue .task_done ()
153+ continue
154+
155+ found_content = False
156+ try :
157+ with open (path , 'rb' ) as f :
158+ for chunk in chunk_reader (f ):
159+ if self .args .fake :
160+ found_content = True
161+ break
162+
163+ if self .args .content :
164+ search_bytes = self .args .content .encode (errors = 'ignore' )
165+
166+ if self .cuda_available :
167+ if cuda_search (chunk , search_bytes ):
168+ found_content = True
169+ break
170+ else :
171+ if search_bytes .lower () in chunk .lower ():
172+ found_content = True
173+ break
174+
175+ elif self .args .hex :
176+ try :
177+ target_bytes = bytes .fromhex (self .args .hex )
178+ if self .cuda_available :
179+ if cuda_search (chunk , target_bytes ):
180+ found_content = True
181+ break
182+ else :
183+ if target_bytes in chunk :
184+ found_content = True
185+ break
186+ except Exception :
187+ pass
188+ elif self .args .base64 :
189+ try :
190+ target_bytes = base64 .b64decode (self .args .base64 )
191+ if self .cuda_available :
192+ if cuda_search (chunk , target_bytes ):
193+ found_content = True
194+ break
195+ else :
196+ if target_bytes in chunk :
197+ found_content = True
198+ break
199+ except Exception :
200+ pass
201+
202+ if self .args .fc :
203+ if found_content or not self .args .content :
204+ self .results .append (path )
205+ if not self .args .quiet :
206+ print (f"[MATCH] { path } (filename match)" )
207+ else :
208+ if self .args .content and found_content :
209+ self .results .append (path )
210+ if not self .args .quiet :
211+ print (f"[MATCH] { path } (contains '{ self .args .content } ')" )
212+ elif not self .args .content and not self .args .fc :
213+ self .results .append (path )
214+ if not self .args .quiet and self .args .noisy :
215+ print (f"[FILE] { path } " )
216+ except Exception as e :
217+ if self .args .errors :
218+ print (f"[ERROR] Cannot open/read { path } : { e } " )
219+
220+ with self .counter_lock :
221+ self .files_scanned [0 ] += 1
222+
223+ self .status_dict [self .tid ] = "> Idle"
224+ self .task_queue .task_done ()
225+ if self .args .delay :
226+ time .sleep (self .args .delay )
227+
228+ def parse_args ():
229+ parser = argparse .ArgumentParser (description = "Epic Multithreaded Python Search Tool (arguments are stackable)" )
230+
231+ parser .add_argument ("path" , nargs = "?" , default = "C:\\ " , help = "Path or disk(s) to search" )
232+
233+ parser .add_argument ("-adisks" , action = "store_true" , help = "Search all available fixed disks" )
234+ parser .add_argument ("-spdisk" , type = str , help = "Specify one disk (like C:\\ )" )
235+ parser .add_argument ("-wdisk" , action = "store_true" , help = "Search root of disks instead of folders" )
236+
237+ parser .add_argument ("-nosub" , action = "store_true" , help = "No recursion into subdirectories" )
238+ parser .add_argument ("-fc" , type = str , help = "Focus on specific filename only" )
239+ parser .add_argument ("-content" , type = str , help = "Search inside files for text" )
240+ parser .add_argument ("-hex" , type = str , help = "Search for hex-encoded bytes inside files" )
241+ parser .add_argument ("-base64" , type = str , help = "Search for base64-encoded string inside files" )
242+ parser .add_argument ("-ext" , type = str , help = "Only scan files with this extension" )
243+
244+ parser .add_argument ("-minsize" , type = int , help = "Only scan files bigger than this size (bytes)" )
245+ parser .add_argument ("-maxsize" , type = int , help = "Only scan files smaller than this size (bytes)" )
246+
247+ parser .add_argument ("-threads" , type = int , help = "Number of threads to use" )
248+ parser .add_argument ("-noisy" , action = "store_true" , help = "Print every file scanned" )
249+ parser .add_argument ("-quiet" , action = "store_true" , help = "Suppress status except matches" )
250+ parser .add_argument ("-nocache" , action = "store_true" , help = "Disable caching chunks to temp files (ignored)" )
251+ parser .add_argument ("-keeptemp" , action = "store_true" , help = "Do NOT delete temp cache files (ignored)" )
252+ parser .add_argument ("-stats" , action = "store_true" , help = "Show final stats" )
253+ parser .add_argument ("-fake" , action = "store_true" , help = "Simulate scanning, no real file open" )
254+ parser .add_argument ("-delay" , type = float , help = "Sleep seconds between scans" )
255+ parser .add_argument ("-errors" , action = "store_true" , help = "Show detailed errors" )
256+ parser .add_argument ("-skip_sys" , action = "store_true" , help = "Skip common system folders (C:\\ Users only)" )
257+
258+ parser .add_argument ("-skibidibounce" , action = "store_true" , help = "Random delays + glitchy output" )
259+ parser .add_argument ("-speedrun" , action = "store_true" , help = "Max threads + no safety checks" )
260+ parser .add_argument ("-amongus" , action = "store_true" , help = "Say 'sus file' on file size 69420" )
261+ parser .add_argument ("-nuke" , action = "store_true" , help = "Scary name, does nothing lol" )
262+ parser .add_argument ("-😎" , action = "store_true" , help = "Cool output mode (animated?)" )
263+
264+ return parser .parse_args ()
265+
266+ def build_status_table (status_dict , files_scanned , elapsed , args ):
267+ table = Table (title = "Thread Statuses (live)" )
268+
269+ table .add_column ("Thread ID" , justify = "center" , style = "white" , no_wrap = True )
270+ table .add_column ("Status" , style = "black" )
271+
272+ for tid , status in sorted (status_dict .items ()):
273+ table .add_row (str (tid ), status )
274+
275+ progress_str = f"Files scanned: { files_scanned [0 ]} "
276+ if elapsed > 0 and files_scanned [0 ] > 0 :
277+ rate = files_scanned [0 ] / elapsed
278+ progress_str += f" | Rate: { rate :.1f} files/s"
279+ else :
280+ rate = 0
281+
282+ if args .speedrun :
283+ progress_str += "Speedrun mode ON"
284+
285+ table .caption = progress_str
286+ return table
287+
288+ def main ():
289+ args = parse_args ()
290+
291+ if args .speedrun :
292+ args .threads = 32
293+ args .nocache = True
294+ args .quiet = True
295+ args .errors = False
296+
297+ start_time = time .time ()
298+ task_queue = queue .Queue ()
299+ results = []
300+ status_dict = {}
301+ counter_lock = threading .Lock ()
302+ files_scanned = [0 ]
303+
304+ base_path = args .spdisk or args .path
305+ if args .adisks :
306+ for letter in 'CDEFGHIJKLMNOPQRSTUVWXYZ' :
307+ drive = f"{ letter } :\\ "
308+ if os .path .exists (drive ):
309+ task_queue .put (drive )
310+ else :
311+ task_queue .put (base_path )
312+
313+ thread_count = args .threads or os .cpu_count ()
314+ threads = []
315+
316+ for i in range (thread_count ):
317+ status_dict [i ] = "init"
318+ t = SearchThread (i , task_queue , results , args , status_dict , counter_lock , files_scanned )
319+ threads .append (t )
320+ t .start ()
321+
322+ console = Console ()
323+ try :
324+ with Live (build_status_table (status_dict , files_scanned , 0 , args ), console = console , refresh_per_second = 5 ) as live :
325+ while any (t .is_alive () for t in threads ):
326+ elapsed = time .time () - start_time
327+ live .update (build_status_table (status_dict , files_scanned , elapsed , args ))
328+ time .sleep (0.2 )
329+ except KeyboardInterrupt :
330+ print ("\n [!] CTRL+c detected. Exiting gracefully..." )
331+ sys .exit (1 )
332+
333+ if args .stats :
334+ elapsed = time .time () - start_time
335+ print (f"\n \n [STATS] Done in { elapsed :.2f} s. Files matched: { len (results )} | Scanned: { files_scanned [0 ]} " )
336+
337+ if __name__ == "__main__" :
338+ main ()
0 commit comments