aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Tamper
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.HLE/HOS/Tamper')
-rw-r--r--Ryujinx.HLE/HOS/Tamper/AtmosphereCompiler.cs36
-rw-r--r--Ryujinx.HLE/HOS/Tamper/AtmosphereProgram.cs5
-rw-r--r--Ryujinx.HLE/HOS/Tamper/CodeEmitters/EndConditionalBlock.cs55
-rw-r--r--Ryujinx.HLE/HOS/Tamper/CompilationContext.cs20
-rw-r--r--Ryujinx.HLE/HOS/Tamper/ITamperProgram.cs2
-rw-r--r--Ryujinx.HLE/HOS/Tamper/ITamperedProcess.cs3
-rw-r--r--Ryujinx.HLE/HOS/Tamper/MemoryHelper.cs6
-rw-r--r--Ryujinx.HLE/HOS/Tamper/MemoryRegion.cs12
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs19
-rw-r--r--Ryujinx.HLE/HOS/Tamper/TamperedKProcess.cs12
10 files changed, 131 insertions, 39 deletions
diff --git a/Ryujinx.HLE/HOS/Tamper/AtmosphereCompiler.cs b/Ryujinx.HLE/HOS/Tamper/AtmosphereCompiler.cs
index 05e248c8..7d7af208 100644
--- a/Ryujinx.HLE/HOS/Tamper/AtmosphereCompiler.cs
+++ b/Ryujinx.HLE/HOS/Tamper/AtmosphereCompiler.cs
@@ -9,14 +9,36 @@ namespace Ryujinx.HLE.HOS.Tamper
{
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)
+ {
+ _exeAddress = exeAddress;
+ _heapAddress = heapAddress;
+ _aliasAddress = aliasAddress;
+ _aslrAddress = aslrAddress;
+ _process = process;
+ }
+
+ public ITamperProgram Compile(string name, IEnumerable<string> rawInstructions)
{
- Logger.Debug?.Print(LogClass.TamperMachine, $"Executable address: {exeAddress:X16}");
- Logger.Debug?.Print(LogClass.TamperMachine, $"Heap address: {heapAddress:X16}");
+ 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
{
- return CompileImpl(rawInstructions, exeAddress, heapAddress, process);
+ return CompileImpl(name, rawInstructions);
}
catch(TamperCompilationException exception)
{
@@ -33,9 +55,9 @@ namespace Ryujinx.HLE.HOS.Tamper
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));
// 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)");
}
- return new AtmosphereProgram(process, context.PressedKeys, new Block(context.CurrentOperations));
+ return new AtmosphereProgram(name, _process, context.PressedKeys, new Block(context.CurrentOperations));
}
}
}
diff --git a/Ryujinx.HLE/HOS/Tamper/AtmosphereProgram.cs b/Ryujinx.HLE/HOS/Tamper/AtmosphereProgram.cs
index 1fd0afb4..dac445b0 100644
--- a/Ryujinx.HLE/HOS/Tamper/AtmosphereProgram.cs
+++ b/Ryujinx.HLE/HOS/Tamper/AtmosphereProgram.cs
@@ -8,10 +8,13 @@ namespace Ryujinx.HLE.HOS.Tamper
private Parameter<long> _pressedKeys;
private IOperation _entryPoint;
+ public string Name { get; }
+ public bool TampersCodeMemory { get; set; } = false;
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;
_pressedKeys = pressedKeys;
_entryPoint = entryPoint;
diff --git a/Ryujinx.HLE/HOS/Tamper/CodeEmitters/EndConditionalBlock.cs b/Ryujinx.HLE/HOS/Tamper/CodeEmitters/EndConditionalBlock.cs
index 4a01992c..a25dddde 100644
--- a/Ryujinx.HLE/HOS/Tamper/CodeEmitters/EndConditionalBlock.cs
+++ b/Ryujinx.HLE/HOS/Tamper/CodeEmitters/EndConditionalBlock.cs
@@ -10,32 +10,73 @@ namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
/// </summary>
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)
{
- // 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.
- instruction = context.CurrentBlock.BaseInstruction;
- CodeType codeType = InstructionHelper.GetCodeType(instruction);
+ var upperInstruction = context.CurrentBlock.BaseInstruction;
+ CodeType codeType = InstructionHelper.GetCodeType(upperInstruction);
// Pop the current block of operations from the stack so control instructions
// for the conditional can be emitted in the upper block.
IEnumerable<IOperation> operations = context.CurrentOperations;
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;
switch (codeType)
{
case CodeType.BeginMemoryConditionalBlock:
- condition = MemoryConditional.Emit(instruction, context);
+ condition = MemoryConditional.Emit(upperInstruction, context);
break;
case CodeType.BeginKeypressConditionalBlock:
- condition = KeyPressConditional.Emit(instruction, context);
+ condition = KeyPressConditional.Emit(upperInstruction, context);
break;
case CodeType.BeginRegisterConditionalBlock:
- condition = RegisterConditional.Emit(instruction, context);
+ condition = RegisterConditional.Emit(upperInstruction, context);
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:
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
// block of the stack.
- IfBlock block = new IfBlock(condition, operations);
+ IfBlock block = new IfBlock(condition, operations, operationsElse);
context.CurrentOperations.Add(block);
}
}
diff --git a/Ryujinx.HLE/HOS/Tamper/CompilationContext.cs b/Ryujinx.HLE/HOS/Tamper/CompilationContext.cs
index 71e64bb8..2dd4029a 100644
--- a/Ryujinx.HLE/HOS/Tamper/CompilationContext.cs
+++ b/Ryujinx.HLE/HOS/Tamper/CompilationContext.cs
@@ -20,17 +20,21 @@ namespace Ryujinx.HLE.HOS.Tamper
public Dictionary<byte, Register> StaticRegisters { get; }
public ulong ExeAddress { 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;
- PressedKeys = new Parameter<long>(0);
- BlockStack = new Stack<OperationBlock>();
- Registers = new Dictionary<byte, Register>();
- SavedRegisters = new Dictionary<byte, Register>();
+ Process = process;
+ PressedKeys = new Parameter<long>(0);
+ BlockStack = new Stack<OperationBlock>();
+ Registers = new Dictionary<byte, Register>();
+ SavedRegisters = new Dictionary<byte, Register>();
StaticRegisters = new Dictionary<byte, Register>();
- ExeAddress = exeAddress;
- HeapAddress = heapAddress;
+ ExeAddress = exeAddress;
+ HeapAddress = heapAddress;
+ AliasAddress = aliasAddress;
+ AslrAddress = aslrAddress;
}
public Register GetRegister(byte index)
diff --git a/Ryujinx.HLE/HOS/Tamper/ITamperProgram.cs b/Ryujinx.HLE/HOS/Tamper/ITamperProgram.cs
index 06bc2243..63702bf7 100644
--- a/Ryujinx.HLE/HOS/Tamper/ITamperProgram.cs
+++ b/Ryujinx.HLE/HOS/Tamper/ITamperProgram.cs
@@ -4,6 +4,8 @@ namespace Ryujinx.HLE.HOS.Tamper
{
interface ITamperProgram
{
+ string Name { get; }
+ bool TampersCodeMemory { get; set; }
ITamperedProcess Process { get; }
void Execute(ControllerKeys pressedKeys);
}
diff --git a/Ryujinx.HLE/HOS/Tamper/ITamperedProcess.cs b/Ryujinx.HLE/HOS/Tamper/ITamperedProcess.cs
index d9da5d00..c86e1021 100644
--- a/Ryujinx.HLE/HOS/Tamper/ITamperedProcess.cs
+++ b/Ryujinx.HLE/HOS/Tamper/ITamperedProcess.cs
@@ -5,6 +5,9 @@ namespace Ryujinx.HLE.HOS.Tamper
interface ITamperedProcess
{
ProcessState State { get; }
+
+ bool TamperedCodeMemory { get; set; }
+
T ReadMemory<T>(ulong va) where T : unmanaged;
void WriteMemory<T>(ulong va, T value) where T : unmanaged;
void PauseProcess();
diff --git a/Ryujinx.HLE/HOS/Tamper/MemoryHelper.cs b/Ryujinx.HLE/HOS/Tamper/MemoryHelper.cs
index 277b3841..1260ed9a 100644
--- a/Ryujinx.HLE/HOS/Tamper/MemoryHelper.cs
+++ b/Ryujinx.HLE/HOS/Tamper/MemoryHelper.cs
@@ -15,6 +15,12 @@ namespace Ryujinx.HLE.HOS.Tamper
case MemoryRegion.Heap:
// Memory address is relative to the heap.
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:
throw new TamperCompilationException($"Invalid memory source {source} in Atmosphere cheat");
}
diff --git a/Ryujinx.HLE/HOS/Tamper/MemoryRegion.cs b/Ryujinx.HLE/HOS/Tamper/MemoryRegion.cs
index 13ba6f18..fb4b25ff 100644
--- a/Ryujinx.HLE/HOS/Tamper/MemoryRegion.cs
+++ b/Ryujinx.HLE/HOS/Tamper/MemoryRegion.cs
@@ -20,6 +20,16 @@ namespace Ryujinx.HLE.HOS.Tamper
/// <summary>
/// The address of the heap, as determined by the kernel.
/// </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,
}
}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs b/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs
index 0ba0f8c3..b7c5684e 100644
--- a/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs
@@ -6,27 +6,26 @@ namespace Ryujinx.HLE.HOS.Tamper.Operations
class IfBlock : IOperation
{
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;
- _operations = operations;
- }
-
- public IfBlock(ICondition condition, params IOperation[] operations)
- {
- _operations = operations;
+ _operationsThen = operationsThen;
+ _operationsElse = operationsElse;
}
public void Execute()
{
- if (!_condition.Evaluate())
+ IEnumerable<IOperation> operations = _condition.Evaluate() ? _operationsThen : _operationsElse;
+
+ if (operations == null)
{
return;
}
- foreach (IOperation op in _operations)
+ foreach (IOperation op in operations)
{
op.Execute();
}
diff --git a/Ryujinx.HLE/HOS/Tamper/TamperedKProcess.cs b/Ryujinx.HLE/HOS/Tamper/TamperedKProcess.cs
index e27c371a..be51264a 100644
--- a/Ryujinx.HLE/HOS/Tamper/TamperedKProcess.cs
+++ b/Ryujinx.HLE/HOS/Tamper/TamperedKProcess.cs
@@ -11,9 +11,11 @@ namespace Ryujinx.HLE.HOS.Tamper
public ProcessState State => _process.State;
+ public bool TamperedCodeMemory { get; set; } = false;
+
public TamperedKProcess(KProcess process)
{
- this._process = process;
+ _process = process;
}
private void AssertMemoryRegion<T>(ulong va, bool isWrite) where T : unmanaged
@@ -32,11 +34,11 @@ namespace Ryujinx.HLE.HOS.Tamper
return;
}
- // TODO (Caian): It is unknown how PPTC behaves if the tamper modifies memory regions
- // belonging to code. So for now just prevent code tampering.
- if ((va >= _process.MemoryManager.CodeRegionStart) && (va + size <= _process.MemoryManager.CodeRegionEnd))
+ // TODO (Caian): The JIT does not support invalidating a code region so writing to code memory may not work
+ // as intended, so taint the operation to issue a warning later.
+ 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;
}
}