Added Panasonic BIOS Package Extractor v2.0_a7

New processes to better handle PE files

Various common package fixes and improvements
This commit is contained in:
platomav 2022-06-21 14:23:08 +03:00
parent f5905ec662
commit fc73921967
12 changed files with 400 additions and 35 deletions

View file

@ -7,7 +7,7 @@ AMI UCP Update Extractor
Copyright (C) 2021-2022 Plato Mavropoulos
"""
TITLE = 'AMI UCP Update Extractor v2.0_a15'
TITLE = 'AMI UCP Update Extractor v2.0_a16'
import os
import re
@ -163,7 +163,7 @@ def chk16_validate(data, tag, padd=0):
def is_ami_ucp(in_file):
buffer = file_to_bytes(in_file)
return bool(get_ami_ucp(buffer)[0] != None)
return bool(get_ami_ucp(buffer)[0] is not None)
# Get all input file AMI UCP patterns
def get_ami_ucp(buffer):
@ -419,7 +419,7 @@ def uaf_extract(buffer, extract_path, mod_info, padding=0, is_checksum=False, na
nested_uaf_off,nested_uaf_bin,nested_uaf_tag = get_ami_ucp(uaf_data_raw)
# Parse Nested AMI UCP Structure
if nested_uaf_off != None:
if nested_uaf_off is not None:
uaf_dir = os.path.join(extract_path, safe_name(f'{uaf_tag}_nested-UCP')) # Generate extraction directory
ucp_extract(nested_uaf_bin, uaf_dir, nested_uaf_tag, padding + 4, is_checksum) # Call recursively
@ -512,7 +512,7 @@ if __name__ == '__main__':
# Get best AMI UCP Pattern match based on @UAF|@HPU Size
main_uaf_off,main_uaf_bin,main_uaf_tag = get_ami_ucp(input_buffer)
if main_uaf_off == None:
if main_uaf_off is None:
printer('Error: This is not an AMI UCP Update executable!', padding)
continue # Next input file

237
Panasonic_BIOS_Extract.py Normal file
View file

@ -0,0 +1,237 @@
#!/usr/bin/env python3
#coding=utf-8
"""
Panasonic BIOS Extract
Panasonic BIOS Package Extractor
Copyright (C) 2018-2022 Plato Mavropoulos
"""
TITLE = 'Panasonic BIOS Package Extractor v2.0_a7'
import os
import io
import sys
import lznt1
import pefile
# Stop __pycache__ generation
sys.dont_write_bytecode = True
from common.comp_szip import is_szip_supported, szip_decompress
from common.path_ops import get_path_files, make_dirs, path_stem, safe_name
from common.pe_ops import get_pe_file, get_pe_info, is_pe_file, show_pe_info
from common.patterns import PAT_MICROSOFT_CAB
from common.system import script_init, argparse_init, printer
from common.text_ops import file_to_bytes
from AMI_PFAT_Extract import get_ami_pfat, parse_pfat_file
# Check if input is Panasonic BIOS Package PE
def is_panasonic_pkg(in_file):
in_buffer = file_to_bytes(in_file)
pe_file = get_pe_file(in_buffer, fast=True)
if not pe_file:
return False
pe_info = get_pe_info(pe_file)
if not pe_info:
return False
if pe_info.get(b'FileDescription',b'').upper() != b'UNPACK UTILITY':
return False
if not PAT_MICROSOFT_CAB.search(in_buffer):
return False
return True
# Search and Extract Panasonic BIOS Package PE CAB archive
def panasonic_cab_extract(buffer, extract_path, padding=0):
pe_path,pe_file,pe_info = [None] * 3
cab_bgn = PAT_MICROSOFT_CAB.search(buffer).start()
cab_len = int.from_bytes(buffer[cab_bgn + 0x8:cab_bgn + 0xC], 'little')
cab_end = cab_bgn + cab_len
cab_bin = buffer[cab_bgn:cab_end]
cab_tag = f'[0x{cab_bgn:06X}-0x{cab_end:06X}]'
cab_path = os.path.join(extract_path, f'CAB_{cab_tag}.cab')
with open(cab_path, 'wb') as cab_file:
cab_file.write(cab_bin) # Store CAB archive
if is_szip_supported(cab_path, padding):
printer(f'Panasonic BIOS Package > PE > CAB {cab_tag}', padding)
if szip_decompress(cab_path, extract_path, 'CAB', padding + 4) == 0:
os.remove(cab_path) # Successful extraction, delete CAB archive
else:
return pe_path, pe_file, pe_info
else:
return pe_path, pe_file, pe_info
for file_path in get_path_files(extract_path):
pe_file = get_pe_file(file_path, fast=True)
if pe_file:
pe_info = get_pe_info(pe_file)
if pe_info.get(b'FileDescription',b'').upper() == b'BIOS UPDATE':
pe_path = file_path
break
else:
return pe_path, pe_file, pe_info
return pe_path, pe_file, pe_info
# Extract & Decompress Panasonic BIOS Update PE RCDATA (LZNT1)
def panasonic_res_extract(pe_name, pe_file, extract_path, padding=0):
is_rcdata = False
# When fast_load is used, IMAGE_DIRECTORY_ENTRY_RESOURCE must be parsed prior to RCDATA Directories
pe_file.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_RESOURCE']])
# Parse all Resource Data Directories > RCDATA (ID = 10)
for entry in pe_file.DIRECTORY_ENTRY_RESOURCE.entries:
if entry.struct.name == 'IMAGE_RESOURCE_DIRECTORY_ENTRY' and entry.struct.Id == 0xA:
is_rcdata = True
for resource in entry.directory.entries:
res_bgn = resource.directory.entries[0].data.struct.OffsetToData
res_len = resource.directory.entries[0].data.struct.Size
res_end = res_bgn + res_len
res_bin = pe_file.get_data(res_bgn, res_len)
res_tag = f'{pe_name} [0x{res_bgn:06X}-0x{res_end:06X}]'
res_out = os.path.join(extract_path, f'{res_tag}')
printer(res_tag, padding + 4)
try:
res_raw = lznt1.decompress(res_bin[0x8:])
printer('Succesfull LZNT1 decompression via lznt1!', padding + 8)
except:
res_raw = res_bin
printer('Succesfull PE Resource extraction!', padding + 8)
# Detect & Unpack AMI BIOS Guard (PFAT) BIOS image
pfat_match,pfat_buffer = get_ami_pfat(res_raw)
if pfat_match:
pfat_dir = os.path.join(extract_path, res_tag)
parse_pfat_file(pfat_buffer, pfat_dir, padding + 12)
else:
if is_pe_file(res_raw):
res_ext = 'exe'
elif res_raw.startswith(b'[') and res_raw.endswith((b'\x0D\x0A',b'\x0A')):
res_ext = 'txt'
else:
res_ext = 'bin'
if res_ext == 'txt':
printer(new_line=False)
for line in io.BytesIO(res_raw).readlines():
line_text = line.decode('utf-8','ignore').rstrip()
printer(line_text, padding + 12, new_line=False)
with open(f'{res_out}.{res_ext}', 'wb') as out_file:
out_file.write(res_raw)
return is_rcdata
# Extract Panasonic BIOS Update PE Data when RCDATA is not available
def panasonic_img_extract(pe_name, pe_path, pe_file, extract_path, padding=0):
pe_data = file_to_bytes(pe_path)
sec_bgn = pe_file.OPTIONAL_HEADER.DATA_DIRECTORY[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_SECURITY']].VirtualAddress
img_bgn = pe_file.OPTIONAL_HEADER.BaseOfData + pe_file.OPTIONAL_HEADER.SizeOfInitializedData
img_end = sec_bgn or len(pe_data)
img_bin = pe_data[img_bgn:img_end]
img_tag = f'{pe_name} [0x{img_bgn:X}-0x{img_end:X}]'
img_out = os.path.join(extract_path, f'{img_tag}.bin')
printer(img_tag, padding + 4)
with open(img_out, 'wb') as out_img:
out_img.write(img_bin)
printer('Succesfull PE Data extraction!', padding + 8)
return bool(img_bin)
# Parse & Extract Panasonic BIOS Package PE
def panasonic_pkg_extract(input_path, input_buffer, output_path, padding=0):
is_upd_res,is_upd_img = [False] * 2
extract_path = os.path.join(f'{output_path}_extracted')
make_dirs(extract_path, delete=True)
pkg_pe_file = get_pe_file(input_buffer, fast=True)
if not pkg_pe_file:
return 2
pkg_pe_info = get_pe_info(pkg_pe_file)
if not pkg_pe_info:
return 3
pkg_pe_name = path_stem(input_path)
printer(f'Panasonic BIOS Package > PE ({pkg_pe_name})\n', padding)
show_pe_info(pkg_pe_info, padding + 4)
upd_pe_path,upd_pe_file,upd_pe_info = panasonic_cab_extract(input_buffer, extract_path, padding + 4)
if not (upd_pe_path and upd_pe_file and upd_pe_info):
return 4
upd_pe_name = safe_name(path_stem(upd_pe_path))
printer(f'Panasonic BIOS Update > PE ({upd_pe_name})\n', padding + 12)
show_pe_info(upd_pe_info, padding + 16)
is_upd_res = panasonic_res_extract(upd_pe_name, upd_pe_file, extract_path, padding + 16)
if not is_upd_res:
is_upd_img = panasonic_img_extract(upd_pe_name, upd_pe_path, upd_pe_file, extract_path, padding + 16)
os.remove(upd_pe_path)
return 0 if is_upd_res or is_upd_img else 1
if __name__ == '__main__':
# Set argparse Arguments
argparser = argparse_init()
arguments = argparser.parse_args()
# Initialize script (must be after argparse)
exit_code,input_files,output_path,padding = script_init(TITLE, arguments, 4)
for input_file in input_files:
input_name = os.path.basename(input_file)
printer(['***', input_name], padding - 4)
with open(input_file, 'rb') as in_file: input_buffer = in_file.read()
# Check if Panasonic BIOS Package pattern was found on executable
if not is_panasonic_pkg(input_buffer):
printer('Error: This is not a Panasonic BIOS Package executable!', padding)
continue # Next input file
extract_path = os.path.join(output_path, input_name)
if panasonic_pkg_extract(input_file, input_buffer, extract_path, padding) == 0:
exit_code -= 1
printer('Done!', pause=True)
sys.exit(exit_code)

View file

@ -7,18 +7,18 @@ Phoenix TDK Packer Extractor
Copyright (C) 2021-2022 Plato Mavropoulos
"""
TITLE = 'Phoenix TDK Packer Extractor v2.0_a7'
TITLE = 'Phoenix TDK Packer Extractor v2.0_a8'
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.pe_ops import get_pe_file, get_pe_info
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
@ -102,21 +102,21 @@ def get_tdk_base(in_buffer, pack_off):
# 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 quickly (fast_load)
pe_file = pefile.PE(data=in_buffer[mz_off:], fast_load=True)
# Parse detected MZ > PE > Image, quickly (fast_load)
pe_file = get_pe_file(in_buffer[mz_off:], fast=True)
# Since fast_load is used, IMAGE_DIRECTORY_ENTRY_RESOURCE must be parsed for FileInfo > StringTable
pe_file.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_RESOURCE']])
# Parse detected MZ > PE > Info
pe_info = get_pe_info(pe_file)
# Attempt to retrieve the PE > "Product Name" version string value
pe_name = pe_file.FileInfo[0][0].StringTable[0].entries[b'ProductName'].upper()
# Parse detected MZ > PE > Info > Product Name
pe_name = pe_info.get(b'ProductName',b'')
except:
# Any error means no PE > "Product Name" retrieved
# Any error means no MZ > PE > Info > Product Name
pe_name = b''
# Check for valid Phoenix TDK Packer PE > "Product Name"
# Check for valid Phoenix TDK Packer PE > Product Name
# Expected value is "TDK Packer (Extractor for Windows)"
if pe_name.startswith(b'TDK PACKER'):
if pe_name.upper().startswith(b'TDK PACKER'):
# Set TDK Base Offset to valid TDK Packer MZ offset
tdk_base_off = mz_off
@ -149,7 +149,7 @@ def get_phoenix_tdk(in_buffer):
def is_phoenix_tdk(in_file):
buffer = file_to_bytes(in_file)
return bool(get_phoenix_tdk(buffer)[1] != None)
return bool(get_phoenix_tdk(buffer)[1] is not None)
# Parse & Extract Phoenix Tools Development Kit (TDK) Packer
def phoenix_tdk_extract(input_buffer, output_path, pack_off, base_off=0, padding=0):
@ -253,7 +253,7 @@ if __name__ == '__main__':
tdk_base_off,tdk_pack_off = get_phoenix_tdk(input_buffer)
# Check if Phoenix TDK Packer pattern was found on executable
if tdk_pack_off == None:
if tdk_pack_off is None:
printer('Error: This is not a Phoenix TDK Packer executable!', padding)
continue # Next input file

View file

@ -7,17 +7,17 @@ Portwell EFI Update Extractor
Copyright (C) 2021-2022 Plato Mavropoulos
"""
TITLE = 'Portwell EFI Update Extractor v2.0_a9'
TITLE = 'Portwell EFI Update Extractor v2.0_a10'
import os
import sys
import pefile
# Stop __pycache__ generation
sys.dont_write_bytecode = True
from common.comp_efi import efi_decompress, is_efi_compressed
from common.path_ops import safe_name, make_dirs
from common.pe_ops import get_pe_file
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
@ -43,8 +43,8 @@ def is_portwell_efi(in_file):
return bool(is_mz and is_uu)
# Get PE of Portwell EFI executable
def get_portwell_pe(in_buffer):
pe_file = pefile.PE(data=in_buffer, fast_load=True) # Analyze EFI Portable Executable (PE)
def get_portwell_pe(in_buffer):
pe_file = get_pe_file(in_buffer, fast=True) # Analyze EFI Portable Executable (PE)
pe_data = in_buffer[pe_file.OPTIONAL_HEADER.SizeOfImage:] # Skip EFI executable (pylint: disable=E1101)
@ -66,9 +66,9 @@ def portwell_efi_extract(input_buffer, output_path, padding=0):
# Split EFI Payload into <UU> file chunks
efi_list = list(PAT_PORTWELL_EFI.finditer(pe_data))
for i,_ in enumerate(efi_list):
efi_bgn = efi_list[i].end()
efi_end = len(pe_data) if i == len(efi_list) - 1 else efi_list[i + 1].start()
for idx,val in enumerate(efi_list):
efi_bgn = val.end()
efi_end = len(pe_data) if idx == len(efi_list) - 1 else efi_list[idx + 1].start()
efi_files.append(pe_data[efi_bgn:efi_end])
parse_efi_files(extract_path, efi_files, padding)
@ -108,7 +108,7 @@ def parse_efi_files(extract_path, efi_files, padding):
file_name = FILE_NAMES.get(file_index, f'Unknown_{file_index}.bin') # Assign Name to EFI file
printer(file_name, padding + 4) # Print EFI file name, indicate progress
printer(f'[{file_index}] {file_name}', padding + 4) # Print EFI file name, indicate progress
if file_name.startswith('Unknown_'):
printer(f'Note: Detected new Portwell EFI file ID {file_index}!', padding + 8, pause=True) # Report new EFI files

View file

@ -6,6 +6,7 @@
* [**AMI BIOS Guard Extractor**](#ami-bios-guard-extractor)
* [**AMI UCP Update Extractor**](#ami-ucp-update-extractor)
* [**Dell PFS Update Extractor**](#dell-pfs-update-extractor)
* [**Panasonic BIOS Package Extractor**](#panasonic-bios-package-extractor)
* [**Phoenix TDK Packer Extractor**](#phoenix-tdk-packer-extractor)
* [**Portwell EFI Update Extractor**](#portwell-efi-update-extractor)
* [**VAIO Packaging Manager Extractor**](#vaio-packaging-manager-extractor)
@ -196,6 +197,73 @@ Some Anti-Virus software may claim that the built/frozen/compiled executable con
![]()
## **Panasonic BIOS Package Extractor**
![]()
#### **Description**
Parses Panasonic BIOS Package executables and extracts their firmware (e.g. SPI, BIOS/UEFI, EC etc) and utilities (e.g. winprom, configuration etc) components. It supports all Panasonic BIOS Package revisions and formats, including those which contain LZNT1 compressed files. The output comprises only final firmware components which are directly usable by end users.
#### **Usage**
You can either Drag & Drop or manually enter Panasonic BIOS Package executable file(s). Optional arguments:
* -h or --help : show help message and exit
* -v or --version : show utility name and version
* -i or --input-dir : extract from given input directory
* -o or --output-dir : extract in given output directory
* -e or --auto-exit : skip press enter to exit prompts
#### **Compatibility**
Should work at all Windows, Linux or macOS operating systems which have Python 3.8 support.
#### **Prerequisites**
To run the utility, you must have the following 3rd party Python modules installed:
* [pefile](https://pypi.org/project/pefile/)
* [lznt1](https://pypi.org/project/lznt1/)
Moreover, you must have the following 3rd party tool at the "external" project directory:
* [7-Zip Console](https://www.7-zip.org/) (i.e. 7z.exe for Windows or 7zzs for Linux)
#### **Build/Freeze/Compile with PyInstaller**
PyInstaller can build/freeze/compile the utility at all three supported platforms, it is simple to run and gets updated often.
1. Make sure Python 3.8.0 or newer is installed:
> python --version
2. Use pip to install PyInstaller:
> pip3 install pyinstaller
3. Use pip to install pefile and lznt1:
> pip3 install pefile lznt1
4. Place prerequisite at the "external" project directory:
> 7-Zip Console
5. Build/Freeze/Compile:
> pyinstaller --add-data="external/*;external/" --noupx --onefile \<path-to-project\>\/Panasonic_BIOS_Extract.py
At dist folder you should find the final utility executable
#### **Anti-Virus False Positives**
Some Anti-Virus software may claim that the built/frozen/compiled executable contains viruses. Any such detections are false positives, usually of PyInstaller. You can switch to a better Anti-Virus software, report the false positive to their support, add the executable to the exclusions, build/freeze/compile yourself or use the Python script directly.
#### **Pictures**
![]()
## **Phoenix TDK Packer Extractor**
![]()

View file

@ -7,7 +7,7 @@ VAIO Packaging Manager Extractor
Copyright (C) 2019-2022 Plato Mavropoulos
"""
TITLE = 'VAIO Packaging Manager Extractor v3.0_a4'
TITLE = 'VAIO Packaging Manager Extractor v3.0_a5'
import os
import sys
@ -53,7 +53,7 @@ def vaio_cabinet(name, buffer, extract_path, padding=0):
with open(cab_path, 'wb') as cab_file: cab_file.write(cab_data) # Create temporary CAB archive
if is_szip_supported(cab_path, padding + 4):
if is_szip_supported(cab_path, padding + 8):
if szip_decompress(cab_path, extract_path, 'CAB', padding + 8) == 0:
os.remove(cab_path) # Successful extraction, delete temporary CAB archive
else:

View file

@ -35,7 +35,7 @@ def get_tiano_path():
return safe_path(project_root(), ['external',exec_name])
# EFI/Tiano Decompression via TianoCompress
def efi_decompress(in_path, out_path, padding=0, comp_type='--uefi'):
def efi_decompress(in_path, out_path, padding=0, silent=False, comp_type='--uefi'):
try:
subprocess.run([get_tiano_path(), '-d', in_path, '-o', out_path, '-q', comp_type], check=True, stdout=subprocess.DEVNULL)
@ -43,10 +43,12 @@ def efi_decompress(in_path, out_path, padding=0, comp_type='--uefi'):
if os.path.getsize(out_path) != size_orig: raise Exception('EFI_DECOMPRESS_ERROR')
except:
printer(f'Error: TianoCompress could not extract file {in_path}!', padding)
if not silent:
printer(f'Error: TianoCompress could not extract file {in_path}!', padding)
return 1
printer('Succesfull EFI decompression via TianoCompress!', padding)
if not silent:
printer('Succesfull EFI decompression via TianoCompress!', padding)
return 0

View file

@ -19,18 +19,19 @@ def get_szip_path():
return safe_path(project_root(), ['external',exec_name])
# Check if file is 7-Zip supported
def is_szip_supported(in_path, padding=0):
def is_szip_supported(in_path, padding=0, silent=False):
try:
subprocess.run([get_szip_path(), 't', in_path, '-bso0', '-bse0', '-bsp0'], check=True)
except:
printer(f'Error: 7-Zip could not check support for file {in_path}!', padding)
if not silent:
printer(f'Error: 7-Zip could not check support for file {in_path}!', padding)
return False
return True
# Archive decompression via 7-Zip
def szip_decompress(in_path, out_path, in_name, padding=0):
def szip_decompress(in_path, out_path, in_name, padding=0, silent=False):
if not in_name: in_name = 'archive'
try:
@ -38,10 +39,12 @@ def szip_decompress(in_path, out_path, in_name, padding=0):
if not os.path.isdir(out_path): raise Exception('EXTRACT_DIR_MISSING')
except:
printer(f'Error: 7-Zip could not extract {in_name} file {in_path}!', padding)
if not silent:
printer(f'Error: 7-Zip could not extract {in_name} file {in_path}!', padding)
return 1
printer(f'Succesfull {in_name} decompression via 7-Zip!', padding)
if not silent:
printer(f'Succesfull {in_name} decompression via 7-Zip!', padding)
return 0

View file

@ -70,6 +70,10 @@ def agnostic_path(in_path):
def path_parent(in_path):
return Path(in_path).parent.absolute()
# Get final path component, w/o suffix
def path_stem(in_path):
return PurePath(in_path).stem
# Check if path is absolute
def is_path_absolute(in_path):
return Path(in_path).is_absolute()

View file

@ -13,6 +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_CAB = re.compile(br'MSCF\x00{4}')
PAT_MICROSOFT_MZ = re.compile(br'MZ')
PAT_MICROSOFT_PE = re.compile(br'PE\x00{2}')
PAT_PHOENIX_TDK = re.compile(br'\$PACK\x00{3}..\x00{2}.\x00{3}', re.DOTALL)

49
common/pe_ops.py Normal file
View file

@ -0,0 +1,49 @@
#!/usr/bin/env python3
#coding=utf-8
"""
Copyright (C) 2022 Plato Mavropoulos
"""
import pefile
from common.system import printer
from common.text_ops import file_to_bytes
# Check if input is a PE file
def is_pe_file(in_file):
return bool(get_pe_file(in_file))
# Get pefile object from PE file
def get_pe_file(in_file, fast=True):
in_buffer = file_to_bytes(in_file)
try:
# Analyze detected MZ > PE image buffer
pe_file = pefile.PE(data=in_buffer, fast_load=fast)
except:
pe_file = None
return pe_file
# Get PE info from pefile object
def get_pe_info(pe_file):
try:
# When fast_load is used, IMAGE_DIRECTORY_ENTRY_RESOURCE must be parsed prior to FileInfo > StringTable
pe_file.parse_data_directories(directories=[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_RESOURCE']])
# Retrieve MZ > PE > FileInfo > StringTable information
pe_info = pe_file.FileInfo[0][0].StringTable[0].entries
except:
pe_info = {}
return pe_info
# Print PE info from pefile StringTable
def show_pe_info(pe_info, padding=0):
if type(pe_info).__name__ == 'dict':
for title,value in pe_info.items():
info_title = title.decode('utf-8','ignore').strip()
info_value = value.decode('utf-8','ignore').strip()
if info_title and info_value:
printer(f'{info_title}: {info_value}', padding, new_line=False)

View file

@ -1 +1,2 @@
lznt1==0.2
pefile==2021.9.3