Overview
The backup extraction feature pulls encrypted WhatsApp database files and media from connected Android devices. It supports both WhatsApp Messenger and WhatsApp Business, handles multiple user profiles, and provides selective extraction options.
Workflow
The dump_backups() method in main.py:214 manages the extraction process:
User Scanning
Detects all user profiles on the device
Package Detection
Identifies installed WhatsApp packages (Messenger/Business)
Backup File Discovery
Locates msgstore.db.cryptXX files in device storage
Backup Selection
User chooses which backups to extract
File Extraction
Pulls selected databases and optionally media files
Finding Backup Files
The find_backups() method in core/device_manager.py:163 searches for encrypted database files:
WhatsApp Messenger Paths
if package == 'com.whatsapp' :
paths = [
base + "WhatsApp/Databases" ,
base + "Android/media/com.whatsapp/WhatsApp/Databases"
]
WhatsApp Business Paths
elif package == 'com.whatsapp.w4b' :
paths = [
base + "WhatsApp Business/Databases" ,
base + "Android/media/com.whatsapp.w4b/WhatsApp Business/Databases"
]
The tool checks both legacy paths (internal storage) and newer Android 11+ media paths.
File Detection Logic
for path in paths:
code, stdout, stderr = self .run_command([ '-s' , device_id, 'shell' , 'ls' , '-l' , f '" { path } "' ])
if code == 0 and "No such file" not in stdout:
lines = stdout.strip().split( ' \n ' )
for line in lines:
parts = line.split()
if len (parts) >= 5 :
filename = parts[ - 1 ]
# Check for duplicates
is_duplicate = False
for b in backups:
if b[ 'name' ] == filename:
is_duplicate = True
break
if is_duplicate: continue
if re.match( r 'msgstore . * \. crypt \d + $ ' , filename):
# Extract file size
backups.append({
'path' : f " { path } / { filename } " ,
'name' : filename,
'size' : size
})
The regex msgstore.*\.crypt\d+$ matches files like msgstore.db.crypt15, msgstore-2024-03-01.1.db.crypt14, etc.
Multiple User Support
The tool iterates through all device users and their WhatsApp installations:
users = self .device_manager.get_users( self .selected_device)
packages = self .device_manager.check_packages( self .selected_device)
all_backups = []
for user in users:
for pkg in packages:
backups = self .device_manager.find_backups(
self .selected_device,
user[ 'id' ],
pkg
)
for b in backups:
all_backups.append({
'remote' : b[ 'path' ],
'user' : user[ 'id' ],
'pkg' : pkg,
'type' : "messenger" if pkg == "com.whatsapp" else "business" ,
'name' : b[ 'name' ],
'size' : b[ 'size' ]
})
Each user profile (User 0, User 10, etc.) has independent WhatsApp data.
After discovering backups, the tool presents extraction options:
ui.print_menu( "Dump Options" , [
"Dump All" ,
"Select Specific Files" ,
"Dump All WhatsApp Messenger" ,
"Dump All WhatsApp Business" ,
"Back"
])
dump_choice = ui.ask( "Choice" , choices = [ "1" , "2" , "3" , "4" , "5" ])
Option 1: Dump All
if dump_choice == '1' :
target_indices = range ( len (all_backups))
Option 2: Select Specific Files
elif dump_choice == '2' :
sel = ui.ask( "Enter file numbers (comma separated, e.g. 1,3)" )
try :
parts = [ int (x.strip()) for x in sel.split( ',' ) if x.strip().isdigit()]
target_indices = [x - 1 for x in parts if 1 <= x <= len (all_backups)]
except : pass
Option 3: Dump WhatsApp Messenger Only
elif dump_choice == '3' :
target_indices = [i for i, x in enumerate (all_backups) if x[ 'type' ] == "messenger" ]
Option 4: Dump WhatsApp Business Only
elif dump_choice == '4' :
target_indices = [i for i, x in enumerate (all_backups) if x[ 'type' ] == "business" ]
The dump_backup() method in core/device_manager.py:238 handles file transfer:
def dump_backup ( self , device_id : str , remote_path : str , user_id : str ,
package_type : str , verbose : bool = True ) -> str :
filename = os.path.basename(remote_path)
local_dir = os.path.join(
self .output_dir,
device_id,
f "user_ { user_id } " ,
package_type
)
if not os.path.exists(local_dir):
os.makedirs(local_dir)
local_path = os.path.join(local_dir, filename)
code, _, stderr = self .run_command([ '-s' , device_id, 'pull' , remote_path, local_path])
if code == 0 and os.path.exists(local_path):
if verbose: print_success( f "Dumped: { filename } " )
return local_path
else :
print_error( f "Failed to pull { remote_path } : { stderr } " )
return ""
Output Directory Structure
Files are organized in a hierarchical structure:
backups/
└── {device_serial}/
└── user_{user_id}/
├── messenger/
│ ├── msgstore.db.crypt15
│ ├── msgstore-2024-03-01.1.db.crypt15
│ └── Media/
│ ├── WhatsApp Images/
│ ├── WhatsApp Video/
│ └── WhatsApp Audio/
└── business/
├── msgstore.db.crypt14
└── Media/
This structure preserves device identity, user profiles, and app types for organized analysis.
Progress Tracking
Database extraction shows progress using a progress bar:
with ui.create_progress( "Dumping Databases..." , total = len (items_to_dump)) as progress:
task = progress.add_task( "Dumping..." , total = len (items_to_dump))
for item in items_to_dump:
self .device_manager.dump_backup(
self .selected_device,
item[ 'remote' ],
item[ 'user' ],
item[ 'type' ],
verbose = False
)
progress.update(task, advance = 1 )
self .session_stats[ "dumped" ] += 1
Users can optionally include media files:
mode = ui.ask( "Include Media? (y/n)" , default = "n" ).lower()
include_media = mode == 'y'
if include_media:
processed_media = set ()
for item in items_to_dump:
key = f " { item[ 'user' ] } _ { item[ 'pkg' ] } "
if key in processed_media: continue
media_path = self .device_manager.find_media(
self .selected_device,
item[ 'user' ],
item[ 'pkg' ]
)
if media_path:
local_dir = os.path.join(
"backups" ,
self .selected_device,
f "user_ { item[ 'user' ] } " ,
item[ 'type' ],
"Media"
)
if not self .device_manager.dump_media_with_progress(
self .selected_device,
media_path,
local_dir
):
ui.print_warning( f "Media dump incomplete for { item[ 'pkg' ] } " )
processed_media.add(key)
Media extraction can take significant time depending on the amount of data (images, videos, audio files).
The find_media() method locates WhatsApp’s media folder:
def find_media ( self , device_id : str , user_id : str , package : str ) -> str :
base = f "/storage/emulated/ { user_id } /"
paths = []
if package == 'com.whatsapp' :
paths = [
base + "WhatsApp/Media" ,
base + "Android/media/com.whatsapp/WhatsApp/Media"
]
elif package == 'com.whatsapp.w4b' :
paths = [
base + "WhatsApp Business/Media" ,
base + "Android/media/com.whatsapp.w4b/WhatsApp Business/Media"
]
for path in paths:
code, stdout, stderr = self .run_command(
[ '-s' , device_id, 'shell' , 'ls' , '-d' , f '" { path } "' ]
)
if code == 0 and "No such file" not in stdout:
return path
return ""
For more details on media extraction implementation, see Media Dumping .
Session Statistics
The tool tracks extraction statistics:
self .session_stats[ "dumped" ] += 1
These statistics are displayed in the session summary when exiting the application.
Permissions Required
Storage Access Read access to WhatsApp directories via ADB
Root Not Required Works on non-rooted devices using standard ADB
USB Debugging Must be enabled in Developer Options
Sufficient Disk Space Local storage for backup files (databases can be 100MB+, media can be GBs)
Troubleshooting
Ensure WhatsApp is installed and has been used
Check that backups exist in WhatsApp Settings > Chats > Chat backup
Try creating a manual backup first
Some devices may require root access for certain paths
Grant file access permissions to WhatsApp in Android settings
On Android 11+, ensure WhatsApp has “All files access” permission
Try using the legacy storage path if media path fails
Incomplete media extraction
Next Steps
Decrypt Backups After extraction, decrypt the encrypted database files using the encryption key