diff --git a/Phoenix_TDK_Extract.py b/Phoenix_TDK_Extract.py
index 85ddcff..8133047 100644
--- a/Phoenix_TDK_Extract.py
+++ b/Phoenix_TDK_Extract.py
@@ -7,18 +7,19 @@ Phoenix TDK Packer Extractor
 Copyright (C) 2021-2022 Plato Mavropoulos
 """
 
-TITLE = 'Phoenix TDK Packer Extractor v2.0_a4'
+TITLE = 'Phoenix TDK Packer Extractor v2.0_a5'
 
 import os
 import sys
 import lzma
+import pefile
 import ctypes
 
 # Stop __pycache__ generation
 sys.dont_write_bytecode = True
 
 from common.path_ops import safe_name, make_dirs
-from common.patterns import PAT_PHOENIX_TDK
+from common.patterns import PAT_PHOENIX_TDK, PAT_MICROSOFT_MZ, PAT_MICROSOFT_PE
 from common.struct_ops import get_struct, char, uint32_t
 from common.system import script_init, argparse_init, printer
 from common.text_ops import file_to_bytes
@@ -53,31 +54,98 @@ class PhoenixTdkEntry(ctypes.LittleEndianStructure):
     
     COMP = {0: 'None', 1: 'LZMA'}
     
+    def __init__(self, mz_base, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.Base = mz_base
+    
     def get_name(self):
         return self.Name.decode('utf-8','replace').strip()
     
+    def get_offset(self):
+        return self.Base + self.Offset
+    
     def get_compression(self):
         return self.COMP.get(self.Compressed, f'Unknown ({self.Compressed})')
     
     def struct_print(self, p):
         printer(['Name       :', self.get_name()], p, False)
-        printer(['Offset     :', f'0x{self.Offset:X}'], p, False)
+        printer(['Offset     :', f'0x{self.get_offset():X}'], p, False)
         printer(['Size       :', f'0x{self.Size:X}'], p, False)
         printer(['Compression:', self.get_compression()], p, False)
         printer(['Reserved   :', f'0x{self.Reserved:X}'], p, False)
 
-# Scan input buffer for Phoenix TDK pattern
-def get_phoenix_tdk(in_buffer):
-    return PAT_PHOENIX_TDK.search(in_buffer)
+# Get Phoenix TDK Executable (MZ) Base Offset
+def get_tdk_base(in_buffer, pack_off):
+    tdk_base_off = None # Initialize Phoenix TDK Base MZ Offset
+    
+    # Scan input file for all Microsoft executable patterns (MZ) before TDK Header Offset
+    mz_all = [mz for mz in PAT_MICROSOFT_MZ.finditer(in_buffer) if mz.start() < pack_off]
+    
+    # Phoenix TDK Header structure is an index table for all TDK files
+    # Each TDK file is referenced from the TDK Packer executable base
+    # The TDK Header is always at the end of the TDK Packer executable
+    # Thus, prefer the TDK Packer executable (MZ) closest to TDK Header
+    # For speed, check MZ closest to (or at) 0x0 first (expected input)
+    mz_ord = [mz_all[0]] + list(reversed(mz_all[1:]))
+    
+    # Parse each detected MZ
+    for mz in mz_ord:
+        mz_off = mz.start()
+        
+        # MZ (DOS) > PE (NT) image offset is found at offset 0x3C-0x40 relative to MZ base 
+        pe_off = mz_off + int.from_bytes(in_buffer[mz_off + 0x3C:mz_off + 0x40], 'little')
+        
+        # Check if potential MZ > PE image magic value is valid
+        if PAT_MICROSOFT_PE.search(in_buffer[pe_off:pe_off + 0x4]):
+            try:
+                # Analyze detected MZ > PE image buffer
+                pe_file = pefile.PE(data=in_buffer[mz_off:])
+                
+                # Attempt to retrieve the PE > "Product Name" version string value
+                pe_name = pe_file.FileInfo[0][0].StringTable[0].entries[b'ProductName']  
+            except:
+                # Any error means no PE > "Product Name" retrieved
+                pe_name = b''
+            
+            # Check for valid Phoenix TDK Packer PE > "Product Name"
+            # Expected value is "TDK Packer (Extractor for Windows)"
+            if pe_name.upper().startswith(b'TDK PACKER'):
+                # Set TDK Base Offset to valid TDK Packer MZ offset
+                tdk_base_off = mz_off
+        
+        # Stop parsing detected MZ once TDK Base Offset is found
+        if tdk_base_off:
+            break
+    else:
+        # No TDK Base Offset could be found, assume 0x0
+        tdk_base_off = 0x0
+    
+    return tdk_base_off
 
-# Check if input is Phoenix TDK image
+# Scan input buffer for valid Phoenix TDK image
+def get_phoenix_tdk(in_buffer):
+    # Scan input buffer for Phoenix TDK pattern
+    tdk_match = PAT_PHOENIX_TDK.search(in_buffer)
+    
+    if not tdk_match:
+        return None, None
+    
+    # Set Phoenix TDK Header ($PACK) Offset
+    tdk_pack_off = tdk_match.start()
+    
+    # Get Phoenix TDK Executable (MZ) Base Offset
+    tdk_base_off = get_tdk_base(in_buffer, tdk_pack_off)
+    
+    return tdk_base_off, tdk_pack_off
+
+# Check if input contains valid Phoenix TDK image
 def is_phoenix_tdk(in_file):
     buffer = file_to_bytes(in_file)
     
-    return bool(get_phoenix_tdk(buffer))
+    return bool(get_phoenix_tdk(buffer)[1])
 
 # Parse & Extract Phoenix Tools Development Kit (TDK) Packer
-def phoenix_tdk_extract(input_buffer, output_path, padding=0):
+def phoenix_tdk_extract(input_buffer, output_path, pack_off, base_off=0, padding=0):
     exit_code = 0
     
     extract_path = os.path.join(f'{output_path}_extracted')
@@ -86,11 +154,8 @@ def phoenix_tdk_extract(input_buffer, output_path, padding=0):
     
     printer('Phoenix Tools Development Kit Packer', padding)
     
-    # Search for Phoenix TDK Package pattern
-    tdk_match = get_phoenix_tdk(input_buffer)
-    
     # Parse TDK Header structure
-    tdk_hdr = get_struct(input_buffer, tdk_match.start(), PhoenixTdkHeader)
+    tdk_hdr = get_struct(input_buffer, pack_off, PhoenixTdkHeader)
     
     # Print TDK Header structure info
     printer('Phoenix TDK Header:\n', padding + 4)
@@ -101,34 +166,46 @@ def phoenix_tdk_extract(input_buffer, output_path, padding=0):
         printer('Error: Phoenix TDK Header Size & Entry Count mismatch!\n', padding + 8, pause=True)
         exit_code = 1
     
-    # Store TDK Entries offset after the dummy/placeholder data
-    entries_off = tdk_match.start() + TDK_HDR_LEN + TDK_DUMMY_LEN
+    # Store TDK Entries offset after the placeholder data
+    entries_off = pack_off + TDK_HDR_LEN + TDK_DUMMY_LEN
     
     # Parse and extract each TDK Header Entry
     for entry_index in range(tdk_hdr.Count):
         # Parse TDK Entry structure
-        tdk_mod = get_struct(input_buffer, entries_off + entry_index * TDK_MOD_LEN, PhoenixTdkEntry)
+        tdk_mod = get_struct(input_buffer, entries_off + entry_index * TDK_MOD_LEN, PhoenixTdkEntry, [base_off])
         
         # Print TDK Entry structure info
         printer(f'Phoenix TDK Entry ({entry_index + 1}/{tdk_hdr.Count}):\n', padding + 8)
         tdk_mod.struct_print(padding + 12)
         
-        # Store TDK Entry raw data (relative to 0x0, not TDK Header)
-        mod_data = input_buffer[tdk_mod.Offset:tdk_mod.Offset + tdk_mod.Size]
+        # Get TDK Entry raw data Offset (TDK Base + Entry Offset)
+        mod_off = tdk_mod.get_offset()
+        
+        # Check if TDK Entry raw data Offset is valid
+        if mod_off >= len(input_buffer):
+            printer('Error: Phoenix TDK Entry > Offset is out of bounds!\n', padding + 12, pause=True)
+            exit_code = 2
+        
+        # Store TDK Entry raw data (relative to TDK Base, not TDK Header)
+        mod_data = input_buffer[mod_off:mod_off + tdk_mod.Size]
         
         # Check if TDK Entry raw data is complete
         if len(mod_data) != tdk_mod.Size:
             printer('Error: Phoenix TDK Entry > Data is truncated!\n', padding + 12, pause=True)
-            exit_code = 2
+            exit_code = 3
         
         # Check if TDK Entry Reserved is present
         if tdk_mod.Reserved:
             printer('Error: Phoenix TDK Entry > Reserved is not empty!\n', padding + 12, pause=True)
-            exit_code = 3            
+            exit_code = 4
         
         # Decompress TDK Entry raw data, when applicable (i.e. LZMA)
         if tdk_mod.get_compression() == 'LZMA':
-            mod_data = lzma.LZMADecompressor().decompress(mod_data)
+            try:
+                mod_data = lzma.LZMADecompressor().decompress(mod_data)
+            except:
+                printer('Error: Phoenix TDK Entry > LZMA decompression failed!\n', padding + 12, pause=True)
+                exit_code = 5
         
         # Generate TDK Entry file name, avoid crash if Entry data is bad
         mod_name = tdk_mod.get_name() or f'Unknown_{entry_index + 1:02d}.bin'
@@ -148,8 +225,8 @@ def phoenix_tdk_extract(input_buffer, output_path, padding=0):
 TDK_HDR_LEN = ctypes.sizeof(PhoenixTdkHeader)
 TDK_MOD_LEN = ctypes.sizeof(PhoenixTdkEntry)
 
-# Set dummy/placeholder TDK Entries Size
-TDK_DUMMY_LEN = 0x200 # Top 2, Names only
+# Set placeholder TDK Entries Size
+TDK_DUMMY_LEN = 0x200
 
 if __name__ == '__main__':
     # Set argparse Arguments    
@@ -166,15 +243,17 @@ if __name__ == '__main__':
         
         with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
         
+        tdk_base_off,tdk_pack_off = get_phoenix_tdk(input_buffer)
+        
         # Check if Phoenix TDK Packer pattern was found on executable
-        if not is_phoenix_tdk(input_buffer):
+        if not tdk_pack_off:
             printer('Error: This is not a Phoenix TDK Packer executable!', padding)
             
             continue # Next input file
         
         extract_path = os.path.join(output_path, input_name)
         
-        if phoenix_tdk_extract(input_buffer, extract_path, padding) == 0:
+        if phoenix_tdk_extract(input_buffer, extract_path, tdk_pack_off, tdk_base_off, padding) == 0:
             exit_code -= 1
     
     printer('Done!', pause=True)
diff --git a/Portwell_EFI_Extract.py b/Portwell_EFI_Extract.py
index c241347..c0abac9 100644
--- a/Portwell_EFI_Extract.py
+++ b/Portwell_EFI_Extract.py
@@ -7,7 +7,7 @@ Portwell EFI Update Extractor
 Copyright (C) 2021-2022 Plato Mavropoulos
 """
 
-TITLE = 'Portwell EFI Update Extractor v2.0_a5'
+TITLE = 'Portwell EFI Update Extractor v2.0_a6'
 
 import os
 import sys
@@ -18,13 +18,10 @@ sys.dont_write_bytecode = True
 
 from common.efi_comp import efi_decompress, is_efi_compressed
 from common.path_ops import safe_name, make_dirs
+from common.patterns import PAT_PORTWELL_EFI, PAT_MICROSOFT_MZ
 from common.system import script_init, argparse_init, printer
 from common.text_ops import file_to_bytes
 
-PEFI_MAGIC = br'MZ'
-
-FILE_MAGIC = br'<UU>'
-
 FILE_NAMES = {
     0 : 'Flash.efi',
     1 : 'Fparts.txt',
@@ -40,8 +37,8 @@ def is_portwell_efi(in_file):
     try: pe_buffer = get_portwell_pe(in_buffer)[1]
     except: pe_buffer = b''
     
-    is_mz = in_buffer.startswith(PEFI_MAGIC) # EFI images start with PE Header MZ
-    is_uu = pe_buffer.startswith(FILE_MAGIC) # Portwell EFI files start with <UU>
+    is_mz = in_buffer.startswith(PAT_MICROSOFT_MZ.pattern) # EFI images start with PE Header MZ
+    is_uu = pe_buffer.startswith(PAT_PORTWELL_EFI.pattern) # Portwell EFI files start with <UU>
     
     return is_mz and is_uu
 
@@ -65,7 +62,7 @@ def portwell_efi_extract(input_buffer, output_path, padding=0):
     
     printer(efi_title, padding)
     
-    efi_files = pe_data.split(FILE_MAGIC) # Split EFI Payload into <UU> file chunks
+    efi_files = pe_data.split(PAT_PORTWELL_EFI.pattern) # Split EFI Payload into <UU> file chunks
     
     parse_efi_files(extract_path, efi_files[1:], padding)
     
diff --git a/README.md b/README.md
index 6bb9277..7f0e12a 100644
--- a/README.md
+++ b/README.md
@@ -225,7 +225,9 @@ Should work at all Windows, Linux or macOS operating systems which have Python 3
 
 #### **Prerequisites**
 
-No prerequisites needed to run the utility.
+To run the utility, you must have the following 3rd party Python module installed:
+
+* [pefile](https://pypi.org/project/pefile/)
 
 #### **Build/Freeze/Compile with PyInstaller**
 
@@ -239,7 +241,11 @@ PyInstaller can build/freeze/compile the utility at all three supported platform
 
 > pip3 install pyinstaller
 
-3. Build/Freeze/Compile:
+3. Use pip to install pefile:
+
+> pip3 install pefile
+
+4. Build/Freeze/Compile:
 
 > pyinstaller --noupx --onefile \<path-to-project\>\/Phoenix_TDK_Extract.py
 
diff --git a/common/patterns.py b/common/patterns.py
index 326cdcb..c26f02b 100644
--- a/common/patterns.py
+++ b/common/patterns.py
@@ -13,4 +13,7 @@ PAT_DELL_FTR = re.compile(br'\xEE\xAA\xEE\x8F\x49\x1B\xE8\xAE\x14\x37\x90')
 PAT_DELL_HDR = re.compile(br'\xEE\xAA\x76\x1B\xEC\xBB\x20\xF1\xE6\x51.\x78\x9C', re.DOTALL)
 PAT_DELL_PKG = re.compile(br'\x72\x13\x55\x00.{45}7zXZ', re.DOTALL)
 PAT_INTEL_ENG = re.compile(br'\x04\x00{3}[\xA1\xE1]\x00{3}.{8}\x86\x80.{9}\x00\$((MN2)|(MAN))', re.DOTALL)
+PAT_MICROSOFT_MZ = re.compile(br'MZ')
+PAT_MICROSOFT_PE = re.compile(br'PE\x00\x00')
 PAT_PHOENIX_TDK = re.compile(br'\$PACK\x00{3}..\x00{2}.\x00{3}', re.DOTALL)
+PAT_PORTWELL_EFI = re.compile(br'<UU>')