chrome-tools 1.1.16 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chrome_abe_decrypt.exe +0 -0
- package/dist/cli.js +238 -3
- package/dist/index.js +238 -3
- package/package.json +1 -1
|
Binary file
|
package/dist/cli.js
CHANGED
|
@@ -6716,6 +6716,7 @@ import { homedir as homedir3 } from "node:os";
|
|
|
6716
6716
|
import { join as join6 } from "node:path";
|
|
6717
6717
|
|
|
6718
6718
|
// src/core/db.ts
|
|
6719
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
6719
6720
|
import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdtempSync, rmSync } from "node:fs";
|
|
6720
6721
|
import { tmpdir } from "node:os";
|
|
6721
6722
|
import { join as join5, basename as basename2 } from "node:path";
|
|
@@ -6750,11 +6751,245 @@ function toCallerTypes(rows) {
|
|
|
6750
6751
|
return plain;
|
|
6751
6752
|
});
|
|
6752
6753
|
}
|
|
6754
|
+
function findLockedCopyHelper() {
|
|
6755
|
+
const base = import.meta.dirname ?? "";
|
|
6756
|
+
const candidates = [
|
|
6757
|
+
join5(base, "chrome_abe_decrypt.exe"),
|
|
6758
|
+
join5(base, "..", "bin", "chrome_abe_decrypt.exe"),
|
|
6759
|
+
join5(base, "..", "..", "bin", "chrome_abe_decrypt.exe"),
|
|
6760
|
+
join5(base, "..", "..", "..", "bin", "chrome_abe_decrypt.exe"),
|
|
6761
|
+
join5(base, "..", "..", "src", "native", "chrome_abe_decrypt.exe")
|
|
6762
|
+
];
|
|
6763
|
+
for (const p of candidates) {
|
|
6764
|
+
if (existsSync3(p)) return p;
|
|
6765
|
+
}
|
|
6766
|
+
return null;
|
|
6767
|
+
}
|
|
6768
|
+
function copyLockedFileWindows(src, dst) {
|
|
6769
|
+
const helper = findLockedCopyHelper();
|
|
6770
|
+
if (helper) {
|
|
6771
|
+
try {
|
|
6772
|
+
execFileSync4(helper, ["--copy-locked", src, dst], {
|
|
6773
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
6774
|
+
windowsHide: true,
|
|
6775
|
+
timeout: 15e3
|
|
6776
|
+
});
|
|
6777
|
+
if (existsSync3(dst)) return;
|
|
6778
|
+
} catch {
|
|
6779
|
+
}
|
|
6780
|
+
}
|
|
6781
|
+
const psScript = `
|
|
6782
|
+
$ErrorActionPreference = "Stop";
|
|
6783
|
+
$in = [Console]::In.ReadToEnd() | ConvertFrom-Json;
|
|
6784
|
+
$src = $in.src;
|
|
6785
|
+
$dst = $in.dst;
|
|
6786
|
+
$code = @"
|
|
6787
|
+
using System;
|
|
6788
|
+
using System.IO;
|
|
6789
|
+
using System.Text;
|
|
6790
|
+
using System.Collections.Generic;
|
|
6791
|
+
using System.Runtime.InteropServices;
|
|
6792
|
+
using Microsoft.Win32.SafeHandles;
|
|
6793
|
+
|
|
6794
|
+
public class LockedFileCopier {
|
|
6795
|
+
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
|
|
6796
|
+
static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
|
|
6797
|
+
|
|
6798
|
+
[DllImport("rstrtmgr.dll")]
|
|
6799
|
+
static extern int RmEndSession(uint pSessionHandle);
|
|
6800
|
+
|
|
6801
|
+
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
|
|
6802
|
+
static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames,
|
|
6803
|
+
uint nApplications, [In] uint[] rgApplications, uint nServices, string[] rgsServiceNames);
|
|
6804
|
+
|
|
6805
|
+
[DllImport("rstrtmgr.dll")]
|
|
6806
|
+
static extern int RmGetList(uint pSessionHandle, out uint pnProcInfoNeeded,
|
|
6807
|
+
ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons);
|
|
6808
|
+
|
|
6809
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
6810
|
+
struct RM_UNIQUE_PROCESS {
|
|
6811
|
+
public int dwProcessId;
|
|
6812
|
+
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
|
|
6813
|
+
}
|
|
6814
|
+
|
|
6815
|
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
6816
|
+
struct RM_PROCESS_INFO {
|
|
6817
|
+
public RM_UNIQUE_PROCESS Process;
|
|
6818
|
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
|
6819
|
+
public string strAppName;
|
|
6820
|
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
|
6821
|
+
public string strServiceShortName;
|
|
6822
|
+
public int ApplicationType;
|
|
6823
|
+
public uint AppStatus;
|
|
6824
|
+
public uint TSSessionId;
|
|
6825
|
+
[MarshalAs(UnmanagedType.Bool)]
|
|
6826
|
+
public bool bRestartable;
|
|
6827
|
+
}
|
|
6828
|
+
|
|
6829
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
6830
|
+
public static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId);
|
|
6831
|
+
|
|
6832
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
6833
|
+
public static extern bool DuplicateHandle(
|
|
6834
|
+
IntPtr hSourceProcessHandle,
|
|
6835
|
+
IntPtr hSourceHandle,
|
|
6836
|
+
IntPtr hTargetProcessHandle,
|
|
6837
|
+
out IntPtr lpTargetHandle,
|
|
6838
|
+
uint dwDesiredAccess,
|
|
6839
|
+
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
|
|
6840
|
+
uint dwOptions);
|
|
6841
|
+
|
|
6842
|
+
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
6843
|
+
public static extern uint GetFinalPathNameByHandle(IntPtr hFile, [Out] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);
|
|
6844
|
+
|
|
6845
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
6846
|
+
public static extern bool CloseHandle(IntPtr hObject);
|
|
6847
|
+
|
|
6848
|
+
[DllImport("ntdll.dll")]
|
|
6849
|
+
public static extern int NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);
|
|
6850
|
+
|
|
6851
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
6852
|
+
public struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
|
|
6853
|
+
public IntPtr Object;
|
|
6854
|
+
public IntPtr UniqueProcessId;
|
|
6855
|
+
public IntPtr HandleValue;
|
|
6856
|
+
public uint GrantedAccess;
|
|
6857
|
+
public ushort CreatorBackTraceIndex;
|
|
6858
|
+
public ushort ObjectTypeIndex;
|
|
6859
|
+
public uint HandleAttributes;
|
|
6860
|
+
public uint Reserved;
|
|
6861
|
+
}
|
|
6862
|
+
|
|
6863
|
+
public static bool CopyLockedFile(string sourcePath, string destPath) {
|
|
6864
|
+
uint sessionHandle;
|
|
6865
|
+
string sessionKey = Guid.NewGuid().ToString();
|
|
6866
|
+
int res = RmStartSession(out sessionHandle, 0, sessionKey);
|
|
6867
|
+
if (res != 0) return false;
|
|
6868
|
+
|
|
6869
|
+
List<int> pids = new List<int>();
|
|
6870
|
+
try {
|
|
6871
|
+
string[] resources = new string[] { sourcePath };
|
|
6872
|
+
res = RmRegisterResources(sessionHandle, (uint)resources.Length, resources, 0, null, 0, null);
|
|
6873
|
+
if (res == 0) {
|
|
6874
|
+
uint nNeeded = 0;
|
|
6875
|
+
uint nProcInfo = 0;
|
|
6876
|
+
uint rebootReasons = 0;
|
|
6877
|
+
res = RmGetList(sessionHandle, out nNeeded, ref nProcInfo, null, ref rebootReasons);
|
|
6878
|
+
if (res == 234 && nNeeded > 0) {
|
|
6879
|
+
RM_PROCESS_INFO[] procInfo = new RM_PROCESS_INFO[nNeeded];
|
|
6880
|
+
nProcInfo = nNeeded;
|
|
6881
|
+
res = RmGetList(sessionHandle, out nNeeded, ref nProcInfo, procInfo, ref rebootReasons);
|
|
6882
|
+
if (res == 0) {
|
|
6883
|
+
for (int i = 0; i < nProcInfo; i++) {
|
|
6884
|
+
pids.Add(procInfo[i].Process.dwProcessId);
|
|
6885
|
+
}
|
|
6886
|
+
}
|
|
6887
|
+
}
|
|
6888
|
+
}
|
|
6889
|
+
} finally {
|
|
6890
|
+
RmEndSession(sessionHandle);
|
|
6891
|
+
}
|
|
6892
|
+
|
|
6893
|
+
if (pids.Count == 0) return false;
|
|
6894
|
+
|
|
6895
|
+
int infoLength = 0x10000;
|
|
6896
|
+
IntPtr infoPtr = Marshal.AllocHGlobal(infoLength);
|
|
6897
|
+
int retLen;
|
|
6898
|
+
while (NtQuerySystemInformation(64, infoPtr, infoLength, out retLen) == unchecked((int)0xc0000004)) {
|
|
6899
|
+
Marshal.FreeHGlobal(infoPtr);
|
|
6900
|
+
infoLength = retLen + 0x10000;
|
|
6901
|
+
infoPtr = Marshal.AllocHGlobal(infoLength);
|
|
6902
|
+
}
|
|
6903
|
+
|
|
6904
|
+
long handleCount = Marshal.ReadInt64(infoPtr);
|
|
6905
|
+
IntPtr currentPtr = new IntPtr(infoPtr.ToInt64() + 16);
|
|
6906
|
+
int entrySize = Marshal.SizeOf(typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
|
|
6907
|
+
string normSource = Path.GetFullPath(sourcePath);
|
|
6908
|
+
|
|
6909
|
+
bool success = false;
|
|
6910
|
+
foreach (int pid in pids) {
|
|
6911
|
+
IntPtr hProcess = OpenProcess(0x0040 | 0x0400, false, pid);
|
|
6912
|
+
if (hProcess == IntPtr.Zero) continue;
|
|
6913
|
+
|
|
6914
|
+
try {
|
|
6915
|
+
IntPtr entryPtr = currentPtr;
|
|
6916
|
+
for (long i = 0; i < handleCount; i++) {
|
|
6917
|
+
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX entry = (SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)Marshal.PtrToStructure(entryPtr, typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
|
|
6918
|
+
entryPtr = new IntPtr(entryPtr.ToInt64() + entrySize);
|
|
6919
|
+
|
|
6920
|
+
if (entry.UniqueProcessId.ToInt64() == pid) {
|
|
6921
|
+
IntPtr dupHandle;
|
|
6922
|
+
if (DuplicateHandle(hProcess, entry.HandleValue, new IntPtr(-1), out dupHandle, 0, false, 2)) {
|
|
6923
|
+
StringBuilder sb = new StringBuilder(1024);
|
|
6924
|
+
uint len = GetFinalPathNameByHandle(dupHandle, sb, (uint)sb.Capacity, 0);
|
|
6925
|
+
if (len > 0) {
|
|
6926
|
+
string filePath = sb.ToString();
|
|
6927
|
+
if (filePath.StartsWith(@"\\\\?\\")) filePath = filePath.Substring(4);
|
|
6928
|
+
if (string.Equals(filePath, normSource, StringComparison.OrdinalIgnoreCase)) {
|
|
6929
|
+
try {
|
|
6930
|
+
using (FileStream fsIn = new FileStream(new SafeFileHandle(dupHandle, false), FileAccess.Read))
|
|
6931
|
+
using (FileStream fsOut = new FileStream(destPath, FileMode.Create, FileAccess.Write)) {
|
|
6932
|
+
fsIn.Position = 0;
|
|
6933
|
+
fsIn.CopyTo(fsOut);
|
|
6934
|
+
}
|
|
6935
|
+
success = true;
|
|
6936
|
+
CloseHandle(dupHandle);
|
|
6937
|
+
break;
|
|
6938
|
+
} catch {}
|
|
6939
|
+
}
|
|
6940
|
+
}
|
|
6941
|
+
CloseHandle(dupHandle);
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
}
|
|
6945
|
+
} finally {
|
|
6946
|
+
CloseHandle(hProcess);
|
|
6947
|
+
}
|
|
6948
|
+
if (success) break;
|
|
6949
|
+
}
|
|
6950
|
+
|
|
6951
|
+
Marshal.FreeHGlobal(infoPtr);
|
|
6952
|
+
return success;
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
"@;
|
|
6956
|
+
Add-Type -TypeDefinition $code;
|
|
6957
|
+
$res = [LockedFileCopier]::CopyLockedFile($src, $dst);
|
|
6958
|
+
if (-not $res) { exit 1 }
|
|
6959
|
+
`;
|
|
6960
|
+
execFileSync4(
|
|
6961
|
+
"powershell.exe",
|
|
6962
|
+
["-NoProfile", "-NonInteractive", "-Command", psScript],
|
|
6963
|
+
{
|
|
6964
|
+
input: JSON.stringify({ src, dst }),
|
|
6965
|
+
encoding: "utf-8",
|
|
6966
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
6967
|
+
windowsHide: true,
|
|
6968
|
+
timeout: 3e4
|
|
6969
|
+
}
|
|
6970
|
+
);
|
|
6971
|
+
}
|
|
6972
|
+
function copySingleFileWithFallback(src, dst) {
|
|
6973
|
+
try {
|
|
6974
|
+
copyFileSync2(src, dst);
|
|
6975
|
+
} catch (err) {
|
|
6976
|
+
if (process.platform === "win32" && (err.code === "EBUSY" || err.code === "EPERM")) {
|
|
6977
|
+
copyLockedFileWindows(src, dst);
|
|
6978
|
+
return;
|
|
6979
|
+
}
|
|
6980
|
+
throw err;
|
|
6981
|
+
}
|
|
6982
|
+
}
|
|
6753
6983
|
function copyLockedDatabase(dbFilePath, tmpDb) {
|
|
6754
|
-
|
|
6755
|
-
for (const suffix of ["-wal", "-shm"]) {
|
|
6984
|
+
copySingleFileWithFallback(dbFilePath, tmpDb);
|
|
6985
|
+
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
6756
6986
|
const sidecar = `${dbFilePath}${suffix}`;
|
|
6757
|
-
if (existsSync3(sidecar))
|
|
6987
|
+
if (existsSync3(sidecar)) {
|
|
6988
|
+
try {
|
|
6989
|
+
copySingleFileWithFallback(sidecar, `${tmpDb}${suffix}`);
|
|
6990
|
+
} catch {
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
6758
6993
|
}
|
|
6759
6994
|
}
|
|
6760
6995
|
function queryDatabase(dbFilePath, sql, params = []) {
|
package/dist/index.js
CHANGED
|
@@ -906,6 +906,7 @@ function resolveTargetProfiles({
|
|
|
906
906
|
}
|
|
907
907
|
|
|
908
908
|
// src/core/db.ts
|
|
909
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
909
910
|
import { copyFileSync as copyFileSync2, existsSync as existsSync3, mkdtempSync, rmSync } from "node:fs";
|
|
910
911
|
import { tmpdir } from "node:os";
|
|
911
912
|
import { join as join5, basename as basename2 } from "node:path";
|
|
@@ -940,11 +941,245 @@ function toCallerTypes(rows) {
|
|
|
940
941
|
return plain;
|
|
941
942
|
});
|
|
942
943
|
}
|
|
944
|
+
function findLockedCopyHelper() {
|
|
945
|
+
const base = import.meta.dirname ?? "";
|
|
946
|
+
const candidates = [
|
|
947
|
+
join5(base, "chrome_abe_decrypt.exe"),
|
|
948
|
+
join5(base, "..", "bin", "chrome_abe_decrypt.exe"),
|
|
949
|
+
join5(base, "..", "..", "bin", "chrome_abe_decrypt.exe"),
|
|
950
|
+
join5(base, "..", "..", "..", "bin", "chrome_abe_decrypt.exe"),
|
|
951
|
+
join5(base, "..", "..", "src", "native", "chrome_abe_decrypt.exe")
|
|
952
|
+
];
|
|
953
|
+
for (const p of candidates) {
|
|
954
|
+
if (existsSync3(p)) return p;
|
|
955
|
+
}
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
function copyLockedFileWindows(src, dst) {
|
|
959
|
+
const helper = findLockedCopyHelper();
|
|
960
|
+
if (helper) {
|
|
961
|
+
try {
|
|
962
|
+
execFileSync4(helper, ["--copy-locked", src, dst], {
|
|
963
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
964
|
+
windowsHide: true,
|
|
965
|
+
timeout: 15e3
|
|
966
|
+
});
|
|
967
|
+
if (existsSync3(dst)) return;
|
|
968
|
+
} catch {
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
const psScript = `
|
|
972
|
+
$ErrorActionPreference = "Stop";
|
|
973
|
+
$in = [Console]::In.ReadToEnd() | ConvertFrom-Json;
|
|
974
|
+
$src = $in.src;
|
|
975
|
+
$dst = $in.dst;
|
|
976
|
+
$code = @"
|
|
977
|
+
using System;
|
|
978
|
+
using System.IO;
|
|
979
|
+
using System.Text;
|
|
980
|
+
using System.Collections.Generic;
|
|
981
|
+
using System.Runtime.InteropServices;
|
|
982
|
+
using Microsoft.Win32.SafeHandles;
|
|
983
|
+
|
|
984
|
+
public class LockedFileCopier {
|
|
985
|
+
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
|
|
986
|
+
static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
|
|
987
|
+
|
|
988
|
+
[DllImport("rstrtmgr.dll")]
|
|
989
|
+
static extern int RmEndSession(uint pSessionHandle);
|
|
990
|
+
|
|
991
|
+
[DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
|
|
992
|
+
static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames,
|
|
993
|
+
uint nApplications, [In] uint[] rgApplications, uint nServices, string[] rgsServiceNames);
|
|
994
|
+
|
|
995
|
+
[DllImport("rstrtmgr.dll")]
|
|
996
|
+
static extern int RmGetList(uint pSessionHandle, out uint pnProcInfoNeeded,
|
|
997
|
+
ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons);
|
|
998
|
+
|
|
999
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1000
|
+
struct RM_UNIQUE_PROCESS {
|
|
1001
|
+
public int dwProcessId;
|
|
1002
|
+
public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
|
1006
|
+
struct RM_PROCESS_INFO {
|
|
1007
|
+
public RM_UNIQUE_PROCESS Process;
|
|
1008
|
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
|
1009
|
+
public string strAppName;
|
|
1010
|
+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
|
1011
|
+
public string strServiceShortName;
|
|
1012
|
+
public int ApplicationType;
|
|
1013
|
+
public uint AppStatus;
|
|
1014
|
+
public uint TSSessionId;
|
|
1015
|
+
[MarshalAs(UnmanagedType.Bool)]
|
|
1016
|
+
public bool bRestartable;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
1020
|
+
public static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId);
|
|
1021
|
+
|
|
1022
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
1023
|
+
public static extern bool DuplicateHandle(
|
|
1024
|
+
IntPtr hSourceProcessHandle,
|
|
1025
|
+
IntPtr hSourceHandle,
|
|
1026
|
+
IntPtr hTargetProcessHandle,
|
|
1027
|
+
out IntPtr lpTargetHandle,
|
|
1028
|
+
uint dwDesiredAccess,
|
|
1029
|
+
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
|
|
1030
|
+
uint dwOptions);
|
|
1031
|
+
|
|
1032
|
+
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
|
1033
|
+
public static extern uint GetFinalPathNameByHandle(IntPtr hFile, [Out] StringBuilder lpszFilePath, uint cchFilePath, uint dwFlags);
|
|
1034
|
+
|
|
1035
|
+
[DllImport("kernel32.dll", SetLastError = true)]
|
|
1036
|
+
public static extern bool CloseHandle(IntPtr hObject);
|
|
1037
|
+
|
|
1038
|
+
[DllImport("ntdll.dll")]
|
|
1039
|
+
public static extern int NtQuerySystemInformation(int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, out int ReturnLength);
|
|
1040
|
+
|
|
1041
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
1042
|
+
public struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
|
|
1043
|
+
public IntPtr Object;
|
|
1044
|
+
public IntPtr UniqueProcessId;
|
|
1045
|
+
public IntPtr HandleValue;
|
|
1046
|
+
public uint GrantedAccess;
|
|
1047
|
+
public ushort CreatorBackTraceIndex;
|
|
1048
|
+
public ushort ObjectTypeIndex;
|
|
1049
|
+
public uint HandleAttributes;
|
|
1050
|
+
public uint Reserved;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
public static bool CopyLockedFile(string sourcePath, string destPath) {
|
|
1054
|
+
uint sessionHandle;
|
|
1055
|
+
string sessionKey = Guid.NewGuid().ToString();
|
|
1056
|
+
int res = RmStartSession(out sessionHandle, 0, sessionKey);
|
|
1057
|
+
if (res != 0) return false;
|
|
1058
|
+
|
|
1059
|
+
List<int> pids = new List<int>();
|
|
1060
|
+
try {
|
|
1061
|
+
string[] resources = new string[] { sourcePath };
|
|
1062
|
+
res = RmRegisterResources(sessionHandle, (uint)resources.Length, resources, 0, null, 0, null);
|
|
1063
|
+
if (res == 0) {
|
|
1064
|
+
uint nNeeded = 0;
|
|
1065
|
+
uint nProcInfo = 0;
|
|
1066
|
+
uint rebootReasons = 0;
|
|
1067
|
+
res = RmGetList(sessionHandle, out nNeeded, ref nProcInfo, null, ref rebootReasons);
|
|
1068
|
+
if (res == 234 && nNeeded > 0) {
|
|
1069
|
+
RM_PROCESS_INFO[] procInfo = new RM_PROCESS_INFO[nNeeded];
|
|
1070
|
+
nProcInfo = nNeeded;
|
|
1071
|
+
res = RmGetList(sessionHandle, out nNeeded, ref nProcInfo, procInfo, ref rebootReasons);
|
|
1072
|
+
if (res == 0) {
|
|
1073
|
+
for (int i = 0; i < nProcInfo; i++) {
|
|
1074
|
+
pids.Add(procInfo[i].Process.dwProcessId);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
} finally {
|
|
1080
|
+
RmEndSession(sessionHandle);
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
if (pids.Count == 0) return false;
|
|
1084
|
+
|
|
1085
|
+
int infoLength = 0x10000;
|
|
1086
|
+
IntPtr infoPtr = Marshal.AllocHGlobal(infoLength);
|
|
1087
|
+
int retLen;
|
|
1088
|
+
while (NtQuerySystemInformation(64, infoPtr, infoLength, out retLen) == unchecked((int)0xc0000004)) {
|
|
1089
|
+
Marshal.FreeHGlobal(infoPtr);
|
|
1090
|
+
infoLength = retLen + 0x10000;
|
|
1091
|
+
infoPtr = Marshal.AllocHGlobal(infoLength);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
long handleCount = Marshal.ReadInt64(infoPtr);
|
|
1095
|
+
IntPtr currentPtr = new IntPtr(infoPtr.ToInt64() + 16);
|
|
1096
|
+
int entrySize = Marshal.SizeOf(typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
|
|
1097
|
+
string normSource = Path.GetFullPath(sourcePath);
|
|
1098
|
+
|
|
1099
|
+
bool success = false;
|
|
1100
|
+
foreach (int pid in pids) {
|
|
1101
|
+
IntPtr hProcess = OpenProcess(0x0040 | 0x0400, false, pid);
|
|
1102
|
+
if (hProcess == IntPtr.Zero) continue;
|
|
1103
|
+
|
|
1104
|
+
try {
|
|
1105
|
+
IntPtr entryPtr = currentPtr;
|
|
1106
|
+
for (long i = 0; i < handleCount; i++) {
|
|
1107
|
+
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX entry = (SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)Marshal.PtrToStructure(entryPtr, typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
|
|
1108
|
+
entryPtr = new IntPtr(entryPtr.ToInt64() + entrySize);
|
|
1109
|
+
|
|
1110
|
+
if (entry.UniqueProcessId.ToInt64() == pid) {
|
|
1111
|
+
IntPtr dupHandle;
|
|
1112
|
+
if (DuplicateHandle(hProcess, entry.HandleValue, new IntPtr(-1), out dupHandle, 0, false, 2)) {
|
|
1113
|
+
StringBuilder sb = new StringBuilder(1024);
|
|
1114
|
+
uint len = GetFinalPathNameByHandle(dupHandle, sb, (uint)sb.Capacity, 0);
|
|
1115
|
+
if (len > 0) {
|
|
1116
|
+
string filePath = sb.ToString();
|
|
1117
|
+
if (filePath.StartsWith(@"\\\\?\\")) filePath = filePath.Substring(4);
|
|
1118
|
+
if (string.Equals(filePath, normSource, StringComparison.OrdinalIgnoreCase)) {
|
|
1119
|
+
try {
|
|
1120
|
+
using (FileStream fsIn = new FileStream(new SafeFileHandle(dupHandle, false), FileAccess.Read))
|
|
1121
|
+
using (FileStream fsOut = new FileStream(destPath, FileMode.Create, FileAccess.Write)) {
|
|
1122
|
+
fsIn.Position = 0;
|
|
1123
|
+
fsIn.CopyTo(fsOut);
|
|
1124
|
+
}
|
|
1125
|
+
success = true;
|
|
1126
|
+
CloseHandle(dupHandle);
|
|
1127
|
+
break;
|
|
1128
|
+
} catch {}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
CloseHandle(dupHandle);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
} finally {
|
|
1136
|
+
CloseHandle(hProcess);
|
|
1137
|
+
}
|
|
1138
|
+
if (success) break;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
Marshal.FreeHGlobal(infoPtr);
|
|
1142
|
+
return success;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
"@;
|
|
1146
|
+
Add-Type -TypeDefinition $code;
|
|
1147
|
+
$res = [LockedFileCopier]::CopyLockedFile($src, $dst);
|
|
1148
|
+
if (-not $res) { exit 1 }
|
|
1149
|
+
`;
|
|
1150
|
+
execFileSync4(
|
|
1151
|
+
"powershell.exe",
|
|
1152
|
+
["-NoProfile", "-NonInteractive", "-Command", psScript],
|
|
1153
|
+
{
|
|
1154
|
+
input: JSON.stringify({ src, dst }),
|
|
1155
|
+
encoding: "utf-8",
|
|
1156
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1157
|
+
windowsHide: true,
|
|
1158
|
+
timeout: 3e4
|
|
1159
|
+
}
|
|
1160
|
+
);
|
|
1161
|
+
}
|
|
1162
|
+
function copySingleFileWithFallback(src, dst) {
|
|
1163
|
+
try {
|
|
1164
|
+
copyFileSync2(src, dst);
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
if (process.platform === "win32" && (err.code === "EBUSY" || err.code === "EPERM")) {
|
|
1167
|
+
copyLockedFileWindows(src, dst);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
throw err;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
943
1173
|
function copyLockedDatabase(dbFilePath, tmpDb) {
|
|
944
|
-
|
|
945
|
-
for (const suffix of ["-wal", "-shm"]) {
|
|
1174
|
+
copySingleFileWithFallback(dbFilePath, tmpDb);
|
|
1175
|
+
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
946
1176
|
const sidecar = `${dbFilePath}${suffix}`;
|
|
947
|
-
if (existsSync3(sidecar))
|
|
1177
|
+
if (existsSync3(sidecar)) {
|
|
1178
|
+
try {
|
|
1179
|
+
copySingleFileWithFallback(sidecar, `${tmpDb}${suffix}`);
|
|
1180
|
+
} catch {
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
948
1183
|
}
|
|
949
1184
|
}
|
|
950
1185
|
function queryDatabase(dbFilePath, sql, params = []) {
|