Last active
May 15, 2026 06:43
-
-
Save topin89/b109342b135649bf8c2e405a6ae79a39 to your computer and use it in GitHub Desktop.
Extract files from LG Backup .lbf file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # For modern LG backup files use a script from here: https://github.com/Mysak0CZ/LBFtool | |
| # with details from there https://forum.xda-developers.com/android/general/tool-lg-restore-com-lge-bnr-lbf-file-t4053579 | |
| # Fair warning, this script was designed for really old version of LGBackup and won't work on with new devices | |
| # So, if you don't get what you wanted, try to use every data carving tools you can get | |
| # | |
| # Also, good person with nickname SEVENTY ONE recommends ExtractJPEG( https://www.gunamoi.com.au/soft/extractjpeg/download.html ) | |
| # To, well, extract JPG Images from a backup | |
| # 0. You will need 7-zip context menu "Extract here". | |
| # 1. Edit filename to your backup file | |
| # 2. Run this script from same folder | |
| # 3. Select all *.brokenscript and choose 7-zip > Extract here | |
| # 4. On overwrite request, choose either "Yes to all" or "No to all", id doesn't matter | |
| # 5. Ta-da! You just got your files. | |
| # 6. Most .db files are in fact SQLite DBs, you can open 'em with SQLiteStudio | |
| # 7. Sms/sms.vmsg you can read here: http://sms-vmsg.org/sms-reader-app/free-app/ | |
| # 8. Guess you can import SMS and MMS to your phone with this app (I don't know, It was friend's backup) https://play.google.com/store/apps/details?id=com.aoe.vmgconverter&hl=ru | |
| # 9. All else, I don't know | |
| # 10. May google be with you | |
| import mmap | |
| index=0 | |
| filename=f"LGBackup_xxxxxx.lbf" | |
| def read_in_chunks(file_object, chunk_size=1024): | |
| """Lazy function (generator) to read a file piece by piece. | |
| Default chunk size: 1k.""" | |
| while True: | |
| data = file_object.read(chunk_size) | |
| if not data: | |
| break | |
| yield data | |
| def find_in_file(f,signature, startpos): | |
| prev=b'' | |
| chunk_size=2**20 | |
| for i,cur in enumerate(read_in_chunks(f,chunk_size)): | |
| searchee=prev+cur | |
| pos=searchee.find(signature) | |
| if pos>=0: | |
| return i*chunk_size+pos-len(prev)+startpos | |
| prev=cur | |
| else: | |
| return -1 | |
| with open(filename,"rb") as backup: | |
| starpos=0 | |
| while True: | |
| pos=find_in_file(backup, b'PK\x03\x04',starpos) | |
| if pos<0: | |
| break | |
| print(backup.tell()) | |
| backup.seek(pos) | |
| print(backup.tell()) | |
| index+=1 | |
| filename=f"{index}.brokenzip" | |
| with open(filename,"wb") as nextfile: | |
| for chunk in read_in_chunks(backup,2**20): | |
| nextfile.write(chunk) | |
| starpos=pos+1 | |
| backup.seek(starpos) | |
| print(backup.tell()) | |
| print() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # For modern LG backup files use a script from here: https://github.com/Mysak0CZ/LBFtool | |
| # with details from there https://forum.xda-developers.com/android/general/tool-lg-restore-com-lge-bnr-lbf-file-t4053579 | |
| # Fair warning, this script was designed for really old version of LGBackup and won't work on with new devices | |
| # So, if you don't get what you wanted, try to use every data carving tools you can get | |
| # | |
| # Also, good person with nickname SEVENTY ONE recommends ExtractJPEG( https://www.gunamoi.com.au/soft/extractjpeg/download.html ) | |
| # To, well, extract JPG Images from a backup | |
| # 0. You will need 7-zip. | |
| # 1. Find 7z.exe in a 7-zip folder in Program Files (or whenever you install it) and copy it to a folder with the script | |
| # 2. Edit filename to your backup file | |
| # 3. Run this script from same folder | |
| # 4. Wait a bit (maybe a lot). New subfolder "restored" should appear. | |
| # 5. Ta-da! You just got your files. | |
| # 6. Most .db files are in fact SQLite DBs, you can open 'em with SQLiteStudio | |
| # 7. Sms/sms.vmsg you can read here: http://sms-vmsg.org/sms-reader-app/free-app/ | |
| # 8. Guess you can import SMS and MMS to your phone with this app (I don't know, It was friend's backup) https://play.google.com/store/apps/details?id=com.aoe.vmgconverter&hl=ru | |
| # 9. All else, I don't know | |
| # 10. May google be with you | |
| import mmap | |
| from os import system, remove | |
| filename=f"LGBackup_xxxxxx.lbf" | |
| filename_output=f"one_and_only.brokenzip" | |
| def read_in_chunks(file_object, chunk_size=1024): | |
| """Lazy function (generator) to read a file piece by piece. | |
| Default chunk size: 1k.""" | |
| while True: | |
| data = file_object.read(chunk_size) | |
| if not data: | |
| break | |
| yield data | |
| def find_in_file(f,signature, startpos): | |
| prev=b'' | |
| chunk_size=2**20 | |
| for i,cur in enumerate(read_in_chunks(f,chunk_size)): | |
| searchee=prev+cur | |
| pos=searchee.find(signature) | |
| if pos>=0: | |
| return i*chunk_size+pos-len(prev)+startpos | |
| prev=cur | |
| else: | |
| return -1 | |
| def unpack_brokenzip(filename_output): | |
| system(f"7z x -aou -orestored {filename_output}") | |
| with open(filename,"rb") as backup: | |
| starpos=0 | |
| while True: | |
| pos=find_in_file(backup, b'PK\x03\x04',starpos) | |
| if pos<0: | |
| break | |
| backup.seek(pos) | |
| print(backup.tell()) | |
| with open(filename_output,"wb") as nextfile: | |
| for chunk in read_in_chunks(backup,2**20): | |
| nextfile.write(chunk) | |
| unpack_brokenzip(filename_output) | |
| starpos=pos+1 | |
| backup.seek(starpos) | |
| remove(filename_output) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # For modern LG backup files use a script from here: https://github.com/Mysak0CZ/LBFtool | |
| # with details from there https://forum.xda-developers.com/android/general/tool-lg-restore-com-lge-bnr-lbf-file-t4053579 | |
| filename="LGBackup_xxxxxx.lbf" | |
| filename_out="LGBackup_xxxxxx_headers_only.lbf" | |
| CHUNK_LENGTH=4096 | |
| HEADER=b'PK\x03\x04' | |
| with open(filename,"rb") as backup, open(filename_out,"wb") as newfile: | |
| window=bytearray(backup.read(CHUNK_LENGTH*2)) | |
| while window: | |
| header_pos=window.find(HEADER) | |
| if header_pos > -1: | |
| newfile.write(b'0'*header_pos+HEADER) | |
| del window[:header_pos+4] | |
| elif len(window)>CHUNK_LENGTH: | |
| newfile.write(b'0'*CHUNK_LENGTH) | |
| del window[:CHUNK_LENGTH] | |
| else: | |
| newfile.write(b'0'*len(window)) | |
| del window[:] | |
| window+=bytearray(backup.read(CHUNK_LENGTH)) |
Author
Try python3 lbf_extractor.py. Default python is still python2 on most Linux distros.
Also, unless your phone is really old, I suggest https://github.com/Mysak0CZ/LBFtool
The author actually used debugger to get lbf structure and it should extract all files, not just zip archives.
Hi,
I have a backup file of my phone in LBF format. Could someone help me write my photos?
I can pay.
I do not speak English. I use a translator.
Thank you
Here's an updated script that doesn't require you to use 7Zip:
import struct
import zlib
import os
import sys
# ── Config ─────────────────────────────────────────────────────────────────────
FILENAME = "LGBackup_FILENAME.lbf"
OUTPUT_DIR = "extracted"
# ───────────────────────────────────────────────────────────────────────────────
LOCAL_SIG = b'PK\x03\x04'
DATA_DESC_SIG = b'PK\x07\x08'
# Local file header layout (after the 4-byte signature):
# version_needed 2B (H)
# flags 2B (H)
# compression 2B (H)
# mod_time 2B (H)
# mod_date 2B (H)
# crc32 4B (I)
# compressed_sz 4B (I)
# uncompressed_sz 4B (I)
# fname_len 2B (H)
# extra_len 2B (H)
HEADER_FMT = '<HHHHHIIIHH'
HEADER_SIZE = struct.calcsize(HEADER_FMT) # 26 bytes
COMPRESSION_STORED = 0
COMPRESSION_DEFLATE = 8
def scan_to_signature(f, sig):
"""Advance f until `sig` is found; return file offset of first byte of sig,
or -1 if EOF is reached first."""
buf = b''
n = len(sig)
while True:
byte = f.read(1)
if not byte:
return -1
buf = (buf + byte)[-n:]
if buf == sig:
return f.tell() - n
def read_local_header(f):
"""Parse a local file header that starts at the current position (after sig)."""
raw = f.read(HEADER_SIZE)
if len(raw) < HEADER_SIZE:
return None
fields = struct.unpack(HEADER_FMT, raw)
(version_needed, flags, compression, mod_time, mod_date,
crc32, compressed_sz, uncompressed_sz, fname_len, extra_len) = fields
fname = f.read(fname_len).decode('utf-8', errors='replace')
f.read(extra_len) # skip extra field
return {
'flags': flags,
'compression': compression,
'crc32': crc32,
'compressed_sz': compressed_sz,
'uncompressed_sz': uncompressed_sz,
'fname': fname,
'has_data_desc': bool(flags & 0x0008),
}
def read_data_with_descriptor(f):
"""When sizes are 0 (data descriptor flag), slurp bytes until we find
PK\\x07\\x08 or the next PK\\x03\\x04, then back up past the descriptor."""
buf = bytearray()
while True:
byte = f.read(1)
if not byte:
# Reached EOF — return whatever we have
return bytes(buf)
buf += byte
tail = bytes(buf[-4:])
if tail == DATA_DESC_SIG:
# Consume the 12-byte descriptor body (crc32 + comp_sz + uncomp_sz)
f.read(12)
return bytes(buf[:-4])
if tail == LOCAL_SIG:
# Stumbled into the next entry — rewind
f.seek(-4, 1)
return bytes(buf[:-4])
def safe_output_path(base_dir, fname):
"""Resolve an Android absolute path safely under base_dir."""
# Strip leading slashes so os.path.join doesn't discard base_dir
fname = fname.lstrip('/')
# Replace internal@/external@ storage prefixes with readable folder names
fname = fname.replace('internal@/', 'internal/').replace('external@/', 'external/')
target = os.path.realpath(os.path.join(base_dir, fname))
if not target.startswith(os.path.realpath(base_dir)):
raise ValueError(f"Path traversal attempt blocked: {fname!r}")
return target
def extract(lbf_path, out_dir):
os.makedirs(out_dir, exist_ok=True)
extracted = skipped = 0
with open(lbf_path, 'rb') as f:
while True:
pos = scan_to_signature(f, LOCAL_SIG)
if pos < 0:
break # No more entries
f.seek(pos + 4) # skip past the 4-byte signature we just found
header = read_local_header(f)
if header is None:
continue
fname = header['fname']
compression = header['compression']
# ── Directory entry ───────────────────────────────────────────────
if fname.endswith('/'):
os.makedirs(safe_output_path(out_dir, fname), exist_ok=True)
continue
# ── Read compressed payload ───────────────────────────────────────
if header['has_data_desc'] and header['compressed_sz'] == 0:
compressed_data = read_data_with_descriptor(f)
else:
compressed_data = f.read(header['compressed_sz'])
# ── Decompress ────────────────────────────────────────────────────
try:
if compression == COMPRESSION_STORED:
raw = compressed_data
elif compression == COMPRESSION_DEFLATE:
raw = zlib.decompress(compressed_data, -15) # raw deflate
else:
print(f" [SKIP] {fname} (unsupported compression={compression})")
skipped += 1
continue
except zlib.error as e:
print(f" [ERR] {fname} ({e})")
skipped += 1
continue
# ── Write ─────────────────────────────────────────────────────────
try:
out_path = safe_output_path(out_dir, fname)
os.makedirs(os.path.dirname(out_path), exist_ok=True)
with open(out_path, 'wb') as out:
out.write(raw)
extracted += 1
print(f" [OK] {fname} ({len(raw):,} bytes)")
except (OSError, ValueError) as e:
print(f" [ERR] {fname} ({e})")
skipped += 1
print(f"\n{'─'*50}")
print(f"Extracted : {extracted}")
print(f"Skipped : {skipped}")
print(f"Output : {os.path.abspath(out_dir)}/")
if __name__ == '__main__':
lbf = sys.argv[1] if len(sys.argv) > 1 else FILENAME
if not os.path.exists(lbf):
sys.exit(f"File not found: {lbf!r}")
extract(lbf, OUTPUT_DIR)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I download zip file and extract theme. After extracting i copied my backup into same folder :
I changed filename=f"LGBackup_201102.lbf" in lbf_extractor.py and run it but i got
How can i run ?