Add Argument parser

This commit is contained in:
Mino 2020-03-29 22:20:30 +09:00
parent a90a5673f2
commit 693babc1e3
8 changed files with 87 additions and 15 deletions

View file

@ -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))
{ {

View file

@ -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>

View file

@ -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)

View 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;
}
}
}

View file

@ -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>

View file

@ -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());
} }

View file

@ -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; }
} }

View file

@ -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)