From b73ab88693fe5eeffc0f0cb0b93903d12e745388 Mon Sep 17 00:00:00 2001 From: tihmstar Date: Thu, 13 Aug 2020 22:51:18 +0200 Subject: [PATCH] added get_rw_and_x_mappings_patch_el1 --- .../liboffsetfinder64/ibootpatchfinder64.hpp | 11 +- .../ibootpatchfinder64_iOS14.hpp | 6 +- .../liboffsetfinder64/kernelpatchfinder64.hpp | 8 +- include/liboffsetfinder64/patchfinder64.hpp | 8 + liboffsetfinder64/ibootpatchfinder64.cpp | 6 +- .../ibootpatchfinder64_iOS14.cpp | 212 +++++++++++++++--- liboffsetfinder64/kernelpatchfinder64.cpp | 31 --- liboffsetfinder64/main.cpp | 10 +- liboffsetfinder64/patchfinder64.cpp | 134 +++++++++++ 9 files changed, 357 insertions(+), 69 deletions(-) diff --git a/include/liboffsetfinder64/ibootpatchfinder64.hpp b/include/liboffsetfinder64/ibootpatchfinder64.hpp index 709e122..51fdc4c 100644 --- a/include/liboffsetfinder64/ibootpatchfinder64.hpp +++ b/include/liboffsetfinder64/ibootpatchfinder64.hpp @@ -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 get_disable_wxn_patch(); + + virtual std::vector get_rw_and_x_mappings_patch_el1(); + }; }; }; diff --git a/include/liboffsetfinder64/ibootpatchfinder64_iOS14.hpp b/include/liboffsetfinder64/ibootpatchfinder64_iOS14.hpp index f32530a..b4a4c83 100644 --- a/include/liboffsetfinder64/ibootpatchfinder64_iOS14.hpp +++ b/include/liboffsetfinder64/ibootpatchfinder64_iOS14.hpp @@ -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 get_disable_wxn_patch() override; - + virtual uint32_t get_el1_pagesize() override; + + virtual std::vector get_rw_and_x_mappings_patch_el1() override; + }; }; }; diff --git a/include/liboffsetfinder64/kernelpatchfinder64.hpp b/include/liboffsetfinder64/kernelpatchfinder64.hpp index 912efc8..70383fa 100644 --- a/include/liboffsetfinder64/kernelpatchfinder64.hpp +++ b/include/liboffsetfinder64/kernelpatchfinder64.hpp @@ -13,15 +13,11 @@ namespace tihmstar { namespace offsetfinder64 { - class kernelpatchfinder64 : public machopatchfinder64{ - std::vector> _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); diff --git a/include/liboffsetfinder64/patchfinder64.hpp b/include/liboffsetfinder64/patchfinder64.hpp index 106afeb..6cf1846 100644 --- a/include/liboffsetfinder64/patchfinder64.hpp +++ b/include/liboffsetfinder64/patchfinder64.hpp @@ -33,6 +33,8 @@ namespace tihmstar { offsetfinder64::loc_t _entrypoint; offsetfinder64::loc_t _base; tihmstar::libinsn::vmem *_vmem; + std::vector> _usedNops; + public: patchfinder64(bool freeBuf); @@ -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); }; diff --git a/liboffsetfinder64/ibootpatchfinder64.cpp b/liboffsetfinder64/ibootpatchfinder64.cpp index 64474db..8d5172b 100644 --- a/liboffsetfinder64/ibootpatchfinder64.cpp +++ b/liboffsetfinder64/ibootpatchfinder64.cpp @@ -137,6 +137,10 @@ loc_t ibootpatchfinder64::find_iBoot_logstr(uint64_t loghex, int skip, uint64_t reterror("not implemented by provider"); } -std::vector ibootpatchfinder64::get_disable_wxn_patch(){ +uint32_t ibootpatchfinder64::get_el1_pagesize(){ + reterror("not implemented by provider"); +} + +std::vector ibootpatchfinder64::get_rw_and_x_mappings_patch_el1(){ reterror("not implemented by provider"); } diff --git a/liboffsetfinder64/ibootpatchfinder64_iOS14.cpp b/liboffsetfinder64/ibootpatchfinder64_iOS14.cpp index 0197149..22060af 100644 --- a/liboffsetfinder64/ibootpatchfinder64_iOS14.cpp +++ b/liboffsetfinder64/ibootpatchfinder64_iOS14.cpp @@ -153,42 +153,202 @@ loc_t ibootpatchfinder64_iOS14::find_iBoot_logstr(uint64_t loghex, int skip, uin return 0; } -std::vector 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 ibootpatchfinder64_iOS14::get_rw_and_x_mappings_patch_el1(){ std::vector 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; ilocmemmem(needle, nopCnt*4,pos+4); - std::pair 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); diff --git a/liboffsetfinder64/main.cpp b/liboffsetfinder64/main.cpp index 713f1ee..187ca27 100644 --- a/liboffsetfinder64/main.cpp +++ b/liboffsetfinder64/main.cpp @@ -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; imemmem(needle, nopCnt*4,pos+4); + std::pair 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; +} + +uint32_t patchfinder64::pageshit_for_pagesize(uint32_t pagesize){ + uint32_t pageshift = 0; + while (pagesize>>=1) pageshift++; + return pageshift; +} + + +uint64_t patchfinder64::pte_vma_to_index(uint32_t pagesize, uint8_t level, uint64_t address){ + switch (pagesize) { + case 0x1000: //4K + switch (level) { + case 0: + return BIT_RANGE(address, 39, 47); + case 1: + return BIT_RANGE(address, 30, 38); + case 2: + return BIT_RANGE(address, 21, 29); + case 3: + return BIT_RANGE(address, 12, 20); + default: + reterror("[4K] bad level=%d",level); + } + break; + case 0x4000: //16K + switch (level) { + case 0: + return BIT_AT(address, 47); + case 1: + return BIT_RANGE(address, 36, 46); + case 2: + return BIT_RANGE(address, 25, 35); + case 3: + return BIT_RANGE(address, 14, 24); + default: + reterror("[16K] bad level=%d",level); + } + break; + case 0x10000: //64K + switch (level) { + case 1: + return BIT_RANGE(address, 42, 51); + case 2: + return BIT_RANGE(address, 29, 41); + case 3: + return BIT_RANGE(address, 16, 28); + default: + reterror("[64K] bad level=%d",level); + } + break; + default: + reterror("bad pagesize"); + } +} + +uint64_t patchfinder64::pte_index_to_vma(uint32_t pagesize, uint8_t level, uint64_t index){ + switch (pagesize) { + case 0x1000: //4K + switch (level) { + case 0: + return (index << 39) & ((1UL<<(47+1))-1); + case 1: + return (index << 30) & ((1UL<<(38+1))-1); + case 2: + return (index << 21) & ((1UL<<(29+1))-1); + case 3: + return (index << 12) & ((1UL<<(20+1))-1); + default: + reterror("[4K] bad level=%d",level); + } + break; + case 0x4000: //16K + switch (level) { + case 0: + return (index << 47) & ((1UL<<(47+1))-1); + case 1: + return (index << 36) & ((1UL<<(46+1))-1); + case 2: + return (index << 25) & ((1UL<<(35+1))-1); + case 3: + return (index << 14) & ((1UL<<(24+1))-1); + default: + reterror("[16K] bad level=%d",level); + } + break; + case 0x10000: //64K + switch (level) { + case 1: + return (index << 42) & ((1UL<<(51+1))-1); + case 2: + return (index << 29) & ((1UL<<(41+1))-1); + case 3: + return (index << 16) & ((1UL<<(28+1))-1); + default: + reterror("[64K] bad level=%d",level); + } + break; + default: + reterror("bad pagesize"); + } +} + + + + //