This is fucking dog shit

This commit is contained in:
Mino 2020-04-25 21:50:11 +09:00
parent 52daf6ada0
commit 54bf6099bf
7 changed files with 281 additions and 268 deletions

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Text.RegularExpressions;
@ -18,17 +19,18 @@ namespace Dalamud.Bootstrap
m_options = options;
}
public static void Test()
public void Launch(string exePath, IDictionary<string, string> arguments)
{
//
}
var options = new GameProcessCreationOptions
{
ImagePath = exePath,
Arguments = arguments,
CreateSuspended = true
};
public void Launch(string exePath, string? commandLine)
{
commandLine = commandLine ?? "";
using var process = GameProcess.Create(options);
//throw new NotImplementedException("TODO");
// TODO: Inject(process);
}
/// <summary>
@ -62,14 +64,9 @@ namespace Dalamud.Bootstrap
using var process = GameProcess.Open(pid);
var exePath = process.GetImageFilePath();
var argument = process.GetGameArguments();
var encryptedArgument = EncryptArgument(argument.ToString());

View file

@ -4,6 +4,8 @@ using Dalamud.Bootstrap.OS.Windows.Raw;
using Dalamud.Bootstrap.SqexArg;
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
@ -181,6 +183,11 @@ namespace Dalamud.Bootstrap
}
}
private static uint CreateCommandLineKey()
{
return (uint)(Environment.TickCount & 0xFFFF_0000);
}
public static GameProcess Create(GameProcessCreationOptions options)
{
unsafe
@ -188,9 +195,17 @@ namespace Dalamud.Bootstrap
SECURITY_ATTRIBUTES processAttr, threadAttr;
STARTUPINFOW startupInfo = default;
PROCESS_INFORMATION processInfo = default;
uint creationFlag;
uint creationFlag = default;
BuildCommandLine(options);
var key = CreateCommandLineKey();
var commandLine = BuildCommandLine(options.Arguments, key);
var currentDirectory = Path.Combine(Directory.GetParent(Path.GetDirectoryName(options.ImagePath)).FullName, "boot"); // this is fucked
var environments = BuildEnvironments(options.Environments);
if (options.CreateSuspended)
{
creationFlag |= (uint)PROCESS_CREATION_FLAGS.CREATE_SUSPENDED;
}
if (!Kernel32.CreateProcessW(
options.ImagePath,
@ -207,10 +222,23 @@ namespace Dalamud.Bootstrap
{
ProcessException.ThrowLastOsError();
}
}
throw new NotImplementedException();
Kernel32.CloseHandle(//////////////////// fucking thread )
return new GameProcess(processInfo.hProcess);
}
}
private static string BuildCommandLine(IDictionary<string, string> arguments, uint key)
{
var builder = new SqexArgBuilder(arguments);
return builder.Build(key);
}
private static byte[] BuildEnvironments(IDictionary<string, string>? environments)
{
}
/// <summary>
@ -290,7 +318,6 @@ namespace Dalamud.Bootstrap
ReadMemoryExact(address, buffer);
}
private IntPtr GetPebAddress()
{
unsafe
@ -428,34 +455,6 @@ namespace Dalamud.Bootstrap
return createdTick & 0xFFFF_0000;
}
/// <summary>
/// Reads command-line arguments from the game and decrypts them if necessary.
/// </summary>
/// <returns>
/// Command-line arguments that looks like this:
/// /DEV.TestSID =ABCD /UserPath =C:\Examples
/// </returns>
public ArgumentBuilder GetGameArguments()
{
var processArguments = GetProcessArguments();
// arg[0] is a path to exe(normally), arg[1] is actual stuff.
if (processArguments.Length < 2)
{
throw new ProcessException($"There's only {processArguments.Length} process arguments. It must have at least 2 arguments.");
}
// We're interested in argument that contains session id
var argument = processArguments[1];
// If it's encrypted, we need to decrypt it first
if (EncryptedArgument.TryParse(argument, out var encryptedArgument))
{
var key = GetArgumentEncryptionKey();
argument = encryptedArgument.Decrypt(key);
}
return argument;
}
public uint Id => Kernel32.GetProcessId(m_handle);
}
}

View file

@ -8,7 +8,7 @@ namespace Dalamud.Bootstrap
{
public string ImagePath { get; set; } = null!;
public IList<string>? Arguments { get; set; }
public IDictionary<string, string> Arguments { get; set; }
public IDictionary<string, string>? Environments { get; set; }

View file

@ -3,18 +3,18 @@ using System.Text;
namespace Dalamud.Bootstrap.SqexArg
{
public sealed class ArgumentBuilder
public sealed class SqexArgBuilder
{
private readonly Dictionary<string, string> m_dict;
private readonly IDictionary<string, string> m_dict;
public ArgumentBuilder()
public SqexArgBuilder()
{
m_dict = new Dictionary<string, string>();
}
public ArgumentBuilder(IEnumerable<KeyValuePair<string, string>> collection)
public SqexArgBuilder(IDictionary<string, string> collection)
{
m_dict = new Dictionary<string, string>(collection);
m_dict = collection;
}
/// <summary>
@ -22,19 +22,21 @@ namespace Dalamud.Bootstrap.SqexArg
/// </summary>
/// <param name="argument"></param>
/// <returns></returns>
public static ArgumentBuilder Parse(string argument)
public static SqexArgBuilder Parse(string argument)
{
return new ArgumentBuilder(ArgumentParser.Parse(argument));
var arguments = new Dictionary<string, string>(SqexArgumentParser.Parse(argument)); // uhhh
return new SqexArgBuilder(arguments);
}
public ArgumentBuilder Add(string key, string value)
public SqexArgBuilder Add(string key, string value)
{
m_dict.Add(key, value);
return this;
}
public ArgumentBuilder Clear()
public SqexArgBuilder Clear()
{
m_dict.Clear();
@ -43,9 +45,9 @@ namespace Dalamud.Bootstrap.SqexArg
public bool ContainsKey(string key) => m_dict.ContainsKey(key);
public bool ContainsValue(string value) => m_dict.ContainsValue(value);
//public bool ContainsValue(string value) => m_dict.ContainsValue(value);
public ArgumentBuilder Remove(string key)
public SqexArgBuilder Remove(string key)
{
m_dict.Remove(key);
@ -54,17 +56,7 @@ namespace Dalamud.Bootstrap.SqexArg
public bool TryRemove(string key) => m_dict.Remove(key);
private static void Write(StringBuilder buffer, string key, string value)
{
var escapedKey = EscapeValue(key);
var escapedvalue = EscapeValue(value);
// TODO: (from chat)
// This line, the = in your version has a space before it
// If you're sending the arguments in plaintext, game doesn't like the space there
// (But I think it needs to be there in crypted args)
buffer.Append($" /{escapedKey} ={escapedvalue}"); // TODO: thanks SE
}
private static string EscapeValue(string value)
{
@ -72,16 +64,37 @@ namespace Dalamud.Bootstrap.SqexArg
return value.Replace(" ", " ");
}
public override string ToString()
private string BuildRawString()
{
// This is not exposed because (from chat):
// This line, the = in your version has a space before it
// If you're sending the arguments in plaintext, game doesn't like the space there
// (But I think it needs to be there in crypted args)
var buffer = new StringBuilder(300);
foreach (var kv in m_dict)
{
Write(buffer, kv.Key, kv.Value);
WriteKeyValue(buffer, kv.Key, kv.Value);
}
return buffer.ToString();
}
private static void WriteKeyValue(StringBuilder buffer, string key, string value)
{
var escapedKey = EscapeValue(key);
var escapedvalue = EscapeValue(value);
buffer.Append($" /{escapedKey} ={escapedvalue}");
}
public string Build(uint key)
{
var plainText = BuildRawString();
var enc = new SqexEncryptedArgument(plainText, key);
return enc.Build();
}
}
}

View file

@ -6,7 +6,7 @@ using static Pidgin.Parser<char>;
namespace Dalamud.Bootstrap.SqexArg
{
public static class ArgumentParser
public static class SqexArgumentParser
{
private static readonly Parser<char, string> KeyMarkerNoEscape = String(" ");

View file

@ -8,7 +8,7 @@ using Dalamud.Bootstrap.Crypto;
namespace Dalamud.Bootstrap.SqexArg
{
internal sealed class EncryptedArgument
internal sealed class SqexEncryptedArgument
{
private static readonly char[] ChecksumTable =
{
@ -32,7 +32,7 @@ namespace Dalamud.Bootstrap.SqexArg
/// </summary>
/// <param name="encodedData">A string that is already encrypted and encoded to url-safe variant of base64.</param>
/// <param name="checksum">A checksum that is used to validate the encryption key.</param>
private EncryptedArgument(string encodedData, char checksum)
private SqexEncryptedArgument(string encodedData, char checksum)
{
Data = encodedData;
Checksum = checksum;
@ -43,7 +43,7 @@ namespace Dalamud.Bootstrap.SqexArg
/// </summary>
/// <param name="plainText">A data that is not encrypted.</param>
/// <param name="key">A key that is used to encrypt the data.</param>
public EncryptedArgument(string plainText, uint key)
public SqexEncryptedArgument(string plainText, uint key)
{
Span<byte> keyBytes = stackalloc byte[8];
CreateKey(key, keyBytes);
@ -157,7 +157,7 @@ namespace Dalamud.Bootstrap.SqexArg
/// </summary>
/// <param name="argument">An argument that is encrypted and usually starts with //**sqex0003 and ends with **//</param>
/// <returns>Returns true if successful, false otherwise.</returns>
public static bool TryParse(string argument, out EncryptedArgument output)
public static bool TryParse(string argument, out SqexEncryptedArgument output)
{
if (!Extract(argument, out var data, out var checksum))
{
@ -165,7 +165,7 @@ namespace Dalamud.Bootstrap.SqexArg
return false;
}
output = new EncryptedArgument(data, checksum);
output = new SqexEncryptedArgument(data, checksum);
return true;
}
@ -196,7 +196,7 @@ namespace Dalamud.Bootstrap.SqexArg
return true;
}
public override string ToString() => $"//**sqex0003{Data}{Checksum}**//";
public string Build() => $"//**sqex0003{Data}{Checksum}**//";
/// <summary>
/// Formats a key.