mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-13 19:37:44 +01:00
This is fucking dog shit
This commit is contained in:
parent
52daf6ada0
commit
54bf6099bf
7 changed files with 281 additions and 268 deletions
|
|
@ -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());
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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(" ");
|
||||
|
||||
|
|
@ -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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue