public static bool AnyOverridesFor(string path, RuntimeProfile profile) { foreach (var item in profile.Mods) { if (item.OverridesFolder(path)) { return(true); } } return(false); }
public static OverrideFile MapFile(string file, RuntimeProfile profile) { foreach (var item in profile.Mods) { foreach (var entry in item.GetOverrides(file)) { if (entry.CFolder == null || entry.CFolder.IsActive(file)) { DebugLogger.WriteLine($"File {file} overridden by {entry.Archive}{entry.File}"); return(entry); } } } return(null); }
public static OverrideFile MapFile(string file, RuntimeProfile profile) { foreach (var item in profile.Mods) { foreach (var entry in item.GetOverrides(file)) { if (entry.CFolder == null || entry.CFolder.IsActive(file)) { System.Diagnostics.Debug.WriteLine("File {0} overridden by {2}{1}", file, entry.File, entry.Archive); return(entry); } } } return(null); }
public void Run(RemoteHooking.IContext context, RuntimeParams parms) { System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US", false); try { RuntimeProfile profile; using (var fs = new FileStream(parms.ProfileFile, FileMode.Open)) { profile = Iros._7th.Util.DeserializeBinary <RuntimeProfile>(fs); } File.Delete(parms.ProfileFile); if (!String.IsNullOrWhiteSpace(profile.LogFile)) { try { try { File.Delete(profile.LogFile); } catch { } // ensure old log is deleted since new run DebugLogger.Init(profile.LogFile); DebugLogger.IsDetailedLogging = profile.Options.HasFlag(RuntimeOptions.DetailedLog); DebugLogger.WriteLine("Logging debug output to " + profile.LogFile); } catch (Exception ex) { DebugLogger.WriteLine("Failed to log debug output: " + ex.ToString()); } } DebugLogger.WriteLine($"Wrap run... Host: {context.HostPID} PID: {RemoteHooking.GetCurrentProcessId()} TID: {RemoteHooking.GetCurrentThreadId()} Path: {profile.ModPath} Capture: {String.Join(", ", profile.MonitorPaths)}"); //_overrides = new Overrides(basepath); _profile = profile; for (int i = _profile.MonitorPaths.Count - 1; i >= 0; i--) { if (!_profile.MonitorPaths[i].EndsWith(System.IO.Path.DirectorySeparatorChar.ToString())) { _profile.MonitorPaths[i] += System.IO.Path.DirectorySeparatorChar; } if (String.IsNullOrWhiteSpace(_profile.MonitorPaths[i])) { _profile.MonitorPaths.RemoveAt(i); } } foreach (var item in profile.Mods) { DebugLogger.WriteLine($" Mod: {item.BaseFolder} has {item.Conditionals.Count} conditionals"); DebugLogger.WriteLine(" Additional paths: " + String.Join(", ", item.ExtraFolders)); item.Startup(); } _hCreateFileW = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"), new DCreateFile(HCreateFileW), this); _hCreateFileW.ThreadACL.SetExclusiveACL(new[] { 0 }); //_hCreateFileA = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateFileA"), new DCreateFileA(HCreateFileA), this); //_hCreateFileA.ThreadACL.SetExclusiveACL(new[] { 0 }); //int init = Init7W(); //_hReadFile = LocalHook.CreateUnmanaged(LocalHook.GetProcAddress("kernel32.dll", "ReadFile"), LocalHook.GetProcAddress("7thWrapperNLib.dll", "ReadFile7W"), IntPtr.Zero); _hReadFile = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "ReadFile"), new DReadFile(HReadFile), this); _hReadFile.ThreadACL.SetExclusiveACL(new[] { 0 }); _hWriteFile = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "WriteFile"), new DWriteFile(HWriteFile), this); _hWriteFile.ThreadACL.SetExclusiveACL(new[] { 0 }); _hFindFirstFile = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "FindFirstFileW"), new DFindFirstFileW(HFindFirstFile), this); _hFindFirstFile.ThreadACL.SetExclusiveACL(new[] { 0 }); //_hFindFirstFileA = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "FindFirstFileA"), new DFindFirstFileA(HFindFirstFileA), this); //_hFindFirstFile.ThreadACL.SetExclusiveACL(new[] { 0 }); _hSetFilePointer = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "SetFilePointer"), new DSetFilePointer(HSetFilePointer), this); _hSetFilePointer.ThreadACL.SetExclusiveACL(new[] { 0 }); _hSetFilePointerEx = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "SetFilePointerEx"), new DSetFilePointerEx(HSetFilePointerEx), this); _hSetFilePointerEx.ThreadACL.SetExclusiveACL(new[] { 0 }); _hCloseHandle = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CloseHandle"), new DCloseHandle(HCloseHandle), this); _hCloseHandle.ThreadACL.SetExclusiveACL(new[] { 0 }); _hGetFileType = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileType"), new DGetFileType(HGetFileType), this); _hGetFileType.ThreadACL.SetExclusiveACL(new[] { 0 }); _hGetFileInformationByHandle = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileInformationByHandle"), new DGetFileInformationByHandle(HGetFileInformationByHandle), this); _hGetFileInformationByHandle.ThreadACL.SetExclusiveACL(new[] { 0 }); //_hReadFileEx = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "ReadFileEx"), new DReadFileEx(HReadFileEx), this); //_hReadFileEx.ThreadACL.SetExclusiveACL(new[] { 0 }); _hDuplicateHandle = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "DuplicateHandle"), new DDuplicateHandle(HDuplicateHandle), this); _hDuplicateHandle.ThreadACL.SetExclusiveACL(new[] { 0 }); _hCreateProcessW = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "CreateProcessW"), new DCreateProcessW(HCreateProcessW), this); _hCreateProcessW.ThreadACL.SetExclusiveACL(new[] { 0 }); _hGetFileSize = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileSize"), new DGetFileSize(HGetFileSize), this); _hGetFileSize.ThreadACL.SetExclusiveACL(new[] { 0 }); _hGetFileSizeEx = LocalHook.Create(LocalHook.GetProcAddress("kernel32.dll", "GetFileSizeEx"), new DGetFileSizeEx(HGetFileSizeEx), this); _hGetFileSizeEx.ThreadACL.SetExclusiveACL(new[] { 0 }); if (profile.MonitorVars != null) { new System.Threading.Thread(MonitorThread) { IsBackground = true } } .Start(profile); //System.Threading.Thread.Sleep(10000); RemoteHooking.WakeUpProcess(); System.Threading.Thread.Sleep(1000); foreach (string LL in profile.Mods.SelectMany(m => m.GetLoadLibraries())) { DebugLogger.WriteLine($"Loading library DLL {LL}"); LoadLibrary(LL); } foreach (var mod in profile.Mods) { foreach (string LA in mod.GetLoadAssemblies()) { DebugLogger.WriteLine($"Loading assembly DLL {LA}"); var asm = System.Reflection.Assembly.LoadFrom(LA); try { string path = mod.BaseFolder; asm.GetType("_7thHeaven.Main") .GetMethod("Init", new[] { typeof(RuntimeMod) }) .Invoke(null, new object[] { mod }); } catch { } } } foreach (var mod in profile.Mods) { foreach (string file in mod.GetPathOverrideNames("hext")) { foreach (var of in mod.GetOverrides("hext\\" + file)) { System.IO.Stream s; if (of.Archive == null) { s = new System.IO.FileStream(of.File, FileMode.Open, FileAccess.Read); } else { s = of.Archive.GetData(of.File); } DebugLogger.WriteLine($"Applying hext patch {file} from mod {mod.BaseFolder}"); try { HexPatch.Apply(s); } catch (Exception ex) { DebugLogger.WriteLine("Error applying patch: " + ex.Message); } } } } } catch (Exception e) {
public LGPWrapper(IntPtr handle, string name, RuntimeProfile profile) { if (!AnyOverridesFor(name, profile)) { DebugLogger.WriteLine($"LGPWrapper: no overrides for {name}, early out"); return; //optimisation, don't run anything else, if no override files } IsActive = true; DebugLogger.WriteLine(" LGPWrapper: Parsing"); var fs = new System.IO.FileStream(new Microsoft.Win32.SafeHandles.SafeFileHandle(handle, false), FileAccess.Read); ProcMonParser.DataFile df = ProcMonParser.FF7Files.LoadLGP(fs, name); fs.Position = 0; Dictionary <string, int> sortKeys = df.Items.ToDictionary(i => i.Name, i => i.Index, StringComparer.InvariantCulture); Dictionary <string, long> dataKeys = df.Items.ToDictionary(i => i.Name, i => i.Start, StringComparer.InvariantCulture); Dictionary <string, int> filesSizes = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase); Dictionary <string, int> filesOptions = new Dictionary <string, int>(StringComparer.InvariantCultureIgnoreCase); Dictionary <string, ProcMonParser.DataItem> lgpItems = df.Items.ToDictionary(i => i.Name, i => i, StringComparer.InvariantCulture); foreach (var item in df.Items) { filesOptions[item.Name] = 0; filesSizes[item.Name] = item.Length - 24; DebugLogger.DetailedWriteLine($"Checking chunk support for {name}~{item.Name}~"); if (profile.Mods.Any(m => m.SupportsChunks(System.IO.Path.Combine(name, item.Name)))) { filesSizes[item.Name] = Math.Max(filesSizes[item.Name], 1024 * 1024 * 2); //This is a horrible hack. TODO. filesOptions[item.Name] |= 0x1; } } DebugLogger.WriteLine(" LGPWrapper: Prepared structures"); List <string> names = profile.Mods.SelectMany(m => m.GetPathOverrideNames(name)).Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); foreach (string fname in names) { if (fname.IndexOf(".chunk.", StringComparison.InvariantCultureIgnoreCase) >= 0) { continue; } if (!filesSizes.ContainsKey(fname)) { filesSizes[fname] = 0; DebugLogger.WriteLine($"Added LGP file {name} {fname}"); } var overrides = profile.Mods.SelectMany(m => m.GetOverrides(System.IO.Path.Combine(name, fname))); foreach (var over in overrides) { filesSizes[fname] = Math.Max(filesSizes[fname], over.Size); if (over.CFolder == null) { break; } } } List <LGPEntry> entries = filesSizes.Select(kv => new LGPEntry(kv.Key, kv.Value)).ToList(); List <LGP.LGPEntryMade> newentries; DebugLogger.WriteLine(" LGPWrapper: creating new headers"); byte[] headers = LGP.CalculateHeaders(entries, s => { int index; sortKeys.TryGetValue(s, out index); return(index); }, s => { long index; dataKeys.TryGetValue(s, out index); return((uint)index); }, out newentries ); int datastart = headers.Length; DebugLogger.WriteLine($" LGPWrapper: Calculated new LGP headers for {name} with {entries.Count} file entries"); /* * int datastart = df.Items[0].Start; * byte[] headers = new byte[datastart]; * fs.Read(headers, 0, datastart); * fs.Position = 0; */ uint offset = (uint)datastart; VFile = new VFile(); try { VFile.Add(new VRangeInline() { Start = 0, Length = offset, Data = headers, Tag = "Headers" }); int count = 0; foreach (var item in newentries.OrderBy(em => em.DataIndex)) { DebugLogger.DetailedWriteLine($"LGPWrapper calculate {item.Entry.Name}"); //Bytes.WriteUInt(headers, 16 + 20 + 27 * item.Index, offset); string fn = System.IO.Path.Combine(name, item.Entry.Name); var overrides = profile.Mods.SelectMany(m => m.GetOverrides(fn)); int fOptions; filesOptions.TryGetValue(item.Entry.Name, out fOptions); bool chunked = (fOptions & 0x1) != 0; //var overrides = Enumerable.Empty<OverrideFile>(); //DebugLogger.WriteLine("Virtualizing LGP entry {0} at offset {1}", item.Entry.Name, offset); if (item.DataOffset != offset) { throw new Exception("LGPWrapper mismatch on offset for " + item.Entry.Name + " offset=" + offset + " hoffset=" + item.DataOffset); } if (chunked) { long pos = lgpItems[item.Entry.Name].Start + 24; int len = lgpItems[item.Entry.Name].Length - 24; VFile.Add(new VRangeChunked(item.Entry.Name, profile.Mods, handle, (uint)pos, len) { Start = offset, Length = (uint)(item.Entry.MaxSize + 24), Name = fn, Tag = "Chunked" }); //DebugLogger.WriteLine("File {0} initialized with chunks", item.Entry.Name, 0); offset += (uint)item.Entry.MaxSize + 24; } else if (!overrides.Any()) //take from original LGP { long pos = lgpItems[item.Entry.Name].Start; VFile.Add(new VRangeHandle() { Start = offset, Length = (uint)(item.Entry.MaxSize + 24), Handle = handle, Offset = (uint)pos, Tag = item.Entry.Name }); offset += (uint)item.Entry.MaxSize + 24; //DebugLogger.WriteLine("--VRangeHandle"); } else if (overrides.First().CFolder == null) //only one override, replace directly { var ov = overrides.First(); byte[] fheader = new byte[24]; System.Text.Encoding.ASCII.GetBytes(item.Entry.Name, 0, item.Entry.Name.Length, fheader, 0); Bytes.WriteUInt(fheader, 20, (uint)ov.Size); VFile.Add(new VRangeInline() { Start = offset, Length = 24, Data = fheader, Tag = item.Entry.Name + "%header" }); offset += 24; VRange vr; if (ov.Archive == null) { var vf = new VRangeFile() { Start = offset, Length = (uint)ov.Size, Filename = ov.File, Tag = ov.File }; VFile.Add(vf); _wFiles.Add(vf); vr = vf; //DebugLogger.WriteLine("LGP entry {0} coming from file {1}", item.Entry.Name, ov.File); } else { vr = new VRangeArchive() { Start = offset, Length = (uint)ov.Size, File = ov.File, Archive = ov.Archive, Tag = ov.File }; VFile.Add(vr); //DebugLogger.WriteLine("LGP entry {0} coming from archive file {1} with size {2}", item.Entry.Name, ov.File, ov.Size); } //if (vr.Length != item.Entry.MaxSize) //DebugLogger.WriteLine("Entry {0} size difference {1} vs {2}", item.Entry.Name, vr.Length, item.Entry.MaxSize); if (vr.Length < item.Entry.MaxSize) { uint diff = (uint)item.Entry.MaxSize - vr.Length; VFile.Add(new VRangeNull() { Length = diff, Start = vr.Start + vr.Length, Tag = "Padding" }); } offset += (uint)item.Entry.MaxSize; //DebugLogger.WriteLine("--VRangeFile"); } else //multiple overrides; tricky! //DebugLogger.WriteLine("Add VRangeConditional for " + item.Entry.Name); { ProcMonParser.DataItem di; lgpItems.TryGetValue(item.Entry.Name, out di); uint fbOffset = (di == null) ? 0 : (uint)di.Start; var vcond = new VRangeConditional(item.Entry.Name, overrides.ToList(), handle, fbOffset) { Length = (uint)item.Entry.MaxSize + 24, Start = offset, Name = item.Entry.Name, Tag = item.Entry.Name }; VFile.Add(vcond); _wFiles.Add(vcond); offset += (uint)item.Entry.MaxSize + 24; //DebugLogger.WriteLine("--VRangeConditional"); } count++; /* * string file = MapFile(System.IO.Path.Combine(name, item.Name), profile); * if (file != null) { * uint length = (uint)new System.IO.FileInfo(file).Length; * byte[] fheader = new byte[24]; * System.Text.Encoding.ASCII.GetBytes(item.Name, 0, item.Name.Length, fheader, 0); * Bytes.WriteUInt(fheader, 20, length); * VFile.Add(new VRangeInline() { Start = offset, Length = 24, Data = fheader }); * offset += 24; * var vf = new VRangeFile() { Start = offset, Length = length, Filename = file }; * VFile.Add(vf); * _wFiles.Add(vf); * offset += length; * } else { * VFile.Add(new VRangeHandle() { Start = offset, Length = (uint)(item.Length), Handle = handle, Offset = (uint)item.Start }); * offset += (uint)item.Length; * }*/ } byte[] footer = System.Text.Encoding.ASCII.GetBytes("FINAL FANTASY7"); VFile.Add(new VRangeInline() { Start = offset, Length = (uint)footer.Length, Data = footer, Tag = "footer" }); DebugLogger.WriteLine("Created: " + VFile.ToString()); } catch { VFile.Dump(); throw; } }