mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Implement xiv fixes into Dalamud.Boot (#857)
This commit is contained in:
parent
02dd1eddec
commit
75de126c9d
40 changed files with 41576 additions and 196 deletions
|
|
@ -22,41 +22,46 @@ namespace Dalamud.Injector
|
|||
/// <param name="workingDir">The working directory.</param>
|
||||
/// <param name="exePath">The path to the executable file.</param>
|
||||
/// <param name="arguments">Arguments to pass to the executable file.</param>
|
||||
/// <param name="dontFixAcl">Don't actually fix the ACL.</param>
|
||||
/// <param name="beforeResume">Action to execute before the process is started.</param>
|
||||
/// <returns>The started process.</returns>
|
||||
/// <exception cref="Win32Exception">Thrown when a win32 error occurs.</exception>
|
||||
/// <exception cref="GameExitedException">Thrown when the process did not start correctly.</exception>
|
||||
public static Process LaunchGame(string workingDir, string exePath, string arguments, Action<Process> beforeResume)
|
||||
public static Process LaunchGame(string workingDir, string exePath, string arguments, bool dontFixAcl, Action<Process> beforeResume)
|
||||
{
|
||||
Process process = null;
|
||||
|
||||
var userName = Environment.UserName;
|
||||
|
||||
var pExplicitAccess = default(PInvoke.EXPLICIT_ACCESS);
|
||||
PInvoke.BuildExplicitAccessWithName(
|
||||
ref pExplicitAccess,
|
||||
userName,
|
||||
PInvoke.STANDARD_RIGHTS_ALL | PInvoke.SPECIFIC_RIGHTS_ALL & ~PInvoke.PROCESS_VM_WRITE,
|
||||
PInvoke.GRANT_ACCESS,
|
||||
0);
|
||||
|
||||
if (PInvoke.SetEntriesInAcl(1, ref pExplicitAccess, IntPtr.Zero, out var newAcl) != 0)
|
||||
|
||||
var psecDesc = IntPtr.Zero;
|
||||
if (!dontFixAcl)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
var userName = Environment.UserName;
|
||||
|
||||
if (!PInvoke.InitializeSecurityDescriptor(out var secDesc, PInvoke.SECURITY_DESCRIPTOR_REVISION))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
var pExplicitAccess = default(PInvoke.EXPLICIT_ACCESS);
|
||||
PInvoke.BuildExplicitAccessWithName(
|
||||
ref pExplicitAccess,
|
||||
userName,
|
||||
PInvoke.STANDARD_RIGHTS_ALL | PInvoke.SPECIFIC_RIGHTS_ALL & ~PInvoke.PROCESS_VM_WRITE,
|
||||
PInvoke.GRANT_ACCESS,
|
||||
0);
|
||||
|
||||
if (!PInvoke.SetSecurityDescriptorDacl(ref secDesc, true, newAcl, false))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
if (PInvoke.SetEntriesInAcl(1, ref pExplicitAccess, IntPtr.Zero, out var newAcl) != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
var psecDesc = Marshal.AllocHGlobal(Marshal.SizeOf<PInvoke.SECURITY_DESCRIPTOR>());
|
||||
Marshal.StructureToPtr(secDesc, psecDesc, true);
|
||||
if (!PInvoke.InitializeSecurityDescriptor(out var secDesc, PInvoke.SECURITY_DESCRIPTOR_REVISION))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
if (!PInvoke.SetSecurityDescriptorDacl(ref secDesc, true, newAcl, false))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
psecDesc = Marshal.AllocHGlobal(Marshal.SizeOf<PInvoke.SECURITY_DESCRIPTOR>());
|
||||
Marshal.StructureToPtr(secDesc, psecDesc, true);
|
||||
}
|
||||
|
||||
var lpProcessInformation = default(PInvoke.PROCESS_INFORMATION);
|
||||
try
|
||||
|
|
@ -109,7 +114,8 @@ namespace Dalamud.Injector
|
|||
Environment.SetEnvironmentVariable("__COMPAT_LAYER", compatLayerPrev);
|
||||
}
|
||||
|
||||
DisableSeDebug(lpProcessInformation.hProcess);
|
||||
if (!dontFixAcl)
|
||||
DisableSeDebug(lpProcessInformation.hProcess);
|
||||
|
||||
process = new ExistingProcess(lpProcessInformation.hProcess);
|
||||
|
||||
|
|
@ -133,30 +139,8 @@ namespace Dalamud.Injector
|
|||
throw new GameExitedException();
|
||||
}
|
||||
|
||||
if (PInvoke.GetSecurityInfo(
|
||||
PInvoke.GetCurrentProcess(),
|
||||
PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
|
||||
PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
out var pACL,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero) != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
if (PInvoke.SetSecurityInfo(
|
||||
lpProcessInformation.hProcess,
|
||||
PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
|
||||
PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | PInvoke.SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
pACL,
|
||||
IntPtr.Zero) != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
if (!dontFixAcl)
|
||||
CopyAclFromSelfToTargetProcess(lpProcessInformation.hProcess);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -175,13 +159,91 @@ namespace Dalamud.Injector
|
|||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(psecDesc);
|
||||
if (psecDesc != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal(psecDesc);
|
||||
PInvoke.CloseHandle(lpProcessInformation.hThread);
|
||||
}
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies ACL of current process to the target process.
|
||||
/// </summary>
|
||||
/// <param name="hProcess">Native handle to the target process.</param>
|
||||
/// <exception cref="Win32Exception">Thrown when a win32 error occurs.</exception>
|
||||
public static void CopyAclFromSelfToTargetProcess(IntPtr hProcess)
|
||||
{
|
||||
if (PInvoke.GetSecurityInfo(
|
||||
PInvoke.GetCurrentProcess(),
|
||||
PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
|
||||
PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
out var pACL,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero) != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
if (PInvoke.SetSecurityInfo(
|
||||
hProcess,
|
||||
PInvoke.SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
|
||||
PInvoke.SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | PInvoke.SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION,
|
||||
IntPtr.Zero,
|
||||
IntPtr.Zero,
|
||||
pACL,
|
||||
IntPtr.Zero) != 0)
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClaimSeDebug()
|
||||
{
|
||||
var hToken = PInvoke.INVALID_HANDLE_VALUE;
|
||||
try
|
||||
{
|
||||
if (!PInvoke.OpenThreadToken(PInvoke.GetCurrentThread(), PInvoke.TOKEN_QUERY | PInvoke.TOKEN_ADJUST_PRIVILEGES, false, out hToken))
|
||||
{
|
||||
if (Marshal.GetLastWin32Error() != PInvoke.ERROR_NO_TOKEN)
|
||||
throw new Exception("ClaimSeDebug.OpenProcessToken#1", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
|
||||
if (!PInvoke.ImpersonateSelf(PInvoke.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation))
|
||||
throw new Exception("ClaimSeDebug.ImpersonateSelf", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
|
||||
if (!PInvoke.OpenThreadToken(PInvoke.GetCurrentThread(), PInvoke.TOKEN_QUERY | PInvoke.TOKEN_ADJUST_PRIVILEGES, false, out hToken))
|
||||
throw new Exception("ClaimSeDebug.OpenProcessToken#2", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
|
||||
var luidDebugPrivilege = default(PInvoke.LUID);
|
||||
if (!PInvoke.LookupPrivilegeValue(null, PInvoke.SE_DEBUG_NAME, ref luidDebugPrivilege))
|
||||
throw new Exception("ClaimSeDebug.LookupPrivilegeValue", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
|
||||
var tpLookup = new PInvoke.TOKEN_PRIVILEGES()
|
||||
{
|
||||
PrivilegeCount = 1,
|
||||
Privileges = new PInvoke.LUID_AND_ATTRIBUTES[1]
|
||||
{
|
||||
new PInvoke.LUID_AND_ATTRIBUTES()
|
||||
{
|
||||
Luid = luidDebugPrivilege,
|
||||
Attributes = PInvoke.SE_PRIVILEGE_ENABLED,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (!PInvoke.AdjustTokenPrivileges(hToken, false, ref tpLookup, 0, IntPtr.Zero, IntPtr.Zero))
|
||||
throw new Exception("ClaimSeDebug.AdjustTokenPrivileges", new Win32Exception(Marshal.GetLastWin32Error()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (hToken != PInvoke.INVALID_HANDLE_VALUE && hToken != IntPtr.Zero)
|
||||
PInvoke.CloseHandle(hToken);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DisableSeDebug(IntPtr processHandle)
|
||||
{
|
||||
if (!PInvoke.OpenProcessToken(processHandle, PInvoke.TOKEN_QUERY | PInvoke.TOKEN_ADJUST_PRIVILEGES, out var tokenHandle))
|
||||
|
|
@ -190,7 +252,7 @@ namespace Dalamud.Injector
|
|||
}
|
||||
|
||||
var luidDebugPrivilege = default(PInvoke.LUID);
|
||||
if (!PInvoke.LookupPrivilegeValue(null, "SeDebugPrivilege", ref luidDebugPrivilege))
|
||||
if (!PInvoke.LookupPrivilegeValue(null, PInvoke.SE_DEBUG_NAME, ref luidDebugPrivilege))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
|
@ -222,7 +284,7 @@ namespace Dalamud.Injector
|
|||
tokenPrivileges.Privileges[0].Luid = luidDebugPrivilege;
|
||||
tokenPrivileges.Privileges[0].Attributes = PInvoke.SE_PRIVILEGE_REMOVED;
|
||||
|
||||
if (!PInvoke.AdjustTokenPrivileges(tokenHandle, false, ref tokenPrivileges, 0, IntPtr.Zero, 0))
|
||||
if (!PInvoke.AdjustTokenPrivileges(tokenHandle, false, ref tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
|
||||
{
|
||||
throw new Win32Exception(Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
|
@ -271,6 +333,10 @@ namespace Dalamud.Injector
|
|||
private static class PInvoke
|
||||
{
|
||||
#region Constants
|
||||
public static readonly IntPtr INVALID_HANDLE_VALUE = new(-1);
|
||||
|
||||
public const string SE_DEBUG_NAME = "SeDebugPrivilege";
|
||||
|
||||
public const UInt32 STANDARD_RIGHTS_ALL = 0x001F0000;
|
||||
public const UInt32 SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
|
||||
public const UInt32 PROCESS_VM_WRITE = 0x0020;
|
||||
|
|
@ -289,6 +355,8 @@ namespace Dalamud.Injector
|
|||
public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004;
|
||||
|
||||
public const UInt32 ERROR_NO_TOKEN = 0x000003F0;
|
||||
|
||||
public enum MULTIPLE_TRUSTEE_OPERATION
|
||||
{
|
||||
NO_MULTIPLE_TRUSTEE,
|
||||
|
|
@ -345,6 +413,14 @@ namespace Dalamud.Injector
|
|||
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
|
||||
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000,
|
||||
}
|
||||
|
||||
public enum SECURITY_IMPERSONATION_LEVEL
|
||||
{
|
||||
SecurityAnonymous,
|
||||
SecurityIdentification,
|
||||
SecurityImpersonation,
|
||||
SecurityDelegation
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
|
@ -395,12 +471,24 @@ namespace Dalamud.Injector
|
|||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool ImpersonateSelf(
|
||||
SECURITY_IMPERSONATION_LEVEL impersonationLevel
|
||||
);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool OpenProcessToken(
|
||||
IntPtr processHandle,
|
||||
UInt32 desiredAccess,
|
||||
out IntPtr tokenHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool OpenThreadToken(
|
||||
IntPtr ThreadHandle,
|
||||
uint DesiredAccess,
|
||||
bool OpenAsSelf,
|
||||
out IntPtr TokenHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref LUID lpLuid);
|
||||
|
||||
|
|
@ -415,9 +503,9 @@ namespace Dalamud.Injector
|
|||
IntPtr tokenHandle,
|
||||
bool disableAllPrivileges,
|
||||
ref TOKEN_PRIVILEGES newState,
|
||||
UInt32 bufferLengthInBytes,
|
||||
int cbPreviousState,
|
||||
IntPtr previousState,
|
||||
UInt32 returnLengthInBytes);
|
||||
IntPtr cbOutPreviousState);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
public static extern uint GetSecurityInfo(
|
||||
|
|
@ -443,6 +531,9 @@ namespace Dalamud.Injector
|
|||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetCurrentThread();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr hWndChildAfter, string className, IntPtr windowTitle);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue