mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 21:45:28 +03:00
Introduce Basic Junction Patching
This commit introduces basic junction patching or patching code to jump to a junction then execute intermediate functions and jump back.
This commit is contained in:
parent
f7ad017726
commit
3e9bfaec0e
3
.idea/codeStyles/Project.xml
generated
3
.idea/codeStyles/Project.xml
generated
@ -15,10 +15,13 @@
|
||||
<option name="FUNCTION_TOP_AFTER_RETURN_TYPE_WRAP" value="0" />
|
||||
<option name="FUNCTION_PARAMETERS_WRAP" value="5" />
|
||||
<option name="FUNCTION_CALL_ARGUMENTS_WRAP" value="5" />
|
||||
<option name="SHIFT_OPERATION_WRAP" value="0" />
|
||||
<option name="TEMPLATE_DECLARATION_STRUCT_WRAP" value="1" />
|
||||
<option name="TEMPLATE_DECLARATION_FUNCTION_WRAP" value="1" />
|
||||
<option name="TEMPLATE_CALL_ARGUMENTS_WRAP" value="5" />
|
||||
<option name="TEMPLATE_CALL_ARGUMENTS_ALIGN_MULTILINE" value="true" />
|
||||
<option name="CLASS_CONSTRUCTOR_INIT_LIST_WRAP" value="0" />
|
||||
<option name="SUPERCLASS_LIST_WRAP" value="0" />
|
||||
<option name="ALIGN_INIT_LIST_IN_COLUMNS" value="false" />
|
||||
<option name="HEADER_GUARD_STYLE_PATTERN" value="${PROJECT_NAME}_${PROJECT_REL_PATH}_${FILE_NAME}_${EXT}" />
|
||||
<option name="MACROS_NAMING_CONVENTION">
|
||||
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -43,7 +43,7 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -7,6 +7,7 @@ set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -Wno-unused-command-line-argument")
|
||||
enable_language(ASM)
|
||||
if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
|
||||
add_compile_definitions(NDEBUG)
|
||||
endif()
|
||||
@ -21,6 +22,7 @@ include_directories(${source_DIR}/skyline)
|
||||
add_library(skyline SHARED
|
||||
${source_DIR}/main.cpp
|
||||
${source_DIR}/skyline/common.cpp
|
||||
${source_DIR}/skyline/guest.S
|
||||
${source_DIR}/skyline/nce.cpp
|
||||
${source_DIR}/skyline/jvm.cpp
|
||||
${source_DIR}/skyline/gpu.cpp
|
||||
|
@ -47,7 +47,7 @@ namespace skyline {
|
||||
// Loader
|
||||
constexpr u32 NroMagic = 0x304F524E; //!< "NRO0" in reverse, this is written at the start of every NRO file
|
||||
// NCE
|
||||
constexpr u8 NumRegs = 31; //!< The amount of registers that ARMv8 has
|
||||
constexpr u8 NumRegs = 30; //!< The amount of registers that ARMv8 has
|
||||
constexpr u16 SvcLast = 0x7F; //!< The index of the last SVC
|
||||
constexpr u16 BrkRdy = 0xFF; //!< This is reserved for our kernel's to know when a process/thread is ready
|
||||
constexpr u32 TpidrroEl0 = 0x5E83; //!< ID of TPIDRRO_EL0 in MRS
|
||||
@ -105,86 +105,6 @@ namespace skyline {
|
||||
NSP, //!< The NSP format from "nspwn" exploit: https://switchbrew.org/wiki/Switch_System_Flaws
|
||||
};
|
||||
|
||||
namespace instr {
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a BRK instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction.
|
||||
*/
|
||||
struct Brk {
|
||||
/**
|
||||
* @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes
|
||||
* @param val The immediate value of the instruction
|
||||
*/
|
||||
Brk(u16 val) {
|
||||
start = 0x0; // First 5 bits of a BRK instruction are 0
|
||||
value = val;
|
||||
end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid BRK instruction
|
||||
*/
|
||||
bool Verify() {
|
||||
return (start == 0x0 && end == 0x6A1);
|
||||
}
|
||||
|
||||
u8 start : 5;
|
||||
u32 value : 16;
|
||||
u16 end : 11;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Brk) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a SVC instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call.
|
||||
*/
|
||||
struct Svc {
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid SVC instruction
|
||||
*/
|
||||
bool Verify() {
|
||||
return (start == 0x1 && end == 0x6A0);
|
||||
}
|
||||
|
||||
u8 start : 5;
|
||||
u32 value : 16;
|
||||
u16 end : 11;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Svc) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register.
|
||||
*/
|
||||
struct Mrs {
|
||||
/**
|
||||
* @brief Creates a MRS instruction, used for generating BRK opcodes
|
||||
* @param srcReg The source system register
|
||||
* @param dstReg The destination Xn register
|
||||
*/
|
||||
Mrs(u32 srcReg, u8 dstReg) {
|
||||
this->srcReg = srcReg;
|
||||
this->dstReg = dstReg;
|
||||
end = 0xD53; // Last 12 bits of a MRS instruction stored as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid MRS instruction
|
||||
*/
|
||||
bool Verify() {
|
||||
return (end == 0xD53);
|
||||
}
|
||||
|
||||
u8 dstReg : 5;
|
||||
u32 srcReg : 15;
|
||||
u16 end : 12;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Mrs) == sizeof(u32));
|
||||
};
|
||||
|
||||
/**
|
||||
* Read about ARMv8 registers here: https://developer.arm.com/docs/100878/latest/registers
|
||||
*/
|
||||
|
46
app/src/main/cpp/skyline/guest.S
Normal file
46
app/src/main/cpp/skyline/guest.S
Normal file
@ -0,0 +1,46 @@
|
||||
.text
|
||||
.global saveCtx
|
||||
saveCtx:
|
||||
STR LR, [SP, #-16]!
|
||||
MRS LR, TPIDR_EL0
|
||||
#LDR LR, [LR]
|
||||
STP X0, X1, [LR, #0]
|
||||
STP X2, X3, [LR, #16]
|
||||
STP X4, X5, [LR, #32]
|
||||
STP X6, X7, [LR, #48]
|
||||
STP X8, X9, [LR, #64]
|
||||
STP X10, X11, [LR, #80]
|
||||
STP X12, X13, [LR, #96]
|
||||
STP X14, X15, [LR, #112]
|
||||
STP X16, X17, [LR, #128]
|
||||
STP X18, X19, [LR, #144]
|
||||
STP X20, X21, [LR, #160]
|
||||
STP X22, X23, [LR, #176]
|
||||
STP X24, X25, [LR, #192]
|
||||
STP X26, X27, [LR, #208]
|
||||
STP X28, X29, [LR, #224]
|
||||
LDR LR, [SP], #16
|
||||
RET
|
||||
|
||||
.global loadCtx
|
||||
loadCtx:
|
||||
STR LR, [SP, #-16]!
|
||||
MRS LR, TPIDR_EL0
|
||||
#LDR LR, [LR]
|
||||
LDP X0, X1, [LR, #0]
|
||||
LDP X2, X3, [LR, #16]
|
||||
LDP X4, X5, [LR, #32]
|
||||
LDP X6, X7, [LR, #48]
|
||||
LDP X8, X9, [LR, #64]
|
||||
LDP X10, X11, [LR, #80]
|
||||
LDP X12, X13, [LR, #96]
|
||||
LDP X14, X15, [LR, #112]
|
||||
LDP X16, X17, [LR, #128]
|
||||
LDP X18, X19, [LR, #144]
|
||||
LDP X20, X21, [LR, #160]
|
||||
LDP X22, X23, [LR, #176]
|
||||
LDP X24, X25, [LR, #192]
|
||||
LDP X26, X27, [LR, #208]
|
||||
LDP X28, X29, [LR, #224]
|
||||
LDR LR, [SP], #16
|
||||
RET
|
8
app/src/main/cpp/skyline/guest.h
Normal file
8
app/src/main/cpp/skyline/guest.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace skyline::guest {
|
||||
constexpr size_t saveCtxSize = 20 * sizeof(u32);
|
||||
constexpr size_t loadCtxSize = 20 * sizeof(u32);
|
||||
extern "C" void saveCtx(void);
|
||||
extern "C" void loadCtx(void);
|
||||
}
|
@ -21,32 +21,6 @@ namespace skyline::loader {
|
||||
pread64(romFd, output, size, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This patches specific parts of the code
|
||||
* @param code A vector with the code to be patched
|
||||
*/
|
||||
inline void PatchCode(std::vector<u8> &code) {
|
||||
u32 *address = reinterpret_cast<u32 *>(code.data());
|
||||
u32 *end = address + (code.size() / sizeof(u32));
|
||||
while (address < end) {
|
||||
auto instrSvc = reinterpret_cast<instr::Svc *>(address);
|
||||
auto instrMrs = reinterpret_cast<instr::Mrs *>(address);
|
||||
if (instrSvc->Verify()) {
|
||||
instr::Brk brk(static_cast<u16>(instrSvc->value));
|
||||
*address = *reinterpret_cast<u32 *>(&brk);
|
||||
} else if (instrMrs->Verify()) {
|
||||
if (instrMrs->srcReg == constant::TpidrroEl0) {
|
||||
instr::Brk brk(static_cast<u16>(constant::SvcLast + 1 + instrMrs->dstReg));
|
||||
*address = *reinterpret_cast<u32 *>(&brk);
|
||||
} else if (instrMrs->srcReg == constant::CntpctEl0) {
|
||||
instr::Mrs mrs(constant::CntvctEl0, instrMrs->dstReg);
|
||||
*address = *reinterpret_cast<u32 *>(&mrs);
|
||||
}
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param filePath The path to the ROM file
|
||||
|
@ -17,11 +17,12 @@ namespace skyline::loader {
|
||||
ReadOffset(rodata.data(), header.ro.offset, header.ro.size);
|
||||
ReadOffset(data.data(), header.data.offset, header.data.size);
|
||||
|
||||
PatchCode(text);
|
||||
std::vector<u32> patch = state.nce->PatchCode(text, header.text.size + header.ro.size + header.data.size + header.bssSize);
|
||||
|
||||
u64 textSize = text.size();
|
||||
u64 rodataSize = rodata.size();
|
||||
u64 dataSize = data.size();
|
||||
u64 patchSize = patch.size() * sizeof(u32);
|
||||
|
||||
process->MapPrivateRegion(constant::BaseAddr, textSize, {true, true, true}, memory::Type::CodeStatic, memory::Region::Text); // R-X
|
||||
state.logger->Debug("Successfully mapped region .text @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddr, textSize);
|
||||
@ -35,8 +36,12 @@ namespace skyline::loader {
|
||||
process->MapPrivateRegion(constant::BaseAddr + textSize + rodataSize + dataSize, header.bssSize, {true, true, true}, memory::Type::CodeMutable, memory::Region::Bss); // RWX
|
||||
state.logger->Debug("Successfully mapped region .bss @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddr + textSize + rodataSize + dataSize, header.bssSize);
|
||||
|
||||
process->MapPrivateRegion(constant::BaseAddr + textSize + rodataSize + dataSize + header.bssSize, patchSize, {true, true, true}, memory::Type::CodeStatic, memory::Region::Text); // RWX
|
||||
state.logger->Debug("Successfully mapped region .patch @ 0x{0:X}, Size = 0x{1:X}", constant::BaseAddr + textSize + rodataSize + dataSize + header.bssSize, patchSize);
|
||||
|
||||
process->WriteMemory(text.data(), constant::BaseAddr, textSize);
|
||||
process->WriteMemory(rodata.data(), constant::BaseAddr + textSize, rodataSize);
|
||||
process->WriteMemory(data.data(), constant::BaseAddr + textSize + rodataSize, dataSize);
|
||||
process->WriteMemory(patch.data(), constant::BaseAddr + textSize + rodataSize + dataSize + header.bssSize, patchSize);
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,182 @@
|
||||
#include <linux/elf.h>
|
||||
#include "os.h"
|
||||
#include "jvm.h"
|
||||
#include "guest.h"
|
||||
|
||||
extern bool Halt;
|
||||
extern std::mutex jniMtx;
|
||||
|
||||
namespace skyline {
|
||||
|
||||
namespace instr {
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a BRK instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/brk-breakpoint-instruction.
|
||||
*/
|
||||
struct Brk {
|
||||
/**
|
||||
* @brief Creates a BRK instruction with a specific immediate value, used for generating BRK opcodes
|
||||
* @param value The immediate value of the instruction
|
||||
*/
|
||||
explicit Brk(u16 value) {
|
||||
start = 0x0; // First 5 bits of a BRK instruction are 0
|
||||
this->value = value;
|
||||
end = 0x6A1; // Last 11 bits of a BRK instruction stored as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid BRK instruction
|
||||
*/
|
||||
inline bool Verify() {
|
||||
return (start == 0x0 && end == 0x6A1);
|
||||
}
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 start : 5;
|
||||
u32 value : 16;
|
||||
u16 end : 11;
|
||||
};
|
||||
u32 raw{};
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(Brk) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a SVC instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/svc-supervisor-call.
|
||||
*/
|
||||
struct Svc {
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid SVC instruction
|
||||
*/
|
||||
inline bool Verify() {
|
||||
return (start == 0x1 && end == 0x6A0);
|
||||
}
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 start : 5;
|
||||
u32 value : 16;
|
||||
u16 end : 11;
|
||||
};
|
||||
u32 raw{};
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(Svc) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a MRS instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/mrs-move-system-register.
|
||||
*/
|
||||
struct Mrs {
|
||||
/**
|
||||
* @brief Creates a MRS instruction, used for generating BRK opcodes
|
||||
* @param srcReg The source system register
|
||||
* @param dstReg The destination Xn register
|
||||
*/
|
||||
Mrs(u32 srcReg, u8 dstReg) {
|
||||
this->srcReg = srcReg;
|
||||
this->dstReg = dstReg;
|
||||
end = 0xD53; // Last 12 bits of a MRS instruction stored as u16
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid MRS instruction
|
||||
*/
|
||||
inline bool Verify() {
|
||||
return (end == 0xD53);
|
||||
}
|
||||
|
||||
union {
|
||||
struct {
|
||||
u8 dstReg : 5;
|
||||
u32 srcReg : 15;
|
||||
u16 end : 12;
|
||||
};
|
||||
u32 raw{};
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(Mrs) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a B instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
|
||||
*/
|
||||
struct B {
|
||||
public:
|
||||
explicit B(i64 offset) {
|
||||
this->offset = static_cast<i32>(offset / 4);
|
||||
end = 0x5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the offset of the instruction
|
||||
* @return The offset encoded within the instruction
|
||||
*/
|
||||
inline i32 Offset() {
|
||||
return offset * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid Branch instruction
|
||||
*/
|
||||
inline bool Verify() {
|
||||
return (end == 0x5);
|
||||
}
|
||||
|
||||
union {
|
||||
struct {
|
||||
i32 offset : 26;
|
||||
u8 end : 6;
|
||||
};
|
||||
u32 raw{};
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(B) == sizeof(u32));
|
||||
|
||||
/**
|
||||
* @brief A bit-field struct that encapsulates a BL instruction. See https://developer.arm.com/docs/ddi0596/latest/base-instructions-alphabetic-order/b-branch.
|
||||
*/
|
||||
struct BL {
|
||||
public:
|
||||
explicit BL(i64 offset) {
|
||||
this->offset = static_cast<i32>(offset / 4);
|
||||
end = 0x25;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the offset of the instruction
|
||||
* @return The offset encoded within the instruction
|
||||
*/
|
||||
inline i32 Offset() {
|
||||
return offset * 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns if the opcode is valid or not
|
||||
* @return If the opcode represents a valid Branch instruction
|
||||
*/
|
||||
inline bool Verify() {
|
||||
return (end == 0x85);
|
||||
}
|
||||
|
||||
union {
|
||||
struct {
|
||||
i32 offset : 26;
|
||||
u8 end : 6;
|
||||
};
|
||||
u32 raw{};
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(BL) == sizeof(u32));
|
||||
}
|
||||
|
||||
void NCE::ReadRegisters(user_pt_regs ®isters, pid_t pid) const {
|
||||
iovec iov = {®isters, sizeof(registers)};
|
||||
long status = ptrace(PTRACE_GETREGSET, pid ? pid : currPid, NT_PRSTATUS, &iov);
|
||||
@ -56,8 +227,10 @@ namespace skyline {
|
||||
SetRegister(static_cast<Xreg>(instr.value - (constant::SvcLast + 1)), state.thisThread->tls);
|
||||
} else if (instr.value == constant::BrkRdy)
|
||||
continue;
|
||||
else
|
||||
else {
|
||||
ProcessTrace();
|
||||
throw exception("Received unhandled BRK: 0x{:X}", static_cast<u64>(instr.value));
|
||||
}
|
||||
}
|
||||
currRegs.pc += sizeof(u32);
|
||||
WriteRegisters(currRegs);
|
||||
@ -181,12 +354,11 @@ namespace skyline {
|
||||
raw += fmt::format("{:08X}", instr);
|
||||
}
|
||||
state.logger->Debug("Raw Instructions: 0x{}", raw);
|
||||
state.logger->Debug("CPU Context:");
|
||||
state.logger->Debug("SP: 0x{:X}", regs.sp);
|
||||
state.logger->Debug("PSTATE: 0x{:X}", regs.pstate);
|
||||
for (u16 index = 0; index < constant::NumRegs - 2; index++) {
|
||||
state.logger->Debug("X{}: 0x{:X}", index, regs.regs[index]);
|
||||
std::string regStr;
|
||||
for (u16 index = 0; index < constant::NumRegs - 1; index+=2) {
|
||||
regStr += fmt::format("\nX{}: 0x{:X}, X{}: 0x{:X}", index, regs.regs[index], index+1, regs.regs[index+1]);
|
||||
}
|
||||
state.logger->Debug("CPU Context:\nSP: 0x{:X}\nLR: 0x{:X}\nPSTATE: 0x{:X}{}", regs.sp, regs.regs[30], regs.pstate, regStr);
|
||||
}
|
||||
|
||||
u64 NCE::GetRegister(Xreg regId, pid_t pid) {
|
||||
@ -228,4 +400,68 @@ namespace skyline {
|
||||
registerMap.at(pid).pstate = value;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u32> NCE::PatchCode(std::vector<u8>& code, i64 offset) {
|
||||
u32 *address = reinterpret_cast<u32 *>(code.data());
|
||||
u32 *end = address + (code.size() / sizeof(u32));
|
||||
i64 patchOffset = offset;
|
||||
|
||||
std::vector<u32> patch;
|
||||
patch.resize((guest::saveCtxSize + guest::loadCtxSize) / sizeof(u32));
|
||||
std::memcpy(patch.data(), reinterpret_cast<void*>(&guest::saveCtx), guest::saveCtxSize);
|
||||
offset += guest::saveCtxSize;
|
||||
|
||||
std::memcpy(reinterpret_cast<u8*>(patch.data()) + guest::saveCtxSize,
|
||||
reinterpret_cast<void*>(&guest::loadCtx), guest::loadCtxSize);
|
||||
offset += guest::loadCtxSize;
|
||||
|
||||
while (address < end) {
|
||||
auto instrSvc = reinterpret_cast<instr::Svc *>(address);
|
||||
auto instrMrs = reinterpret_cast<instr::Mrs *>(address);
|
||||
|
||||
if (instrSvc->Verify()) {
|
||||
instr::B bjunc(offset);
|
||||
constexpr u32 strLr = 0xF81F0FFE; // STR LR, [SP, #-16]!
|
||||
offset += sizeof(strLr);
|
||||
instr::Brk brk(static_cast<u16>(instrSvc->value));
|
||||
offset += sizeof(brk);
|
||||
instr::BL bSvCtx(patchOffset - offset);
|
||||
offset += sizeof(bSvCtx);
|
||||
instr::BL bLdCtx((patchOffset + guest::saveCtxSize) - offset);
|
||||
offset += sizeof(bLdCtx);
|
||||
constexpr u32 ldrLr = 0xF84107FE; // LDR LR, [SP], #16
|
||||
offset += sizeof(ldrLr);
|
||||
instr::B bret(-offset + sizeof(u32));
|
||||
offset += sizeof(bret);
|
||||
|
||||
*address = bjunc.raw;
|
||||
patch.push_back(strLr);
|
||||
patch.push_back(brk.raw);
|
||||
patch.push_back(bSvCtx.raw);
|
||||
patch.push_back(bLdCtx.raw);
|
||||
patch.push_back(ldrLr);
|
||||
patch.push_back(bret.raw);
|
||||
} else if (instrMrs->Verify()) {
|
||||
if (instrMrs->srcReg == constant::TpidrroEl0) {
|
||||
instr::B bjunc(offset);
|
||||
instr::Brk brk(static_cast<u16>(constant::SvcLast + 1 + instrMrs->dstReg));
|
||||
offset += sizeof(u32);
|
||||
instr::B bret(-offset + sizeof(u32));
|
||||
offset += sizeof(u32);
|
||||
|
||||
*address = bjunc.raw;
|
||||
patch.push_back(brk.raw);
|
||||
patch.push_back(bret.raw);
|
||||
} else if (instrMrs->srcReg == constant::CntpctEl0) {
|
||||
instr::Mrs mrs(constant::CntvctEl0, instrMrs->dstReg);
|
||||
*address = mrs.raw;
|
||||
}
|
||||
}
|
||||
address++;
|
||||
offset -= sizeof(u32);
|
||||
patchOffset -= sizeof(u32);
|
||||
}
|
||||
return patch;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
#include "kernel/types/KSharedMemory.h"
|
||||
|
||||
namespace skyline {
|
||||
namespace instr {
|
||||
struct Brk;
|
||||
}
|
||||
/**
|
||||
* @brief The NCE (Native Code Execution) class is responsible for managing the state of catching instructions and directly controlling processes/threads
|
||||
*/
|
||||
@ -140,5 +143,11 @@ namespace skyline {
|
||||
* @param pid The PID of the process (Defaults to currPid)
|
||||
*/
|
||||
void SetRegister(Sreg regId, u32 value, pid_t pid = 0);
|
||||
|
||||
/**
|
||||
* @brief This patches specific parts of the code
|
||||
* @param code A vector with the code to be patched
|
||||
*/
|
||||
std::vector<u32> PatchCode(std::vector<u8> &code, i64 offset);
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user