mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-19 14:27:45 +01:00
Add Argument parser
This commit is contained in:
parent
a90a5673f2
commit
693babc1e3
8 changed files with 87 additions and 15 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using CoreHook.BinaryInjection.RemoteInjection;
|
using CoreHook.BinaryInjection.RemoteInjection;
|
||||||
using CoreHook.BinaryInjection.RemoteInjection.Configuration;
|
using CoreHook.BinaryInjection.RemoteInjection.Configuration;
|
||||||
using CoreHook.IPC.Platform;
|
using CoreHook.IPC.Platform;
|
||||||
|
|
@ -72,6 +73,9 @@ namespace Dalamud.Bootstrap
|
||||||
// TODO: launch new exe with the argument from encryptedArgument.ToString()
|
// TODO: launch new exe with the argument from encryptedArgument.ToString()
|
||||||
// TODO: we also need to figure out where the exe is located
|
// TODO: we also need to figure out where the exe is located
|
||||||
|
|
||||||
|
// This is just for poc purpose.
|
||||||
|
System.Diagnostics.Process.Start(exePath, encryptedArgument.ToString());
|
||||||
|
|
||||||
process.Terminate();
|
process.Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,12 +97,12 @@ namespace Dalamud.Bootstrap
|
||||||
{
|
{
|
||||||
var arguments = process.ReadArguments();
|
var arguments = process.ReadArguments();
|
||||||
|
|
||||||
if (arguments.Length < 1)
|
if (arguments.Length < 2)
|
||||||
{
|
{
|
||||||
throw new BootstrapException($"Process id {process.GetPid()} does not have any arguments to parse.");
|
throw new BootstrapException($"Process id {process.GetPid()} does not have any arguments to parse.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var argument = arguments[0];
|
var argument = arguments[1];
|
||||||
|
|
||||||
if (EncryptedArgument.TryParse(argument, out var encryptedArgument))
|
if (EncryptedArgument.TryParse(argument, out var encryptedArgument))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Pidgin" Version="2.3.0" />
|
||||||
<PackageReference Include="System.Resources.Extensions" Version="4.7.0" /> <!-- Required by CoreHook to build -->
|
<PackageReference Include="System.Resources.Extensions" Version="4.7.0" /> <!-- Required by CoreHook to build -->
|
||||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.0" />
|
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.7.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,19 @@ namespace Dalamud.Bootstrap.SqexArg
|
||||||
m_dict = new Dictionary<string, string>();
|
m_dict = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArgumentBuilder(IEnumerable<KeyValuePair<string, string>> collection)
|
||||||
|
{
|
||||||
|
m_dict = new Dictionary<string, string>(collection);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an argument builder from the argument (e.g. /T =1234)
|
/// Creates an argument builder from the argument (e.g. /T =1234)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="argument"></param>
|
/// <param name="argument"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static ArgumentBuilder Parse(string argument)
|
public static ArgumentBuilder Parse(ReadOnlySpan<char> argument)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("TODO");
|
return new ArgumentBuilder(ArgumentParser.Parse(argument));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArgumentBuilder Add(string key, string value)
|
public ArgumentBuilder Add(string key, string value)
|
||||||
|
|
|
||||||
51
Dalamud.Bootstrap/SqexArg/ArgumentParser.cs
Normal file
51
Dalamud.Bootstrap/SqexArg/ArgumentParser.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Pidgin;
|
||||||
|
using static Pidgin.Parser;
|
||||||
|
using static Pidgin.Parser<char>;
|
||||||
|
|
||||||
|
namespace Dalamud.Bootstrap.SqexArg
|
||||||
|
{
|
||||||
|
public static class ArgumentParser
|
||||||
|
{
|
||||||
|
private static readonly Parser<char, string> KeyMarkerNoEscape = String(" ");
|
||||||
|
|
||||||
|
private static readonly Parser<char, string> KeyMarkerEscape = String(" /");
|
||||||
|
|
||||||
|
private static readonly Parser<char, string> KeyMarker = Try(KeyMarkerEscape).Or(KeyMarkerNoEscape);
|
||||||
|
|
||||||
|
private static readonly Parser<char, string> ValueMarker = String(" =");
|
||||||
|
|
||||||
|
private static readonly Parser<char, char> EscapedSpace = String(" ").ThenReturn(' ');
|
||||||
|
|
||||||
|
//private static readonly Parser<char, string> String = Try(EscapedSpace).Or(AnyCharExcept(' ')).ManyString();
|
||||||
|
private static readonly Parser<char, string> String = Try(EscapedSpace).Or(AnyCharExcept(' ')).ManyString();
|
||||||
|
|
||||||
|
private static readonly Parser<char, KeyValuePair<string, string>> KeyValue = Map
|
||||||
|
(
|
||||||
|
(_, key, _, value) => new KeyValuePair<string, string>(key, value),
|
||||||
|
KeyMarker, String, ValueMarker, String
|
||||||
|
);
|
||||||
|
|
||||||
|
private static readonly Parser<char, IEnumerable<KeyValuePair<string, string>>> Parser = KeyValue.Many();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the argument
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="SqexArgException">Thrown when failed to parse the input.</exception>
|
||||||
|
public static IEnumerable<KeyValuePair<string, string>> Parse(ReadOnlySpan<char> input)
|
||||||
|
{
|
||||||
|
var test = KeyMarker.Parse(input);
|
||||||
|
var result = Parser.Parse(input);
|
||||||
|
|
||||||
|
if (!result.Success)
|
||||||
|
{
|
||||||
|
throw new SqexArgException($"Failed to parse the argument.\n{result.Error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Buffers.Text;
|
using System.Buffers.Text;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Dalamud.Bootstrap.Crypto;
|
using Dalamud.Bootstrap.Crypto;
|
||||||
|
|
@ -90,7 +91,7 @@ namespace Dalamud.Bootstrap.SqexArg
|
||||||
// plainText <- utf8Bytes <- encryptedBytes(payload) <- base64(payloadStr)
|
// plainText <- utf8Bytes <- encryptedBytes(payload) <- base64(payloadStr)
|
||||||
|
|
||||||
// base64: 3 bytes per 4 characters
|
// base64: 3 bytes per 4 characters
|
||||||
// We also want the size to be aligned with the block size.
|
// We also want the size to be aligned with the block size. Usually this is not a problem but we don't know what payload is actually from.
|
||||||
var dataLength = (payload.Length / 4) * 3;
|
var dataLength = (payload.Length / 4) * 3;
|
||||||
var alignedDataLength = AlignBufferLength(dataLength);
|
var alignedDataLength = AlignBufferLength(dataLength);
|
||||||
var encryptedData = new byte[alignedDataLength];
|
var encryptedData = new byte[alignedDataLength];
|
||||||
|
|
@ -112,9 +113,14 @@ namespace Dalamud.Bootstrap.SqexArg
|
||||||
blowfish.Decrypt(encryptedData, decryptedData);
|
blowfish.Decrypt(encryptedData, decryptedData);
|
||||||
|
|
||||||
// utf8Bytes -> C# string
|
// utf8Bytes -> C# string
|
||||||
var plainText = Encoding.UTF8.GetString(decryptedData[..dataLength]);
|
// notice that decryptedData is a null terminated string.
|
||||||
|
unsafe
|
||||||
return plainText;
|
{
|
||||||
|
fixed (byte* pDecryptedData = decryptedData)
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringUTF8(new IntPtr(pDecryptedData));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ namespace Dalamud.Bootstrap
|
||||||
{
|
{
|
||||||
FileTime creationTime, exitTime, kernelTime, userTime;
|
FileTime creationTime, exitTime, kernelTime, userTime;
|
||||||
|
|
||||||
if (Win32.GetProcessTimes(m_handle, &creationTime, &exitTime, &kernelTime, &userTime))
|
if (!Win32.GetProcessTimes(m_handle, &creationTime, &exitTime, &kernelTime, &userTime))
|
||||||
{
|
{
|
||||||
ProcessException.ThrowLastOsError(GetPid());
|
ProcessException.ThrowLastOsError(GetPid());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,10 @@ namespace Dalamud.Injector
|
||||||
[Option('p', "pid", Required = true, HelpText = "A target process id to inject.")]
|
[Option('p', "pid", Required = true, HelpText = "A target process id to inject.")]
|
||||||
public uint Pid { get; set; }
|
public uint Pid { get; set; }
|
||||||
|
|
||||||
[Option("root", Required = false)]
|
[Option("root")]
|
||||||
public string? RootDirectory { get; set; }
|
public string? RootDirectory { get; set; }
|
||||||
|
|
||||||
[Option("bin", Required = false)]
|
[Option("bin")]
|
||||||
public string? BinaryDirectory { get; set; }
|
public string? BinaryDirectory { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,17 @@ namespace Dalamud.Injector
|
||||||
{
|
{
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
var pid = 12336u;
|
||||||
|
var binDirectory = "";
|
||||||
|
var rootDirectory = "";
|
||||||
|
|
||||||
var boot = new Bootstrapper(new BootstrapperOptions
|
var boot = new Bootstrapper(new BootstrapperOptions
|
||||||
{
|
{
|
||||||
BinaryDirectory = "",
|
BinaryDirectory = "",
|
||||||
RootDirectory = "",
|
RootDirectory = "",
|
||||||
});
|
});
|
||||||
|
|
||||||
boot.Launch("", "");
|
boot.Relaunch(pid);
|
||||||
|
|
||||||
Parser.Default.ParseArguments<InjectOptions, LaunchOptions>(args)
|
Parser.Default.ParseArguments<InjectOptions, LaunchOptions>(args)
|
||||||
.WithParsed<InjectOptions>(Inject)
|
.WithParsed<InjectOptions>(Inject)
|
||||||
|
|
@ -25,6 +29,7 @@ namespace Dalamud.Injector
|
||||||
|
|
||||||
private static void Inject(InjectOptions options)
|
private static void Inject(InjectOptions options)
|
||||||
{
|
{
|
||||||
|
var pid = options.Pid;
|
||||||
var binDirectory = options.BinaryDirectory ?? GetDefaultBinaryDirectory();
|
var binDirectory = options.BinaryDirectory ?? GetDefaultBinaryDirectory();
|
||||||
var rootDirectory = options.RootDirectory ?? GetDefaultRootDirectory();
|
var rootDirectory = options.RootDirectory ?? GetDefaultRootDirectory();
|
||||||
|
|
||||||
|
|
@ -34,7 +39,7 @@ namespace Dalamud.Injector
|
||||||
RootDirectory = rootDirectory,
|
RootDirectory = rootDirectory,
|
||||||
});
|
});
|
||||||
|
|
||||||
boot.Relaunch(options.Pid);
|
boot.Relaunch(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Launch(LaunchOptions options)
|
private static void Launch(LaunchOptions options)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue