└── jni ├── And64InlineHook.cpp ├── And64InlineHook.hpp ├── Android.mk ├── Application.mk ├── Substrate ├── Buffer.hpp ├── CydiaSubstrate.h ├── SubstrateARM.hpp ├── SubstrateDebug.cpp ├── SubstrateDebug.hpp ├── SubstrateHook.cpp ├── SubstrateHook.h ├── SubstrateLog.hpp ├── SubstratePosixMemory.cpp ├── SubstrateX86.hpp ├── hde64.c ├── hde64.h └── table64.h ├── cas.cpp ├── fake_dlfcn.cpp └── fake_dlfcn.h /jni/And64InlineHook.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @date : 2018/04/18 3 | * @author : Rprop (r_prop@outlook.com) 4 | * https://github.com/Rprop/And64InlineHook 5 | */ 6 | /* 7 | MIT License 8 | 9 | Copyright (c) 2018 Rprop (r_prop@outlook.com) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | */ 29 | #define __STDC_FORMAT_MACROS 30 | 31 | #if defined(__aarch64__) 32 | 33 | #include 34 | #include 35 | #include 36 | #include "And64InlineHook.hpp" 37 | #define A64_MAX_INSTRUCTIONS 5 38 | #define A64_MAX_REFERENCES (A64_MAX_INSTRUCTIONS * 2) 39 | #define A64_NOP 0xd503201fu 40 | #define A64_JNIEXPORT __attribute__((visibility("default"))) 41 | #define __flush_cache(c, n) __builtin___clear_cache(reinterpret_cast(c), reinterpret_cast(c) + n) 42 | 43 | 44 | typedef uint32_t *__restrict *__restrict instruction; 45 | typedef struct 46 | { 47 | struct fix_info 48 | { 49 | uint32_t *bp; 50 | uint32_t ls; // left-shift counts 51 | uint32_t ad; // & operand 52 | }; 53 | struct insns_info 54 | { 55 | union 56 | { 57 | uint64_t insu; 58 | int64_t ins; 59 | void *insp; 60 | }; 61 | fix_info fmap[A64_MAX_REFERENCES]; 62 | }; 63 | int64_t basep; 64 | int64_t endp; 65 | insns_info dat[A64_MAX_INSTRUCTIONS]; 66 | 67 | public: 68 | inline bool is_in_fixing_range(const int64_t absolute_addr) { 69 | return absolute_addr >= this->basep && absolute_addr < this->endp; 70 | } 71 | inline intptr_t get_ref_ins_index(const int64_t absolute_addr) { 72 | return static_cast((absolute_addr - this->basep) / sizeof(uint32_t)); 73 | } 74 | inline intptr_t get_and_set_current_index(uint32_t *__restrict inp, uint32_t *__restrict outp) { 75 | intptr_t current_idx = this->get_ref_ins_index(reinterpret_cast(inp)); 76 | this->dat[current_idx].insp = outp; 77 | return current_idx; 78 | } 79 | inline void reset_current_ins(const intptr_t idx, uint32_t *__restrict outp) { 80 | this->dat[idx].insp = outp; 81 | } 82 | void insert_fix_map(const intptr_t idx, uint32_t *bp, uint32_t ls = 0u, uint32_t ad = 0xffffffffu) { 83 | for (auto &f : this->dat[idx].fmap) { 84 | if (f.bp == NULL) { 85 | f.bp = bp; 86 | f.ls = ls; 87 | f.ad = ad; 88 | return; 89 | } //if 90 | } 91 | // What? GGing.. 92 | } 93 | void process_fix_map(const intptr_t idx) { 94 | for (auto &f : this->dat[idx].fmap) { 95 | if (f.bp == NULL) break; 96 | *(f.bp) = *(f.bp) | (((int32_t(this->dat[idx].ins - reinterpret_cast(f.bp)) >> 2) << f.ls) & f.ad); 97 | f.bp = NULL; 98 | } 99 | } 100 | } context; 101 | 102 | //------------------------------------------------------------------------- 103 | 104 | static bool __fix_branch_imm(instruction inpp, instruction outpp, context *ctxp) 105 | { 106 | static constexpr uint32_t mbits = 6u; 107 | static constexpr uint32_t mask = 0xfc000000u; // 0b11111100000000000000000000000000 108 | static constexpr uint32_t rmask = 0x03ffffffu; // 0b00000011111111111111111111111111 109 | static constexpr uint32_t op_b = 0x14000000u; // "b" ADDR_PCREL26 110 | static constexpr uint32_t op_bl = 0x94000000u; // "bl" ADDR_PCREL26 111 | 112 | const uint32_t ins = *(*inpp); 113 | const uint32_t opc = ins & mask; 114 | switch (opc) { 115 | case op_b: 116 | case op_bl: 117 | { 118 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 119 | int64_t absolute_addr = reinterpret_cast(*inpp) + (static_cast(ins << mbits) >> (mbits - 2u)); // sign-extended 120 | int64_t new_pc_offset = static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 121 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 122 | // whether the branch should be converted to absolute jump 123 | if (!special_fix_type && llabs(new_pc_offset) >= (rmask >> 1)) { 124 | bool b_aligned = (reinterpret_cast(*outpp + 2) & 7u) == 0u; 125 | if (opc == op_b) { 126 | if (b_aligned != true) { 127 | (*outpp)[0] = A64_NOP; 128 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 129 | } //if 130 | (*outpp)[0] = 0x58000051u; // LDR X17, #0x8 131 | (*outpp)[1] = 0xd61f0220u; // BR X17 132 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); 133 | *outpp += 4; 134 | } else { 135 | if (b_aligned == true) { 136 | (*outpp)[0] = A64_NOP; 137 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 138 | } //if 139 | (*outpp)[0] = 0x58000071u; // LDR X17, #12 140 | (*outpp)[1] = 0x1000009eu; // ADR X30, #16 141 | (*outpp)[2] = 0xd61f0220u; // BR X17 142 | memcpy(*outpp + 3, &absolute_addr, sizeof(absolute_addr)); 143 | *outpp += 5; 144 | } //if 145 | } else { 146 | if (special_fix_type) { 147 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); 148 | if (ref_idx <= current_idx) { 149 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - reinterpret_cast(*outpp)) >> 2; 150 | } else { 151 | ctxp->insert_fix_map(ref_idx, *outpp, 0u, rmask); 152 | new_pc_offset = 0; 153 | } //if 154 | } //if 155 | 156 | (*outpp)[0] = opc | (new_pc_offset & ~mask); 157 | ++(*outpp); 158 | } //if 159 | 160 | ++(*inpp); 161 | return ctxp->process_fix_map(current_idx), true; 162 | } 163 | } 164 | return false; 165 | } 166 | 167 | //------------------------------------------------------------------------- 168 | 169 | static bool __fix_cond_comp_test_branch(instruction inpp, instruction outpp, context *ctxp) 170 | { 171 | static constexpr uint32_t lsb = 5u; 172 | static constexpr uint32_t lmask01 = 0xff00001fu; // 0b11111111000000000000000000011111 173 | static constexpr uint32_t mask0 = 0xff000010u; // 0b11111111000000000000000000010000 174 | static constexpr uint32_t op_bc = 0x54000000u; // "b.c" ADDR_PCREL19 175 | static constexpr uint32_t mask1 = 0x7f000000u; // 0b01111111000000000000000000000000 176 | static constexpr uint32_t op_cbz = 0x34000000u; // "cbz" Rt, ADDR_PCREL19 177 | static constexpr uint32_t op_cbnz = 0x35000000u; // "cbnz" Rt, ADDR_PCREL19 178 | static constexpr uint32_t lmask2 = 0xfff8001fu; // 0b11111111111110000000000000011111 179 | static constexpr uint32_t mask2 = 0x7f000000u; // 0b01111111000000000000000000000000 180 | static constexpr uint32_t op_tbz = 0x36000000u; // 0b00110110000000000000000000000000 "tbz" Rt, BIT_NUM, ADDR_PCREL14 181 | static constexpr uint32_t op_tbnz = 0x37000000u; // 0b00110111000000000000000000000000 "tbnz" Rt, BIT_NUM, ADDR_PCREL14 182 | 183 | const uint32_t ins = *(*inpp); 184 | uint32_t lmask = lmask01; 185 | if ((ins & mask0) != op_bc) { 186 | uint32_t opc = ins & mask1; 187 | if (opc != op_cbz && opc != op_cbnz) { 188 | opc = ins & mask2; 189 | if (opc != op_tbz && opc != op_tbnz) { 190 | return false; 191 | } //if 192 | lmask = lmask2; 193 | } //if 194 | } //if 195 | 196 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 197 | int64_t absolute_addr = reinterpret_cast(*inpp) + ((ins & ~lmask) >> (lsb - 2u)); 198 | int64_t new_pc_offset = static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 199 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 200 | if (!special_fix_type && llabs(new_pc_offset) >= (~lmask >> (lsb + 1))) { 201 | if ((reinterpret_cast(*outpp + 4) & 7u) != 0u) { 202 | (*outpp)[0] = A64_NOP; 203 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 204 | } //if 205 | (*outpp)[0] = (((8u >> 2u) << lsb) & ~lmask) | (ins & lmask); // B.C #0x8 206 | (*outpp)[1] = 0x14000005u; // B #0x14 207 | (*outpp)[2] = 0x58000051u; // LDR X17, #0x8 208 | (*outpp)[3] = 0xd61f0220u; // BR X17 209 | memcpy(*outpp + 4, &absolute_addr, sizeof(absolute_addr)); 210 | *outpp += 6; 211 | } else { 212 | if (special_fix_type) { 213 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); 214 | if (ref_idx <= current_idx) { 215 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - reinterpret_cast(*outpp)) >> 2; 216 | } else { 217 | ctxp->insert_fix_map(ref_idx, *outpp, lsb, ~lmask); 218 | new_pc_offset = 0; 219 | } //if 220 | } //if 221 | 222 | (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~lmask) | (ins & lmask); 223 | ++(*outpp); 224 | } //if 225 | 226 | ++(*inpp); 227 | return ctxp->process_fix_map(current_idx), true; 228 | } 229 | 230 | //------------------------------------------------------------------------- 231 | 232 | static bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp) 233 | { 234 | const uint32_t ins = *(*inpp); 235 | 236 | // memory prefetch("prfm"), just skip it 237 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html 238 | if ((ins & 0xff000000u) == 0xd8000000u) { 239 | ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp)); 240 | ++(*inpp); 241 | return true; 242 | } //if 243 | 244 | static constexpr uint32_t msb = 8u; 245 | static constexpr uint32_t lsb = 5u; 246 | static constexpr uint32_t mask_30 = 0x40000000u; // 0b01000000000000000000000000000000 247 | static constexpr uint32_t mask_31 = 0x80000000u; // 0b10000000000000000000000000000000 248 | static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 249 | static constexpr uint32_t mask_ldr = 0xbf000000u; // 0b10111111000000000000000000000000 250 | static constexpr uint32_t op_ldr = 0x18000000u; // 0b00011000000000000000000000000000 "LDR Wt/Xt, label" | ADDR_PCREL19 251 | static constexpr uint32_t mask_ldrv = 0x3f000000u; // 0b00111111000000000000000000000000 252 | static constexpr uint32_t op_ldrv = 0x1c000000u; // 0b00011100000000000000000000000000 "LDR St/Dt/Qt, label" | ADDR_PCREL19 253 | static constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000 254 | static constexpr uint32_t op_ldrsw = 0x98000000u; // "LDRSW Xt, label" | ADDR_PCREL19 | load register signed word 255 | // LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit 256 | // LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit 257 | // LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit 258 | // INVALID | 0b11011100000000000000000000000000 | may be 256-bit 259 | 260 | uint32_t mask = mask_ldr; 261 | uintptr_t faligned = (ins & mask_30) ? 7u : 3u; 262 | if ((ins & mask_ldr) != op_ldr) { 263 | mask = mask_ldrv; 264 | if (faligned != 7u) 265 | faligned = (ins & mask_31) ? 15u : 3u; 266 | if ((ins & mask_ldrv) != op_ldrv) { 267 | if ((ins & mask_ldrsw) != op_ldrsw) { 268 | return false; 269 | } //if 270 | mask = mask_ldrsw; 271 | faligned = 7u; 272 | } //if 273 | } //if 274 | 275 | intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 276 | int64_t absolute_addr = reinterpret_cast(*inpp) + ((static_cast(ins << msb) >> (msb + lsb - 2u)) & ~3u); 277 | int64_t new_pc_offset = static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; // shifted 278 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 279 | // special_fix_type may encounter issue when there are mixed data and code 280 | if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u) / 4u) >= (~lmask >> (lsb + 1))) { // inaccurate, but it works 281 | while ((reinterpret_cast(*outpp + 2) & faligned) != 0u) { 282 | *(*outpp)++ = A64_NOP; 283 | } 284 | ctxp->reset_current_ins(current_idx, *outpp); 285 | 286 | // Note that if memory at absolute_addr is writeable (non-const), we will fail to fetch it. 287 | // And what's worse, we may unexpectedly overwrite something if special_fix_type is true... 288 | uint32_t ns = static_cast((faligned + 1) / sizeof(uint32_t)); 289 | (*outpp)[0] = (((8u >> 2u) << lsb) & ~mask) | (ins & lmask); // LDR #0x8 290 | (*outpp)[1] = 0x14000001u + ns; // B #0xc 291 | memcpy(*outpp + 2, reinterpret_cast(absolute_addr), faligned + 1); 292 | *outpp += 2 + ns; 293 | } else { 294 | faligned >>= 2; // new_pc_offset is shifted and 4-byte aligned 295 | while ((new_pc_offset & faligned) != 0) { 296 | *(*outpp)++ = A64_NOP; 297 | new_pc_offset = static_cast(absolute_addr - reinterpret_cast(*outpp)) >> 2; 298 | } 299 | ctxp->reset_current_ins(current_idx, *outpp); 300 | 301 | (*outpp)[0] = (static_cast(new_pc_offset << lsb) & ~mask) | (ins & lmask); 302 | ++(*outpp); 303 | } //if 304 | 305 | ++(*inpp); 306 | return ctxp->process_fix_map(current_idx), true; 307 | } 308 | 309 | //------------------------------------------------------------------------- 310 | 311 | static bool __fix_pcreladdr(instruction inpp, instruction outpp, context *ctxp) 312 | { 313 | // Load a PC-relative address into a register 314 | // http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897645644.html 315 | static constexpr uint32_t msb = 8u; 316 | static constexpr uint32_t lsb = 5u; 317 | static constexpr uint32_t mask = 0x9f000000u; // 0b10011111000000000000000000000000 318 | static constexpr uint32_t rmask = 0x0000001fu; // 0b00000000000000000000000000011111 319 | static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111 320 | static constexpr uint32_t fmask = 0x00ffffffu; // 0b00000000111111111111111111111111 321 | static constexpr uint32_t max_val = 0x001fffffu; // 0b00000000000111111111111111111111 322 | static constexpr uint32_t op_adr = 0x10000000u; // "adr" Rd, ADDR_PCREL21 323 | static constexpr uint32_t op_adrp = 0x90000000u; // "adrp" Rd, ADDR_ADRP 324 | 325 | const uint32_t ins = *(*inpp); 326 | intptr_t current_idx; 327 | switch (ins & mask) { 328 | case op_adr: 329 | { 330 | current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 331 | int64_t lsb_bytes = static_cast(ins << 1u) >> 30u; 332 | int64_t absolute_addr = reinterpret_cast(*inpp) + (((static_cast(ins << msb) >> (msb + lsb - 2u)) & ~3u) | lsb_bytes); 333 | int64_t new_pc_offset = static_cast(absolute_addr - reinterpret_cast(*outpp)); 334 | bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); 335 | if (!special_fix_type && llabs(new_pc_offset) >= (max_val >> 1)) { 336 | if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { 337 | (*outpp)[0] = A64_NOP; 338 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 339 | } //if 340 | 341 | (*outpp)[0] = 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 342 | (*outpp)[1] = 0x14000003u; // B #0xc 343 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); 344 | *outpp += 4; 345 | } else { 346 | if (special_fix_type) { 347 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr & ~3ull); 348 | if (ref_idx <= current_idx) { 349 | new_pc_offset = static_cast(ctxp->dat[ref_idx].ins - reinterpret_cast(*outpp)); 350 | } else { 351 | ctxp->insert_fix_map(ref_idx, *outpp, lsb, fmask); 352 | new_pc_offset = 0; 353 | } //if 354 | } //if 355 | 356 | // the lsb_bytes will never be changed, so we can use lmask to keep it 357 | (*outpp)[0] = (static_cast(new_pc_offset << (lsb - 2u)) & fmask) | (ins & lmask); 358 | ++(*outpp); 359 | } //if 360 | } 361 | break; 362 | case op_adrp: 363 | { 364 | current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); 365 | int32_t lsb_bytes = static_cast(ins << 1u) >> 30u; 366 | int64_t absolute_addr = (reinterpret_cast(*inpp) & ~0xfffll) + ((((static_cast(ins << msb) >> (msb + lsb - 2u)) & ~3u) | lsb_bytes) << 12); 367 | if (ctxp->is_in_fixing_range(absolute_addr)) { 368 | intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr/* & ~3ull*/); 369 | if (ref_idx > current_idx) { 370 | // the bottom 12 bits of absolute_addr are masked out, 371 | // so ref_idx must be less than or equal to current_idx! 372 | } //if 373 | 374 | // *absolute_addr may be changed due to relocation fixing 375 | *(*outpp)++ = ins; // 0x90000000u; 376 | } else { 377 | if ((reinterpret_cast(*outpp + 2) & 7u) != 0u) { 378 | (*outpp)[0] = A64_NOP; 379 | ctxp->reset_current_ins(current_idx, ++(*outpp)); 380 | } //if 381 | 382 | (*outpp)[0] = 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8 383 | (*outpp)[1] = 0x14000003u; // B #0xc 384 | memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); // potential overflow? 385 | *outpp += 4; 386 | } //if 387 | } 388 | break; 389 | default: 390 | return false; 391 | } 392 | 393 | ctxp->process_fix_map(current_idx); 394 | ++(*inpp); 395 | return true; 396 | } 397 | 398 | //------------------------------------------------------------------------- 399 | 400 | static void __fix_instructions(uint32_t *__restrict inp, int32_t count, uint32_t *__restrict outp) 401 | { 402 | context ctx; 403 | ctx.basep = reinterpret_cast(inp); 404 | ctx.endp = reinterpret_cast(inp + count); 405 | memset(ctx.dat, 0, sizeof(ctx.dat)); 406 | static_assert(sizeof(ctx.dat) / sizeof(ctx.dat[0]) == A64_MAX_INSTRUCTIONS, 407 | "please use A64_MAX_INSTRUCTIONS!"); 408 | #ifndef NDEBUG 409 | if (count > A64_MAX_INSTRUCTIONS) { 410 | A64_LOGE("too many fixing instructions!"); 411 | } //if 412 | #endif // NDEBUG 413 | 414 | uint32_t *const outp_base = outp; 415 | 416 | while (--count >= 0) { 417 | if (__fix_branch_imm(&inp, &outp, &ctx)) continue; 418 | if (__fix_cond_comp_test_branch(&inp, &outp, &ctx)) continue; 419 | if (__fix_loadlit(&inp, &outp, &ctx)) continue; 420 | if (__fix_pcreladdr(&inp, &outp, &ctx)) continue; 421 | 422 | // without PC-relative offset 423 | ctx.process_fix_map(ctx.get_and_set_current_index(inp, outp)); 424 | *(outp++) = *(inp++); 425 | } 426 | 427 | static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 428 | auto callback = reinterpret_cast(inp); 429 | auto pc_offset = static_cast(callback - reinterpret_cast(outp)) >> 2; 430 | if (llabs(pc_offset) >= (mask >> 1)) { 431 | if ((reinterpret_cast(outp + 2) & 7u) != 0u) { 432 | outp[0] = A64_NOP; 433 | ++outp; 434 | } //if 435 | outp[0] = 0x58000051u; // LDR X17, #0x8 436 | outp[1] = 0xd61f0220u; // BR X17 437 | *reinterpret_cast(outp + 2) = callback; 438 | outp += 4; 439 | } else { 440 | outp[0] = 0x14000000u | (pc_offset & mask); // "B" ADDR_PCREL26 441 | ++outp; 442 | } //if 443 | 444 | const uintptr_t total = (outp - outp_base) * sizeof(uint32_t); 445 | __flush_cache(outp_base, total); // necessary 446 | } 447 | 448 | //------------------------------------------------------------------------- 449 | 450 | extern "C" { 451 | #define __attribute __attribute__ 452 | #define aligned(x) __aligned__(x) 453 | #define __intval(p) reinterpret_cast(p) 454 | #define __uintval(p) reinterpret_cast(p) 455 | #define __ptr(p) reinterpret_cast(p) 456 | #define __page_size 4096 457 | #define __page_align(n) __align_up(static_cast(n), __page_size) 458 | #define __ptr_align(x) __ptr(__align_down(reinterpret_cast(x), __page_size)) 459 | #define __align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) 460 | #define __align_down(x, n) ((x) & -(n)) 461 | #define __countof(x) static_cast(sizeof(x) / sizeof((x)[0])) // must be signed 462 | #define __atomic_increase(p) __sync_add_and_fetch(p, 1) 463 | #define __sync_cmpswap(p, v, n) __sync_bool_compare_and_swap(p, v, n) 464 | #define __predict_true(exp) __builtin_expect((exp) != 0, 1) 465 | #define __make_rwx(p, n) ::mprotect(__ptr_align(p), \ 466 | __page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \ 467 | PROT_READ | PROT_WRITE | PROT_EXEC) 468 | 469 | //------------------------------------------------------------------------- 470 | 471 | static __attribute((aligned(__page_size))) uint32_t __insns_pool[A64_MAX_BACKUPS][A64_MAX_INSTRUCTIONS * 10]; 472 | 473 | //------------------------------------------------------------------------- 474 | 475 | class A64HookInit 476 | { 477 | public: 478 | A64HookInit() 479 | { 480 | __make_rwx(__insns_pool, sizeof(__insns_pool)); 481 | } 482 | }; 483 | static A64HookInit __init; 484 | 485 | //------------------------------------------------------------------------- 486 | 487 | static uint32_t *FastAllocateTrampoline() 488 | { 489 | static_assert((A64_MAX_INSTRUCTIONS * 10 * sizeof(uint32_t)) % 8 == 0, "8-byte align"); 490 | static volatile int32_t __index = -1; 491 | 492 | int32_t i = __atomic_increase(&__index); 493 | if (__predict_true(i >= 0 && i < __countof(__insns_pool))) { 494 | return __insns_pool[i]; 495 | } //if 496 | 497 | return NULL; 498 | } 499 | 500 | //------------------------------------------------------------------------- 501 | 502 | A64_JNIEXPORT void *A64HookFunctionV(void *const symbol, void *const replace, 503 | void *const rwx, const uintptr_t rwx_size) 504 | { 505 | static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111 506 | 507 | uint32_t *trampoline = static_cast(rwx), *original = static_cast(symbol); 508 | 509 | static_assert(A64_MAX_INSTRUCTIONS >= 5, "please fix A64_MAX_INSTRUCTIONS!"); 510 | auto pc_offset = static_cast(__intval(replace) - __intval(symbol)) >> 2; 511 | if (llabs(pc_offset) >= (mask >>1)) { 512 | int32_t count = (reinterpret_cast(original + 2) & 7u) != 0u ? 5 : 4; 513 | if (trampoline) { 514 | if (rwx_size < count * 10u) { 515 | return NULL; 516 | } //if 517 | __fix_instructions(original, count, trampoline); 518 | } //if 519 | 520 | if (__make_rwx(original, 5 * sizeof(uint32_t)) == 0) { 521 | if (count == 5) { 522 | original[0] = A64_NOP; 523 | ++original; 524 | } //if 525 | original[0] = 0x58000051u; // LDR X17, #0x8 526 | original[1] = 0xd61f0220u; // BR X17 527 | *reinterpret_cast(original + 2) = __intval(replace); 528 | __flush_cache(symbol, 5 * sizeof(uint32_t)); 529 | 530 | } else { 531 | trampoline = NULL; 532 | } //if 533 | } else { 534 | if (trampoline) { 535 | if (rwx_size < 1u * 10u) { 536 | return NULL; 537 | } //if 538 | __fix_instructions(original, 1, trampoline); 539 | } //if 540 | 541 | if (__make_rwx(original, 1 * sizeof(uint32_t)) == 0) { 542 | __sync_cmpswap(original, *original, 0x14000000u | (pc_offset & mask)); // "B" ADDR_PCREL26 543 | __flush_cache(symbol, 1 * sizeof(uint32_t)); 544 | 545 | } else { 546 | trampoline = NULL; 547 | } //if 548 | } //if 549 | 550 | return trampoline; 551 | } 552 | 553 | //------------------------------------------------------------------------- 554 | 555 | A64_JNIEXPORT void A64HookFunction(void *const symbol, void *const replace, void **result) 556 | { 557 | void *trampoline = NULL; 558 | if (result != NULL) { 559 | trampoline = FastAllocateTrampoline(); 560 | *result = trampoline; 561 | if (trampoline == NULL) return; 562 | } //if 563 | 564 | trampoline = A64HookFunctionV(symbol, replace, trampoline, A64_MAX_INSTRUCTIONS * 10u); 565 | if (trampoline == NULL && result != NULL) { 566 | *result = NULL; 567 | } //if 568 | } 569 | } 570 | 571 | #endif // defined(__aarch64__) -------------------------------------------------------------------------------- /jni/And64InlineHook.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @date : 2018/04/18 3 | * @author : Rprop (r_prop@outlook.com) 4 | * https://github.com/Rprop/And64InlineHook 5 | */ 6 | /* 7 | MIT License 8 | 9 | Copyright (c) 2018 Rprop (r_prop@outlook.com) 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | */ 29 | #pragma once 30 | 31 | #include 32 | 33 | #define A64_MAX_BACKUPS 256 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | void A64HookFunction(void *const symbol, void *const replace, void **result); 40 | void *A64HookFunctionV(void *const symbol, void *const replace, 41 | void *const rwx, const uintptr_t rwx_size); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | LOCAL_MODULE := cas 5 | LOCAL_SRC_FILES := \ 6 | cas.cpp \ 7 | fake_dlfcn.cpp 8 | 9 | ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) 10 | LOCAL_SRC_FILES += Substrate/hde64.c \ 11 | Substrate/SubstrateDebug.cpp \ 12 | Substrate/SubstrateHook.cpp \ 13 | Substrate/SubstratePosixMemory.cpp 14 | endif 15 | ifeq ($(TARGET_ARCH_ABI),arm64-v8a) 16 | LOCAL_SRC_FILES += And64InlineHook.cpp 17 | endif 18 | 19 | LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog -lz 20 | LOCAL_CPPFLAGS := -fexceptions -frtti -g -std=c++11 21 | LOCAL_CFLAGS += -pie -fPIE -std=c++11 -g 22 | include $(BUILD_SHARED_LIBRARY) 23 | 24 | include $(CLEAR_VARS) 25 | 26 | dest_path := /data/local/tmp 27 | p_path := /data/app/com.game.dir-i_RMvdy5OSL55GfGzCemdw==/lib/arm64 28 | all: 29 | adb push $(NDK_APP_DST_DIR)/libcas.so $(dest_path)/ 30 | adb shell "su -c "cp $(dest_path)/libcas.so $(p_path)/"" 31 | adb shell "su -c "chmod 777 $(p_path)/libcas.so"" -------------------------------------------------------------------------------- /jni/Application.mk: -------------------------------------------------------------------------------- 1 | NDK_TOOLCHAIN_VERSION := 4.9 2 | APP_STL := c++_static 3 | APP_CPPFLAGS += -std=c++11 4 | # APP_PLATFORM := android-9 5 | #APP_OPTIM := debug 6 | APP_ABI := arm64-v8a 7 | # APP_ABI := armeabi-v7a 8 | # APP_ABI := x86 -------------------------------------------------------------------------------- /jni/Substrate/Buffer.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_BUFFER_HPP 23 | #define SUBSTRATE_BUFFER_HPP 24 | 25 | #include 26 | 27 | template 28 | _disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { 29 | *reinterpret_cast(buffer) = value; 30 | buffer += sizeof(Type_); 31 | } 32 | 33 | _disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { 34 | memcpy(buffer, data, size); 35 | buffer += size; 36 | } 37 | 38 | #endif//SUBSTRATE_BUFFER_HPP 39 | -------------------------------------------------------------------------------- /jni/Substrate/CydiaSubstrate.h: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_H_ 23 | #define SUBSTRATE_H_ 24 | 25 | #ifdef __APPLE__ 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | #include 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | 34 | #include 35 | #include 36 | #endif 37 | 38 | #include 39 | #include 40 | 41 | #define _finline \ 42 | inline __attribute__((__always_inline__)) 43 | #define _disused \ 44 | __attribute__((__unused__)) 45 | 46 | #define _extern \ 47 | extern "C" __attribute__((__visibility__("default"))) 48 | 49 | #ifdef __cplusplus 50 | #define _default(value) = value 51 | #else 52 | #define _default(value) 53 | #endif 54 | 55 | #ifdef __cplusplus 56 | extern "C" { 57 | #endif 58 | 59 | bool MSHookProcess(pid_t pid, const char *library); 60 | 61 | typedef const void *MSImageRef; 62 | 63 | MSImageRef MSGetImageByName(const char *file); 64 | void *MSFindSymbol(MSImageRef image, const char *name); 65 | 66 | void MSHookFunction(void *symbol, void *replace, void **result); 67 | 68 | #ifdef __APPLE__ 69 | #ifdef __arm__ 70 | __attribute__((__deprecated__)) 71 | IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); 72 | #endif 73 | void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); 74 | #endif 75 | 76 | #ifdef SubstrateInternal 77 | typedef void *SubstrateAllocatorRef; 78 | typedef struct __SubstrateProcess *SubstrateProcessRef; 79 | typedef struct __SubstrateMemory *SubstrateMemoryRef; 80 | 81 | SubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid); 82 | void SubstrateProcessRelease(SubstrateProcessRef process); 83 | 84 | SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size); 85 | void SubstrateMemoryRelease(SubstrateMemoryRef memory); 86 | #endif 87 | 88 | #ifdef __cplusplus 89 | } 90 | #endif 91 | 92 | #ifdef __cplusplus 93 | 94 | #ifdef SubstrateInternal 95 | struct SubstrateHookMemory { 96 | SubstrateMemoryRef handle_; 97 | 98 | SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) : 99 | handle_(SubstrateMemoryCreate(NULL, NULL, data, size)) 100 | { 101 | } 102 | 103 | ~SubstrateHookMemory() { 104 | if (handle_ != NULL) 105 | SubstrateMemoryRelease(handle_); 106 | } 107 | }; 108 | #endif 109 | 110 | 111 | template 112 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { 113 | MSHookFunction( 114 | reinterpret_cast(symbol), 115 | reinterpret_cast(replace), 116 | reinterpret_cast(result) 117 | ); 118 | } 119 | 120 | template 121 | static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { 122 | return MSHookFunction(symbol, replace, reinterpret_cast(NULL)); 123 | } 124 | 125 | template 126 | static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { 127 | value = reinterpret_cast(MSFindSymbol(image, name)); 128 | } 129 | 130 | template 131 | static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { 132 | Type_ *symbol; 133 | MSHookSymbol(symbol, name); 134 | return MSHookFunction(symbol, replace, result); 135 | } 136 | 137 | #endif 138 | 139 | #define MSHook(type, name, args...) \ 140 | _disused static type (*_ ## name)(args); \ 141 | static type $ ## name(args) 142 | 143 | #ifdef __cplusplus 144 | #define MSHake(name) \ 145 | &$ ## name, &_ ## name 146 | #else 147 | #define MSHake(name) \ 148 | &$ ## name, (void **) &_ ## name 149 | #endif 150 | 151 | 152 | #endif//SUBSTRATE_H_ 153 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateARM.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_ARM_HPP 23 | #define SUBSTRATE_ARM_HPP 24 | 25 | enum A$r { 26 | A$r0, A$r1, A$r2, A$r3, 27 | A$r4, A$r5, A$r6, A$r7, 28 | A$r8, A$r9, A$r10, A$r11, 29 | A$r12, A$r13, A$r14, A$r15, 30 | A$sp = A$r13, 31 | A$lr = A$r14, 32 | A$pc = A$r15 33 | }; 34 | 35 | enum A$c { 36 | A$eq, A$ne, A$cs, A$cc, 37 | A$mi, A$pl, A$vs, A$vc, 38 | A$hi, A$ls, A$ge, A$lt, 39 | A$gt, A$le, A$al, 40 | A$hs = A$cs, 41 | A$lo = A$cc 42 | }; 43 | 44 | #define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ 45 | (0xe10f0000 | ((rd) << 12)) 46 | #define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ 47 | (0xe128f000 | (rm)) 48 | #define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ 49 | (0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) 50 | #define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ 51 | (0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | abs(im)) 52 | #define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ 53 | (0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) 54 | #define A$blx_rm(rm) /* blx rm */ \ 55 | (0xe12fff30 | (rm)) 56 | #define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ 57 | (0xe1a00000 | ((rd) << 12) | (rm)) 58 | #define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ 59 | (0xe8b00000 | (A$sp << 16) | (rs)) 60 | #define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ 61 | (0xe9200000 | (A$sp << 16) | (rs)) 62 | #define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ 63 | #define A$bx_r0 0xe12fff10 /* bx r0 */ 64 | 65 | #endif//SUBSTRATE_ARM_HPP 66 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateDebug.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #include "SubstrateHook.h" 23 | #include "SubstrateDebug.hpp" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | _extern bool MSDebug; 30 | bool MSDebug = false; 31 | 32 | static char _MSHexChar(uint8_t value) { 33 | return value < 0x20 || value >= 0x80 ? '.' : value; 34 | } 35 | 36 | #define HexWidth_ 16 37 | #define HexDepth_ 4 38 | 39 | void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { 40 | const uint8_t *data((const uint8_t *) vdata); 41 | 42 | size_t i(0), j; 43 | 44 | char d[256]; 45 | size_t b(0); 46 | d[0] = '\0'; 47 | 48 | while (i != size) { 49 | if (i % HexWidth_ == 0) { 50 | if (mark != NULL) 51 | b += sprintf(d + b, "\n[%s] ", mark); 52 | b += sprintf(d + b, "0x%.3zx:", i); 53 | } 54 | 55 | b += sprintf(d + b, " "); 56 | 57 | for (size_t q(0); q != stride; ++q) 58 | b += sprintf(d + b, "%.2x", data[i + stride - q - 1]); 59 | 60 | i += stride; 61 | 62 | for (size_t q(1); q != stride; ++q) 63 | b += sprintf(d + b, " "); 64 | 65 | if (i % HexDepth_ == 0) 66 | b += sprintf(d + b, " "); 67 | 68 | if (i % HexWidth_ == 0) { 69 | b += sprintf(d + b, " "); 70 | for (j = i - HexWidth_; j != i; ++j) 71 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 72 | 73 | lprintf("%s", d); 74 | b = 0; 75 | d[0] = '\0'; 76 | } 77 | } 78 | 79 | if (i % HexWidth_ != 0) { 80 | for (j = i % HexWidth_; j != HexWidth_; ++j) 81 | b += sprintf(d + b, " "); 82 | for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) 83 | b += sprintf(d + b, " "); 84 | b += sprintf(d + b, " "); 85 | for (j = i / HexWidth_ * HexWidth_; j != i; ++j) 86 | b += sprintf(d + b, "%c", _MSHexChar(data[j])); 87 | 88 | lprintf("%s", d); 89 | b = 0; 90 | d[0] = '\0'; 91 | } 92 | } 93 | 94 | void MSLogHex(const void *vdata, size_t size, const char *mark) { 95 | return MSLogHexEx(vdata, size, 1, mark); 96 | } 97 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateDebug.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_DEBUG_HPP 23 | #define SUBSTRATE_DEBUG_HPP 24 | 25 | #include "SubstrateLog.hpp" 26 | #define lprintf(format, ...) \ 27 | MSLog(MSLogLevelNotice, format, ## __VA_ARGS__) 28 | 29 | extern "C" bool MSDebug; 30 | void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0); 31 | void MSLogHex(const void *vdata, size_t size, const char *mark = 0); 32 | 33 | #endif//SUBSTRATE_DEBUG_HPP 34 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateHook.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #define SubstrateInternal 23 | #include "CydiaSubstrate.h" 24 | 25 | #include 26 | 27 | #define _trace() do { \ 28 | MSLog(MSLogLevelNotice, "_trace(%u)", __LINE__); \ 29 | } while (false) 30 | 31 | #if defined(__i386__) || defined(__x86_64__) 32 | #include "hde64.h" 33 | #endif 34 | 35 | #include "SubstrateDebug.hpp" 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #ifdef __arm__ 42 | /* WebCore (ARM) PC-Relative: 43 | X 1 ldr r*,[pc,r*] != 44 | 2 fldd d*,[pc,#*] 45 | X 5 str r*,[pc,r*] != 46 | 8 flds s*,[pc,#*] 47 | 400 ldr r*,[pc,r*] == 48 | 515 add r*, pc,r* == 49 | X 4790 ldr r*,[pc,#*] */ 50 | 51 | // x=0; while IFS= read -r line; do if [[ ${#line} -ne 0 && $line == +([^\;]): ]]; then x=2; elif [[ $line == ' +'* && $x -ne 0 ]]; then ((--x)); echo "$x${line}"; fi; done WebCore.pc 52 | // grep pc WebCore.pc | cut -c 40- | sed -Ee 's/^ldr *(ip|r[0-9]*),\[pc,\#0x[0-9a-f]*\].*/ ldr r*,[pc,#*]/;s/^add *r[0-9]*,pc,r[0-9]*.*/ add r*, pc,r*/;s/^(st|ld)r *r([0-9]*),\[pc,r([0-9]*)\].*/ \1r r\2,[pc,r\3]/;s/^fld(s|d) *(s|d)[0-9]*,\[pc,#0x[0-9a-f]*].*/fld\1 \2*,[pc,#*]/' | sort | uniq -c | sort -n 53 | 54 | #include "SubstrateARM.hpp" 55 | 56 | #define T$Label(l, r) \ 57 | (((r) - (l)) * 2 - 4 + ((l) % 2 == 0 ? 0 : 2)) 58 | 59 | #define T$pop_$r0$ 0xbc01 // pop {r0} 60 | #define T$b(im) /* b im */ \ 61 | (0xde00 | (im & 0xff)) 62 | #define T$blx(rm) /* blx rm */ \ 63 | (0x4780 | (rm << 3)) 64 | #define T$bx(rm) /* bx rm */ \ 65 | (0x4700 | (rm << 3)) 66 | #define T$nop /* nop */ \ 67 | (0x46c0) 68 | 69 | #define T$add_rd_rm(rd, rm) /* add rd, rm */ \ 70 | (0x4400 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) 71 | #define T$push_r(r) /* push r... */ \ 72 | (0xb400 | (((r) & (1 << A$lr)) >> A$lr << 8) | ((r) & 0xff)) 73 | #define T$pop_r(r) /* pop r... */ \ 74 | (0xbc00 | (((r) & (1 << A$pc)) >> A$pc << 8) | ((r) & 0xff)) 75 | #define T$mov_rd_rm(rd, rm) /* mov rd, rm */ \ 76 | (0x4600 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) 77 | #define T$ldr_rd_$rn_im_4$(rd, rn, im) /* ldr rd, [rn, #im * 4] */ \ 78 | (0x6800 | (((im) & 0x1f) << 6) | ((rn) << 3) | (rd)) 79 | #define T$ldr_rd_$pc_im_4$(rd, im) /* ldr rd, [PC, #im * 4] */ \ 80 | (0x4800 | ((rd) << 8) | ((im) & 0xff)) 81 | #define T$cmp_rn_$im(rn, im) /* cmp rn, #im */ \ 82 | (0x2000 | ((rn) << 8) | ((im) & 0xff)) 83 | #define T$it$_cd(cd, ms) /* it, cd */ \ 84 | (0xbf00 | ((cd) << 4) | (ms)) 85 | #define T$cbz$_rn_$im(op,rn,im) /* cbz rn, #im */ \ 86 | (0xb100 | ((op) << 11) | (((im) & 0x40) >> 6 << 9) | (((im) & 0x3e) >> 1 << 3) | (rn)) 87 | #define T$b$_$im(cond,im) /* b #im */ \ 88 | (cond == A$al ? 0xe000 | (((im) >> 1) & 0x7ff) : 0xd000 | ((cond) << 8) | (((im) >> 1) & 0xff)) 89 | 90 | #define T1$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ 91 | (0xf850 | ((im < 0 ? 0 : 1) << 7) | (rn)) 92 | #define T2$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ 93 | (((rt) << 12) | abs(im)) 94 | 95 | #define T1$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ 96 | (0xf3ef) 97 | #define T2$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ 98 | (0x8000 | ((rd) << 8)) 99 | 100 | #define T1$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ 101 | (0xf380 | (rn)) 102 | #define T2$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ 103 | (0x8c00) 104 | #define T$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ 105 | (T2$msr_apsr_nzcvqg_rn(rn) << 16 | T1$msr_apsr_nzcvqg_rn(rn)) 106 | 107 | static inline bool A$pcrel$r(uint32_t ic) { 108 | return (ic & 0x0c000000) == 0x04000000 && (ic & 0xf0000000) != 0xf0000000 && (ic & 0x000f0000) == 0x000f0000; 109 | } 110 | 111 | static inline bool T$32bit$i(uint16_t ic) { 112 | return ((ic & 0xe000) == 0xe000 && (ic & 0x1800) != 0x0000); 113 | } 114 | 115 | static inline bool T$pcrel$cbz(uint16_t ic) { 116 | return (ic & 0xf500) == 0xb100; 117 | } 118 | 119 | static inline bool T$pcrel$b(uint16_t ic) { 120 | return (ic & 0xf000) == 0xd000 && (ic & 0x0e00) != 0x0e00; 121 | } 122 | 123 | static inline bool T2$pcrel$b(uint16_t *ic) { 124 | return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0x9000 || (ic[1] & 0xd000) == 0x8000 && (ic[0] & 0x0380) != 0x0380); 125 | } 126 | 127 | static inline bool T$pcrel$bl(uint16_t *ic) { 128 | return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0xd000 || (ic[1] & 0xd001) == 0xc000); 129 | } 130 | 131 | static inline bool T$pcrel$ldr(uint16_t ic) { 132 | return (ic & 0xf800) == 0x4800; 133 | } 134 | 135 | static inline bool T$pcrel$add(uint16_t ic) { 136 | return (ic & 0xff78) == 0x4478; 137 | } 138 | 139 | static inline bool T$pcrel$ldrw(uint16_t ic) { 140 | return (ic & 0xff7f) == 0xf85f; 141 | } 142 | 143 | static size_t MSGetInstructionWidthThumb(void *start) { 144 | uint16_t *thumb(reinterpret_cast(start)); 145 | return T$32bit$i(thumb[0]) ? 4 : 2; 146 | } 147 | 148 | static size_t MSGetInstructionWidthARM(void *start) { 149 | return 4; 150 | } 151 | 152 | extern "C" size_t MSGetInstructionWidth(void *start) { 153 | if ((reinterpret_cast(start) & 0x1) == 0) 154 | return MSGetInstructionWidthARM(start); 155 | else 156 | return MSGetInstructionWidthThumb(reinterpret_cast(reinterpret_cast(start) & ~0x1)); 157 | } 158 | 159 | static size_t SubstrateHookFunctionThumb(SubstrateProcessRef process, void *symbol, void *replace, void **result) { 160 | if (symbol == NULL) 161 | return 0; 162 | printf("SubstrateHookFunctionThumb\n"); 163 | uint16_t *area(reinterpret_cast(symbol)); 164 | 165 | unsigned align((reinterpret_cast(area) & 0x2) == 0 ? 0 : 1); 166 | uint16_t *thumb(area + align); 167 | 168 | uint32_t *arm(reinterpret_cast(thumb + 2)); 169 | uint16_t *trail(reinterpret_cast(arm + 2)); 170 | 171 | if ( 172 | (align == 0 || area[0] == T$nop) && 173 | thumb[0] == T$bx(A$pc) && 174 | thumb[1] == T$nop && 175 | arm[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8) 176 | ) { 177 | if (result != NULL) 178 | *result = reinterpret_cast(arm[1]); 179 | 180 | SubstrateHookMemory code(process, arm + 1, sizeof(uint32_t) * 1); 181 | 182 | arm[1] = reinterpret_cast(replace); 183 | 184 | return sizeof(arm[0]); 185 | } 186 | 187 | size_t required((trail - area) * sizeof(uint16_t)); 188 | 189 | size_t used(0); 190 | while (used < required) 191 | used += MSGetInstructionWidthThumb(reinterpret_cast(area) + used); 192 | used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t); 193 | 194 | size_t blank((used - required) / sizeof(uint16_t)); 195 | 196 | uint16_t backup[used / sizeof(uint16_t)]; 197 | memcpy(backup, area, used); 198 | 199 | if (MSDebug) { 200 | char name[16]; 201 | sprintf(name, "%p", area); 202 | MSLogHexEx(area, used + sizeof(uint16_t), 2, name); 203 | } 204 | 205 | if (result != NULL) { 206 | 207 | size_t length(used); 208 | for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) 209 | if (T$pcrel$ldr(backup[offset])) 210 | length += 3 * sizeof(uint16_t); 211 | else if (T$pcrel$b(backup[offset])) 212 | length += 6 * sizeof(uint16_t); 213 | else if (T2$pcrel$b(backup + offset)) { 214 | length += 5 * sizeof(uint16_t); 215 | ++offset; 216 | } else if (T$pcrel$bl(backup + offset)) { 217 | length += 5 * sizeof(uint16_t); 218 | ++offset; 219 | } else if (T$pcrel$cbz(backup[offset])) { 220 | length += 16 * sizeof(uint16_t); 221 | } else if (T$pcrel$ldrw(backup[offset])) { 222 | length += 4 * sizeof(uint16_t); 223 | ++offset; 224 | } else if (T$pcrel$add(backup[offset])) 225 | length += 6 * sizeof(uint16_t); 226 | else if (T$32bit$i(backup[offset])) 227 | ++offset; 228 | 229 | unsigned pad((length & 0x2) == 0 ? 0 : 1); 230 | length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t); 231 | 232 | uint16_t *buffer(reinterpret_cast(mmap( 233 | NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 234 | ))); 235 | 236 | if (buffer == MAP_FAILED) { 237 | MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); 238 | *result = NULL; 239 | return 0; 240 | } 241 | 242 | if (false) fail: { 243 | munmap(buffer, length); 244 | *result = NULL; 245 | return 0; 246 | } 247 | 248 | size_t start(pad), end(length / sizeof(uint16_t)); 249 | uint32_t *trailer(reinterpret_cast(buffer + end)); 250 | for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) { 251 | if (T$pcrel$ldr(backup[offset])) { 252 | union { 253 | uint16_t value; 254 | 255 | struct { 256 | uint16_t immediate : 8; 257 | uint16_t rd : 3; 258 | uint16_t : 5; 259 | }; 260 | } bits = {backup[offset+0]}; 261 | 262 | buffer[start+0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+0, end-2) / 4); 263 | buffer[start+1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0); 264 | 265 | // XXX: this code "works", but is "wrong": the mechanism is more complex than this 266 | *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + bits.immediate * 4; 267 | 268 | start += 2; 269 | end -= 2; 270 | } else if (T$pcrel$b(backup[offset])) { 271 | union { 272 | uint16_t value; 273 | 274 | struct { 275 | uint16_t imm8 : 8; 276 | uint16_t cond : 4; 277 | uint16_t /*1101*/ : 4; 278 | }; 279 | } bits = {backup[offset+0]}; 280 | 281 | intptr_t jump(bits.imm8 << 1); 282 | jump |= 1; 283 | jump <<= 23; 284 | jump >>= 23; 285 | 286 | buffer[start+0] = T$b$_$im(bits.cond, (end-6 - (start+0)) * 2 - 4); 287 | 288 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 289 | *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 290 | *--trailer = T$nop << 16 | T$bx(A$pc); 291 | 292 | start += 1; 293 | end -= 6; 294 | } else if (T2$pcrel$b(backup + offset)) { 295 | union { 296 | uint16_t value; 297 | 298 | struct { 299 | uint16_t imm6 : 6; 300 | uint16_t cond : 4; 301 | uint16_t s : 1; 302 | uint16_t : 5; 303 | }; 304 | } bits = {backup[offset+0]}; 305 | 306 | union { 307 | uint16_t value; 308 | 309 | struct { 310 | uint16_t imm11 : 11; 311 | uint16_t j2 : 1; 312 | uint16_t a : 1; 313 | uint16_t j1 : 1; 314 | uint16_t : 2; 315 | }; 316 | } exts = {backup[offset+1]}; 317 | 318 | intptr_t jump(1); 319 | jump |= exts.imm11 << 1; 320 | jump |= bits.imm6 << 12; 321 | 322 | if (exts.a) { 323 | jump |= bits.s << 24; 324 | jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; 325 | jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; 326 | jump |= bits.cond << 18; 327 | jump <<= 7; 328 | jump >>= 7; 329 | } else { 330 | jump |= bits.s << 20; 331 | jump |= exts.j2 << 19; 332 | jump |= exts.j1 << 18; 333 | jump <<= 11; 334 | jump >>= 11; 335 | } 336 | 337 | buffer[start+0] = T$b$_$im(exts.a ? A$al : bits.cond, (end-6 - (start+0)) * 2 - 4); 338 | 339 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 340 | *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 341 | *--trailer = T$nop << 16 | T$bx(A$pc); 342 | 343 | ++offset; 344 | start += 1; 345 | end -= 6; 346 | } else if (T$pcrel$bl(backup + offset)) { 347 | union { 348 | uint16_t value; 349 | 350 | struct { 351 | uint16_t immediate : 10; 352 | uint16_t s : 1; 353 | uint16_t : 5; 354 | }; 355 | } bits = {backup[offset+0]}; 356 | 357 | union { 358 | uint16_t value; 359 | 360 | struct { 361 | uint16_t immediate : 11; 362 | uint16_t j2 : 1; 363 | uint16_t x : 1; 364 | uint16_t j1 : 1; 365 | uint16_t : 2; 366 | }; 367 | } exts = {backup[offset+1]}; 368 | 369 | int32_t jump(0); 370 | jump |= bits.s << 24; 371 | jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; 372 | jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; 373 | jump |= bits.immediate << 12; 374 | jump |= exts.immediate << 1; 375 | jump |= exts.x; 376 | jump <<= 7; 377 | jump >>= 7; 378 | 379 | buffer[start+0] = T$push_r(1 << A$r7); 380 | buffer[start+1] = T$ldr_rd_$pc_im_4$(A$r7, ((end-2 - (start+1)) * 2 - 4 + 2) / 4); 381 | buffer[start+2] = T$mov_rd_rm(A$lr, A$r7); 382 | buffer[start+3] = T$pop_r(1 << A$r7); 383 | buffer[start+4] = T$blx(A$lr); 384 | 385 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 386 | 387 | ++offset; 388 | start += 5; 389 | end -= 2; 390 | } else if (T$pcrel$cbz(backup[offset])) { 391 | union { 392 | uint16_t value; 393 | 394 | struct { 395 | uint16_t rn : 3; 396 | uint16_t immediate : 5; 397 | uint16_t : 1; 398 | uint16_t i : 1; 399 | uint16_t : 1; 400 | uint16_t op : 1; 401 | uint16_t : 4; 402 | }; 403 | } bits = {backup[offset+0]}; 404 | 405 | intptr_t jump(1); 406 | jump |= bits.i << 6; 407 | jump |= bits.immediate << 1; 408 | 409 | //jump <<= 24; 410 | //jump >>= 24; 411 | 412 | unsigned rn(bits.rn); 413 | unsigned rt(rn == A$r7 ? A$r6 : A$r7); 414 | 415 | buffer[start+0] = T$push_r(1 << rt); 416 | buffer[start+1] = T1$mrs_rd_apsr(rt); 417 | buffer[start+2] = T2$mrs_rd_apsr(rt); 418 | buffer[start+3] = T$cbz$_rn_$im(bits.op, rn, (end-10 - (start+3)) * 2 - 4); 419 | buffer[start+4] = T1$msr_apsr_nzcvqg_rn(rt); 420 | buffer[start+5] = T2$msr_apsr_nzcvqg_rn(rt); 421 | buffer[start+6] = T$pop_r(1 << rt); 422 | 423 | *--trailer = reinterpret_cast(area + offset) + 4 + jump; 424 | *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 425 | *--trailer = T$nop << 16 | T$bx(A$pc); 426 | *--trailer = T$nop << 16 | T$pop_r(1 << rt); 427 | *--trailer = T$msr_apsr_nzcvqg_rn(rt); 428 | 429 | #if 0 430 | if ((start & 0x1) == 0) 431 | buffer[start++] = T$nop; 432 | buffer[start++] = T$bx(A$pc); 433 | buffer[start++] = T$nop; 434 | 435 | uint32_t *arm(reinterpret_cast(buffer + start)); 436 | arm[0] = A$add(A$lr, A$pc, 1); 437 | arm[1] = A$ldr_rd_$rn_im$(A$pc, A$pc, (trailer - arm) * sizeof(uint32_t) - 8); 438 | #endif 439 | 440 | start += 7; 441 | end -= 10; 442 | } else if (T$pcrel$ldrw(backup[offset])) { 443 | union { 444 | uint16_t value; 445 | 446 | struct { 447 | uint16_t : 7; 448 | uint16_t u : 1; 449 | uint16_t : 8; 450 | }; 451 | } bits = {backup[offset+0]}; 452 | 453 | union { 454 | uint16_t value; 455 | 456 | struct { 457 | uint16_t immediate : 12; 458 | uint16_t rt : 4; 459 | }; 460 | } exts = {backup[offset+1]}; 461 | 462 | buffer[start+0] = T1$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start+0, end-2)); 463 | buffer[start+1] = T2$ldr_rt_$rn_im$(exts.rt, A$pc, (int)T$Label(start+0, end-2)); 464 | 465 | buffer[start+2] = T1$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); 466 | buffer[start+3] = T2$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); 467 | 468 | // XXX: this code "works", but is "wrong": the mechanism is more complex than this 469 | *--trailer = ((reinterpret_cast(area + offset) + 4) & ~0x2) + (bits.u == 0 ? -exts.immediate : exts.immediate); 470 | 471 | ++offset; 472 | start += 4; 473 | end -= 2; 474 | } else if (T$pcrel$add(backup[offset])) { 475 | union { 476 | uint16_t value; 477 | 478 | struct { 479 | uint16_t rd : 3; 480 | uint16_t rm : 3; 481 | uint16_t h2 : 1; 482 | uint16_t h1 : 1; 483 | uint16_t : 8; 484 | }; 485 | } bits = {backup[offset+0]}; 486 | 487 | if (bits.h1) { 488 | MSLog(MSLogLevelError, "MS:Error:pcrel(%u):add (rd > r7)", offset); 489 | goto fail; 490 | } 491 | 492 | unsigned rt(bits.rd == A$r7 ? A$r6 : A$r7); 493 | 494 | buffer[start+0] = T$push_r(1 << rt); 495 | buffer[start+1] = T$mov_rd_rm(rt, (bits.h1 << 3) | bits.rd); 496 | buffer[start+2] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+2, end-2) / 4); 497 | buffer[start+3] = T$add_rd_rm((bits.h1 << 3) | bits.rd, rt); 498 | buffer[start+4] = T$pop_r(1 << rt); 499 | *--trailer = reinterpret_cast(area + offset) + 4; 500 | 501 | start += 5; 502 | end -= 2; 503 | } else if (T$32bit$i(backup[offset])) { 504 | buffer[start++] = backup[offset]; 505 | buffer[start++] = backup[++offset]; 506 | } else { 507 | buffer[start++] = backup[offset]; 508 | } 509 | } 510 | 511 | buffer[start++] = T$bx(A$pc); 512 | buffer[start++] = T$nop; 513 | 514 | uint32_t *transfer = reinterpret_cast(buffer + start); 515 | transfer[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 516 | transfer[1] = reinterpret_cast(area + used / sizeof(uint16_t)) + 1; 517 | 518 | if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { 519 | MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); 520 | return 0; 521 | } 522 | 523 | *result = reinterpret_cast(buffer + pad) + 1; 524 | 525 | if (MSDebug) { 526 | char name[16]; 527 | sprintf(name, "%p", *result); 528 | MSLogHexEx(buffer, length, 2, name); 529 | } 530 | 531 | } 532 | 533 | { 534 | SubstrateHookMemory code(process, area, used); 535 | 536 | if (align != 0) 537 | area[0] = T$nop; 538 | 539 | thumb[0] = T$bx(A$pc); 540 | thumb[1] = T$nop; 541 | 542 | arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 543 | arm[1] = reinterpret_cast(replace); 544 | 545 | for (unsigned offset(0); offset != blank; ++offset) 546 | trail[offset] = T$nop; 547 | } 548 | 549 | if (MSDebug) { 550 | char name[16]; 551 | sprintf(name, "%p", area); 552 | MSLogHexEx(area, used + sizeof(uint16_t), 2, name); 553 | } 554 | 555 | return used; 556 | } 557 | 558 | static size_t SubstrateHookFunctionARM(SubstrateProcessRef process, void *symbol, void *replace, void **result) { 559 | if (symbol == NULL) 560 | return 0; 561 | printf("SubstrateHookFunctionARM\n"); 562 | uint32_t *area(reinterpret_cast(symbol)); 563 | uint32_t *arm(area); 564 | 565 | const size_t used(8); 566 | 567 | uint32_t backup[used / sizeof(uint32_t)] = {arm[0], arm[1]}; 568 | 569 | if (MSDebug) { 570 | char name[16]; 571 | sprintf(name, "%p", area); 572 | MSLogHexEx(area, used + sizeof(uint32_t), 4, name); 573 | } 574 | 575 | if (result != NULL) { 576 | 577 | if (backup[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)) { 578 | *result = reinterpret_cast(backup[1]); 579 | 580 | return sizeof(backup[0]); 581 | } 582 | 583 | size_t length(used); 584 | for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) 585 | if (A$pcrel$r(backup[offset])) { 586 | if ((backup[offset] & 0x02000000) == 0 || (backup[offset] & 0x0000f000 >> 12) != (backup[offset] & 0x0000000f)) 587 | length += 2 * sizeof(uint32_t); 588 | else 589 | length += 4 * sizeof(uint32_t); 590 | } 591 | 592 | length += 2 * sizeof(uint32_t); 593 | 594 | uint32_t *buffer(reinterpret_cast(mmap( 595 | NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 596 | ))); 597 | 598 | if (buffer == MAP_FAILED) { 599 | MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); 600 | *result = NULL; 601 | return 0; 602 | } 603 | 604 | if (false) fail: { 605 | munmap(buffer, length); 606 | *result = NULL; 607 | return 0; 608 | } 609 | 610 | size_t start(0), end(length / sizeof(uint32_t)); 611 | uint32_t *trailer(reinterpret_cast(buffer + end)); 612 | for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) 613 | if (A$pcrel$r(backup[offset])) { 614 | union { 615 | uint32_t value; 616 | 617 | struct { 618 | uint32_t rm : 4; 619 | uint32_t : 1; 620 | uint32_t shift : 2; 621 | uint32_t shiftamount : 5; 622 | uint32_t rd : 4; 623 | uint32_t rn : 4; 624 | uint32_t l : 1; 625 | uint32_t w : 1; 626 | uint32_t b : 1; 627 | uint32_t u : 1; 628 | uint32_t p : 1; 629 | uint32_t mode : 1; 630 | uint32_t type : 2; 631 | uint32_t cond : 4; 632 | }; 633 | } bits = {backup[offset+0]}, copy(bits); 634 | 635 | bool guard; 636 | if (bits.mode == 0 || bits.rd != bits.rm) { 637 | copy.rn = bits.rd; 638 | guard = false; 639 | } else { 640 | copy.rn = bits.rm != A$r0 ? A$r0 : A$r1; 641 | guard = true; 642 | } 643 | 644 | if (guard) 645 | buffer[start++] = A$stmdb_sp$_$rs$((1 << copy.rn)); 646 | 647 | buffer[start+0] = A$ldr_rd_$rn_im$(copy.rn, A$pc, (int)(end-1 - (start+0)) * 4 - 8); 648 | buffer[start+1] = copy.value; 649 | 650 | start += 2; 651 | 652 | if (guard) 653 | buffer[start++] = A$ldmia_sp$_$rs$((1 << copy.rn)); 654 | 655 | *--trailer = reinterpret_cast(area + offset) + 8; 656 | end -= 1; 657 | } else 658 | buffer[start++] = backup[offset]; 659 | 660 | buffer[start+0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 661 | buffer[start+1] = reinterpret_cast(area + used / sizeof(uint32_t)); 662 | 663 | if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { 664 | MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); 665 | goto fail; 666 | } 667 | 668 | *result = buffer; 669 | 670 | if (MSDebug) { 671 | char name[16]; 672 | sprintf(name, "%p", *result); 673 | MSLogHexEx(buffer, length, 4, name); 674 | } 675 | 676 | } 677 | 678 | { 679 | SubstrateHookMemory code(process, symbol, used); 680 | 681 | arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); 682 | arm[1] = reinterpret_cast(replace); 683 | } 684 | 685 | if (MSDebug) { 686 | char name[16]; 687 | sprintf(name, "%p", area); 688 | MSLogHexEx(area, used + sizeof(uint32_t), 4, name); 689 | } 690 | 691 | return used; 692 | } 693 | 694 | static size_t SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { 695 | if (MSDebug) 696 | MSLog(MSLogLevelNotice, "SubstrateHookFunction(%p, %p, %p, %p)\n", process, symbol, replace, result); 697 | if ((reinterpret_cast(symbol) & 0x1) == 0) 698 | return SubstrateHookFunctionARM(process, symbol, replace, result); 699 | else 700 | return SubstrateHookFunctionThumb(process, reinterpret_cast(reinterpret_cast(symbol) & ~0x1), replace, result); 701 | } 702 | #endif 703 | 704 | #if defined(__i386__) || defined(__x86_64__) 705 | 706 | #include "SubstrateX86.hpp" 707 | 708 | static size_t MSGetInstructionWidthIntel(void *start) { 709 | hde64s decode; 710 | return hde64_disasm(start, &decode); 711 | } 712 | 713 | static void SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { 714 | if (MSDebug) 715 | MSLog(MSLogLevelNotice, "MSHookFunction(%p, %p, %p)\n", symbol, replace, result); 716 | if (symbol == NULL) 717 | return; 718 | 719 | uintptr_t source(reinterpret_cast(symbol)); 720 | uintptr_t target(reinterpret_cast(replace)); 721 | 722 | uint8_t *area(reinterpret_cast(symbol)); 723 | 724 | size_t required(MSSizeOfJump(target, source)); 725 | 726 | if (MSDebug) { 727 | char name[16]; 728 | sprintf(name, "%p", area); 729 | MSLogHex(area, 32, name); 730 | } 731 | 732 | size_t used(0); 733 | while (used < required) { 734 | size_t width(MSGetInstructionWidthIntel(area + used)); 735 | if (width == 0) { 736 | MSLog(MSLogLevelError, "MS:Error:MSGetInstructionWidthIntel(%p) == 0", area + used); 737 | return; 738 | } 739 | 740 | used += width; 741 | } 742 | 743 | size_t blank(used - required); 744 | 745 | if (MSDebug) { 746 | char name[16]; 747 | sprintf(name, "%p", area); 748 | MSLogHex(area, used + sizeof(uint16_t), name); 749 | } 750 | 751 | uint8_t backup[used]; 752 | memcpy(backup, area, used); 753 | 754 | if (result != NULL) { 755 | 756 | if (backup[0] == 0xe9) { 757 | *result = reinterpret_cast(source + 5 + *reinterpret_cast(backup + 1)); 758 | return; 759 | } 760 | 761 | if (!ia32 && backup[0] == 0xff && backup[1] == 0x25) { 762 | *result = *reinterpret_cast(source + 6 + *reinterpret_cast(backup + 2)); 763 | return; 764 | } 765 | 766 | size_t length(used + MSSizeOfJump(source + used)); 767 | 768 | for (size_t offset(0), width; offset != used; offset += width) { 769 | hde64s decode; 770 | hde64_disasm(backup + offset, &decode); 771 | width = decode.len; 772 | //_assert(width != 0 && offset + width <= used); 773 | 774 | #ifdef __LP64__ 775 | if ((decode.modrm & 0xc7) == 0x05) { 776 | if (decode.opcode == 0x8b) { 777 | void *destiny(area + offset + width + int32_t(decode.disp.disp32)); 778 | uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); 779 | length -= decode.len; 780 | length += MSSizeOfPushPointer(destiny); 781 | length += MSSizeOfPop(reg); 782 | length += MSSizeOfMove64(); 783 | } else { 784 | MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); 785 | continue; 786 | } 787 | } else 788 | #endif 789 | 790 | if (backup[offset] == 0xe8) { 791 | int32_t relative(*reinterpret_cast(backup + offset + 1)); 792 | void *destiny(area + offset + decode.len + relative); 793 | 794 | if (relative == 0) { 795 | length -= decode.len; 796 | length += MSSizeOfPushPointer(destiny); 797 | } else { 798 | length += MSSizeOfSkip(); 799 | length += MSSizeOfJump(destiny); 800 | } 801 | } else if (backup[offset] == 0xeb) { 802 | length -= decode.len; 803 | length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 804 | } else if (backup[offset] == 0xe9) { 805 | length -= decode.len; 806 | length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 807 | } else if ( 808 | backup[offset] == 0xe3 || 809 | (backup[offset] & 0xf0) == 0x70 810 | // XXX: opcode2 & 0xf0 is 0x80? 811 | ) { 812 | length += decode.len; 813 | length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 814 | } 815 | } 816 | 817 | uint8_t *buffer(reinterpret_cast(mmap( 818 | NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 819 | ))); 820 | 821 | if (buffer == MAP_FAILED) { 822 | MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); 823 | *result = NULL; 824 | return; 825 | } 826 | 827 | if (false) fail: { 828 | munmap(buffer, length); 829 | *result = NULL; 830 | return; 831 | } 832 | 833 | { 834 | uint8_t *current(buffer); 835 | 836 | for (size_t offset(0), width; offset != used; offset += width) { 837 | hde64s decode; 838 | hde64_disasm(backup + offset, &decode); 839 | width = decode.len; 840 | //_assert(width != 0 && offset + width <= used); 841 | 842 | #ifdef __LP64__ 843 | if ((decode.modrm & 0xc7) == 0x05) { 844 | if (decode.opcode == 0x8b) { 845 | void *destiny(area + offset + width + int32_t(decode.disp.disp32)); 846 | uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); 847 | MSPushPointer(current, destiny); 848 | MSWritePop(current, reg); 849 | MSWriteMove64(current, reg, reg); 850 | } else { 851 | MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); 852 | goto copy; 853 | } 854 | } else 855 | #endif 856 | 857 | if (backup[offset] == 0xe8) { 858 | int32_t relative(*reinterpret_cast(backup + offset + 1)); 859 | if (relative == 0) 860 | MSPushPointer(current, area + offset + decode.len); 861 | else { 862 | MSWrite(current, 0xe8); 863 | MSWrite(current, MSSizeOfSkip()); 864 | void *destiny(area + offset + decode.len + relative); 865 | MSWriteSkip(current, MSSizeOfJump(destiny, current + MSSizeOfSkip())); 866 | MSWriteJump(current, destiny); 867 | } 868 | } else if (backup[offset] == 0xeb) 869 | MSWriteJump(current, area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 870 | else if (backup[offset] == 0xe9) 871 | MSWriteJump(current, area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 872 | else if ( 873 | backup[offset] == 0xe3 || 874 | (backup[offset] & 0xf0) == 0x70 875 | ) { 876 | MSWrite(current, backup[offset]); 877 | MSWrite(current, 2); 878 | MSWrite(current, 0xeb); 879 | void *destiny(area + offset + decode.len + *reinterpret_cast(backup + offset + 1)); 880 | MSWrite(current, MSSizeOfJump(destiny, current + 1)); 881 | MSWriteJump(current, destiny); 882 | } else 883 | #ifdef __LP64__ 884 | copy: 885 | #endif 886 | { 887 | MSWrite(current, backup + offset, width); 888 | } 889 | } 890 | 891 | MSWriteJump(current, area + used); 892 | } 893 | 894 | if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { 895 | MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); 896 | goto fail; 897 | } 898 | 899 | *result = buffer; 900 | 901 | if (MSDebug) { 902 | char name[16]; 903 | sprintf(name, "%p", *result); 904 | MSLogHex(buffer, length, name); 905 | } 906 | 907 | } 908 | 909 | { 910 | SubstrateHookMemory code(process, area, used); 911 | 912 | uint8_t *current(area); 913 | MSWriteJump(current, target); 914 | for (unsigned offset(0); offset != blank; ++offset) 915 | MSWrite(current, 0x90); 916 | } 917 | 918 | if (MSDebug) { 919 | char name[16]; 920 | sprintf(name, "%p", area); 921 | MSLogHex(area, used + sizeof(uint16_t), name); 922 | } 923 | } 924 | #endif 925 | 926 | _extern void MSHookFunction(void *symbol, void *replace, void **result) { 927 | #ifndef __aarch64__ 928 | SubstrateHookFunction(NULL, symbol, replace, result); 929 | #endif 930 | } 931 | 932 | #if defined(__APPLE__) && defined(__arm__) 933 | _extern void _Z14MSHookFunctionPvS_PS_(void *symbol, void *replace, void **result) { 934 | return MSHookFunction(symbol, replace, result); 935 | } 936 | #endif 937 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateHook.h: -------------------------------------------------------------------------------- 1 | #ifndef __SUBSTRATEHOOK_H__ 2 | #define __SUBSTRATEHOOK_H__ 3 | 4 | 5 | #include 6 | 7 | #define _extern extern "C" __attribute__((__visibility__("default"))) 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void MSHookFunction(void *symbol, void *replace, void **result); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateLog.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_LOG_HPP 23 | #define SUBSTRATE_LOG_HPP 24 | 25 | #if 0 26 | #include 27 | 28 | #define MSLog(level, format, ...) ((void)__android_log_print(level, "NNNN", format, __VA_ARGS__)) 29 | 30 | #define MSLogLevelNotice ANDROID_LOG_INFO 31 | #define MSLogLevelWarning ANDROID_LOG_WARN 32 | #define MSLogLevelError ANDROID_LOG_ERROR 33 | 34 | #else 35 | 36 | #define MSLog(level, format, ...) printf(format, __VA_ARGS__) 37 | 38 | #endif 39 | 40 | #endif//SUBSTRATE_LOG_HPP 41 | -------------------------------------------------------------------------------- /jni/Substrate/SubstratePosixMemory.cpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #define SubstrateInternal 23 | #include "CydiaSubstrate.h" 24 | #include "SubstrateLog.hpp" 25 | 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | extern "C" void __clear_cache (void *beg, void *end); 33 | 34 | struct __SubstrateMemory { 35 | void *address_; 36 | size_t width_; 37 | 38 | __SubstrateMemory(void *address, size_t width) : 39 | address_(address), 40 | width_(width) 41 | { 42 | } 43 | }; 44 | 45 | extern "C" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) { 46 | if (allocator != NULL) { 47 | MSLog(MSLogLevelError, "MS:Error:allocator != %d", 0); 48 | return NULL; 49 | } 50 | 51 | if (size == 0) 52 | return NULL; 53 | 54 | long page(sysconf(_SC_PAGESIZE)); // Portable applications should employ sysconf(_SC_PAGESIZE) instead of getpagesize 55 | 56 | uintptr_t base(reinterpret_cast(data) / page * page); 57 | size_t width(((reinterpret_cast(data) + size - 1) / page + 1) * page - base); 58 | void *address(reinterpret_cast(base)); 59 | 60 | if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { 61 | MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); 62 | return NULL; 63 | } 64 | 65 | return new __SubstrateMemory(address, width); 66 | } 67 | 68 | extern "C" void SubstrateMemoryRelease(SubstrateMemoryRef memory) { 69 | if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) 70 | MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); 71 | 72 | __clear_cache(reinterpret_cast(memory->address_), reinterpret_cast(memory->address_) + memory->width_); 73 | 74 | delete memory; 75 | } 76 | -------------------------------------------------------------------------------- /jni/Substrate/SubstrateX86.hpp: -------------------------------------------------------------------------------- 1 | /* Cydia Substrate - Powerful Code Insertion Platform 2 | * Copyright (C) 2008-2011 Jay Freeman (saurik) 3 | */ 4 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ 6 | /* 7 | * Substrate is free software: you can redistribute it and/or modify it under 8 | * the terms of the GNU Lesser General Public License as published by the 9 | * Free Software Foundation, either version 3 of the License, or (at your 10 | * option) any later version. 11 | * 12 | * Substrate is distributed in the hope that it will be useful, but WITHOUT 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 | * License for more details. 16 | * 17 | * You should have received a copy of the GNU Lesser General Public License 18 | * along with Substrate. If not, see . 19 | **/ 20 | /* }}} */ 21 | 22 | #ifndef SUBSTRATE_X86_HPP 23 | #define SUBSTRATE_X86_HPP 24 | 25 | #include "Buffer.hpp" 26 | 27 | #ifdef __LP64__ 28 | static const bool ia32 = false; 29 | #else 30 | static const bool ia32 = true; 31 | #endif 32 | 33 | enum I$r { 34 | I$rax, I$rcx, I$rdx, I$rbx, 35 | I$rsp, I$rbp, I$rsi, I$rdi, 36 | I$r8, I$r9, I$r10, I$r11, 37 | I$r12, I$r13, I$r14, I$r15, 38 | }; 39 | 40 | _disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { 41 | intptr_t offset(target - source); 42 | return int32_t(offset) == offset; 43 | } 44 | 45 | _disused static size_t MSSizeOfSkip() { 46 | return 5; 47 | } 48 | 49 | _disused static size_t MSSizeOfPushPointer(uintptr_t target) { 50 | return uint64_t(target) >> 32 == 0 ? 5 : 13; 51 | } 52 | 53 | _disused static size_t MSSizeOfPushPointer(void *target) { 54 | return MSSizeOfPushPointer(reinterpret_cast(target)); 55 | } 56 | 57 | _disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { 58 | if (ia32 || !blind && MSIs32BitOffset(target, source + 5)) 59 | return MSSizeOfSkip(); 60 | else 61 | return MSSizeOfPushPointer(target) + 1; 62 | } 63 | 64 | _disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { 65 | return MSSizeOfJump(false, target, source); 66 | } 67 | 68 | _disused static size_t MSSizeOfJump(uintptr_t target) { 69 | return MSSizeOfJump(true, target); 70 | } 71 | 72 | _disused static size_t MSSizeOfJump(void *target, void *source) { 73 | return MSSizeOfJump(reinterpret_cast(target), reinterpret_cast(source)); 74 | } 75 | 76 | _disused static size_t MSSizeOfJump(void *target) { 77 | return MSSizeOfJump(reinterpret_cast(target)); 78 | } 79 | 80 | _disused static void MSWriteSkip(uint8_t *¤t, ssize_t size) { 81 | MSWrite(current, 0xe9); 82 | MSWrite(current, size); 83 | } 84 | 85 | _disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { 86 | MSWrite(current, 0x68); 87 | MSWrite(current, target); 88 | 89 | if (uint32_t high = uint64_t(target) >> 32) { 90 | MSWrite(current, 0xc7); 91 | MSWrite(current, 0x44); 92 | MSWrite(current, 0x24); 93 | MSWrite(current, 0x04); 94 | MSWrite(current, high); 95 | } 96 | } 97 | 98 | _disused static void MSPushPointer(uint8_t *¤t, void *target) { 99 | return MSPushPointer(current, reinterpret_cast(target)); 100 | } 101 | 102 | _disused static void MSWriteCall(uint8_t *¤t, I$r target) { 103 | if (target >> 3 != 0) 104 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 105 | MSWrite(current, 0xff); 106 | MSWrite(current, 0xd0 | target & 0x07); 107 | } 108 | 109 | _disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { 110 | uintptr_t source(reinterpret_cast(current)); 111 | 112 | if (ia32 || MSIs32BitOffset(target, source + 5)) { 113 | MSWrite(current, 0xe8); 114 | MSWrite(current, target - (source + 5)); 115 | } else { 116 | MSPushPointer(current, target); 117 | 118 | MSWrite(current, 0x83); 119 | MSWrite(current, 0xc4); 120 | MSWrite(current, 0x08); 121 | 122 | MSWrite(current, 0x67); 123 | MSWrite(current, 0xff); 124 | MSWrite(current, 0x54); 125 | MSWrite(current, 0x24); 126 | MSWrite(current, 0xf8); 127 | } 128 | } 129 | 130 | template 131 | _disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { 132 | return MSWriteCall(current, reinterpret_cast(target)); 133 | } 134 | 135 | _disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { 136 | uintptr_t source(reinterpret_cast(current)); 137 | 138 | if (ia32 || MSIs32BitOffset(target, source + 5)) 139 | MSWriteSkip(current, target - (source + 5)); 140 | else { 141 | MSPushPointer(current, target); 142 | MSWrite(current, 0xc3); 143 | } 144 | } 145 | 146 | _disused static void MSWriteJump(uint8_t *¤t, void *target) { 147 | return MSWriteJump(current, reinterpret_cast(target)); 148 | } 149 | 150 | _disused static void MSWriteJump(uint8_t *¤t, I$r target) { 151 | if (target >> 3 != 0) 152 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 153 | MSWrite(current, 0xff); 154 | MSWrite(current, 0xe0 | target & 0x07); 155 | } 156 | 157 | _disused static void MSWritePop(uint8_t *¤t, uint8_t target) { 158 | if (target >> 3 != 0) 159 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 160 | MSWrite(current, 0x58 | target & 0x07); 161 | } 162 | 163 | _disused static size_t MSSizeOfPop(uint8_t target) { 164 | return target >> 3 != 0 ? 2 : 1; 165 | } 166 | 167 | _disused static void MSWritePush(uint8_t *¤t, I$r target) { 168 | if (target >> 3 != 0) 169 | MSWrite(current, 0x40 | (target & 0x08) >> 3); 170 | MSWrite(current, 0x50 | target & 0x07); 171 | } 172 | 173 | _disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { 174 | MSWrite(current, 0x83); 175 | MSWrite(current, 0xc4 | target & 0x07); 176 | MSWrite(current, source); 177 | } 178 | 179 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { 180 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2); 181 | MSWrite(current, 0xb8 | target & 0x7); 182 | MSWrite(current, source); 183 | } 184 | 185 | template 186 | _disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { 187 | return MSWriteSet64(current, target, reinterpret_cast(source)); 188 | } 189 | 190 | _disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { 191 | MSWrite(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); 192 | MSWrite(current, 0x8b); 193 | MSWrite(current, (target & 0x07) << 3 | source & 0x07); 194 | } 195 | 196 | _disused static size_t MSSizeOfMove64() { 197 | return 3; 198 | } 199 | 200 | #endif//SUBSTRATE_X86_HPP 201 | -------------------------------------------------------------------------------- /jni/Substrate/hde64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #include 9 | #include 10 | 11 | #include "hde64.h" 12 | #include "table64.h" 13 | 14 | unsigned int hde64_disasm(const void *code, hde64s *hs) 15 | { 16 | uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; 17 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 18 | uint8_t op64 = 0; 19 | 20 | memset(hs,0,sizeof(hde64s)); 21 | char *tmp=(char*)hs; 22 | 23 | for (x = 16; x; x--) 24 | switch (c = *p++) { 25 | case 0xf3: 26 | hs->p_rep = c; 27 | pref |= PRE_F3; 28 | break; 29 | case 0xf2: 30 | hs->p_rep = c; 31 | pref |= PRE_F2; 32 | break; 33 | case 0xf0: 34 | hs->p_lock = c; 35 | pref |= PRE_LOCK; 36 | break; 37 | case 0x26: case 0x2e: case 0x36: 38 | case 0x3e: case 0x64: case 0x65: 39 | hs->p_seg = c; 40 | pref |= PRE_SEG; 41 | break; 42 | case 0x66: 43 | hs->p_66 = c; 44 | pref |= PRE_66; 45 | break; 46 | case 0x67: 47 | hs->p_67 = c; 48 | pref |= PRE_67; 49 | break; 50 | default: 51 | goto pref_done; 52 | } 53 | pref_done: 54 | 55 | hs->flags = (uint32_t)pref << 23; 56 | 57 | if (!pref) 58 | pref |= PRE_NONE; 59 | 60 | if ((c & 0xf0) == 0x40) { 61 | hs->flags |= F_PREFIX_REX; 62 | if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) 63 | op64++; 64 | hs->rex_r = (c & 7) >> 2; 65 | hs->rex_x = (c & 3) >> 1; 66 | hs->rex_b = c & 1; 67 | if (((c = *p++) & 0xf0) == 0x40) { 68 | opcode = c; 69 | goto error_opcode; 70 | } 71 | } 72 | 73 | if ((hs->opcode = c) == 0x0f) { 74 | hs->opcode2 = c = *p++; 75 | ht += DELTA_OPCODES; 76 | } else if (c >= 0xa0 && c <= 0xa3) { 77 | op64++; 78 | if (pref & PRE_67) 79 | pref |= PRE_66; 80 | else 81 | pref &= ~PRE_66; 82 | } 83 | 84 | opcode = c; 85 | cflags = ht[ht[opcode / 4] + (opcode % 4)]; 86 | 87 | if (cflags == C_ERROR) { 88 | error_opcode: 89 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 90 | cflags = 0; 91 | if ((opcode & -3) == 0x24) 92 | cflags++; 93 | } 94 | 95 | x = 0; 96 | if (cflags & C_GROUP) { 97 | uint16_t t; 98 | t = *(uint16_t *)(ht + (cflags & 0x7f)); 99 | cflags = (uint8_t)t; 100 | x = (uint8_t)(t >> 8); 101 | } 102 | 103 | if (hs->opcode2) { 104 | ht = hde64_table + DELTA_PREFIXES; 105 | if (ht[ht[opcode / 4] + (opcode % 4)] & pref) 106 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 107 | } 108 | 109 | if (cflags & C_MODRM) { 110 | hs->flags |= F_MODRM; 111 | hs->modrm = c = *p++; 112 | hs->modrm_mod = m_mod = c >> 6; 113 | hs->modrm_rm = m_rm = c & 7; 114 | hs->modrm_reg = m_reg = (c & 0x3f) >> 3; 115 | 116 | if (x && ((x << m_reg) & 0x80)) 117 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 118 | 119 | if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { 120 | uint8_t t = opcode - 0xd9; 121 | if (m_mod == 3) { 122 | ht = hde64_table + DELTA_FPU_MODRM + t*8; 123 | t = ht[m_reg] << m_rm; 124 | } else { 125 | ht = hde64_table + DELTA_FPU_REG; 126 | t = ht[t] << m_reg; 127 | } 128 | if (t & 0x80) 129 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 130 | } 131 | 132 | if (pref & PRE_LOCK) { 133 | if (m_mod == 3) { 134 | hs->flags |= F_ERROR | F_ERROR_LOCK; 135 | } else { 136 | uint8_t *table_end, op = opcode; 137 | if (hs->opcode2) { 138 | ht = hde64_table + DELTA_OP2_LOCK_OK; 139 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 140 | } else { 141 | ht = hde64_table + DELTA_OP_LOCK_OK; 142 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 143 | op &= -2; 144 | } 145 | for (; ht != table_end; ht++) 146 | if (*ht++ == op) { 147 | if (!((*ht << m_reg) & 0x80)) 148 | goto no_lock_error; 149 | else 150 | break; 151 | } 152 | hs->flags |= F_ERROR | F_ERROR_LOCK; 153 | no_lock_error: 154 | ; 155 | } 156 | } 157 | 158 | if (hs->opcode2) { 159 | switch (opcode) { 160 | case 0x20: case 0x22: 161 | m_mod = 3; 162 | if (m_reg > 4 || m_reg == 1) 163 | goto error_operand; 164 | else 165 | goto no_error_operand; 166 | case 0x21: case 0x23: 167 | m_mod = 3; 168 | if (m_reg == 4 || m_reg == 5) 169 | goto error_operand; 170 | else 171 | goto no_error_operand; 172 | } 173 | } else { 174 | switch (opcode) { 175 | case 0x8c: 176 | if (m_reg > 5) 177 | goto error_operand; 178 | else 179 | goto no_error_operand; 180 | case 0x8e: 181 | if (m_reg == 1 || m_reg > 5) 182 | goto error_operand; 183 | else 184 | goto no_error_operand; 185 | } 186 | } 187 | 188 | if (m_mod == 3) { 189 | uint8_t *table_end; 190 | if (hs->opcode2) { 191 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 192 | table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; 193 | } else { 194 | ht = hde64_table + DELTA_OP_ONLY_MEM; 195 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 196 | } 197 | for (; ht != table_end; ht += 2) 198 | if (*ht++ == opcode) { 199 | if (*ht++ & pref && !((*ht << m_reg) & 0x80)) 200 | goto error_operand; 201 | else 202 | break; 203 | } 204 | goto no_error_operand; 205 | } else if (hs->opcode2) { 206 | switch (opcode) { 207 | case 0x50: case 0xd7: case 0xf7: 208 | if (pref & (PRE_NONE | PRE_66)) 209 | goto error_operand; 210 | break; 211 | case 0xd6: 212 | if (pref & (PRE_F2 | PRE_F3)) 213 | goto error_operand; 214 | break; 215 | case 0xc5: 216 | goto error_operand; 217 | } 218 | goto no_error_operand; 219 | } else 220 | goto no_error_operand; 221 | 222 | error_operand: 223 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 224 | no_error_operand: 225 | 226 | c = *p++; 227 | if (m_reg <= 1) { 228 | if (opcode == 0xf6) 229 | cflags |= C_IMM8; 230 | else if (opcode == 0xf7) 231 | cflags |= C_IMM_P66; 232 | } 233 | 234 | switch (m_mod) { 235 | case 0: 236 | if (pref & PRE_67) { 237 | if (m_rm == 6) 238 | disp_size = 2; 239 | } else 240 | if (m_rm == 5) 241 | disp_size = 4; 242 | break; 243 | case 1: 244 | disp_size = 1; 245 | break; 246 | case 2: 247 | disp_size = 2; 248 | if (!(pref & PRE_67)) 249 | disp_size <<= 1; 250 | } 251 | 252 | if (m_mod != 3 && m_rm == 4) { 253 | hs->flags |= F_SIB; 254 | p++; 255 | hs->sib = c; 256 | hs->sib_scale = c >> 6; 257 | hs->sib_index = (c & 0x3f) >> 3; 258 | if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) 259 | disp_size = 4; 260 | } 261 | 262 | p--; 263 | switch (disp_size) { 264 | case 1: 265 | hs->flags |= F_DISP8; 266 | hs->disp.disp8 = *p; 267 | break; 268 | case 2: 269 | hs->flags |= F_DISP16; 270 | hs->disp.disp16 = *(uint16_t *)p; 271 | break; 272 | case 4: 273 | hs->flags |= F_DISP32; 274 | hs->disp.disp32 = *(uint32_t *)p; 275 | } 276 | p += disp_size; 277 | } else if (pref & PRE_LOCK) 278 | hs->flags |= F_ERROR | F_ERROR_LOCK; 279 | 280 | if (cflags & C_IMM_P66) { 281 | if (cflags & C_REL32) { 282 | if (pref & PRE_66) { 283 | hs->flags |= F_IMM16 | F_RELATIVE; 284 | hs->imm.imm16 = *(uint16_t *)p; 285 | p += 2; 286 | goto disasm_done; 287 | } 288 | goto rel32_ok; 289 | } 290 | if (op64) { 291 | hs->flags |= F_IMM64; 292 | hs->imm.imm64 = *(uint64_t *)p; 293 | p += 8; 294 | } else if (!(pref & PRE_66)) { 295 | hs->flags |= F_IMM32; 296 | hs->imm.imm32 = *(uint32_t *)p; 297 | p += 4; 298 | } else 299 | goto imm16_ok; 300 | } 301 | 302 | 303 | if (cflags & C_IMM16) { 304 | imm16_ok: 305 | hs->flags |= F_IMM16; 306 | hs->imm.imm16 = *(uint16_t *)p; 307 | p += 2; 308 | } 309 | if (cflags & C_IMM8) { 310 | hs->flags |= F_IMM8; 311 | hs->imm.imm8 = *p++; 312 | } 313 | 314 | if (cflags & C_REL32) { 315 | rel32_ok: 316 | hs->flags |= F_IMM32 | F_RELATIVE; 317 | hs->imm.imm32 = *(uint32_t *)p; 318 | p += 4; 319 | } else if (cflags & C_REL8) { 320 | hs->flags |= F_IMM8 | F_RELATIVE; 321 | hs->imm.imm8 = *p++; 322 | } 323 | 324 | disasm_done: 325 | 326 | if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { 327 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 328 | hs->len = 15; 329 | } 330 | 331 | return (unsigned int)hs->len; 332 | } 333 | -------------------------------------------------------------------------------- /jni/Substrate/hde64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | /* stdint.h - C99 standard header 14 | * http://en.wikipedia.org/wiki/stdint.h 15 | * 16 | * if your compiler doesn't contain "stdint.h" header (for 17 | * example, Microsoft Visual C++), you can download file: 18 | * http://www.azillionmonkeys.com/qed/pstdint.h 19 | * and change next line to: 20 | * #include "pstdint.h" 21 | */ 22 | #include 23 | 24 | #define F_MODRM 0x00000001 25 | #define F_SIB 0x00000002 26 | #define F_IMM8 0x00000004 27 | #define F_IMM16 0x00000008 28 | #define F_IMM32 0x00000010 29 | #define F_IMM64 0x00000020 30 | #define F_DISP8 0x00000040 31 | #define F_DISP16 0x00000080 32 | #define F_DISP32 0x00000100 33 | #define F_RELATIVE 0x00000200 34 | #define F_ERROR 0x00001000 35 | #define F_ERROR_OPCODE 0x00002000 36 | #define F_ERROR_LENGTH 0x00004000 37 | #define F_ERROR_LOCK 0x00008000 38 | #define F_ERROR_OPERAND 0x00010000 39 | #define F_PREFIX_REPNZ 0x01000000 40 | #define F_PREFIX_REPX 0x02000000 41 | #define F_PREFIX_REP 0x03000000 42 | #define F_PREFIX_66 0x04000000 43 | #define F_PREFIX_67 0x08000000 44 | #define F_PREFIX_LOCK 0x10000000 45 | #define F_PREFIX_SEG 0x20000000 46 | #define F_PREFIX_REX 0x40000000 47 | #define F_PREFIX_ANY 0x7f000000 48 | 49 | #define PREFIX_SEGMENT_CS 0x2e 50 | #define PREFIX_SEGMENT_SS 0x36 51 | #define PREFIX_SEGMENT_DS 0x3e 52 | #define PREFIX_SEGMENT_ES 0x26 53 | #define PREFIX_SEGMENT_FS 0x64 54 | #define PREFIX_SEGMENT_GS 0x65 55 | #define PREFIX_LOCK 0xf0 56 | #define PREFIX_REPNZ 0xf2 57 | #define PREFIX_REPX 0xf3 58 | #define PREFIX_OPERAND_SIZE 0x66 59 | #define PREFIX_ADDRESS_SIZE 0x67 60 | 61 | #pragma pack(push,1) 62 | 63 | typedef struct { 64 | uint8_t len; 65 | uint8_t p_rep; 66 | uint8_t p_lock; 67 | uint8_t p_seg; 68 | uint8_t p_66; 69 | uint8_t p_67; 70 | uint8_t rex; 71 | uint8_t rex_w; 72 | uint8_t rex_r; 73 | uint8_t rex_x; 74 | uint8_t rex_b; 75 | uint8_t opcode; 76 | uint8_t opcode2; 77 | uint8_t modrm; 78 | uint8_t modrm_mod; 79 | uint8_t modrm_reg; 80 | uint8_t modrm_rm; 81 | uint8_t sib; 82 | uint8_t sib_scale; 83 | uint8_t sib_index; 84 | uint8_t sib_base; 85 | union { 86 | uint8_t imm8; 87 | uint16_t imm16; 88 | uint32_t imm32; 89 | uint64_t imm64; 90 | } imm; 91 | union { 92 | uint8_t disp8; 93 | uint16_t disp16; 94 | uint32_t disp32; 95 | } disp; 96 | uint32_t flags; 97 | } hde64s; 98 | 99 | #pragma pack(pop) 100 | 101 | #ifdef __cplusplus 102 | extern "C" { 103 | #endif 104 | 105 | /* __cdecl */ 106 | unsigned int hde64_disasm(const void *code, hde64s *hs); 107 | 108 | #ifdef __cplusplus 109 | } 110 | #endif 111 | 112 | #endif /* _HDE64_H_ */ 113 | -------------------------------------------------------------------------------- /jni/Substrate/table64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, 39 | 0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, 40 | 0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, 41 | 0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, 42 | 0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, 43 | 0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, 44 | 0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, 45 | 0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, 46 | 0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, 47 | 0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, 48 | 0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, 49 | 0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, 50 | 0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, 51 | 0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, 52 | 0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, 53 | 0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, 54 | 0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, 55 | 0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, 56 | 0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, 57 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, 58 | 0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, 59 | 0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, 60 | 0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, 61 | 0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 62 | 0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, 63 | 0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, 64 | 0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, 65 | 0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, 66 | 0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, 67 | 0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, 68 | 0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, 69 | 0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, 70 | 0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, 71 | 0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, 72 | 0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, 73 | 0x00,0xf0,0x02,0x00 74 | }; 75 | -------------------------------------------------------------------------------- /jni/cas.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #define __STDC_FORMAT_MACROS 12 | #include 13 | 14 | // #include 15 | 16 | #include "fake_dlfcn.h" 17 | 18 | #if defined(__aarch64__) 19 | #include "And64InlineHook.hpp" 20 | #endif 21 | #if defined(__arm__) 22 | #include "Substrate/SubstrateHook.h" 23 | #endif 24 | 25 | #define LOG_TAG "LOGXX" 26 | #define LOG_BUF_SIZE 40960 27 | #define LOGD(fmt,args...) __android_log_print(3,LOG_TAG, fmt, ##args) 28 | 29 | typedef int (*t__android_log_write)(int prio, const char *tag, const char *msg); 30 | typedef int (*t__android_log_vprint)(int prio, const char *tag, const char *fmt, va_list ap); 31 | t__android_log_write __android_log_write = nullptr; 32 | t__android_log_vprint __android_log_vprint = nullptr; 33 | 34 | typedef void (*PFN_MSHookFunction)(void *symbol, void *replace, void **result); 35 | 36 | #if defined(__aarch64__) 37 | PFN_MSHookFunction pfn_MSHookFunction = A64HookFunction; 38 | #endif 39 | #if defined(__arm__) 40 | PFN_MSHookFunction pfn_MSHookFunction = MSHookFunction; 41 | #endif 42 | 43 | extern "C" int __android_log_print(int prio, const char *tag, const char *fmt,...) 44 | { 45 | va_list ap; 46 | char buf[LOG_BUF_SIZE] = {0}; 47 | 48 | va_start(ap, fmt); 49 | vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); 50 | va_end(ap); 51 | 52 | return __android_log_write(prio,tag,buf); 53 | } 54 | 55 | uint64_t get_module_base(const char *module_name) { 56 | uint64_t addr = 0; 57 | char line[1024]; 58 | uint64_t start = 0; 59 | uint64_t end = 0; 60 | char flags[5]; 61 | char path[PATH_MAX]; 62 | 63 | FILE *fp = fopen("/proc/self/maps", "r"); 64 | if (fp != nullptr) { 65 | while (fgets(line, sizeof(line), fp)) { 66 | strcpy(path, ""); 67 | sscanf(line, "%" PRIx64"-%" PRIx64" %s %*" PRIx64" %*x:%*x %*u %s\n", &start, &end, 68 | flags, path); 69 | #if defined(__aarch64__) 70 | if (strstr(flags, "x") == 0) 71 | continue; 72 | #endif 73 | if (strstr(path, module_name)) { 74 | addr = start; 75 | break; 76 | } 77 | } 78 | fclose(fp); 79 | } 80 | return addr; 81 | } 82 | 83 | #ifndef HEXDUMP_COLS 84 | #define HEXDUMP_COLS 16 85 | #endif 86 | 87 | void hex_dump(void *mem, unsigned int len) { 88 | 89 | char szTmp[40960] = {0x00}; 90 | unsigned int i, j; 91 | 92 | for (i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++) { 93 | /* print offset */ 94 | if (i % HEXDUMP_COLS == 0) { 95 | #if defined(__x86_64__) 96 | sprintf(&szTmp[strlen(szTmp)], "0x%06x:\t", (unsigned long)mem + i); 97 | #elif defined(__aarch64__) 98 | sprintf(&szTmp[strlen(szTmp)], "0x%06x:\t", (unsigned long)mem + i); 99 | #elif defined(__mips64) 100 | sprintf(&szTmp[strlen(szTmp)], "0x%06x:\t", (unsigned long)mem + i); 101 | #else 102 | sprintf(&szTmp[strlen(szTmp)], "0x%06x:\t", (unsigned int) mem + i); 103 | #endif 104 | } 105 | 106 | /* print hex data */ 107 | if (i < len) { 108 | sprintf(&szTmp[strlen(szTmp)], "%02x ", 0xFF & ((char *) mem)[i]); 109 | } else /* end of block, just aligning for ASCII dump */ 110 | { 111 | sprintf(&szTmp[strlen(szTmp)], " "); 112 | } 113 | 114 | /* print ASCII dump */ 115 | if (i % HEXDUMP_COLS == (HEXDUMP_COLS - 1)) { 116 | for (j = i - (HEXDUMP_COLS - 1); j <= i; j++) { 117 | if (j >= len) /* end of block, not really printing */ 118 | { 119 | sprintf(&szTmp[strlen(szTmp)], " "); 120 | } else if (((char *) mem)[j] > 0x20 && 121 | ((char *) mem)[j] < 0x7e) /* printable char */ 122 | { 123 | sprintf(&szTmp[strlen(szTmp)], "%c", 0xFF & ((char *) mem)[j]); 124 | } else /* other char */ 125 | { 126 | sprintf(&szTmp[strlen(szTmp)], "."); 127 | } 128 | } 129 | sprintf(&szTmp[strlen(szTmp)], "\n"); 130 | } 131 | } 132 | LOGD("%s", szTmp); 133 | } 134 | 135 | int count = 0; 136 | 137 | int (*old_lua_loadbuffer)(void *,char *,size_t,char *, int a5 ,int a6); 138 | int my_lua_loadbuffer(void *L,char *buff,size_t sz,char *name, int a5 ,int a6) 139 | { 140 | // LOGD("AAAAAAAAAAAAAAAAAAAAAaa"); 141 | int ret = old_lua_loadbuffer(L,buff,sz,name, a5, a6); 142 | if(name[strlen(name)-1] == 0x61 143 | &&name[strlen(name)-2] == 0x75 144 | &&name[strlen(name)-3] == 0x6c) 145 | // std::string ssss(name); 146 | if (strlen(name) < 128) 147 | { 148 | LOGD("luaname is :%s---",name); 149 | int name_len = strlen(name); 150 | char *base_dir = (char *)"/data/data/com.game.dir/files/lua_out/"; 151 | char *tail = (char *)".lua"; 152 | char full_name[256]; 153 | //"config/battleConf.luac" 154 | char *name_t = strdup(name); 155 | if(strstr(name,"LogoScene") != NULL) 156 | { 157 | LOGD("LogoScene:%s",buff); 158 | } 159 | int i = name_len; 160 | while(i>0) 161 | { 162 | if(name_t[i] == 0x2f) 163 | { 164 | LOGD("in--%s",(char *)&name_t[i+1]); 165 | sprintf(full_name,"%s%s%d%s",base_dir,(char *)&name_t[i+1],count,tail); 166 | LOGD("%s\n",full_name); 167 | count++; 168 | break; 169 | } 170 | i--; 171 | } 172 | FILE *fp = fopen(full_name,"w+"); 173 | if(fp != NULL && sz != 0) 174 | { 175 | size_t len = 0; 176 | LOGD("sz1 is %d",sz); 177 | fwrite(buff,1,sz,fp); 178 | fclose(fp); 179 | }else 180 | { 181 | LOGD("open file fail!!!"); 182 | } 183 | free(name_t); 184 | } 185 | LOGD("sz2 is %d",sz); 186 | LOGD("name is %s",name); 187 | return ret; 188 | } 189 | 190 | int (*old_xxtea_decrypt)(int a1, int a2, int a3, unsigned int a4, void *a5); 191 | int new_xxtea_decrypt(int a1, int a2, int a3, unsigned int a4, void *a5) { 192 | LOGD("xxtea_decrypt"); 193 | return old_xxtea_decrypt(a1, a2, a3, a4, a5); 194 | } 195 | 196 | void hook_entry() __attribute__((constructor)); 197 | void hook_entry() 198 | { 199 | void * liblog_handle = dlopen("/system/lib64/liblog.so", RTLD_NOW);///system/lib/arm/liblog.so 200 | if (liblog_handle) 201 | { 202 | __android_log_write = (t__android_log_write)dlsym(liblog_handle,"__android_log_write"); 203 | __android_log_vprint = (t__android_log_vprint)dlsym(liblog_handle,"__android_log_vprint"); 204 | } 205 | 206 | LOGD("hook_entry"); 207 | // AKInitializeOnce(); 208 | void * libm_handle = dlopen("/data/app/com.game.dir-i_RMvdy5OSL55GfGzCemdw==/lib/arm64/libcocos2dlua.so", RTLD_LAZY); 209 | if (!libm_handle) 210 | { 211 | LOGD("Open Error:%s",(char*)dlerror()); 212 | return; 213 | } 214 | LOGD("libm_handle = %p", (char*)libm_handle); 215 | void *p = dlsym(libm_handle, "luaL_loadbufferx"); 216 | LOGD("luaL_loadbuffer = %p", (char*)p); 217 | pfn_MSHookFunction(p, (void *)my_lua_loadbuffer, (void **)&old_lua_loadbuffer); 218 | p = dlsym(libm_handle, "xxtea_decrypt"); 219 | LOGD("xxtea_decrypt = %p", (char*)p); 220 | // uint64_t base = get_module_base("libcocos2dlua.so"); 221 | // LOGD("base ==> %lx", (unsigned long)base); 222 | // // 5FF374 223 | // p = (void*)(base + 0x5FF374); 224 | // pfn_MSHookFunction(p, (void *)new_xxtea_decrypt, (void **)&old_xxtea_decrypt); 225 | } -------------------------------------------------------------------------------- /jni/fake_dlfcn.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 avs333 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include "fake_dlfcn.h" 27 | 28 | #define TAG_NAME "test2:fake_dlfcn" 29 | 30 | #define log_info(fmt,args...) __android_log_print(ANDROID_LOG_INFO, TAG_NAME, (const char *) fmt, ##args) 31 | #define log_err(fmt,args...) __android_log_print(ANDROID_LOG_ERROR, TAG_NAME, (const char *) fmt, ##args) 32 | 33 | //#ifdef LOG_DBG 34 | #define log_dbg log_info 35 | //#else 36 | //#define log_dbg(...) 37 | //#endif 38 | 39 | #ifdef __arm__ 40 | #define Elf_Ehdr Elf32_Ehdr 41 | #define Elf_Shdr Elf32_Shdr 42 | #define Elf_Sym Elf32_Sym 43 | #elif defined(__aarch64__) 44 | #define Elf_Ehdr Elf64_Ehdr 45 | #define Elf_Shdr Elf64_Shdr 46 | #define Elf_Sym Elf64_Sym 47 | #elif defined(__i386__) 48 | #define Elf_Ehdr Elf32_Ehdr 49 | #define Elf_Shdr Elf32_Shdr 50 | #define Elf_Sym Elf32_Sym 51 | #else 52 | #error "Arch unknown, please port me" 53 | #endif 54 | 55 | struct ctx { 56 | void *load_addr; 57 | void *dynstr; 58 | void *dynsym; 59 | int nsyms; 60 | off_t bias; 61 | }; 62 | 63 | extern "C" { 64 | int fake_dlclose(void *handle) { 65 | if (handle) { 66 | struct ctx *ctx = (struct ctx *) handle; 67 | if (ctx->dynsym) free(ctx->dynsym); /* we're saving dynsym and dynstr */ 68 | if (ctx->dynstr) free(ctx->dynstr); /* from library file just in case */ 69 | free(ctx); 70 | } 71 | return 0; 72 | } 73 | 74 | /* flags are ignored */ 75 | 76 | void *fake_dlopen(const char *libpath, int flags) { 77 | FILE *maps; 78 | char buff[256]; 79 | struct ctx *ctx = 0; 80 | off_t load_addr, size; 81 | int k, fd = -1, found = 0; 82 | void *shoff; 83 | Elf_Ehdr *elf = (Elf_Ehdr *) MAP_FAILED; 84 | 85 | #define fatal(fmt, args...) do { log_err(fmt,##args); goto err_exit; } while(0) 86 | 87 | maps = fopen("/proc/self/maps", "r"); 88 | if (!maps) fatal("failed to open maps"); 89 | 90 | while (!found && fgets(buff, sizeof(buff), maps)) 91 | if (strstr(buff, "r-xp") && strstr(buff, libpath)) found = 1; 92 | 93 | fclose(maps); 94 | 95 | if (!found) fatal("%s not found in my userspace", libpath); 96 | 97 | if (sscanf(buff, "%lx", &load_addr) != 1) 98 | fatal("failed to read load address for %s", libpath); 99 | 100 | log_info("%s loaded in Android at 0x%08lx", libpath, load_addr); 101 | 102 | /* Now, mmap the same library once again */ 103 | 104 | fd = open(libpath, O_RDONLY); 105 | if (fd < 0) fatal("failed to open %s", libpath); 106 | 107 | size = lseek(fd, 0, SEEK_END); 108 | if (size <= 0) fatal("lseek() failed for %s", libpath); 109 | 110 | elf = (Elf_Ehdr *) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); 111 | close(fd); 112 | fd = -1; 113 | 114 | if (elf == MAP_FAILED) fatal("mmap() failed for %s", libpath); 115 | 116 | ctx = (struct ctx *) calloc(1, sizeof(struct ctx)); 117 | if (!ctx) fatal("no memory for %s", libpath); 118 | 119 | ctx->load_addr = (void *) load_addr; 120 | shoff = ((void *) elf) + elf->e_shoff; 121 | 122 | for (k = 0; k < elf->e_shnum; k++, shoff += elf->e_shentsize) { 123 | 124 | Elf_Shdr *sh = (Elf_Shdr *) shoff; 125 | log_dbg("%s: k=%d shdr=%p type=%x", __func__, k, sh, sh->sh_type); 126 | 127 | switch (sh->sh_type) { 128 | 129 | case SHT_DYNSYM: 130 | if (ctx->dynsym) fatal("%s: duplicate DYNSYM sections", libpath); /* .dynsym */ 131 | ctx->dynsym = malloc(sh->sh_size); 132 | if (!ctx->dynsym) fatal("%s: no memory for .dynsym", libpath); 133 | memcpy(ctx->dynsym, ((void *) elf) + sh->sh_offset, sh->sh_size); 134 | ctx->nsyms = (sh->sh_size / sizeof(Elf_Sym)); 135 | break; 136 | 137 | case SHT_STRTAB: 138 | if (ctx->dynstr) break; /* .dynstr is guaranteed to be the first STRTAB */ 139 | ctx->dynstr = malloc(sh->sh_size); 140 | if (!ctx->dynstr) fatal("%s: no memory for .dynstr", libpath); 141 | memcpy(ctx->dynstr, ((void *) elf) + sh->sh_offset, sh->sh_size); 142 | break; 143 | 144 | case SHT_PROGBITS: 145 | if (!ctx->dynstr || !ctx->dynsym) break; 146 | /* won't even bother checking against the section name */ 147 | ctx->bias = (off_t) sh->sh_addr - (off_t) sh->sh_offset; 148 | k = elf->e_shnum; /* exit for */ 149 | break; 150 | } 151 | } 152 | 153 | munmap(elf, size); 154 | elf = 0; 155 | 156 | if (!ctx->dynstr || !ctx->dynsym) fatal("dynamic sections not found in %s", libpath); 157 | 158 | #undef fatal 159 | 160 | log_dbg("%s: ok, dynsym = %p, dynstr = %p", libpath, ctx->dynsym, ctx->dynstr); 161 | 162 | return ctx; 163 | 164 | err_exit: 165 | if (fd >= 0) close(fd); 166 | if (elf != MAP_FAILED) munmap(elf, size); 167 | fake_dlclose(ctx); 168 | return 0; 169 | } 170 | 171 | void *fake_dlsym(void *handle, const char *name) { 172 | int k; 173 | struct ctx *ctx = (struct ctx *) handle; 174 | Elf_Sym *sym = (Elf_Sym *) ctx->dynsym; 175 | char *strings = (char *) ctx->dynstr; 176 | 177 | for (k = 0; k < ctx->nsyms; k++, sym++) 178 | if (strcmp(strings + sym->st_name, name) == 0) { 179 | /* NB: sym->st_value is an offset into the section for relocatables, 180 | but a VMA for shared libs or exe files, so we have to subtract the bias */ 181 | void *ret = ctx->load_addr + sym->st_value - ctx->bias; 182 | log_info("%s found at %p", name, ret); 183 | return ret; 184 | } 185 | return 0; 186 | } 187 | } 188 | 189 | 190 | -------------------------------------------------------------------------------- /jni/fake_dlfcn.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 avs333 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | #ifndef DEXPOSED_DLFCN_H 22 | #define DEXPOSED_DLFCN_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | extern "C" { 29 | 30 | void *fake_dlopen(const char *libpath, int flags); 31 | void *fake_dlsym(void *handle, const char *name); 32 | 33 | }; 34 | #endif //DEXPOSED_DLFCN_H 35 | --------------------------------------------------------------------------------