Skip to content

Instantly share code, notes, and snippets.

@Micrologist
Created August 15, 2022 03:17
Show Gist options
  • Save Micrologist/b0eaa094ff947941d44818a681ed0838 to your computer and use it in GitHub Desktop.
Save Micrologist/b0eaa094ff947941d44818a681ed0838 to your computer and use it in GitHub Desktop.
using MemUtil;
using System.Diagnostics;
using System.Globalization;
Console.Write("Enter the name of the game process: ");
string? procName = Console.ReadLine()?.Replace(".exe", "");
List<Process> procList = Process.GetProcesses().ToList().FindAll(x => x.ProcessName == procName);
if (procList.Count == 0)
{
Console.WriteLine("Process not found!");
Console.ReadKey();
return;
}
Process game = procList[0];
var modules = game.ModulesWow64Safe();
var GetStaticPointerFromSig = (Func<string, int, IntPtr>)((signature, instructionOffset) =>
{
var scanner = new SignatureScanner(game, modules.First().BaseAddress, (int)modules.First().ModuleMemorySize);
var pattern = new SigScanTarget(signature);
var location = scanner.Scan(pattern);
if (location == IntPtr.Zero) return IntPtr.Zero;
int offset = game.ReadValue<int>((IntPtr)location + instructionOffset);
return (IntPtr)location + offset + instructionOffset + 0x4;
});
var FNamePool = GetStaticPointerFromSig("74 09 48 8D 15 ?? ?? ?? ?? EB 16", 0x5);
var UWorld = GetStaticPointerFromSig("0F 2E ?? 74 ?? 48 8B 1D ?? ?? ?? ?? 48 85 DB 74", 0x8);
var GetNameFromFName = (Func<long, string>)(longKey =>
{
int key = (int)(longKey & uint.MaxValue);
int partial = (int)(longKey >> 32);
int chunkOffset = key >> 16;
int nameOffset = (ushort)key;
IntPtr namePoolChunk = game.ReadValue<IntPtr>((IntPtr)FNamePool + ((chunkOffset + 2) * 0x8));
Int16 nameEntry = game.ReadValue<Int16>((IntPtr)namePoolChunk + (2 * nameOffset));
int nameLength = nameEntry >> 6;
string output = game.ReadString((IntPtr)namePoolChunk + (2 * nameOffset) + 2, nameLength);
return (partial == 0) ? output : output + "_" + partial.ToString();
});
Console.Write("Enter \"Levels\" offset (in hex): ");
string? levelsOffsetString = Console.ReadLine()?.Replace("0x", "");
if(!int.TryParse(levelsOffsetString, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int levelsOffset))
{
Console.WriteLine("invalid input");
Console.ReadKey();
return;
}
Console.Write("Enter \"StreamingLevels\" offset (in hex): ");
string? streamingLevelsOffsetString = Console.ReadLine()?.Replace("0x", "");
if (!int.TryParse(streamingLevelsOffsetString, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int streamingLevelsOffset))
{
Console.WriteLine("invalid input");
Console.ReadKey();
return;
}
string persistentLevelName = GetNameFromFName(new DeepPointer(UWorld, 0x30, 0x20, 0x20, 0x18).Deref<long>(game));
Console.WriteLine("\nPersistent Level: " + persistentLevelName);
IntPtr levelsPtr = new DeepPointer(UWorld, levelsOffset).Deref<IntPtr>(game);
int levelsCount = new DeepPointer(UWorld, levelsOffset + 0x8).Deref<int>(game);
Console.WriteLine("\nLevel Array at \"{0}\" containing {1} entries.", levelsPtr.ToString("X16"), levelsCount);
for (int i = 1; i < levelsCount; i++)
{
string levelName = GetNameFromFName(new DeepPointer(UWorld, levelsOffset, 0x8 * i, 0x20, 0x20, 0x18).Deref<long>(game));
Console.WriteLine(levelName);
}
IntPtr streamingLevelsPtr = new DeepPointer(UWorld, streamingLevelsOffset).Deref<IntPtr>(game);
int streamingLevelsCount = new DeepPointer(UWorld, streamingLevelsOffset + 0x8).Deref<int>(game);
Console.WriteLine("\nStreaming Level Array at \"{0}\" containing {1} entries.", streamingLevelsPtr.ToString("X16"), streamingLevelsCount);
for (int i = 0; i < streamingLevelsCount; i++)
{
string levelName = GetNameFromFName(new DeepPointer(UWorld, streamingLevelsOffset, 0x8 * i, 0x38).Deref<long>(game));
levelName = levelName[..levelName.LastIndexOf('.')];
Console.WriteLine(levelName);
}
Console.ReadKey();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment