public static ReparsePoint ChangeReparsePointTarget(string reparsePointPath, string newReparsePointTarget) { reparsePointPath = reparsePointPath.GetFullPath(); newReparsePointTarget = newReparsePointTarget.GetFullPath(); var oldReparsePointTarget = GetActualPath(reparsePointPath).GetFullPath(); if (newReparsePointTarget.Equals(oldReparsePointTarget, StringComparison.CurrentCultureIgnoreCase)) { return(Open(reparsePointPath)); } if (!IsReparsePoint(reparsePointPath)) { throw new IOException("Path is not a reparse point."); } if (Directory.Exists(reparsePointPath)) { if (!Directory.Exists(newReparsePointTarget)) { throw new IOException("Reparse point is a directory, but no directory exists for new reparse point target."); } } else if (File.Exists(reparsePointPath)) { if (!File.Exists(newReparsePointTarget)) { throw new IOException("Reparse point is a file, but no file exists for new reparse point target."); } } else { throw new IOException("Reparse Point is not a file or directory ?"); } var reparsePoint = Open(reparsePointPath); var isSymlink = reparsePoint._reparseDataData.ReparseTag == IoReparseTag.Symlink; if (reparsePoint._reparseDataData.ReparseTag != IoReparseTag.MountPoint && reparsePoint._reparseDataData.ReparseTag != IoReparseTag.Symlink) { throw new IOException("ChangeReparsePointTarget only works on junctions and symlink reparse points."); } // dark magic kung-fu to get privilige to create symlink. var state = IntPtr.Zero; UInt32 privilege = 35; if (isSymlink) { Ntdll.RtlAcquirePrivilege(ref privilege, 1, 0, ref state); } using (var handle = GetReparsePointHandle(reparsePointPath, NativeFileAccess.GenericWrite)) { var substituteName = Encoding.Unicode.GetBytes(NonInterpretedPathPrefix + newReparsePointTarget); var printName = Encoding.Unicode.GetBytes(newReparsePointTarget); var extraOffset = isSymlink ? 4 : 0; reparsePoint._reparseDataData.SubstituteNameOffset = 0; reparsePoint._reparseDataData.SubstituteNameLength = (ushort)substituteName.Length; reparsePoint._reparseDataData.PrintNameOffset = (ushort)(substituteName.Length + 2); reparsePoint._reparseDataData.PrintNameLength = (ushort)printName.Length; reparsePoint._reparseDataData.PathBuffer = new byte[0x3ff0]; reparsePoint._reparseDataData.ReparseDataLength = (ushort)(reparsePoint._reparseDataData.PrintNameLength + reparsePoint._reparseDataData.PrintNameOffset + 10 + extraOffset); Array.Copy(substituteName, 0, reparsePoint._reparseDataData.PathBuffer, extraOffset, substituteName.Length); Array.Copy(printName, 0, reparsePoint._reparseDataData.PathBuffer, reparsePoint._reparseDataData.PrintNameOffset + extraOffset, printName.Length); var inBufferSize = Marshal.SizeOf(reparsePoint._reparseDataData); var inBuffer = Marshal.AllocHGlobal(inBufferSize); try { Marshal.StructureToPtr(reparsePoint._reparseDataData, inBuffer, false); int bytesReturned; var result = Kernel32.DeviceIoControl(handle, ControlCodes.SetReparsePoint, inBuffer, reparsePoint._reparseDataData.ReparseDataLength + 8, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); if (!result) { throw new IOException("Unable to modify reparse point.", Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error())); } return(Open(reparsePointPath)); } finally { if (isSymlink) { try { if (state != IntPtr.Zero) { Ntdll.RtlReleasePrivilege(state); } } catch { // sometimes this doesn't work so well } } Marshal.FreeHGlobal(inBuffer); } } }
private static bool DoRehash(int processId) { SizeT written = 0; uint threadId = 0; // Find target var processHandle = Kernel32.OpenProcess(0x000F0000 | 0x00100000 | 0xFFFF /* PROCESS_ALL_ACCESS */, false, processId); if (processHandle.IsInvalid) { return(false); } // Create some space in target memory space var processType = GetProcessProcessorType(processHandle); if (!_reHashDlls.ContainsKey(processType)) { Logger.Error("Rehash: Unable to get rehash DLL for {0}", processType); return(false); } var pathInAscii = _reHashDlls[processType]; var length = (uint)pathInAscii.Length; // before we actually allocate any memory in the target process, // let's make sure we get out module/fn pointers ok. var moduleHandle = Kernel32.GetModuleHandle("kernel32"); if (moduleHandle.IsInvalid) { Logger.Error("Rehash: Can't get Kernel32 Module Handle"); // failed to get Module Handle to Kernel32? Whoa. return(false); } var fnLoadLibrary = Kernel32.GetProcAddress(moduleHandle, "LoadLibraryA"); if (fnLoadLibrary == IntPtr.Zero) { // Failed to get LoadLibraryA ptr. Logger.Error("Rehash: Can't get LoadLibraryA Handle"); return(false); } var remoteMemory = Kernel32.VirtualAllocEx(processHandle, IntPtr.Zero, length, AllocationType.Reserve | AllocationType.Commit, MemoryProtection.ExecuteReadWrite); if (remoteMemory == IntPtr.Zero) { // Target alloc mem error Logger.Error("Rehash: Can't allocate memory in process pid:{0}", processId); return(false); } // Write library name into target memory space if (!Kernel32.WriteProcessMemory(processHandle, remoteMemory, pathInAscii, length, ref written) || written == 0) { // Target write mem error. // cleanup what we allocated? // var err = Marshal.GetLastWin32Error(); Logger.Error("Rehash: Can't write memory in process pid:{0}", processId); Kernel32.VirtualFreeEx(processHandle, remoteMemory, length, AllocationType.Release); return(false); } // flush the instruction cache, to make sure that the processor will see the changes. // Note: In the matrix, this can cause "deja vu" Kernel32.FlushInstructionCache(processHandle, IntPtr.Zero, 0); // tell the remote process to load our DLL (which does the actual rehash!) if (WindowsVersionInfo.IsVistaOrBeyond) { if (0 != Ntdll.RtlCreateUserThread(processHandle, IntPtr.Zero, false, 0, IntPtr.Zero, IntPtr.Zero, fnLoadLibrary, remoteMemory, out threadId, IntPtr.Zero)) { Logger.Error("Rehash: Can't create remote thread (via RtlCreateUserThread) in pid:{0}", processId); return(false); } } else { if ( Kernel32.CreateRemoteThread(processHandle, IntPtr.Zero, 0, fnLoadLibrary, remoteMemory, CreateRemoteThreadFlags.None, out threadId). IsInvalid) { Logger.Error("Rehash: Can't create remote thread in pid:{0}", processId); return(false); } } //Logger.Warning("Rehash: Success with pid:{0}", processId); return(true); }
public static ReparsePoint CreateSymlink(string symlinkPath, string linkTarget) { symlinkPath = symlinkPath.GetFullPath(); linkTarget = linkTarget.GetFullPath(); if (Directory.Exists(symlinkPath) || File.Exists(symlinkPath)) { throw new IOException("Symlink path already exists."); } if (Directory.Exists(linkTarget)) { Directory.CreateDirectory(symlinkPath); } else if (File.Exists(linkTarget)) { File.Create(symlinkPath).Close(); } else { throw new IOException("Target path does not exist or is not a directory."); } // dark magic kung-fu to get privilige to create symlink. var state = IntPtr.Zero; UInt32 privilege = 35; Ntdll.RtlAcquirePrivilege(ref privilege, 1, 0, ref state); using (var handle = GetReparsePointHandle(symlinkPath, NativeFileAccess.GenericWrite)) { var substituteName = Encoding.Unicode.GetBytes(NonInterpretedPathPrefix + linkTarget); var printName = Encoding.Unicode.GetBytes(linkTarget); var extraOffset = 4; var reparseDataBuffer = new ReparseData { ReparseTag = IoReparseTag.Symlink, SubstituteNameOffset = 0, SubstituteNameLength = (ushort)substituteName.Length, PrintNameOffset = (ushort)(substituteName.Length + 2), PrintNameLength = (ushort)printName.Length, PathBuffer = new byte[0x3ff0], }; reparseDataBuffer.ReparseDataLength = (ushort)(reparseDataBuffer.PrintNameLength + reparseDataBuffer.PrintNameOffset + 10 + extraOffset); Array.Copy(substituteName, 0, reparseDataBuffer.PathBuffer, extraOffset, substituteName.Length); Array.Copy(printName, 0, reparseDataBuffer.PathBuffer, reparseDataBuffer.PrintNameOffset + extraOffset, printName.Length); var inBufferSize = Marshal.SizeOf(reparseDataBuffer); var inBuffer = Marshal.AllocHGlobal(inBufferSize); try { Marshal.StructureToPtr(reparseDataBuffer, inBuffer, false); int bytesReturned; var result = Kernel32.DeviceIoControl(handle, ControlCodes.SetReparsePoint, inBuffer, reparseDataBuffer.ReparseDataLength + 8, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); if (!result) { if (Directory.Exists(symlinkPath)) { Directory.Delete(symlinkPath); } else if (File.Exists(symlinkPath)) { File.Delete(symlinkPath); } throw new IOException("Unable to create symlink.", Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error())); } return(Open(symlinkPath)); } finally { Marshal.FreeHGlobal(inBuffer); try { if (state != IntPtr.Zero) { Ntdll.RtlReleasePrivilege(state); } } catch { // sometimes this doesn't work so well } } } }