public static void CopyLockedFile(ProcessFileHandle fileHandle, string copyTo = "") { // Copies a locked file to a random temp file or the location specified // -Opens the process with DuplicateHandle permissions // -Duplicates the file handle supplied // -Uses CreateFileMapping() on the duplicated handle // -Uses MapViewOfFile() to map the entire file into memory // -Writes the mapped data to the new temp file // open the target process with "duplicate handle" permissions IntPtr processHandle = Kernel32.OpenProcess(ProcessAccessFlags.DuplicateHandle, true, (uint)fileHandle.ProcessID); IntPtr currentProcessHandle = Kernel32.GetCurrentProcess(); IntPtr duplicatedHandle = new IntPtr(); // duplicate the specific file handle opened by the process locking it bool success = Kernel32.DuplicateHandle(processHandle, new IntPtr(fileHandle.FileHandleID), currentProcessHandle, out duplicatedHandle, 0, false, DuplicateOptions.DUPLICATE_SAME_ACCESS); if (success) { long fileSize = 0; // size of the file we're copying out Kernel32.GetFileSizeEx(duplicatedHandle, out fileSize); // create a file mapping with the duplicated handle IntPtr mappedPtr = Kernel32.CreateFileMapping(duplicatedHandle, IntPtr.Zero, FileMapProtection.PageReadonly, 0, 0, null); // map the entire file into memory IntPtr mappedViewPtr = Kernel32.MapViewOfFile(mappedPtr, FileMapAccess.FileMapRead, 0, 0, 0); // generate a temporary file name if a target isn't specified if (String.IsNullOrEmpty(copyTo)) { copyTo = Path.GetTempFileName(); } Console.WriteLine($"[*] Copying to: {copyTo}"); // create the temporary file to copy to // GENERIC_READ = 0x80000000 // GENERIC_WRITE = 0x40000000 // FILE_SHARE_READ = 0x00000001 // FILE_SHARE_WRITE = 0x00000002 // CREATE_ALWAYS = 0x00000002 IntPtr tempFilePtr = Kernel32.CreateFile(copyTo, 0x80000000 | 0x40000000, 0x00000001 | 0x00000002, (IntPtr)null, 0x00000002, 0, (IntPtr)null); // write out the memory mapped file to the new temp file uint written = 0; Kernel32.WriteFile(tempFilePtr, mappedViewPtr, (uint)fileSize, out written, (IntPtr)null); Console.WriteLine($"[*] Copied {written} bytes from \"{fileHandle.FileName}\" to \"{copyTo}\""); // cleanup Kernel32.UnmapViewOfFile(mappedViewPtr); Kernel32.CloseHandle(tempFilePtr); Kernel32.CloseHandle(duplicatedHandle); } Kernel32.CloseHandle(processHandle); }
static void Main(string[] args) { var parsed = ArgumentParser.Parse(args); string[] candidateProcesses = null; bool copyFile = false; string copyDestination = ""; if (parsed.ParsedOk == false) { Usage(); return; } if ( parsed.Arguments.ContainsKey("/h") || parsed.Arguments.ContainsKey("/H") || parsed.Arguments.ContainsKey("/?") || parsed.Arguments.ContainsKey("/help") || parsed.Arguments.ContainsKey("/HELP") || parsed.Arguments.ContainsKey("-h") || parsed.Arguments.ContainsKey("-H") || parsed.Arguments.ContainsKey("-?") || parsed.Arguments.ContainsKey("-help") || parsed.Arguments.ContainsKey("-HELP")) { Usage(); return; } var targetFile = args.Length != 0 ? args[0] : ""; if (String.IsNullOrEmpty(targetFile)) { Usage(); return; } if (parsed.Arguments.ContainsKey("/process")) { candidateProcesses = parsed.Arguments["/process"].Split(','); } if (parsed.Arguments.ContainsKey("/copy")) { copyFile = true; copyDestination = parsed.Arguments["/copy"]; } if (targetFile == "all") { Console.WriteLine($"ProcessName,ProcessID,FileHandleID,FileName"); List <ProcessFileHandle> handles = GetAllFileHandles(); foreach (ProcessFileHandle handle in handles) { Console.WriteLine($"{handle.ProcessName},{handle.ProcessID},{handle.FileHandleID},{handle.FileName}"); } } else { Console.WriteLine($"\r\n[*] Searching processes for an open handle to \"{targetFile}\""); ProcessFileHandle foundHandle = FindFileHandle(targetFile, candidateProcesses); if (foundHandle.ProcessID != 0) { Console.WriteLine($"[+] Process \"{foundHandle.ProcessName}\" ({foundHandle.ProcessID}) has a file handle (ID {foundHandle.FileHandleID}) to \"{foundHandle.FileName}\""); if (copyFile) { CopyLockedFile(foundHandle, copyDestination); } } else { Console.WriteLine($"[X] Handle not found for \"{targetFile}\""); } } }