Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI support for obfuscation and deobfuscation #5

Merged
merged 2 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<AssemblyName>VpaxObfuscator</AssemblyName>
</PropertyGroup>

<ItemGroup>
Expand Down
119 changes: 91 additions & 28 deletions src/Dax.Vpax.Obfuscator.CLI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,54 +1,117 @@
using Dax.Vpax.Obfuscator.Common;
using System.CommandLine;
using System.CommandLine;
using Dax.Vpax.Obfuscator.Common;

namespace Dax.Vpax.Obfuscator.CLI;

internal class Program
{
public static int Main(string[] args)
public static int Main(string[] args) => BuildCommand().Invoke(args);

private static RootCommand BuildCommand()
{
var command = BuildCommand();
return command.Invoke(args);
var allowOverwriteOption = new Option<bool>(name: "--allow-overwrite")
{
Description = "Allow output files to be overwritten. If not provided, the command will fail if an output file already exists.",
IsRequired = false,
};
var command = new RootCommand("VertiPaq-Analyzer obfuscator CLI");
command.AddGlobalOption(allowOverwriteOption);
command.AddCommand(BuildCommandObfuscate(allowOverwriteOption));
command.AddCommand(BuildCommandDeobfuscate(allowOverwriteOption));
return command;
}

private static RootCommand BuildCommand()
private static Command BuildCommandObfuscate(Option<bool> allowOverwriteOption)
{
var fileOption = new Option<FileInfo>("--file")
var vpaxOption = new Option<FileInfo>(name: "--vpax")
{
Description = "The full path to the VPAX file to obfuscate.",
Description = "Path to the unobfuscated VPAX file.",
IsRequired = true,
};
fileOption.AddAlias("-f");

var dictionaryOption = new Option<FileInfo>("--dictionary")
var dictionaryOption = new Option<FileInfo>(name: "--dictionary")
{
Description = "The full path to the JSON dictionary file to use for obfuscation.",
Description = "Path to the dictionary file to be used for incremental obfuscation. If not provided, a new dictionary will be created.",
IsRequired = false,
};
dictionaryOption.AddAlias("-d");

var rootCommand = new RootCommand("VertiPaq-Analyzer obfuscator.");
rootCommand.AddOption(fileOption);
rootCommand.AddOption(dictionaryOption);
rootCommand.SetHandler(Obfuscate, fileOption, dictionaryOption);
var outputVpaxOption = new Option<FileInfo>(name: "--output-vpax")
{
Description = "Path to write the obfuscated VPAX file.",
IsRequired = true,
};
var outputDictionaryOption = new Option<FileInfo>(name: "--output-dictionary")
{
Description = "Path to write the obfuscation dictionary file.",
IsRequired = true,
};

return rootCommand;
var command = new Command("obfuscate", "Obfuscate the DaxModel.json file and delete all other contents from a VPAX file.");
command.AddOption(vpaxOption);
command.AddOption(dictionaryOption);
command.AddOption(outputVpaxOption);
command.AddOption(outputDictionaryOption);
command.SetHandler(Obfuscate, vpaxOption, dictionaryOption, outputVpaxOption, outputDictionaryOption, allowOverwriteOption);
return command;
}

private static void Obfuscate(FileInfo vpaxFile, FileInfo dictionaryFile)
private static Command BuildCommandDeobfuscate(Option<bool> allowOverwriteOption)
{
var buffer = File.ReadAllBytes(vpaxFile.FullName);
using var stream = new MemoryStream();
stream.Write(buffer, 0, buffer.Length);
var vpaxOption = new Option<FileInfo>(name: "--vpax")
{
Description = "Path to the obfuscated VPAX file.",
IsRequired = true,
};
var dictionaryOption = new Option<FileInfo>(name: "--dictionary")
{
Description = "Path to the dictionary file.",
IsRequired = true,
};
var outputVpaxOption = new Option<FileInfo>(name: "--output-vpax")
{
Description = "Path to write the deobfuscated VPAX file.",
IsRequired = true,
};
var command = new Command("deobfuscate", "Deobfuscate the DaxModel.json file from an obfuscated VPAX file using the provided dictionary.");
command.AddOption(vpaxOption);
command.AddOption(dictionaryOption);
command.AddOption(outputVpaxOption);
command.SetHandler(Deobfuscate, vpaxOption, dictionaryOption, outputVpaxOption, allowOverwriteOption);
return command;
}

private static void Obfuscate(FileInfo vpaxFile, FileInfo? dictionaryOption, FileInfo outputVpaxFile, FileInfo outputDictionaryFile, bool allowOverwrite)
{
using var stream = Read(vpaxFile);
var obfuscator = new VpaxObfuscator();
var dictionary = dictionaryFile != null
? obfuscator.Obfuscate(stream, ObfuscationDictionary.ReadFrom(dictionaryFile.FullName))
var outputDictionary = dictionaryOption is not null
? obfuscator.Obfuscate(stream, dictionary: ObfuscationDictionary.ReadFrom(dictionaryOption.FullName))
: obfuscator.Obfuscate(stream);

var path = Path.Combine(vpaxFile.DirectoryName!, Path.ChangeExtension(vpaxFile.Name, ".dictionary.json"));
dictionary.WriteTo(path, overwrite: false, indented: true);
outputDictionary.WriteTo(outputDictionaryFile.FullName, overwrite: allowOverwrite, indented: true);
Write(stream, outputVpaxFile, allowOverwrite);
}

private static void Deobfuscate(FileInfo vpaxFile, FileInfo dictionaryFile, FileInfo outputVpaxFile, bool allowOverwrite)
{
using var stream = Read(vpaxFile);
var obfuscator = new VpaxObfuscator();

File.WriteAllBytes(vpaxFile.FullName, stream.ToArray());
obfuscator.Deobfuscate(stream, dictionary: ObfuscationDictionary.ReadFrom(dictionaryFile.FullName));
Write(stream, outputVpaxFile, allowOverwrite);
}

private static MemoryStream Read(FileInfo file)
{
var buffer = File.ReadAllBytes(file.FullName);
var stream = new MemoryStream();
stream.Write(buffer, 0, buffer.Length);
return stream;
}

private static void Write(MemoryStream stream, FileInfo file, bool allowOverwrite)
{
var bytes = stream.ToArray();
var mode = allowOverwrite ? FileMode.Create : FileMode.CreateNew;
using var fileStream = new FileStream(file.FullName, mode, FileAccess.Write, FileShare.Read);
fileStream.Write(bytes, 0, bytes.Length);
}
}
Loading