public static Action<long, long> Concat(ISourceReader reader, ProcessSample transforms, Func<bool> isAborted) { return (offsetA, offsetV) => { reader.SetCurrentPosition(0); var stream = FromSource(reader, isAborted); bool firstV = false; stream(s => { if (isAborted()) return false; if (s.Flags.EndOfStream) return transforms(s); if (!firstV && s.Stream.CurrentMediaType.IsVideo) { firstV = true; return true; } if (s.Stream.CurrentMediaType.IsVideo) s.Resequence(offsetV); if (s.Stream.CurrentMediaType.IsAudio) s.Resequence(offsetA); return transforms(s); }); }; }
public static ProcessSample If(Func<SourceReaderSample, bool> selector, ProcessSample trueSamples, ProcessSample falseSamples) { return sample => { if (selector(sample)) return trueSamples(sample); return falseSamples(sample); }; }
public static ProcessSample MediaTypeChange(SinkStream sinkStream, ProcessSample next) { return sample => { if (sample.Flags.CurrentMediaTypeChanged) sinkStream.InputMediaType = sample.Stream.CurrentMediaType; return next(sample); }; }
static ProcessSample _AudioFadeIn(ProcessSample next) { return (sample) => { var fadeOut = (sample.SegmentTimeStamp).FromNanoToSeconds(); FadeAudio(sample, fadeOut); return next(sample); }; }
static ProcessSample FadeIn(ProcessSample streamFader, ProcessSample next) { return DataSamplesOnly( s => { if (s.SegmentTimeStamp < TimingExtensions.OneNanoSecond) return streamFader(s); return next(s); }, next); }
public static ProcessSample Overlay(Action<SourceReaderSampleWithBitmap> applyImage, ProcessSample processSample) { return SeperateAudioVideo(processSample, sample => { if( sample.Sample != null) using (var sampleWithBitmap = new SourceReaderSampleWithBitmap(sample)) applyImage(sampleWithBitmap); return processSample(sample); }); }
ProcessSample MonitorProgress(ProcessSample next) { return(sample => { if (!sample.Flags.EndOfStream && progressReporter != null) { progressReporter(sample.SampleTime, totalDuration); } return next(sample); }); }
static ProcessSample _VideoFadeIn(ProcessSample next) { return (sample) => { var fadeIn = Math.Min(255, 255 - ((sample.SegmentTimeStamp).FromNanoToSeconds() * 255)); fadeIn = Math.Max(0, fadeIn); using (var videoSample = new SourceReaderSampleWithBitmap(sample)) videoSample.Graphic.FillRectangle(new SolidBrush(Color.FromArgb((int)fadeIn, Color.Black)), 0, 0, videoSample.ImageWidth, videoSample.ImageHeight); return next(sample); }; }
private static ProcessSample aFadeOut(ProcessSample streamFader, long duration, ProcessSample next) { return DataSamplesOnly(s => { var fadingOutFrom = s.SegmentDuration - duration; if (fadingOutFrom <= s.SegmentTimeStamp) return streamFader(s); return next(s); }, next); }
private static ProcessSample _AudioFadeOut(long duration, ProcessSample next) { return sample => { var fadingOutFrom = sample.SegmentDuration - duration; var fadeOut = 1.0 - (sample.SegmentTimeStamp - fadingOutFrom).FromNanoToSeconds(); FadeAudio(sample, fadeOut); return next(sample); }; }
public static ProcessSample SeperateAudioVideo(ProcessSample audioStreams, ProcessSample videoStreams) { return sample => { if (sample.Stream.NativeMediaType.IsVideo) return videoStreams(sample); if (sample.Stream.NativeMediaType.IsAudio) return audioStreams(sample); throw new Exception("Unknown stream type"); }; }
private static ProcessSample _VideoFadeOut(long duration, ProcessSample next) { return sample => { var fadingOutFrom = sample.SegmentDuration - duration; var fadeOut = Math.Min(255, (sample.SegmentTimeStamp - fadingOutFrom).FromNanoToSeconds() * 255.0 / duration.FromNanoToSeconds()); fadeOut = Math.Max(0, fadeOut); using (var videoSample = new SourceReaderSampleWithBitmap(sample)) videoSample.Graphic.FillRectangle(new SolidBrush(Color.FromArgb((int)fadeOut, Color.Black)), 0, 0, videoSample.ImageWidth, videoSample.ImageHeight); return next(sample); }; }
ProcessSample ApplyEdits(ProcessSample next) { var cut = next; var raceEdits = leaderBoard.OverlayData.RaceEvents.GetRaceEdits(); if (raceEdits.Count() == 0) { throw new Exception("Unable to create highlight - try reducing time for highlight duration"); } var firstEdit = raceEdits.First(); var lastEdit = raceEdits.Last(); foreach (var editCut in raceEdits) { cut = AVOperations.Cut(editCut.StartTime.FromSecondsToNano(), editCut.EndTime.FromSecondsToNano(), AVOperations.FadeInOut(cut)); totalDuration -= editCut.EndTime.FromSecondsToNano() - editCut.StartTime.FromSecondsToNano(); } return(cut); }
public static Action<long, long> Concat(ISourceReader reader, ProcessSample transforms, Action<long, long> next, Func<bool> isAborted) { return (offsetA, offsetV) => { var newOffsetA = offsetA; var newOffsetV = offsetV; reader.SetCurrentPosition(0); var stream = FromSource(reader, isAborted); stream(s => { if (isAborted()) return false; if (s.Flags.EndOfStream) return false; if (s.Stream.CurrentMediaType.IsVideo) s.Resequence(offsetV); if (s.Stream.CurrentMediaType.IsAudio) s.Resequence(offsetA); var r = transforms(s); if (s.Stream.CurrentMediaType.IsVideo) newOffsetV = s.SampleTime; if (s.Stream.CurrentMediaType.IsAudio) newOffsetA = s.SampleTime; return r; }); next(newOffsetA, newOffsetV); }; }
public static ProcessSample Cut(long from, long to, ProcessSample beforeEdit, ProcessSample afterEdit) { var offset = to - from; var hasJumped = false; return sample => { if (sample.Flags.EndOfStream) return afterEdit(sample); if (from > sample.Duration) throw new Exception(string.Format("Error. Edit starting position beyond end of segment. {0}, {1}, {2}", from.FromNanoToSeconds(), sample.Duration.FromNanoToSeconds(), sample.Timestamp.FromNanoToSeconds())); if (to > sample.Duration) throw new Exception(string.Format("Error. Edit to position beyond end of segment. {0}, {1}", to.FromNanoToSeconds(), sample.Duration.FromNanoToSeconds())); if (sample.Timestamp < from) { sample.SegmentDuration = from; return beforeEdit(sample); } if (sample.Timestamp < to) { if (!hasJumped) sample.Reader.SetCurrentPosition(to); hasJumped = true; return true; } sample.SampleTime -= offset; sample.SegmentTimeStamp = sample.Timestamp - to; sample.SegmentDuration = sample.Duration - to; return afterEdit(sample); }; }
public static ProcessSample Cut(long from, long to, ProcessSample next) { return Cut(from, to, next, next); }
public static void StartConcat(ISourceReader reader, ProcessSample transforms, Action<long, long> next, Func<bool> isAborted) { Concat(reader, transforms, next, isAborted)(0, 0); }
public static ProcessSample FadeOut(ProcessSample next, long duration = TimingExtensions.OneNanoSecond) { return SeperateAudioVideo( aFadeOut(_AudioFadeOut(duration, next), duration, next), aFadeOut(_VideoFadeOut(duration, next), duration, next)); }
public static ProcessSample FadeInOut(ProcessSample next) { return FadeIn(FadeOut(next)); }
ProcessSample MonitorProgress(ProcessSample next) { return sample => { if (!sample.Flags.EndOfStream && progressReporter != null) progressReporter(sample.SampleTime, totalDuration); return next(sample); }; }
ProcessSample ApplyEdits(ProcessSample next) { var cut = next; var raceEdits = leaderBoard.OverlayData.RaceEvents.GetRaceEdits(); if (raceEdits.Count() == 0) throw new Exception("Unable to create highlight - try reducing time for highlight duration"); var firstEdit = raceEdits.First(); var lastEdit = raceEdits.Last(); foreach (var editCut in raceEdits) { cut = AVOperations.Cut(editCut.StartTime.FromSecondsToNano(), editCut.EndTime.FromSecondsToNano(), AVOperations.FadeInOut(cut)); totalDuration -= editCut.EndTime.FromSecondsToNano() - editCut.StartTime.FromSecondsToNano(); } return cut; }
static byte[] GetProcessSampleFileFromProcessId(int processId) { var logEntries = new List<string>(); void logLine(string lineText) { logEntries.Add(lineText); Console.WriteLine(lineText); } logLine("Reading from process " + processId + "."); var processHandle = OpenProcess( (int)(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryRead), false, processId); long address = 0; var committedRegions = new List<(ulong baseAddress, byte[] content)>(); do { MEMORY_BASIC_INFORMATION64 m; int result = VirtualQueryEx(processHandle, (IntPtr)address, out m, (uint)Marshal.SizeOf(typeof(MEMORY_BASIC_INFORMATION64))); var regionProtection = (MemoryInformationProtection)m.Protect; logLine($"{m.BaseAddress}-{(uint)m.BaseAddress + (uint)m.RegionSize - 1} : {m.RegionSize} bytes result={result}, state={(MemoryInformationState)m.State}, type={(MemoryInformationType)m.Type}, protection={regionProtection}"); if (address == (long)m.BaseAddress + (long)m.RegionSize) break; address = (long)m.BaseAddress + (long)m.RegionSize; if (m.State != (int)MemoryInformationState.MEM_COMMIT) continue; var protectionFlagsToSkip = MemoryInformationProtection.PAGE_GUARD | MemoryInformationProtection.PAGE_NOACCESS; var matchingFlagsToSkip = protectionFlagsToSkip & regionProtection; if (matchingFlagsToSkip != 0) { logLine($"Skipping region beginning at {m.BaseAddress:X} as it has flags {matchingFlagsToSkip}."); continue; } var regionBaseAddress = m.BaseAddress; int bytesRead = 0; byte[] regionContentBuffer = new byte[(long)m.RegionSize]; ReadProcessMemory(processHandle, regionBaseAddress, regionContentBuffer, regionContentBuffer.Length, ref bytesRead); if (bytesRead != regionContentBuffer.Length) throw new Exception($"Failed to ReadProcessMemory at 0x{regionBaseAddress:X}: Only read " + bytesRead + " bytes."); committedRegions.Add((regionBaseAddress, regionContentBuffer)); } while (true); logLine($"Found {committedRegions.Count} committed regions with a total size of {committedRegions.Select(region => region.content.Length).Sum()}."); return ProcessSample.ZipArchiveFromProcessSample(committedRegions.ToImmutableList(), logEntries.ToImmutableList()); }
public static ProcessSample FadeIn(ProcessSample next ) { return SeperateAudioVideo( FadeIn(_AudioFadeIn(next), next), FadeIn(_VideoFadeIn(next), next)); }
ProcessSample ApplyEdits(ProcessSample next) { var cut = next; var firstEdit = leaderBoard.OverlayData.RaceEvents.GetRaceEdits().First(); var lastEdit = leaderBoard.OverlayData.RaceEvents.GetRaceEdits().Last(); foreach (var editCut in leaderBoard.OverlayData.RaceEvents.GetRaceEdits()) { cut = AVOperations.Cut(editCut.StartTime.FromSecondsToNano(), editCut.EndTime.FromSecondsToNano(), AVOperations.FadeInOut(cut)); totalDuration -= editCut.EndTime.FromSecondsToNano() - editCut.StartTime.FromSecondsToNano(); } return cut; }
public static ProcessSample DataSamplesOnly(ProcessSample dataSamples, ProcessSample next) { return If(s => s.Sample != null, dataSamples, next); }
static int Main(string[] args) { (bool isPresent, string argumentValue) argumentFromParameterName(string parameterName) { var match = args .Select(arg => Regex.Match(arg, parameterName + "(=(.*)|)", RegexOptions.IgnoreCase)) .FirstOrDefault(matchCandidate => matchCandidate.Success); if (match == null) return (false, null); if (match.Groups[1].Length < 1) return (true, null); return (true, match?.Groups[2].Value); } var app = new CommandLineApplication { Name = "read-memory-64-bit", Description = "Read memory from 64 bit EVE Online client processes.", }; app.HelpOption(inherited: true); app.VersionOption(template: "-v|--version", shortFormVersion: "version " + AppVersionId); app.Command("save-process-sample", saveProcessSampleCmd => { saveProcessSampleCmd.Description = "Save a sample from a live process to a file. Use the '--pid' parameter to specify the process id."; saveProcessSampleCmd.ThrowOnUnexpectedArgument = false; saveProcessSampleCmd.OnExecute(() => { var processIdArgument = argumentFromParameterName("--pid"); if (!processIdArgument.isPresent) throw new Exception("Missing argument --pid for process ID."); var processId = int.Parse(processIdArgument.argumentValue); var processSampleFile = GetProcessSampleFileFromProcessId(processId); var processSampleId = Kalmit.CommonConversion.StringBase16FromByteArray(Kalmit.CommonConversion.HashSHA256(processSampleFile)); var fileName = "process-sample-" + processSampleId.Substring(0, 10) + ".zip"; System.IO.File.WriteAllBytes(fileName, processSampleFile); Console.WriteLine("Saved sample {0} to file '{1}'.", processSampleId, fileName); }); }); app.Command("read-memory-eve-online", readMemoryEveOnlineCmd => { readMemoryEveOnlineCmd.Description = "Read the memory of an 64 bit EVE Online client process. You can use a live process ('--pid') or a process sample file ('--source-file') as the source."; readMemoryEveOnlineCmd.ThrowOnUnexpectedArgument = false; readMemoryEveOnlineCmd.OnExecute(() => { var processIdArgument = argumentFromParameterName("--pid"); var sourceFileArgument = argumentFromParameterName("--source-file"); var outputFileArgument = argumentFromParameterName("--output-file"); var removeOtherDictEntriesArgument = argumentFromParameterName("--remove-other-dict-entries"); if (!processIdArgument.isPresent && !sourceFileArgument.isPresent) throw new Exception("Where should I read from?"); byte[] processSampleFile = null; if (processIdArgument.isPresent) { var processId = int.Parse(processIdArgument.argumentValue); processSampleFile = GetProcessSampleFileFromProcessId(processId); } if (sourceFileArgument.isPresent) { processSampleFile = System.IO.File.ReadAllBytes(sourceFileArgument.argumentValue); } var processSampleId = Kalmit.CommonConversion.StringBase16FromByteArray(Kalmit.CommonConversion.HashSHA256(processSampleFile)); Console.WriteLine($"Reading from process sample {processSampleId}."); var processSampleUnpacked = ProcessSample.ProcessSampleFromZipArchive(processSampleFile); var searchUIRootsStopwatch = System.Diagnostics.Stopwatch.StartNew(); var uiRootCandidatesAddresses = EveOnline64.EnumeratePossibleAddressesForUIRootObjects(processSampleUnpacked.memoryRegions) .ToImmutableList(); searchUIRootsStopwatch.Stop(); Console.WriteLine($"Found {uiRootCandidatesAddresses.Count} candidates for UIRoot in {(int)searchUIRootsStopwatch.Elapsed.TotalSeconds} seconds: " + string.Join(",", uiRootCandidatesAddresses.Select(address => $"0x{address:X}"))); var memoryReader = new MemoryReaderFromProcessSample(processSampleUnpacked.memoryRegions); var readUiTreesStopwatch = System.Diagnostics.Stopwatch.StartNew(); var uiTrees = uiRootCandidatesAddresses .Select(uiTreeRoot => EveOnline64.ReadUITreeFromAddress(uiTreeRoot, memoryReader, 99)) .Where(uiTree => uiTree != null) .ToImmutableList(); readUiTreesStopwatch.Stop(); var uiTreesWithStats = uiTrees .Select(uiTree => new { uiTree = uiTree, nodeCount = uiTree.EnumerateSelfAndDescendants().Count() }) .OrderByDescending(uiTreeWithStats => uiTreeWithStats.nodeCount) .ToImmutableList(); var uiTreesReport = uiTreesWithStats .Select(uiTreeWithStats => $"\n0x{uiTreeWithStats.uiTree.pythonObjectAddress:X}: {uiTreeWithStats.nodeCount} nodes.") .ToImmutableList(); Console.WriteLine($"Read {uiTrees.Count} UI trees in {(int)readUiTreesStopwatch.Elapsed.TotalSeconds} seconds:" + string.Join("", uiTreesReport)); var largestUiTree = uiTreesWithStats .OrderByDescending(uiTreeWithStats => uiTreeWithStats.nodeCount) .FirstOrDefault().uiTree; if (largestUiTree != null) { if (outputFileArgument.isPresent) { var uiTreePreparedForFile = largestUiTree; if (removeOtherDictEntriesArgument.isPresent) { uiTreePreparedForFile = uiTreePreparedForFile.WithOtherDictEntriesRemoved(); } var uiTreeAsJson = System.Text.Json.JsonSerializer.Serialize(uiTreePreparedForFile); var outputFilePath = outputFileArgument.argumentValue; System.IO.File.WriteAllText(outputFilePath, uiTreeAsJson, System.Text.Encoding.UTF8); Console.WriteLine($"I saved ui tree {largestUiTree.pythonObjectAddress:X} to file '{outputFilePath}'."); } else { Console.WriteLine("I found no configuration of an output file path."); } } }); }); app.OnExecute(() => { Console.WriteLine("Please specify a subcommand."); app.ShowHelp(); return 1; }); return app.Execute(args); }