Skip to content

Commit be86223

Browse files
committed
Release
0 parents  commit be86223

File tree

4 files changed

+294
-0
lines changed

4 files changed

+294
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Swezy <3
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.

README.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<h1 align="center">⚙️ Batch Dump ⚙️</h1>
2+
3+
<p align="center">
4+
<a href="https://www.python.org" target="_blank"><img src="https://img.shields.io/badge/Language-Python-blue?style=for-the-badge&logo=python" /></a>
5+
<a href="https://t.me/swezy" target="_blank"><img src="https://img.shields.io/badge/Telegram-@Swezy-blue?style=for-the-badge&logo=telegram" /></a>
6+
<br>
7+
<code>Leave a ⭐ if you like this Repository</code>
8+
</p>
9+
10+
---
11+
12+
## 🚩 Project overview
13+
14+
**Batch Dump** is a compact Python utility that **watches common system/user directories** for newly created compiled `.bat` files, **copies them to the tool directory** for inspection, and optionally **deobfuscates** certain compiled batch stubs by removing a known hex sequence.
15+
16+
The program uses a **clean CLI interface**, a **gradient ASCII logo**, and a lightweight **watchdog**-based file monitor to automate discovery and basic recovery of batch source code.
17+
18+
> [!CAUTION]
19+
> This tool is intended for **legitimate reverse-engineering, debugging, recovery, and research** in environments where you have explicit permission.
20+
> Do **not** use this to access or exfiltrate files you are not authorized to access. The author and contributors are **not** responsible for misuse of this code.
21+
22+
---
23+
24+
## ✨ Features
25+
26+
* 📁 **Watch & Dump `.bat` files** — Monitors a configurable set of likely locations (Temp, Desktop, Documents, Downloads, ProgramData, etc.) and copies newly created `.bat` files into the script folder.
27+
* 🧩 **Deobfuscate Batch Files** — Removes a specific byte/hex pattern (`FF FE 26 63 6C 73 0D 0A FF FE 0A 0D`) to reveal readable batch source where applicable.
28+
* 🎨 **Aesthetic CLI** — Displays a gradient ASCII logo and menu using `rgbprint` and colored output via `colorama`.
29+
* 🔁 **Duplicate protection** — Tracks already-processed files to avoid copying the same file multiple times during a session.
30+
31+
---
32+
33+
## 🧭 How It Works
34+
35+
1. Run the tool (`python main.py`).
36+
2. Choose one of the two options:
37+
38+
* `[1] Dump compiled Batch` — start monitoring the configured directories and copy discovered `.bat` files to the script directory.
39+
* `[2] Deobfuscate Batch` — provide a path to a `.bat` file and the script will remove the configured hex sequence and open the result in your system editor.
40+
3. The tool prints progress to the console and saves discovered files for offline inspection.
41+
42+
> ✅ When dumping, any discovered `.bat` will be copied into the same folder as `main.py`. When deobfuscating, the file is modified in-place (make backups if needed).
43+
44+
---
45+
46+
## 🧰 Requirements
47+
48+
* 🐍 Python **3.9+**
49+
* 📦 Dependencies:
50+
51+
```bash
52+
pip install watchdog rgbprint colorama
53+
```
54+
* 💾 Access to the directories you want to monitor (run with appropriate permissions).
55+
56+
---
57+
58+
## 🔑 Notes on Safety & Usage
59+
60+
* Only run this tool on machines you own or where you have explicit permission.
61+
* `utility.delete_hex()` modifies files in-place — always keep backups of originals if you need to preserve them.
62+
* Reduce risk for false detections during testing by limiting `utility.possible_paths` to a single controlled directory.
63+
64+
---
65+
66+
## 📝 Repository structure
67+
68+
```/
69+
├─ assets/ ➔ Screenshots of the Program in action
70+
│ └─ preview.png ➔ A screenshot of the Program running
71+
├─ main.py ➔ Main program logic and CLI
72+
├─ LICENSE ➔ License file
73+
└─ README.md ➔ Read me file
74+
```
75+
76+
---
77+
78+
## 🖼️ Preview
79+
80+
<p align="center">
81+
<img src="https://img.shields.io/badge/UI-Gradient%20CLI-blueviolet?style=for-the-badge"/>
82+
<br><br>
83+
<img src="https://github.com/SwezyDev/Batch-Dump/blob/main/assets/preview.png?raw=true" alt="Program preview">
84+
</p>
85+
86+
---
87+
88+
## 🧠 Hex Sequence Removed
89+
90+
The script removes the following hex byte sequence (shown as hex groups):
91+
92+
```
93+
FF FE 26 63 6C 73 0D 0A FF FE 0A 0D
94+
```
95+
96+
You can change the target pattern by editing the `utility.delete_hex()` call in `BatchDump.deobfuscate()`, but doing so is not recommended as it may break the deobfuscation process.
97+
98+
---
99+
100+
## ⚙️ Technical Details
101+
102+
* `watchdog.Observer` + `utility.FileCreationHandler` (subclass of `FileSystemEventHandler`) to react to file creation events.
103+
* `shutil.copy()` copies detected files into the running script directory.
104+
* `utility.delete_hex()` reads file bytes, replaces occurrences of `bytes.fromhex(hex)` with `b''`, and writes back the result.
105+
* `rgbprint.gradient_print()` for the logo and menu; `colorama.Fore` for colored status lines.
106+
107+
---
108+
109+
## ⚖️ License
110+
111+
Distributed under the **MIT License**. See `LICENSE` for more information.
112+
113+
---
114+
115+
## 🙌 Credits & contact
116+
117+
- Maintainer: [@SwezyDev](https://github.com/SwezyDev) — reach out via Telegram: [@Swezy](https://t.me/swezy)
118+
- Inspiration: public security research and community writeups.
119+
120+
---
121+
122+
## 🚨 Disclaimer
123+
124+
This project is **unofficial** and is **not** affiliated with any vendor. It is meant for **educational, analysis, and recovery** tasks only. Use responsibly and legally.
125+
126+
---
127+
128+
## 📣 Final note
129+
130+
This utility exists to help researchers and devs recover and inspect compiled/obfuscated batch stubs. Use responsibly — do **not** use it to spy, exfiltrate, or automate access to systems you don't own or have permission to test.

assets/preview.png

369 KB
Loading

main.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
from watchdog.events import FileSystemEventHandler
2+
from rgbprint import gradient_print, Color
3+
from watchdog.observers import Observer
4+
from colorama import Fore
5+
import shutil
6+
import time
7+
import os
8+
9+
10+
class utility:
11+
logo = """ ::::::::: ::: ::: ::: ::: ::::::::: ::::::::::: :::::::::: ::: :::
12+
:+: :+: :+: :+: :+:+: :+:+: :+: :+: :+: :+: :+: :+:
13+
+:+ +:+ +:+ +:+ +:+ +:+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
14+
+#+ +:+ +#+ +:+ +#+ +:+ +#+ +#++:++#+ +#+ :#::+::# +#++:
15+
+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+
16+
#+# #+# #+# #+# #+# #+# #+# #+# #+# #+#
17+
######### ######## ### ### ### ########### ### ###""" # Logo art
18+
19+
menu = """
20+
╔═══ ═══╗
21+
[1] Dump compiled Batch
22+
[2] Deobfuscate Batch
23+
╚═══ ═══╝""" # Menu art
24+
25+
possible_paths = [
26+
os.path.join(os.getenv("LOCALAPPDATA"), "Temp"),
27+
os.getenv("APPDATA"),
28+
os.path.join(os.path.expanduser("~"), "Desktop"),
29+
os.path.join(os.path.expanduser("~"), "Documents"),
30+
os.path.join(os.path.expanduser("~"), "Pictures"),
31+
os.path.join(os.path.expanduser("~"), "Music"),
32+
os.path.join(os.path.expanduser("~"), "Videos"),
33+
os.path.join(os.path.expanduser("~"), "Downloads"),
34+
os.environ["ProgramW6432"],
35+
os.environ["ProgramData"]
36+
]
37+
38+
39+
def delete_hex(path: str, hex: str): # Function to delete specific hex bytes from a file
40+
with open(path, 'rb') as f: # Open the file in binary read mode
41+
src = f.read() # Read the file content
42+
43+
hex_bytes = bytes.fromhex(hex) # Convert hex string to bytes
44+
45+
new = src.replace(hex_bytes, b'') # Remove the specified hex bytes
46+
47+
with open(path, 'wb') as f: # Open the file in binary write mode
48+
f.write(new) # Write the modified content back to the file
49+
50+
def watchdog(dir: str, current_path: str):
51+
try:
52+
handle = utility.FileCreationHandler(current_path) # Try to create a file creation handle
53+
observer = Observer() # Create an Observer instance
54+
observer.schedule(handle, dir, recursive=True) # Schedule the observer to monitor the directory
55+
observer.start() # Start the observer
56+
57+
try:
58+
while True:
59+
time.sleep(1) # Keep the script running
60+
except KeyboardInterrupt: # Handle keyboard interrupt
61+
observer.stop() # Stop the observer
62+
63+
observer.join() # Wait for the observer to finish
64+
except Exception as e:
65+
print(f"{Fore.RESET} [{Fore.RED}!{Fore.RESET}] Could not access the directory {Fore.RED}>{Fore.RESET} {dir} {Fore.LIGHTBLACK_EX}({e}){Fore.RESET}") # Print error message if directory cannot be accessed
66+
67+
68+
class FileCreationHandler(FileSystemEventHandler): # Event handler for file creation
69+
def __init__(self, dir): # Initialize the event handler
70+
super().__init__() # Initialize the parent class
71+
self.dir = dir # Directory to copy detected files to
72+
self.files = set() # To keep track of already processed files
73+
74+
def on_created(self, event): # Handle file creation events
75+
if not event.is_directory and event.src_path.endswith(".bat"): # Check if the created file is a batch file
76+
if event.src_path not in self.files: # Check if the file has already been processed
77+
dest_path = os.path.join(self.dir, os.path.basename(event.src_path)) # Destination path for the copied file
78+
print(f"{Fore.RESET} [{Fore.GREEN}+{Fore.RESET}] Found a Possible Source Code {Fore.GREEN}>{Fore.RESET} {event.src_path}") # Notify user of detected batch file
79+
try: # Try to copy the detected batch file
80+
shutil.copy(event.src_path, dest_path) # Copy the detected batch file to the current script directory
81+
except Exception as e: # Handle exceptions during file copy
82+
print(f"{Fore.RESET} [{Fore.RED}!{Fore.RESET}] Error while copying file {Fore.RED}>{Fore.RESET} {str(e)}") # Print error message if file cannot be copied
83+
84+
self.files.add(event.src_path) # Mark the file as processed
85+
86+
87+
class BatchDump:
88+
@staticmethod
89+
def dump():
90+
os.system("cls" if os.name == "nt" else "clear") # Clear the console
91+
os.system("mode 135,30" if os.name == "nt" else "printf '\e[8;30;135t'") # Set console size
92+
gradient_print(utility.logo, start_color=Color.lawn_green, end_color=Color.ghost_white) # Print logo with a nice color gradient
93+
94+
print(f"\n{Fore.RESET} [{Fore.GREEN}+{Fore.RESET}] Please open the target compiled batch file now. I will try to detect it.") # Prompt user to open the batch file
95+
96+
current_path = os.path.dirname(os.path.abspath(__file__)) # Get the current script directory
97+
98+
for dir in utility.possible_paths:
99+
utility.watchdog(dir, current_path) # Call watchdog for each possible path
100+
101+
@staticmethod
102+
def deobfuscate():
103+
os.system("cls" if os.name == "nt" else "clear") # Clear the console
104+
os.system("mode 135,30" if os.name == "nt" else "printf '\e[8;30;135t'") # Set console size
105+
gradient_print(utility.logo, start_color=Color.lawn_green, end_color=Color.ghost_white) # Print logo with a nice color gradient
106+
107+
batch_path = input(f"\n{Fore.RESET} [{Fore.GREEN}+{Fore.RESET}] Enter the path to the batch file >{Fore.GREEN} ").strip().strip('"') # Input for batch file path
108+
if not os.path.isfile(batch_path): # Check if the file exists
109+
print() # New line for better readability
110+
print(f"{Fore.RESET} [{Fore.RED}!{Fore.RESET}] The specified file does not exist. Please restart the program and provide a valid file path.") # Error message
111+
return
112+
113+
utility.delete_hex(batch_path, "FF FE 26 63 6C 73 0D 0A FF FE 0A 0D") # Remove specific hex bytes from the batch file to deobfuscate it
114+
115+
os.system("start notepad.exe " + batch_path if os.name == "nt" else "xdg-open " + batch_path) # Open the deobfuscated batch file in Notepad or default text editor
116+
117+
print() # New line for better readability
118+
print(f"{Fore.RESET} [{Fore.GREEN}+{Fore.RESET}] Deobfuscation complete! The batch file has been successfully deobfuscated.") # Success message
119+
return
120+
121+
@staticmethod
122+
def error():
123+
print() # New line for better readability
124+
print(f"{Fore.RESET} [{Fore.RED}!{Fore.RESET}] Invalid choice! Please restart the program and select a valid option from the menu.") # Error message
125+
126+
127+
def main():
128+
os.system("cls" if os.name == "nt" else "clear") # Clear the console
129+
os.system("mode 135,30" if os.name == "nt" else "printf '\e[8;30;135t'") # Set console size
130+
gradient_print(utility.logo, start_color=Color.lawn_green, end_color=Color.ghost_white) # Print logo with a nice color gradient
131+
gradient_print(utility.menu, start_color=Color.lawn_green, end_color=Color.ghost_white) # Print menu with a nice color gradient
132+
133+
choice = input(f"{Fore.RESET} [{Fore.GREEN}+{Fore.RESET}] Enter your choice (1-2) >{Fore.GREEN} ") # Input for user choice
134+
135+
if choice == "1": # If user chooses to dump batch
136+
BatchDump.dump() # Call the dump function
137+
elif choice == "2": # If user chooses to deobfuscate batch
138+
BatchDump.deobfuscate() # Call the deobfuscate function
139+
else:
140+
BatchDump.error() # Call the error function for invalid choice
141+
142+
if __name__ == "__main__":
143+
main()

0 commit comments

Comments
 (0)