Update TamperMachine and disable write-to-code prevention (#2506)
* Enable write to memory and improve logging * Update tamper machine opcodes and improve reporting * Add Else support * Add missing private statement
This commit is contained in:
parent
a27986c311
commit
ff8849671a
15 changed files with 156 additions and 66 deletions
|
@ -1,9 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.Exceptions
|
|
||||||
{
|
|
||||||
public class CodeRegionTamperedException : TamperExecutionException
|
|
||||||
{
|
|
||||||
public CodeRegionTamperedException(string message) : base(message) { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,13 +8,17 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
public IEnumerable<string> BuildIds { get; }
|
public IEnumerable<string> BuildIds { get; }
|
||||||
public IEnumerable<ulong> CodeAddresses { get; }
|
public IEnumerable<ulong> CodeAddresses { get; }
|
||||||
public ulong HeapAddress { get; }
|
public ulong HeapAddress { get; }
|
||||||
|
public ulong AliasAddress { get; }
|
||||||
|
public ulong AslrAddress { get; }
|
||||||
|
|
||||||
public ProcessTamperInfo(KProcess process, IEnumerable<string> buildIds, IEnumerable<ulong> codeAddresses, ulong heapAddress)
|
public ProcessTamperInfo(KProcess process, IEnumerable<string> buildIds, IEnumerable<ulong> codeAddresses, ulong heapAddress, ulong aliasAddress, ulong aslrAddress)
|
||||||
{
|
{
|
||||||
Process = process;
|
Process = process;
|
||||||
BuildIds = buildIds;
|
BuildIds = buildIds;
|
||||||
CodeAddresses = codeAddresses;
|
CodeAddresses = codeAddresses;
|
||||||
HeapAddress = heapAddress;
|
HeapAddress = heapAddress;
|
||||||
|
AliasAddress = aliasAddress;
|
||||||
|
AslrAddress = aslrAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -658,7 +658,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.ModLoader, $"Installing cheat '{cheat.Name}'");
|
Logger.Info?.Print(LogClass.ModLoader, $"Installing cheat '{cheat.Name}'");
|
||||||
|
|
||||||
tamperMachine.InstallAtmosphereCheat(cheat.Instructions, tamperInfo, exeAddress);
|
tamperMachine.InstallAtmosphereCheat(cheat.Name, cheat.Instructions, tamperInfo, exeAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -280,7 +280,8 @@ namespace Ryujinx.HLE.HOS
|
||||||
// Keep the build ids because the tamper machine uses them to know which process to associate a
|
// Keep the build ids because the tamper machine uses them to know which process to associate a
|
||||||
// tamper to and also keep the starting address of each executable inside a process because some
|
// tamper to and also keep the starting address of each executable inside a process because some
|
||||||
// memory modifications are relative to this address.
|
// memory modifications are relative to this address.
|
||||||
tamperInfo = new ProcessTamperInfo(process, buildIds, nsoBase, process.MemoryManager.HeapRegionStart);
|
tamperInfo = new ProcessTamperInfo(process, buildIds, nsoBase, process.MemoryManager.HeapRegionStart,
|
||||||
|
process.MemoryManager.AliasRegionStart, process.MemoryManager.CodeRegionStart);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,36 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
{
|
{
|
||||||
class AtmosphereCompiler
|
class AtmosphereCompiler
|
||||||
{
|
{
|
||||||
public ITamperProgram Compile(IEnumerable<string> rawInstructions, ulong exeAddress, ulong heapAddress, ITamperedProcess process)
|
private ulong _exeAddress;
|
||||||
|
private ulong _heapAddress;
|
||||||
|
private ulong _aliasAddress;
|
||||||
|
private ulong _aslrAddress;
|
||||||
|
private ITamperedProcess _process;
|
||||||
|
|
||||||
|
public AtmosphereCompiler(ulong exeAddress, ulong heapAddress, ulong aliasAddress, ulong aslrAddress, ITamperedProcess process)
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, $"Executable address: {exeAddress:X16}");
|
_exeAddress = exeAddress;
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, $"Heap address: {heapAddress:X16}");
|
_heapAddress = heapAddress;
|
||||||
|
_aliasAddress = aliasAddress;
|
||||||
|
_aslrAddress = aslrAddress;
|
||||||
|
_process = process;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITamperProgram Compile(string name, IEnumerable<string> rawInstructions)
|
||||||
|
{
|
||||||
|
string[] addresses = new string[]
|
||||||
|
{
|
||||||
|
$" Executable address: 0x{_exeAddress:X16}",
|
||||||
|
$" Heap address : 0x{_heapAddress:X16}",
|
||||||
|
$" Alias address : 0x{_aliasAddress:X16}",
|
||||||
|
$" Aslr address : 0x{_aslrAddress:X16}"
|
||||||
|
};
|
||||||
|
|
||||||
|
Logger.Debug?.Print(LogClass.TamperMachine, $"Compiling Atmosphere cheat {name}...\n{string.Join('\n', addresses)}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return CompileImpl(rawInstructions, exeAddress, heapAddress, process);
|
return CompileImpl(name, rawInstructions);
|
||||||
}
|
}
|
||||||
catch(TamperCompilationException exception)
|
catch(TamperCompilationException exception)
|
||||||
{
|
{
|
||||||
|
@ -33,9 +55,9 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ITamperProgram CompileImpl(IEnumerable<string> rawInstructions, ulong exeAddress, ulong heapAddress, ITamperedProcess process)
|
private ITamperProgram CompileImpl(string name, IEnumerable<string> rawInstructions)
|
||||||
{
|
{
|
||||||
CompilationContext context = new CompilationContext(exeAddress, heapAddress, process);
|
CompilationContext context = new CompilationContext(_exeAddress, _heapAddress, _aliasAddress, _aslrAddress, _process);
|
||||||
context.BlockStack.Push(new OperationBlock(null));
|
context.BlockStack.Push(new OperationBlock(null));
|
||||||
|
|
||||||
// Parse the instructions.
|
// Parse the instructions.
|
||||||
|
@ -124,7 +146,7 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
throw new TamperCompilationException($"Reached end of compilation with unmatched conditional(s) or loop(s)");
|
throw new TamperCompilationException($"Reached end of compilation with unmatched conditional(s) or loop(s)");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AtmosphereProgram(process, context.PressedKeys, new Block(context.CurrentOperations));
|
return new AtmosphereProgram(name, _process, context.PressedKeys, new Block(context.CurrentOperations));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,13 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
private Parameter<long> _pressedKeys;
|
private Parameter<long> _pressedKeys;
|
||||||
private IOperation _entryPoint;
|
private IOperation _entryPoint;
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public bool TampersCodeMemory { get; set; } = false;
|
||||||
public ITamperedProcess Process { get; }
|
public ITamperedProcess Process { get; }
|
||||||
|
|
||||||
public AtmosphereProgram(ITamperedProcess process, Parameter<long> pressedKeys, IOperation entryPoint)
|
public AtmosphereProgram(string name, ITamperedProcess process, Parameter<long> pressedKeys, IOperation entryPoint)
|
||||||
{
|
{
|
||||||
|
Name = name;
|
||||||
Process = process;
|
Process = process;
|
||||||
_pressedKeys = pressedKeys;
|
_pressedKeys = pressedKeys;
|
||||||
_entryPoint = entryPoint;
|
_entryPoint = entryPoint;
|
||||||
|
|
|
@ -10,32 +10,73 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class EndConditionalBlock
|
class EndConditionalBlock
|
||||||
{
|
{
|
||||||
|
const int TerminationTypeIndex = 1;
|
||||||
|
|
||||||
|
private const byte End = 0; // True end of the conditional.
|
||||||
|
private const byte Else = 1; // End of the 'then' block and beginning of 'else' block.
|
||||||
|
|
||||||
public static void Emit(byte[] instruction, CompilationContext context)
|
public static void Emit(byte[] instruction, CompilationContext context)
|
||||||
{
|
{
|
||||||
// 20000000
|
Emit(instruction, context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Emit(byte[] instruction, CompilationContext context, IEnumerable<IOperation> operationsElse)
|
||||||
|
{
|
||||||
|
// 2X000000
|
||||||
|
// X: End type (0 = End, 1 = Else).
|
||||||
|
|
||||||
|
byte terminationType = instruction[TerminationTypeIndex];
|
||||||
|
|
||||||
|
switch (terminationType)
|
||||||
|
{
|
||||||
|
case End:
|
||||||
|
break;
|
||||||
|
case Else:
|
||||||
|
// Start a new operation block with the 'else' instruction to signal that there is the 'then' block just above it.
|
||||||
|
context.BlockStack.Push(new OperationBlock(instruction));
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new TamperCompilationException($"Unknown conditional termination type {terminationType}");
|
||||||
|
}
|
||||||
|
|
||||||
// Use the conditional begin instruction stored in the stack.
|
// Use the conditional begin instruction stored in the stack.
|
||||||
instruction = context.CurrentBlock.BaseInstruction;
|
var upperInstruction = context.CurrentBlock.BaseInstruction;
|
||||||
CodeType codeType = InstructionHelper.GetCodeType(instruction);
|
CodeType codeType = InstructionHelper.GetCodeType(upperInstruction);
|
||||||
|
|
||||||
// Pop the current block of operations from the stack so control instructions
|
// Pop the current block of operations from the stack so control instructions
|
||||||
// for the conditional can be emitted in the upper block.
|
// for the conditional can be emitted in the upper block.
|
||||||
IEnumerable<IOperation> operations = context.CurrentOperations;
|
IEnumerable<IOperation> operations = context.CurrentOperations;
|
||||||
context.BlockStack.Pop();
|
context.BlockStack.Pop();
|
||||||
|
|
||||||
|
// If the else operations are already set, then the upper block must not be another end.
|
||||||
|
if (operationsElse != null && codeType == CodeType.EndConditionalBlock)
|
||||||
|
{
|
||||||
|
throw new TamperCompilationException($"Expected an upper 'if' conditional instead of 'end conditional'");
|
||||||
|
}
|
||||||
|
|
||||||
ICondition condition;
|
ICondition condition;
|
||||||
|
|
||||||
switch (codeType)
|
switch (codeType)
|
||||||
{
|
{
|
||||||
case CodeType.BeginMemoryConditionalBlock:
|
case CodeType.BeginMemoryConditionalBlock:
|
||||||
condition = MemoryConditional.Emit(instruction, context);
|
condition = MemoryConditional.Emit(upperInstruction, context);
|
||||||
break;
|
break;
|
||||||
case CodeType.BeginKeypressConditionalBlock:
|
case CodeType.BeginKeypressConditionalBlock:
|
||||||
condition = KeyPressConditional.Emit(instruction, context);
|
condition = KeyPressConditional.Emit(upperInstruction, context);
|
||||||
break;
|
break;
|
||||||
case CodeType.BeginRegisterConditionalBlock:
|
case CodeType.BeginRegisterConditionalBlock:
|
||||||
condition = RegisterConditional.Emit(instruction, context);
|
condition = RegisterConditional.Emit(upperInstruction, context);
|
||||||
break;
|
break;
|
||||||
|
case CodeType.EndConditionalBlock:
|
||||||
|
terminationType = upperInstruction[TerminationTypeIndex];
|
||||||
|
// If there is an end instruction above then it must be an else.
|
||||||
|
if (terminationType != Else)
|
||||||
|
{
|
||||||
|
throw new TamperCompilationException($"Expected an upper 'else' conditional instead of {terminationType}");
|
||||||
|
}
|
||||||
|
// Re-run the Emit with the else operations set.
|
||||||
|
Emit(instruction, context, operations);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
throw new TamperCompilationException($"Conditional end does not match code type {codeType} in Atmosphere cheat");
|
throw new TamperCompilationException($"Conditional end does not match code type {codeType} in Atmosphere cheat");
|
||||||
}
|
}
|
||||||
|
@ -43,7 +84,7 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
|
||||||
// Create a conditional block with the current operations and nest it in the upper
|
// Create a conditional block with the current operations and nest it in the upper
|
||||||
// block of the stack.
|
// block of the stack.
|
||||||
|
|
||||||
IfBlock block = new IfBlock(condition, operations);
|
IfBlock block = new IfBlock(condition, operations, operationsElse);
|
||||||
context.CurrentOperations.Add(block);
|
context.CurrentOperations.Add(block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,10 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
public Dictionary<byte, Register> StaticRegisters { get; }
|
public Dictionary<byte, Register> StaticRegisters { get; }
|
||||||
public ulong ExeAddress { get; }
|
public ulong ExeAddress { get; }
|
||||||
public ulong HeapAddress { get; }
|
public ulong HeapAddress { get; }
|
||||||
|
public ulong AliasAddress { get; }
|
||||||
|
public ulong AslrAddress { get; }
|
||||||
|
|
||||||
public CompilationContext(ulong exeAddress, ulong heapAddress, ITamperedProcess process)
|
public CompilationContext(ulong exeAddress, ulong heapAddress, ulong aliasAddress, ulong aslrAddress, ITamperedProcess process)
|
||||||
{
|
{
|
||||||
Process = process;
|
Process = process;
|
||||||
PressedKeys = new Parameter<long>(0);
|
PressedKeys = new Parameter<long>(0);
|
||||||
|
@ -31,6 +33,8 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
StaticRegisters = new Dictionary<byte, Register>();
|
StaticRegisters = new Dictionary<byte, Register>();
|
||||||
ExeAddress = exeAddress;
|
ExeAddress = exeAddress;
|
||||||
HeapAddress = heapAddress;
|
HeapAddress = heapAddress;
|
||||||
|
AliasAddress = aliasAddress;
|
||||||
|
AslrAddress = aslrAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Register GetRegister(byte index)
|
public Register GetRegister(byte index)
|
||||||
|
|
|
@ -4,6 +4,8 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
{
|
{
|
||||||
interface ITamperProgram
|
interface ITamperProgram
|
||||||
{
|
{
|
||||||
|
string Name { get; }
|
||||||
|
bool TampersCodeMemory { get; set; }
|
||||||
ITamperedProcess Process { get; }
|
ITamperedProcess Process { get; }
|
||||||
void Execute(ControllerKeys pressedKeys);
|
void Execute(ControllerKeys pressedKeys);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
interface ITamperedProcess
|
interface ITamperedProcess
|
||||||
{
|
{
|
||||||
ProcessState State { get; }
|
ProcessState State { get; }
|
||||||
|
|
||||||
|
bool TamperedCodeMemory { get; set; }
|
||||||
|
|
||||||
T ReadMemory<T>(ulong va) where T : unmanaged;
|
T ReadMemory<T>(ulong va) where T : unmanaged;
|
||||||
void WriteMemory<T>(ulong va, T value) where T : unmanaged;
|
void WriteMemory<T>(ulong va, T value) where T : unmanaged;
|
||||||
void PauseProcess();
|
void PauseProcess();
|
||||||
|
|
|
@ -15,6 +15,12 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
case MemoryRegion.Heap:
|
case MemoryRegion.Heap:
|
||||||
// Memory address is relative to the heap.
|
// Memory address is relative to the heap.
|
||||||
return context.HeapAddress;
|
return context.HeapAddress;
|
||||||
|
case MemoryRegion.Alias:
|
||||||
|
// Memory address is relative to the alias region.
|
||||||
|
return context.AliasAddress;
|
||||||
|
case MemoryRegion.Asrl:
|
||||||
|
// Memory address is relative to the asrl region, which matches the code region.
|
||||||
|
return context.AslrAddress;
|
||||||
default:
|
default:
|
||||||
throw new TamperCompilationException($"Invalid memory source {source} in Atmosphere cheat");
|
throw new TamperCompilationException($"Invalid memory source {source} in Atmosphere cheat");
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,16 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The address of the heap, as determined by the kernel.
|
/// The address of the heap, as determined by the kernel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Heap = 0x1
|
Heap = 0x1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The address of the alias region, as determined by the kernel.
|
||||||
|
/// </summary>
|
||||||
|
Alias = 0x2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The address of the code region with address space layout randomization included.
|
||||||
|
/// </summary>
|
||||||
|
Asrl = 0x3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,27 +6,26 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
|
||||||
class IfBlock : IOperation
|
class IfBlock : IOperation
|
||||||
{
|
{
|
||||||
private ICondition _condition;
|
private ICondition _condition;
|
||||||
private IEnumerable<IOperation> _operations;
|
private IEnumerable<IOperation> _operationsThen;
|
||||||
|
private IEnumerable<IOperation> _operationsElse;
|
||||||
|
|
||||||
public IfBlock(ICondition condition, IEnumerable<IOperation> operations)
|
public IfBlock(ICondition condition, IEnumerable<IOperation> operationsThen, IEnumerable<IOperation> operationsElse)
|
||||||
{
|
{
|
||||||
_condition = condition;
|
_condition = condition;
|
||||||
_operations = operations;
|
_operationsThen = operationsThen;
|
||||||
}
|
_operationsElse = operationsElse;
|
||||||
|
|
||||||
public IfBlock(ICondition condition, params IOperation[] operations)
|
|
||||||
{
|
|
||||||
_operations = operations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Execute()
|
public void Execute()
|
||||||
{
|
{
|
||||||
if (!_condition.Evaluate())
|
IEnumerable<IOperation> operations = _condition.Evaluate() ? _operationsThen : _operationsElse;
|
||||||
|
|
||||||
|
if (operations == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (IOperation op in _operations)
|
foreach (IOperation op in operations)
|
||||||
{
|
{
|
||||||
op.Execute();
|
op.Execute();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,11 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
|
|
||||||
public ProcessState State => _process.State;
|
public ProcessState State => _process.State;
|
||||||
|
|
||||||
|
public bool TamperedCodeMemory { get; set; } = false;
|
||||||
|
|
||||||
public TamperedKProcess(KProcess process)
|
public TamperedKProcess(KProcess process)
|
||||||
{
|
{
|
||||||
this._process = process;
|
_process = process;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertMemoryRegion<T>(ulong va, bool isWrite) where T : unmanaged
|
private void AssertMemoryRegion<T>(ulong va, bool isWrite) where T : unmanaged
|
||||||
|
@ -32,11 +34,11 @@ namespace Ryujinx.HLE.HOS.Tamper
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (Caian): It is unknown how PPTC behaves if the tamper modifies memory regions
|
// TODO (Caian): The JIT does not support invalidating a code region so writing to code memory may not work
|
||||||
// belonging to code. So for now just prevent code tampering.
|
// as intended, so taint the operation to issue a warning later.
|
||||||
if ((va >= _process.MemoryManager.CodeRegionStart) && (va + size <= _process.MemoryManager.CodeRegionEnd))
|
if (isWrite && (va >= _process.MemoryManager.CodeRegionStart) && (va + size <= _process.MemoryManager.CodeRegionEnd))
|
||||||
{
|
{
|
||||||
throw new CodeRegionTamperedException($"Writing {size} bytes to address 0x{va:X16} alters code");
|
TamperedCodeMemory = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void InstallAtmosphereCheat(IEnumerable<string> rawInstructions, ProcessTamperInfo info, ulong exeAddress)
|
internal void InstallAtmosphereCheat(string name, IEnumerable<string> rawInstructions, ProcessTamperInfo info, ulong exeAddress)
|
||||||
{
|
{
|
||||||
if (!CanInstallOnPid(info.Process.Pid))
|
if (!CanInstallOnPid(info.Process.Pid))
|
||||||
{
|
{
|
||||||
|
@ -39,11 +39,13 @@ namespace Ryujinx.HLE.HOS
|
||||||
}
|
}
|
||||||
|
|
||||||
ITamperedProcess tamperedProcess = new TamperedKProcess(info.Process);
|
ITamperedProcess tamperedProcess = new TamperedKProcess(info.Process);
|
||||||
AtmosphereCompiler compiler = new AtmosphereCompiler();
|
AtmosphereCompiler compiler = new AtmosphereCompiler(exeAddress, info.HeapAddress, info.AliasAddress, info.AslrAddress, tamperedProcess);
|
||||||
ITamperProgram program = compiler.Compile(rawInstructions, exeAddress, info.HeapAddress, tamperedProcess);
|
ITamperProgram program = compiler.Compile(name, rawInstructions);
|
||||||
|
|
||||||
if (program != null)
|
if (program != null)
|
||||||
{
|
{
|
||||||
|
program.TampersCodeMemory = false;
|
||||||
|
|
||||||
_programs.Enqueue(program);
|
_programs.Enqueue(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,27 +118,27 @@ namespace Ryujinx.HLE.HOS
|
||||||
// Re-enqueue the tampering program because the process is still valid.
|
// Re-enqueue the tampering program because the process is still valid.
|
||||||
_programs.Enqueue(program);
|
_programs.Enqueue(program);
|
||||||
|
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, "Running tampering program");
|
Logger.Debug?.Print(LogClass.TamperMachine, $"Running tampering program {program.Name}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ControllerKeys pressedKeys = (ControllerKeys)Thread.VolatileRead(ref _pressedKeys);
|
ControllerKeys pressedKeys = (ControllerKeys)Thread.VolatileRead(ref _pressedKeys);
|
||||||
|
program.Process.TamperedCodeMemory = false;
|
||||||
program.Execute(pressedKeys);
|
program.Execute(pressedKeys);
|
||||||
}
|
|
||||||
catch (CodeRegionTamperedException ex)
|
|
||||||
{
|
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, $"Prevented tampering program from modifing code memory");
|
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(ex.Message))
|
// Detect the first attempt to tamper memory and log it.
|
||||||
|
if (!program.TampersCodeMemory && program.Process.TamperedCodeMemory)
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, ex.Message);
|
program.TampersCodeMemory = true;
|
||||||
|
|
||||||
|
Logger.Warning?.Print(LogClass.TamperMachine, $"Tampering program {program.Name} modifies code memory so it may not work properly");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, $"The tampering program crashed, this can happen while the game is starting");
|
Logger.Debug?.Print(LogClass.TamperMachine, $"The tampering program {program.Name} crashed, this can happen while the game is starting");
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(ex.Message))
|
if (!string.IsNullOrEmpty(ex.Message))
|
||||||
{
|
{
|
||||||
Logger.Debug?.Print(LogClass.TamperMachine, ex.Message);
|
Logger.Debug?.Print(LogClass.TamperMachine, ex.Message);
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue