mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 20:24:17 +01:00
Some cleanup of PeSigScanner.
This commit is contained in:
parent
8351b74b21
commit
0db70c89b1
2 changed files with 57 additions and 65 deletions
|
|
@ -17,7 +17,5 @@ public sealed class PapHandler(PapRewriter.PapResourceHandlerPrototype papResour
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
=> _papRewriter.Dispose();
|
||||||
_papRewriter.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,65 +5,56 @@ using Decoder = Iced.Intel.Decoder;
|
||||||
|
|
||||||
namespace Penumbra.Interop.Hooks.ResourceLoading;
|
namespace Penumbra.Interop.Hooks.ResourceLoading;
|
||||||
|
|
||||||
// A good chunk of this was blatantly stolen from Dalamud's SigScanner 'cause I could not be faffed, maybe I'll rewrite it later
|
// A good chunk of this was blatantly stolen from Dalamud's SigScanner 'cause Winter could not be faffed, Winter will definitely not rewrite it later
|
||||||
public class PeSigScanner : IDisposable
|
public unsafe class PeSigScanner : IDisposable
|
||||||
{
|
{
|
||||||
private MemoryMappedFile File { get; }
|
private readonly MemoryMappedFile _file;
|
||||||
|
private readonly MemoryMappedViewAccessor _textSection;
|
||||||
|
|
||||||
|
private readonly nint _moduleBaseAddress;
|
||||||
|
private readonly uint _textSectionVirtualAddress;
|
||||||
|
|
||||||
|
|
||||||
private uint TextSectionStart { get; }
|
|
||||||
private uint TextSectionSize { get; }
|
|
||||||
|
|
||||||
private IntPtr ModuleBaseAddress { get; }
|
|
||||||
private uint TextSectionVirtualAddress { get; }
|
|
||||||
|
|
||||||
private MemoryMappedViewAccessor TextSection { get; }
|
|
||||||
|
|
||||||
|
|
||||||
public PeSigScanner()
|
public PeSigScanner()
|
||||||
{
|
{
|
||||||
var mainModule = Process.GetCurrentProcess().MainModule!;
|
var mainModule = Process.GetCurrentProcess().MainModule!;
|
||||||
var fileName = mainModule.FileName;
|
var fileName = mainModule.FileName;
|
||||||
ModuleBaseAddress = mainModule.BaseAddress;
|
_moduleBaseAddress = mainModule.BaseAddress;
|
||||||
|
|
||||||
if (fileName == null)
|
if (fileName == null)
|
||||||
{
|
throw new Exception("Unable to obtain main module path. This should not happen.");
|
||||||
throw new Exception("Can't get main module path, the fuck is going on?");
|
|
||||||
}
|
|
||||||
|
|
||||||
File = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, null, 0, MemoryMappedFileAccess.Read);
|
|
||||||
|
|
||||||
using var fileStream = File.CreateViewStream(0, 0, MemoryMappedFileAccess.Read);
|
_file = MemoryMappedFile.CreateFromFile(fileName, FileMode.Open, null, 0, MemoryMappedFileAccess.Read);
|
||||||
|
|
||||||
|
using var fileStream = _file.CreateViewStream(0, 0, MemoryMappedFileAccess.Read);
|
||||||
var pe = new PeFile(fileStream);
|
var pe = new PeFile(fileStream);
|
||||||
|
|
||||||
var textSection = pe.ImageSectionHeaders!.First(header => header.Name == ".text");
|
var textSection = pe.ImageSectionHeaders!.First(header => header.Name == ".text");
|
||||||
|
|
||||||
TextSectionStart = textSection.PointerToRawData;
|
var textSectionStart = textSection.PointerToRawData;
|
||||||
TextSectionSize = textSection.SizeOfRawData;
|
var textSectionSize = textSection.SizeOfRawData;
|
||||||
TextSectionVirtualAddress = textSection.VirtualAddress;
|
_textSectionVirtualAddress = textSection.VirtualAddress;
|
||||||
|
|
||||||
TextSection = File.CreateViewAccessor(TextSectionStart, TextSectionSize, MemoryMappedFileAccess.Read);
|
_textSection = _file.CreateViewAccessor(textSectionStart, textSectionSize, MemoryMappedFileAccess.Read);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private IntPtr ScanText(string signature)
|
private nint ScanText(string signature)
|
||||||
{
|
{
|
||||||
var scanRet = Scan(TextSection, signature);
|
var scanRet = Scan(_textSection, signature);
|
||||||
|
if (*(byte*)scanRet is 0xE8 or 0xE9)
|
||||||
var instrByte = Marshal.ReadByte(scanRet);
|
|
||||||
|
|
||||||
if (instrByte is 0xE8 or 0xE9)
|
|
||||||
scanRet = ReadJmpCallSig(scanRet);
|
scanRet = ReadJmpCallSig(scanRet);
|
||||||
|
|
||||||
return scanRet;
|
return scanRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntPtr ReadJmpCallSig(IntPtr sigLocation)
|
private static nint ReadJmpCallSig(nint sigLocation)
|
||||||
{
|
{
|
||||||
var jumpOffset = Marshal.ReadInt32(sigLocation, 1);
|
var jumpOffset = *(int*)(sigLocation + 1);
|
||||||
return IntPtr.Add(sigLocation, 5 + jumpOffset);
|
return sigLocation + 5 + jumpOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryScanText(string signature, out IntPtr result)
|
public bool TryScanText(string signature, out nint result)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -72,21 +63,22 @@ public class PeSigScanner : IDisposable
|
||||||
}
|
}
|
||||||
catch (KeyNotFoundException)
|
catch (KeyNotFoundException)
|
||||||
{
|
{
|
||||||
result = IntPtr.Zero;
|
result = nint.Zero;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntPtr Scan(MemoryMappedViewAccessor section, string signature)
|
private nint Scan(MemoryMappedViewAccessor section, string signature)
|
||||||
{
|
{
|
||||||
var (needle, mask) = ParseSignature(signature);
|
var (needle, mask) = ParseSignature(signature);
|
||||||
|
|
||||||
var index = IndexOf(section, needle, mask);
|
var index = IndexOf(section, needle, mask);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
throw new KeyNotFoundException($"Can't find a signature of {signature}");
|
throw new KeyNotFoundException($"Can't find a signature of {signature}");
|
||||||
return new IntPtr(ModuleBaseAddress + index - section.PointerOffset + TextSectionVirtualAddress);
|
|
||||||
|
return (nint)(_moduleBaseAddress + index - section.PointerOffset + _textSectionVirtualAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (byte[] Needle, bool[] Mask) ParseSignature(string signature)
|
private static (byte[] Needle, bool[] Mask) ParseSignature(string signature)
|
||||||
{
|
{
|
||||||
signature = signature.Replace(" ", string.Empty);
|
signature = signature.Replace(" ", string.Empty);
|
||||||
|
|
@ -99,7 +91,7 @@ public class PeSigScanner : IDisposable
|
||||||
for (var i = 0; i < needleLength; i++)
|
for (var i = 0; i < needleLength; i++)
|
||||||
{
|
{
|
||||||
var hexString = signature.Substring(i * 2, 2);
|
var hexString = signature.Substring(i * 2, 2);
|
||||||
if (hexString == "??" || hexString == "**")
|
if (hexString is "??" or "**")
|
||||||
{
|
{
|
||||||
needle[i] = 0;
|
needle[i] = 0;
|
||||||
mask[i] = true;
|
mask[i] = true;
|
||||||
|
|
@ -112,10 +104,12 @@ public class PeSigScanner : IDisposable
|
||||||
|
|
||||||
return (needle, mask);
|
return (needle, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe int IndexOf(MemoryMappedViewAccessor section, byte[] needle, bool[] mask)
|
private static int IndexOf(MemoryMappedViewAccessor section, byte[] needle, bool[] mask)
|
||||||
{
|
{
|
||||||
if (needle.Length > section.Capacity) return -1;
|
if (needle.Length > section.Capacity)
|
||||||
|
return -1;
|
||||||
|
|
||||||
var badShift = BuildBadCharTable(needle, mask);
|
var badShift = BuildBadCharTable(needle, mask);
|
||||||
var last = needle.Length - 1;
|
var last = needle.Length - 1;
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
@ -144,19 +138,19 @@ public class PeSigScanner : IDisposable
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static int[] BuildBadCharTable(byte[] needle, bool[] mask)
|
private static int[] BuildBadCharTable(byte[] needle, bool[] mask)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
var last = needle.Length - 1;
|
var last = needle.Length - 1;
|
||||||
var badShift = new int[256];
|
var badShift = new int[256];
|
||||||
for (idx = last; idx > 0 && !mask[idx]; --idx)
|
for (idx = last; idx > 0 && !mask[idx]; --idx)
|
||||||
{
|
{ }
|
||||||
}
|
|
||||||
|
|
||||||
var diff = last - idx;
|
var diff = last - idx;
|
||||||
if (diff == 0) diff = 1;
|
if (diff == 0)
|
||||||
|
diff = 1;
|
||||||
|
|
||||||
for (idx = 0; idx <= 255; ++idx)
|
for (idx = 0; idx <= 255; ++idx)
|
||||||
badShift[idx] = diff;
|
badShift[idx] = diff;
|
||||||
|
|
@ -164,16 +158,16 @@ public class PeSigScanner : IDisposable
|
||||||
badShift[needle[idx]] = last - idx;
|
badShift[needle[idx]] = last - idx;
|
||||||
return badShift;
|
return badShift;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detects function termination; this is done in a really stupid way that will possibly break if looked at wrong, but it'll work for now
|
// Detects function termination; this is done in a really stupid way that will possibly break if looked at wrong, but it'll work for now
|
||||||
// If this shits itself, go bother Winter to implement proper CFG + basic block detection
|
// If this shits itself, go bother Winter to implement proper CFG + basic block detection
|
||||||
public IEnumerable<Instruction> GetFunctionInstructions(IntPtr addr)
|
public IEnumerable<Instruction> GetFunctionInstructions(nint address)
|
||||||
{
|
{
|
||||||
var fileOffset = addr - TextSectionVirtualAddress - ModuleBaseAddress;
|
var fileOffset = address - _textSectionVirtualAddress - _moduleBaseAddress;
|
||||||
|
|
||||||
var codeReader = new MappedCodeReader(TextSection, fileOffset);
|
var codeReader = new MappedCodeReader(_textSection, fileOffset);
|
||||||
var decoder = Decoder.Create(64, codeReader, (ulong)addr.ToInt64());
|
var decoder = Decoder.Create(64, codeReader, (ulong)address.ToInt64());
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
decoder.Decode(out var instr);
|
decoder.Decode(out var instr);
|
||||||
|
|
@ -188,7 +182,7 @@ public class PeSigScanner : IDisposable
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
TextSection.Dispose();
|
_textSection.Dispose();
|
||||||
File.Dispose();
|
_file.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue