Skip to content

Commit

Permalink
added get_rw_and_x_mappings_patch_el1
Browse files Browse the repository at this point in the history
  • Loading branch information
tihmstar committed Aug 13, 2020
1 parent 3f80605 commit b73ab88
Show file tree
Hide file tree
Showing 9 changed files with 357 additions and 69 deletions.
11 changes: 9 additions & 2 deletions include/liboffsetfinder64/ibootpatchfinder64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,18 @@ namespace tihmstar {

virtual loc_t find_iBoot_logstr(uint64_t loghex, int skip = 0, uint64_t shortdec = 0);


virtual uint32_t get_el1_pagesize();

/*
set SCTLR_EL1_WXN to 0
maps iBoot block writable at 0x2000000
maps loadaddr block executable at 0x4000000
*/
virtual std::vector<patch> get_disable_wxn_patch();

virtual std::vector<patch> get_rw_and_x_mappings_patch_el1();


};
};
};
Expand Down
6 changes: 4 additions & 2 deletions include/liboffsetfinder64/ibootpatchfinder64_iOS14.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ namespace tihmstar {

virtual loc_t find_iBoot_logstr(uint64_t loghex, int skip = 0, uint64_t shortdec = 0) override;

virtual std::vector<patch> get_disable_wxn_patch() override;

virtual uint32_t get_el1_pagesize() override;

virtual std::vector<patch> get_rw_and_x_mappings_patch_el1() override;

};
};
};
Expand Down
8 changes: 2 additions & 6 deletions include/liboffsetfinder64/kernelpatchfinder64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,11 @@

namespace tihmstar {
namespace offsetfinder64 {
class kernelpatchfinder64 : public machopatchfinder64{
std::vector<std::pair<loc_t, loc_t>> _usedNops;

class kernelpatchfinder64 : public machopatchfinder64{
public:
kernelpatchfinder64(const char *filename);
kernelpatchfinder64(const void *buffer, size_t bufSize);

loc_t findnops(uint16_t nopCnt, bool useNops = true);


loc_t find_syscall0();
loc_t find_machtrap_table();
loc_t find_function_for_syscall(int syscall);
Expand Down
8 changes: 8 additions & 0 deletions include/liboffsetfinder64/patchfinder64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ namespace tihmstar {
offsetfinder64::loc_t _entrypoint;
offsetfinder64::loc_t _base;
tihmstar::libinsn::vmem *_vmem;
std::vector<std::pair<loc_t, loc_t>> _usedNops;


public:
patchfinder64(bool freeBuf);
Expand All @@ -52,6 +54,12 @@ namespace tihmstar {
loc_t find_literal_ref(loc_t pos, int ignoreTimes = 0, loc_t startPos = 0);
loc_t find_call_ref(loc_t pos, int ignoreTimes = 0);
loc_t find_branch_ref(loc_t pos, int limit, int ignoreTimes = 0);
loc_t findnops(uint16_t nopCnt, bool useNops = true);


uint32_t pageshit_for_pagesize(uint32_t pagesize);
uint64_t pte_vma_to_index(uint32_t pagesize, uint8_t level, uint64_t address);
uint64_t pte_index_to_vma(uint32_t pagesize, uint8_t level, uint64_t index);

};

Expand Down
6 changes: 5 additions & 1 deletion liboffsetfinder64/ibootpatchfinder64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ loc_t ibootpatchfinder64::find_iBoot_logstr(uint64_t loghex, int skip, uint64_t
reterror("not implemented by provider");
}

std::vector<patch> ibootpatchfinder64::get_disable_wxn_patch(){
uint32_t ibootpatchfinder64::get_el1_pagesize(){
reterror("not implemented by provider");
}

std::vector<patch> ibootpatchfinder64::get_rw_and_x_mappings_patch_el1(){
reterror("not implemented by provider");
}
212 changes: 186 additions & 26 deletions liboffsetfinder64/ibootpatchfinder64_iOS14.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,42 +153,202 @@ loc_t ibootpatchfinder64_iOS14::find_iBoot_logstr(uint64_t loghex, int skip, uin
return 0;
}

std::vector<patch> ibootpatchfinder64_iOS14::get_disable_wxn_patch(){

uint32_t ibootpatchfinder64_iOS14::get_el1_pagesize(){
vmem iter(*_vmem);

while (++iter != insn::msr || iter().special() != insn::tcr_el1);

loc_t write_tcr_el1 = iter;
debug("write_tcr_el1=%p",write_tcr_el1);

loc_t ref_write_tcr_el1 = find_call_ref(write_tcr_el1);
debug("ref_write_tcr_el1=%p",ref_write_tcr_el1);

iter = ref_write_tcr_el1;
--iter;

assure(iter() == insn::bl);

loc_t get_tcr_el1 = iter().imm();
debug("get_tcr_el1=%p",get_tcr_el1);

iter = get_tcr_el1;

while (++iter != insn::ret);
loc_t get_tcr_el1_eof = iter;
debug("get_tcr_el1_eof=%p",get_tcr_el1_eof);

uint64_t tcr_el1_val = find_register_value(get_tcr_el1_eof,0,get_tcr_el1);
debug("tcr_el1_val=%p",tcr_el1_val);

uint8_t TG0 = (tcr_el1_val >> 14) & 0b11;

switch (TG0) {
case 0b00:
return 0x1000;
case 0b01:
return 0x10000;
case 0b10:
return 0x4000;
default:
reterror("invalid TG0=%d",TG0);
}
}


std::vector<patch> ibootpatchfinder64_iOS14::get_rw_and_x_mappings_patch_el1(){
std::vector<patch> patches;

uint32_t pagesize = get_el1_pagesize();

vmem iter(*_vmem);

while (++iter != insn::msr || iter().special() != insn::ttbr0_el1);

while (true) {
while (++iter != insn::msr || iter().special() != insn::sctlr_el1 || iter().rt() != 0);

for (int i=0; i<10; i++) {
if (++iter == insn::mov && iter().rd() == 1 && iter().rm() == 0){
goto found_place;
}
if (iter() == insn::ret) break;
}
continue;

found_place:
break;
loc_t write_ttbr0_el1 = iter;
debug("write_ttbr0_el1=%p",write_ttbr0_el1);

while (++iter != insn::ret);
loc_t write_ttbr0_el1_eof = iter;
debug("write_ttbr0_el1_eof=%p",write_ttbr0_el1_eof);

uint32_t pageshift = pageshit_for_pagesize(pagesize);

/*
create iboot_base_block_entry (rw)
*/
uint64_t iboot_base_block_entry = find_base();

//mask off unneeded bits
iboot_base_block_entry = pte_vma_to_index(pagesize,2,iboot_base_block_entry);
iboot_base_block_entry = pte_index_to_vma(pagesize, 2, iboot_base_block_entry);

//set pte bits
iboot_base_block_entry |= 0x445;

/*
create loadaddr_block_entry (rx)
*/
loc_t loadaddr_str = findstr("loadaddr", true);
debug("loadaddr_str=%p",loadaddr_str);
loc_t loadaddr = 0;
while (!loadaddr) {
loc_t loadaddr_ref = find_literal_ref(loadaddr_str);
debug("loadaddr_ref=%p",loadaddr_ref);
vmem iter(*_vmem,loadaddr_ref);

while (++iter != insn::bl);
loc_t loadaddr_ref_firstbl = iter;
debug("loadaddr_ref_firstbl=%p",loadaddr_ref_firstbl);

loadaddr = find_register_value(loadaddr_ref_firstbl, 1, loadaddr_ref);
}

debug("loadaddr=%p",loadaddr);

loc_t msr_sctlr_el1 = iter;
debug("msr_sctlr_el1=%p",msr_sctlr_el1);
//mask off unneeded bits
uint64_t loadaddr_block_entry = pte_vma_to_index(pagesize,2,loadaddr);
loadaddr_block_entry = pte_index_to_vma(pagesize, 2, loadaddr_block_entry);

while (++iter == insn::orr) {
if (iter().imm() == 0x80000) {
goto found_patch;
}
//set pte bits
loadaddr_block_entry |= 0x4c5;

uint32_t orig_write_ttbr0_el1_insn_cnt = (write_ttbr0_el1_eof-write_ttbr0_el1+4)/4;
bool needs_alignment = ! (orig_write_ttbr0_el1_insn_cnt&1);


/*
create patch
ldr x1, =0x180000445
nop
ldr x2, =0x8000004c5
stp x1, x2, [x0, #0x8]
dmb sy
///orig
msr ttbr0_el1, x0
isb
ret
///orig end
dq 0x0000000180000445
dq 0x00000008000004c5
*/
uint8_t cinsn = 0;
{
//ldr x1, =0x180000445
insn pins = insn::new_literal_ldr(0, (5+orig_write_ttbr0_el1_insn_cnt)*4, 1);
uint32_t opcode = pins.opcode();
patches.push_back({(loc_t)(cinsn++*4),&opcode, sizeof(opcode)});
}
reterror("failed to find loc");
{
//nop
insn pins = insn::new_general_nop(0);
uint32_t opcode = pins.opcode();
patches.push_back({(loc_t)(cinsn++*4),&opcode, sizeof(opcode)});
}
{
//ldr x2, =0x8000004c5
insn pins = insn::new_literal_ldr(0, (5+orig_write_ttbr0_el1_insn_cnt)*4, 2);
uint32_t opcode = pins.opcode();
patches.push_back({(loc_t)(cinsn++*4),&opcode, sizeof(opcode)});
}
{
//stp x1, x2, [x0, #0x8]
insn pins = insn::new_general_stp_offset(0, 8, 1, 2, 0);
uint32_t opcode = pins.opcode();
patches.push_back({(loc_t)(cinsn++*4),&opcode, sizeof(opcode)});
}
//dmb sy
patches.push_back({(loc_t)(cinsn++*4),"\xBF\x3F\x03\xD5",4});

found_patch:
loc_t patchloc = iter;
debug("patchloc=%p",patchloc);
uint32_t *orig_opcodes = (uint32_t*)memoryForLoc(write_ttbr0_el1);
patches.push_back({(loc_t)(cinsn*4),orig_opcodes,4*orig_write_ttbr0_el1_insn_cnt});cinsn+=orig_write_ttbr0_el1_insn_cnt;

//and x0, x0, #0xfffffffffff7ffff
patches.push_back({(loc_t)iter.pc(), "\x00\xF8\x6C\x92", 4});
patches.push_back({(loc_t)(cinsn*4),&iboot_base_block_entry,sizeof(iboot_base_block_entry)}); cinsn+=sizeof(iboot_base_block_entry)/4;
patches.push_back({(loc_t)(cinsn*4),&loadaddr_block_entry,sizeof(loadaddr_block_entry)}); cinsn+=sizeof(loadaddr_block_entry)/4;

uint32_t fullpatch_size = 0;
for (auto p: patches){
fullpatch_size += p._patchSize;
}

/*
now find an empty spot for to place the payload
*/
loc_t nopspace = findnops(fullpatch_size/4 + 1, true); //alloc 1 more nop than we need
debug("nopspace=%p",nopspace);

/*
ldp needs to load from 8 byte aligned address
if needs_alignment is false, we start at 8 byte aligned address and the data is placed at 8 byte aligned
if needs_alignmend is true, then we need to start at 8byte aligned + 4 for the data to be 8 byte aligned
*/
if (((nopspace & 0x4) && !needs_alignment /* we don't need alignment, but we start at an +4 address*/ )
|| (((nopspace & 0x4) == 0) && needs_alignment) /* we are at 8 byte aligned, but we need fixup*/) {
nopspace+=4;
}

//now fixup payload addresses
for (auto &p: patches){
p._location += nopspace;
}

/*
finally rewrite write_ttbr0 to jump to payload
*/
for (loc_t iloc = write_ttbr0_el1; iloc<write_ttbr0_el1_eof; iloc+=4) {
insn pins = insn::new_general_nop(iloc);
uint32_t opcode = pins.opcode();
patches.push_back({pins,&opcode,sizeof(opcode)});
}

{
//make last orig insn of write_ttbr0 jump to payload
insn pins = insn::new_immediate_b(write_ttbr0_el1_eof, nopspace);
uint32_t opcode = pins.opcode();
patches.push_back({pins,&opcode,sizeof(opcode)});
}


return patches;
}
31 changes: 0 additions & 31 deletions liboffsetfinder64/kernelpatchfinder64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,6 @@ kernelpatchfinder64::kernelpatchfinder64(const void *buffer, size_t bufSize)
//
}

loc_t kernelpatchfinder64::findnops(uint16_t nopCnt, bool useNops){
uint32_t *needle = NULL;
cleanup([&]{
safeFree(needle);
});
loc_t pos = 0;
needle = (uint32_t *)malloc(nopCnt*4);

for (uint16_t i=0; i<nopCnt; i++) {
needle[i] = *(uint32_t*)"\x1F\x20\x03\xD5";
}


pos = -4;
nextNops:
pos = _vmem->memmem(needle, nopCnt*4,pos+4);
std::pair<loc_t, loc_t> range(pos,pos+4*nopCnt);

for (auto &r : _usedNops) {
if (r.first > range.first && r.first < range.second) goto nextNops; //used range inside found range
if (range.first > r.first && range.first < r.second) goto nextNops; //found range inside used range
}

if (useNops) {
_usedNops.push_back(range);
}

return pos;
}


loc_t kernelpatchfinder64::find_syscall0(){
constexpr char sig_syscall_3[] = "\x06\x00\x00\x00\x03\x00\x0c\x00";
loc_t sys3 = _vmem->memmem(sig_syscall_3, sizeof(sig_syscall_3)-1);
Expand Down
10 changes: 9 additions & 1 deletion liboffsetfinder64/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ int main(int argc, const char * argv[]) {
//
// loc_t dsa = ibpf->find_iBoot_logstr(0xdce7b01f6ef60a3);

ibpf->get_disable_wxn_patch();
auto patches = ibpf->get_rw_and_x_mappings_patch_el1();

for (auto p : patches) {
printf(": Applying patch=%p : ",(void*)p._location);
for (int i=0; i<p._patchSize; i++) {
printf("%02x",((uint8_t*)p._patch)[i]);
}
printf("\n");
}

printf("done\n");
return 0;
Expand Down
Loading

0 comments on commit b73ab88

Please sign in to comment.