Skip to content

Commit b3cd296

Browse files
feat: add headers subcommand to CLI (#96)
1 parent 33a47b8 commit b3cd296

1 file changed

Lines changed: 72 additions & 0 deletions

File tree

cmd/llvm-obfuscator/cli/obfuscate.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,78 @@ def jotai(
606606
except Exception as exc:
607607
logger.error("Jotai benchmark failed: %s", exc)
608608
raise typer.Exit(code=1)
609+
610+
@app.command()
611+
def headers(
612+
input_file: Path = typer.Argument(..., help="C/C++ source file to obfuscate"),
613+
output: Optional[Path] = typer.Option(None, "--output", "-o", help="Output file (default: input_obfuscated.c)"),
614+
stdlib_only: bool = typer.Option(False, "--stdlib-only", help="Obfuscate only standard library functions"),
615+
custom_only: bool = typer.Option(False, "--custom-only", help="Obfuscate only custom functions"),
616+
dry_run: bool = typer.Option(False, "--dry-run", help="Show what would be obfuscated without writing output"),
617+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show function pointer mapping"),
618+
):
619+
"""Obfuscate function calls in a C/C++ source file using indirect calls via function pointers."""
620+
621+
from core.indirect_call_obfuscator import obfuscate_indirect_calls
622+
623+
if not input_file.exists():
624+
typer.echo(f"Error: Input file not found: {input_file}", err=True)
625+
raise typer.Exit(code=1)
626+
627+
output_file = output or input_file.parent / f"{input_file.stem}_obfuscated{input_file.suffix}"
628+
629+
if stdlib_only:
630+
obfuscate_stdlib = True
631+
obfuscate_custom = False
632+
elif custom_only:
633+
obfuscate_stdlib = False
634+
obfuscate_custom = True
635+
else:
636+
obfuscate_stdlib = True
637+
obfuscate_custom = True
638+
639+
typer.echo(f"📄 Reading: {input_file}")
640+
source_code = input_file.read_text(encoding="utf-8", errors="replace")
641+
642+
typer.echo("🔒 Obfuscating function calls...")
643+
typer.echo(f" - Standard library: {'Yes' if obfuscate_stdlib else 'No'}")
644+
typer.echo(f" - Custom functions: {'Yes' if obfuscate_custom else 'No'}")
645+
646+
try:
647+
transformed_code, metadata = obfuscate_indirect_calls(
648+
source_code,
649+
input_file,
650+
obfuscate_stdlib=obfuscate_stdlib,
651+
obfuscate_custom=obfuscate_custom,
652+
)
653+
654+
typer.echo("\n✅ Obfuscation complete:")
655+
typer.echo(f" - Standard library functions: {metadata['obfuscated_stdlib_functions']}")
656+
typer.echo(f" - Custom functions: {metadata['obfuscated_custom_functions']}")
657+
typer.echo(f" - Total obfuscated: {metadata['total_obfuscated']}")
658+
659+
if verbose:
660+
typer.echo("\n📋 Function pointers created:")
661+
for func, ptr in sorted(metadata["function_pointers"].items()):
662+
typer.echo(f" {func}{ptr}")
663+
664+
if dry_run:
665+
typer.echo("\n Dry run mode - no file written")
666+
typer.echo("\n Preview (first 50 lines):")
667+
typer.echo("=" * 60)
668+
for i, line in enumerate(transformed_code.split("\n")[:50], 1):
669+
typer.echo(f"{i:3}: {line}")
670+
typer.echo("=" * 60)
671+
else:
672+
output_file.write_text(transformed_code, encoding="utf-8")
673+
typer.echo(f"\n💾 Output written to: {output_file}")
674+
675+
except Exception as exc:
676+
typer.echo(f"\n❌ Error during obfuscation: {exc}", err=True)
677+
if verbose:
678+
import traceback
679+
traceback.print_exc()
680+
raise typer.Exit(code=1)
609681

610682

611683
if __name__ == "__main__":

0 commit comments

Comments
 (0)