Created
July 8, 2025 23:00
-
-
Save davidberard98/b60f62cd76faa726662bfbad48174950 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env python3 | |
import argparse | |
import os | |
import sys | |
import stat | |
import subprocess | |
import re | |
def parse_glibcxx_version(version_string): | |
"""Parse GLIBCXX version string and return tuple for comparison.""" | |
# Extract version numbers from GLIBCXX_3.4.21 format | |
match = re.match(r'GLIBCXX_(\d+)\.(\d+)(?:\.(\d+))?', version_string) | |
if match: | |
major = int(match.group(1)) | |
minor = int(match.group(2)) | |
patch = int(match.group(3)) if match.group(3) else 0 | |
return (major, minor, patch) | |
return (0, 0, 0) | |
def get_glibcxx_requirements(binary_path): | |
"""Run objdump on binary and extract GLIBCXX version requirements.""" | |
try: | |
# Run objdump -T and filter for GLIBCXX | |
result = subprocess.run( | |
['objdump', '-T', binary_path], | |
capture_output=True, | |
text=True, | |
timeout=30 | |
) | |
if result.returncode != 0: | |
print(f"Warning: objdump failed for {binary_path}: {result.stderr}") | |
return [] | |
# Extract GLIBCXX versions from output | |
glibcxx_versions = [] | |
for line in result.stdout.splitlines(): | |
if 'GLIBCXX_' in line: | |
# Extract the GLIBCXX version using regex | |
match = re.search(r'GLIBCXX_\d+\.\d+(?:\.\d+)?', line) | |
if match: | |
version = match.group(0) | |
if version not in glibcxx_versions: | |
glibcxx_versions.append(version) | |
return glibcxx_versions | |
except subprocess.TimeoutExpired: | |
print(f"Warning: objdump timeout for {binary_path}") | |
return [] | |
except FileNotFoundError: | |
print("Error: objdump command not found. Please install binutils.") | |
return [] | |
except Exception as e: | |
print(f"Error running objdump on {binary_path}: {e}") | |
return [] | |
def find_max_glibcxx_version(versions): | |
"""Find the maximum GLIBCXX version from a list of version strings.""" | |
if not versions: | |
return None | |
max_version = versions[0] | |
max_parsed = parse_glibcxx_version(max_version) | |
for version in versions[1:]: | |
parsed = parse_glibcxx_version(version) | |
if parsed > max_parsed: | |
max_version = version | |
max_parsed = parsed | |
return max_version | |
def collect_binary_files(bin_directory): | |
"""Collect all binary files from the bin directory.""" | |
binary_files = [] | |
if not os.path.exists(bin_directory): | |
print(f"Warning: bin/ subdirectory not found at '{bin_directory}'") | |
return binary_files | |
if not os.path.isdir(bin_directory): | |
print(f"Warning: '{bin_directory}' exists but is not a directory") | |
return binary_files | |
print(f"Scanning bin directory: {bin_directory}") | |
try: | |
for item in os.listdir(bin_directory): | |
item_path = os.path.join(bin_directory, item) | |
# Skip directories, only process files | |
if os.path.isfile(item_path): | |
if os.access(item_path, os.X_OK): | |
binary_files.append({ | |
'name': item, | |
'path': item_path, | |
}) | |
except PermissionError: | |
print(f"Error: Permission denied accessing '{bin_directory}'") | |
except OSError as e: | |
print(f"Error reading directory '{bin_directory}': {e}") | |
return binary_files | |
def parse_directory(directory_path): | |
"""Parse the specified directory for binary files in bin/ subdirectory.""" | |
if not os.path.exists(directory_path): | |
print(f"Error: Directory '{directory_path}' does not exist.") | |
return False | |
if not os.path.isdir(directory_path): | |
print(f"Error: '{directory_path}' is not a directory.") | |
return False | |
print(f"Parsing directory: {directory_path}") | |
# Look for bin/ subdirectory | |
bin_directory = os.path.join(directory_path, 'bin') | |
binary_files = collect_binary_files(bin_directory) | |
if not binary_files: | |
print("No binary files found to analyze.") | |
return True | |
print("\nAnalyzing GLIBCXX requirements for each binary:") | |
all_versions = [] | |
binary_results = [] | |
for bf in binary_files: | |
versions = get_glibcxx_requirements(bf['path']) | |
if versions: | |
max_version = find_max_glibcxx_version(versions) | |
all_versions.extend(versions) | |
binary_results.append({ | |
'name': bf['name'], | |
'versions': versions, | |
'max_version': max_version | |
}) | |
# Find overall maximum GLIBCXX version required | |
if all_versions: | |
overall_max = find_max_glibcxx_version(list(set(all_versions))) | |
print(f"\n" + "="*60) | |
print(f"OVERALL ANALYSIS RESULTS:") | |
print(f"="*60) | |
print(f"Total binaries analyzed: {len(binary_files)}") | |
print(f"Binaries with GLIBCXX requirements: {len([r for r in binary_results if r['versions']])}") | |
print(f"Maximum GLIBCXX version required: {overall_max}") | |
# Show unique versions found across all binaries | |
unique_versions = sorted(list(set(all_versions)), key=lambda v: parse_glibcxx_version(v)) | |
print(f"All GLIBCXX versions found: {', '.join(unique_versions)}") | |
print(f"\Example binary requiring the maximum version ({overall_max}):") | |
for result in binary_results: | |
if result['max_version'] == overall_max: | |
print(f" - {result['name']}") | |
break | |
else: | |
print(f"\n" + "="*60) | |
print(f"No GLIBCXX requirements found in any binary files.") | |
print(f"="*60) | |
return True | |
def main(): | |
parser = argparse.ArgumentParser(description='Parse directory for glibc++ related content') | |
parser.add_argument('directory', | |
help='Directory path to parse') | |
parser.add_argument('-v', '--verbose', | |
action='store_true', | |
help='Enable verbose output') | |
args = parser.parse_args() | |
if args.verbose: | |
print(f"Verbose mode enabled") | |
print(f"Target directory: {args.directory}") | |
success = parse_directory(args.directory) | |
if not success: | |
sys.exit(1) | |
print("Parsing completed successfully.") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment