parent
20c2e96b75
commit
6583317f02
@ -1,567 +0,0 @@ |
||||
/*
|
||||
* @date : 2018/04/18 |
||||
* @author : Rprop (r_prop@outlook.com) |
||||
* https://github.com/Rprop/And64InlineHook
|
||||
*/ |
||||
/*
|
||||
MIT License |
||||
|
||||
Copyright (c) 2018 Rprop (r_prop@outlook.com) |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
#define __STDC_FORMAT_MACROS |
||||
|
||||
#if defined(__aarch64__) |
||||
|
||||
#include <cassert> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <sys/mman.h> |
||||
#include "And64InlineHook.hpp" |
||||
#define A64_MAX_INSTRUCTIONS 5 |
||||
#define A64_MAX_REFERENCES (A64_MAX_INSTRUCTIONS * 2) |
||||
#define A64_NOP 0xd503201fu |
||||
#define A64_JNIEXPORT __attribute__((visibility("default"))) |
||||
#define __flush_cache(c, n) __builtin___clear_cache(reinterpret_cast<char *>(c), reinterpret_cast<char *>(c) + n) |
||||
|
||||
|
||||
typedef uint32_t *__restrict *__restrict instruction; |
||||
typedef struct
|
||||
{ |
||||
struct fix_info |
||||
{ |
||||
uint32_t *bp; |
||||
uint32_t ls; // left-shift counts
|
||||
uint32_t ad; // & operand
|
||||
}; |
||||
struct insns_info |
||||
{ |
||||
union
|
||||
{ |
||||
uint64_t insu; |
||||
int64_t ins; |
||||
void *insp; |
||||
}; |
||||
fix_info fmap[A64_MAX_REFERENCES]; |
||||
}; |
||||
int64_t basep; |
||||
int64_t endp; |
||||
insns_info dat[A64_MAX_INSTRUCTIONS]; |
||||
|
||||
public: |
||||
inline bool is_in_fixing_range(const int64_t absolute_addr) { |
||||
return absolute_addr >= this->basep && absolute_addr < this->endp; |
||||
} |
||||
inline intptr_t get_ref_ins_index(const int64_t absolute_addr) { |
||||
return static_cast<intptr_t>((absolute_addr - this->basep) / sizeof(uint32_t)); |
||||
} |
||||
inline intptr_t get_and_set_current_index(uint32_t *__restrict inp, uint32_t *__restrict outp) { |
||||
intptr_t current_idx = this->get_ref_ins_index(reinterpret_cast<int64_t>(inp)); |
||||
this->dat[current_idx].insp = outp; |
||||
return current_idx; |
||||
} |
||||
inline void reset_current_ins(const intptr_t idx, uint32_t *__restrict outp) { |
||||
this->dat[idx].insp = outp; |
||||
} |
||||
void insert_fix_map(const intptr_t idx, uint32_t *bp, uint32_t ls = 0u, uint32_t ad = 0xffffffffu) { |
||||
for (auto &f : this->dat[idx].fmap) { |
||||
if (f.bp == NULL) { |
||||
f.bp = bp; |
||||
f.ls = ls; |
||||
f.ad = ad; |
||||
return; |
||||
} //if
|
||||
} |
||||
// What? GGing..
|
||||
} |
||||
void process_fix_map(const intptr_t idx) { |
||||
for (auto &f : this->dat[idx].fmap) { |
||||
if (f.bp == NULL) break; |
||||
*(f.bp) = *(f.bp) | (((int32_t(this->dat[idx].ins - reinterpret_cast<int64_t>(f.bp)) >> 2) << f.ls) & f.ad); |
||||
f.bp = NULL; |
||||
} |
||||
} |
||||
} context; |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static bool __fix_branch_imm(instruction inpp, instruction outpp, context *ctxp) |
||||
{ |
||||
static constexpr uint32_t mbits = 6u; |
||||
static constexpr uint32_t mask = 0xfc000000u; // 0b11111100000000000000000000000000
|
||||
static constexpr uint32_t rmask = 0x03ffffffu; // 0b00000011111111111111111111111111
|
||||
static constexpr uint32_t op_b = 0x14000000u; // "b" ADDR_PCREL26
|
||||
static constexpr uint32_t op_bl = 0x94000000u; // "bl" ADDR_PCREL26
|
||||
|
||||
const uint32_t ins = *(*inpp); |
||||
const uint32_t opc = ins & mask; |
||||
switch (opc) { |
||||
case op_b: |
||||
case op_bl: |
||||
{ |
||||
intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); |
||||
int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + (static_cast<int32_t>(ins << mbits) >> (mbits - 2u)); // sign-extended
|
||||
int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted
|
||||
bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); |
||||
// whether the branch should be converted to absolute jump
|
||||
if (!special_fix_type && llabs(new_pc_offset) >= (rmask >> 1)) { |
||||
bool b_aligned = (reinterpret_cast<uint64_t>(*outpp + 2) & 7u) == 0u; |
||||
if (opc == op_b) { |
||||
if (b_aligned != true) { |
||||
(*outpp)[0] = A64_NOP; |
||||
ctxp->reset_current_ins(current_idx, ++(*outpp)); |
||||
} //if
|
||||
(*outpp)[0] = 0x58000051u; // LDR X17, #0x8
|
||||
(*outpp)[1] = 0xd61f0220u; // BR X17
|
||||
memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); |
||||
*outpp += 4; |
||||
} else { |
||||
if (b_aligned == true) { |
||||
(*outpp)[0] = A64_NOP; |
||||
ctxp->reset_current_ins(current_idx, ++(*outpp)); |
||||
} //if
|
||||
(*outpp)[0] = 0x58000071u; // LDR X17, #12
|
||||
(*outpp)[1] = 0x1000009eu; // ADR X30, #16
|
||||
(*outpp)[2] = 0xd61f0220u; // BR X17
|
||||
memcpy(*outpp + 3, &absolute_addr, sizeof(absolute_addr)); |
||||
*outpp += 5; |
||||
} //if
|
||||
} else { |
||||
if (special_fix_type) { |
||||
intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); |
||||
if (ref_idx <= current_idx) { |
||||
new_pc_offset = static_cast<int64_t>(ctxp->dat[ref_idx].ins - reinterpret_cast<int64_t>(*outpp)) >> 2; |
||||
} else { |
||||
ctxp->insert_fix_map(ref_idx, *outpp, 0u, rmask); |
||||
new_pc_offset = 0; |
||||
} //if
|
||||
} //if
|
||||
|
||||
(*outpp)[0] = opc | (new_pc_offset & ~mask); |
||||
++(*outpp); |
||||
} //if
|
||||
|
||||
++(*inpp); |
||||
return ctxp->process_fix_map(current_idx), true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static bool __fix_cond_comp_test_branch(instruction inpp, instruction outpp, context *ctxp) |
||||
{ |
||||
static constexpr uint32_t lsb = 5u; |
||||
static constexpr uint32_t lmask01 = 0xff00001fu; // 0b11111111000000000000000000011111
|
||||
static constexpr uint32_t mask0 = 0xff000010u; // 0b11111111000000000000000000010000
|
||||
static constexpr uint32_t op_bc = 0x54000000u; // "b.c" ADDR_PCREL19
|
||||
static constexpr uint32_t mask1 = 0x7f000000u; // 0b01111111000000000000000000000000
|
||||
static constexpr uint32_t op_cbz = 0x34000000u; // "cbz" Rt, ADDR_PCREL19
|
||||
static constexpr uint32_t op_cbnz = 0x35000000u; // "cbnz" Rt, ADDR_PCREL19
|
||||
static constexpr uint32_t lmask2 = 0xfff8001fu; // 0b11111111111110000000000000011111
|
||||
static constexpr uint32_t mask2 = 0x7f000000u; // 0b01111111000000000000000000000000
|
||||
static constexpr uint32_t op_tbz = 0x36000000u; // 0b00110110000000000000000000000000 "tbz" Rt, BIT_NUM, ADDR_PCREL14
|
||||
static constexpr uint32_t op_tbnz = 0x37000000u; // 0b00110111000000000000000000000000 "tbnz" Rt, BIT_NUM, ADDR_PCREL14
|
||||
|
||||
const uint32_t ins = *(*inpp); |
||||
uint32_t lmask = lmask01; |
||||
if ((ins & mask0) != op_bc) { |
||||
uint32_t opc = ins & mask1; |
||||
if (opc != op_cbz && opc != op_cbnz) { |
||||
opc = ins & mask2; |
||||
if (opc != op_tbz && opc != op_tbnz) { |
||||
return false; |
||||
} //if
|
||||
lmask = lmask2; |
||||
} //if
|
||||
} //if
|
||||
|
||||
intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); |
||||
int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + ((ins & ~lmask) >> (lsb - 2u)); |
||||
int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted
|
||||
bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); |
||||
if (!special_fix_type && llabs(new_pc_offset) >= (~lmask >> (lsb + 1))) { |
||||
if ((reinterpret_cast<uint64_t>(*outpp + 4) & 7u) != 0u) { |
||||
(*outpp)[0] = A64_NOP; |
||||
ctxp->reset_current_ins(current_idx, ++(*outpp)); |
||||
} //if
|
||||
(*outpp)[0] = (((8u >> 2u) << lsb) & ~lmask) | (ins & lmask); // B.C #0x8
|
||||
(*outpp)[1] = 0x14000005u; // B #0x14
|
||||
(*outpp)[2] = 0x58000051u; // LDR X17, #0x8
|
||||
(*outpp)[3] = 0xd61f0220u; // BR X17
|
||||
memcpy(*outpp + 4, &absolute_addr, sizeof(absolute_addr)); |
||||
*outpp += 6; |
||||
} else { |
||||
if (special_fix_type) { |
||||
intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr); |
||||
if (ref_idx <= current_idx) { |
||||
new_pc_offset = static_cast<int64_t>(ctxp->dat[ref_idx].ins - reinterpret_cast<int64_t>(*outpp)) >> 2; |
||||
} else { |
||||
ctxp->insert_fix_map(ref_idx, *outpp, lsb, ~lmask); |
||||
new_pc_offset = 0; |
||||
} //if
|
||||
} //if
|
||||
|
||||
(*outpp)[0] = (static_cast<uint32_t>(new_pc_offset << lsb) & ~lmask) | (ins & lmask); |
||||
++(*outpp); |
||||
} //if
|
||||
|
||||
++(*inpp); |
||||
return ctxp->process_fix_map(current_idx), true; |
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static bool __fix_loadlit(instruction inpp, instruction outpp, context *ctxp) |
||||
{ |
||||
const uint32_t ins = *(*inpp); |
||||
|
||||
// memory prefetch("prfm"), just skip it
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897420050.html
|
||||
if ((ins & 0xff000000u) == 0xd8000000u) { |
||||
ctxp->process_fix_map(ctxp->get_and_set_current_index(*inpp, *outpp)); |
||||
++(*inpp); |
||||
return true; |
||||
} //if
|
||||
|
||||
static constexpr uint32_t msb = 8u; |
||||
static constexpr uint32_t lsb = 5u; |
||||
static constexpr uint32_t mask_30 = 0x40000000u; // 0b01000000000000000000000000000000
|
||||
static constexpr uint32_t mask_31 = 0x80000000u; // 0b10000000000000000000000000000000
|
||||
static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111
|
||||
static constexpr uint32_t mask_ldr = 0xbf000000u; // 0b10111111000000000000000000000000
|
||||
static constexpr uint32_t op_ldr = 0x18000000u; // 0b00011000000000000000000000000000 "LDR Wt/Xt, label" | ADDR_PCREL19
|
||||
static constexpr uint32_t mask_ldrv = 0x3f000000u; // 0b00111111000000000000000000000000
|
||||
static constexpr uint32_t op_ldrv = 0x1c000000u; // 0b00011100000000000000000000000000 "LDR St/Dt/Qt, label" | ADDR_PCREL19
|
||||
static constexpr uint32_t mask_ldrsw = 0xff000000u; // 0b11111111000000000000000000000000
|
||||
static constexpr uint32_t op_ldrsw = 0x98000000u; // "LDRSW Xt, label" | ADDR_PCREL19 | load register signed word
|
||||
// LDR S0, #0 | 0b00011100000000000000000000000000 | 32-bit
|
||||
// LDR D0, #0 | 0b01011100000000000000000000000000 | 64-bit
|
||||
// LDR Q0, #0 | 0b10011100000000000000000000000000 | 128-bit
|
||||
// INVALID | 0b11011100000000000000000000000000 | may be 256-bit
|
||||
|
||||
uint32_t mask = mask_ldr; |
||||
uintptr_t faligned = (ins & mask_30) ? 7u : 3u; |
||||
if ((ins & mask_ldr) != op_ldr) { |
||||
mask = mask_ldrv; |
||||
if (faligned != 7u) |
||||
faligned = (ins & mask_31) ? 15u : 3u; |
||||
if ((ins & mask_ldrv) != op_ldrv) { |
||||
if ((ins & mask_ldrsw) != op_ldrsw) { |
||||
return false; |
||||
} //if
|
||||
mask = mask_ldrsw; |
||||
faligned = 7u; |
||||
} //if
|
||||
} //if
|
||||
|
||||
intptr_t current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); |
||||
int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + ((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u); |
||||
int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; // shifted
|
||||
bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); |
||||
// special_fix_type may encounter issue when there are mixed data and code
|
||||
if (special_fix_type || (llabs(new_pc_offset) + (faligned + 1u - 4u) / 4u) >= (~lmask >> (lsb + 1))) { // inaccurate, but it works
|
||||
while ((reinterpret_cast<uint64_t>(*outpp + 2) & faligned) != 0u) { |
||||
*(*outpp)++ = A64_NOP; |
||||
} |
||||
ctxp->reset_current_ins(current_idx, *outpp); |
||||
|
||||
// Note that if memory at absolute_addr is writeable (non-const), we will fail to fetch it.
|
||||
// And what's worse, we may unexpectedly overwrite something if special_fix_type is true...
|
||||
uint32_t ns = static_cast<uint32_t>((faligned + 1) / sizeof(uint32_t)); |
||||
(*outpp)[0] = (((8u >> 2u) << lsb) & ~mask) | (ins & lmask); // LDR #0x8
|
||||
(*outpp)[1] = 0x14000001u + ns; // B #0xc
|
||||
memcpy(*outpp + 2, reinterpret_cast<void *>(absolute_addr), faligned + 1); |
||||
*outpp += 2 + ns; |
||||
} else { |
||||
faligned >>= 2; // new_pc_offset is shifted and 4-byte aligned
|
||||
while ((new_pc_offset & faligned) != 0) { |
||||
*(*outpp)++ = A64_NOP; |
||||
new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)) >> 2; |
||||
} |
||||
ctxp->reset_current_ins(current_idx, *outpp); |
||||
|
||||
(*outpp)[0] = (static_cast<uint32_t>(new_pc_offset << lsb) & ~mask) | (ins & lmask); |
||||
++(*outpp); |
||||
} //if
|
||||
|
||||
++(*inpp); |
||||
return ctxp->process_fix_map(current_idx), true; |
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static bool __fix_pcreladdr(instruction inpp, instruction outpp, context *ctxp) |
||||
{ |
||||
// Load a PC-relative address into a register
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.100069_0608_00_en/pge1427897645644.html
|
||||
static constexpr uint32_t msb = 8u; |
||||
static constexpr uint32_t lsb = 5u; |
||||
static constexpr uint32_t mask = 0x9f000000u; // 0b10011111000000000000000000000000
|
||||
static constexpr uint32_t rmask = 0x0000001fu; // 0b00000000000000000000000000011111
|
||||
static constexpr uint32_t lmask = 0xff00001fu; // 0b11111111000000000000000000011111
|
||||
static constexpr uint32_t fmask = 0x00ffffffu; // 0b00000000111111111111111111111111
|
||||
static constexpr uint32_t max_val = 0x001fffffu; // 0b00000000000111111111111111111111
|
||||
static constexpr uint32_t op_adr = 0x10000000u; // "adr" Rd, ADDR_PCREL21
|
||||
static constexpr uint32_t op_adrp = 0x90000000u; // "adrp" Rd, ADDR_ADRP
|
||||
|
||||
const uint32_t ins = *(*inpp); |
||||
intptr_t current_idx; |
||||
switch (ins & mask) { |
||||
case op_adr: |
||||
{ |
||||
current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); |
||||
int64_t lsb_bytes = static_cast<uint32_t>(ins << 1u) >> 30u; |
||||
int64_t absolute_addr = reinterpret_cast<int64_t>(*inpp) + (((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u) | lsb_bytes); |
||||
int64_t new_pc_offset = static_cast<int64_t>(absolute_addr - reinterpret_cast<int64_t>(*outpp)); |
||||
bool special_fix_type = ctxp->is_in_fixing_range(absolute_addr); |
||||
if (!special_fix_type && llabs(new_pc_offset) >= (max_val >> 1)) { |
||||
if ((reinterpret_cast<uint64_t>(*outpp + 2) & 7u) != 0u) { |
||||
(*outpp)[0] = A64_NOP; |
||||
ctxp->reset_current_ins(current_idx, ++(*outpp)); |
||||
} //if
|
||||
|
||||
(*outpp)[0] = 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8
|
||||
(*outpp)[1] = 0x14000003u; // B #0xc
|
||||
memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); |
||||
*outpp += 4; |
||||
} else { |
||||
if (special_fix_type) { |
||||
intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr & ~3ull); |
||||
if (ref_idx <= current_idx) { |
||||
new_pc_offset = static_cast<int64_t>(ctxp->dat[ref_idx].ins - reinterpret_cast<int64_t>(*outpp)); |
||||
} else { |
||||
ctxp->insert_fix_map(ref_idx, *outpp, lsb, fmask); |
||||
new_pc_offset = 0; |
||||
} //if
|
||||
} //if
|
||||
|
||||
// the lsb_bytes will never be changed, so we can use lmask to keep it
|
||||
(*outpp)[0] = (static_cast<uint32_t>(new_pc_offset << (lsb - 2u)) & fmask) | (ins & lmask); |
||||
++(*outpp); |
||||
} //if
|
||||
} |
||||
break; |
||||
case op_adrp: |
||||
{ |
||||
current_idx = ctxp->get_and_set_current_index(*inpp, *outpp); |
||||
int32_t lsb_bytes = static_cast<uint32_t>(ins << 1u) >> 30u; |
||||
int64_t absolute_addr = (reinterpret_cast<int64_t>(*inpp) & ~0xfffll) + ((((static_cast<int32_t>(ins << msb) >> (msb + lsb - 2u)) & ~3u) | lsb_bytes) << 12); |
||||
if (ctxp->is_in_fixing_range(absolute_addr)) { |
||||
intptr_t ref_idx = ctxp->get_ref_ins_index(absolute_addr/* & ~3ull*/); |
||||
if (ref_idx > current_idx) { |
||||
// the bottom 12 bits of absolute_addr are masked out,
|
||||
// so ref_idx must be less than or equal to current_idx!
|
||||
} //if
|
||||
|
||||
// *absolute_addr may be changed due to relocation fixing
|
||||
*(*outpp)++ = ins; // 0x90000000u;
|
||||
} else { |
||||
if ((reinterpret_cast<uint64_t>(*outpp + 2) & 7u) != 0u) { |
||||
(*outpp)[0] = A64_NOP; |
||||
ctxp->reset_current_ins(current_idx, ++(*outpp)); |
||||
} //if
|
||||
|
||||
(*outpp)[0] = 0x58000000u | (((8u >> 2u) << lsb) & ~mask) | (ins & rmask); // LDR #0x8
|
||||
(*outpp)[1] = 0x14000003u; // B #0xc
|
||||
memcpy(*outpp + 2, &absolute_addr, sizeof(absolute_addr)); // potential overflow?
|
||||
*outpp += 4; |
||||
} //if
|
||||
} |
||||
break; |
||||
default: |
||||
return false; |
||||
} |
||||
|
||||
ctxp->process_fix_map(current_idx); |
||||
++(*inpp); |
||||
return true; |
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static void __fix_instructions(uint32_t *__restrict inp, int32_t count, uint32_t *__restrict outp) |
||||
{ |
||||
context ctx; |
||||
ctx.basep = reinterpret_cast<int64_t>(inp); |
||||
ctx.endp = reinterpret_cast<int64_t>(inp + count); |
||||
memset(ctx.dat, 0, sizeof(ctx.dat)); |
||||
static_assert(sizeof(ctx.dat) / sizeof(ctx.dat[0]) == A64_MAX_INSTRUCTIONS, |
||||
"please use A64_MAX_INSTRUCTIONS!"); |
||||
|
||||
uint32_t *const outp_base = outp; |
||||
|
||||
while (--count >= 0) { |
||||
if (__fix_branch_imm(&inp, &outp, &ctx)) continue; |
||||
if (__fix_cond_comp_test_branch(&inp, &outp, &ctx)) continue; |
||||
if (__fix_loadlit(&inp, &outp, &ctx)) continue; |
||||
if (__fix_pcreladdr(&inp, &outp, &ctx)) continue; |
||||
|
||||
// without PC-relative offset
|
||||
ctx.process_fix_map(ctx.get_and_set_current_index(inp, outp)); |
||||
*(outp++) = *(inp++); |
||||
} |
||||
|
||||
static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111
|
||||
auto callback = reinterpret_cast<int64_t>(inp); |
||||
auto pc_offset = static_cast<int64_t>(callback - reinterpret_cast<int64_t>(outp)) >> 2; |
||||
if (llabs(pc_offset) >= (mask >> 1)) { |
||||
if ((reinterpret_cast<uint64_t>(outp + 2) & 7u) != 0u) { |
||||
outp[0] = A64_NOP; |
||||
++outp; |
||||
} //if
|
||||
outp[0] = 0x58000051u; // LDR X17, #0x8
|
||||
outp[1] = 0xd61f0220u; // BR X17
|
||||
*reinterpret_cast<int64_t *>(outp + 2) = callback; |
||||
outp += 4; |
||||
} else { |
||||
outp[0] = 0x14000000u | (pc_offset & mask); // "B" ADDR_PCREL26
|
||||
++outp; |
||||
} //if
|
||||
|
||||
const uintptr_t total = (outp - outp_base) * sizeof(uint32_t); |
||||
__flush_cache(outp_base, total); // necessary
|
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
extern "C" { |
||||
#define __attribute __attribute__ |
||||
#define aligned(x) __aligned__(x) |
||||
#define __intval(p) reinterpret_cast<intptr_t>(p) |
||||
#define __uintval(p) reinterpret_cast<uintptr_t>(p) |
||||
#define __ptr(p) reinterpret_cast<void *>(p) |
||||
#define __page_size 4096 |
||||
#define __page_align(n) __align_up(static_cast<uintptr_t>(n), __page_size) |
||||
#define __ptr_align(x) __ptr(__align_down(reinterpret_cast<uintptr_t>(x), __page_size)) |
||||
#define __align_up(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) |
||||
#define __align_down(x, n) ((x) & -(n)) |
||||
#define __countof(x) static_cast<intptr_t>(sizeof(x) / sizeof((x)[0])) // must be signed
|
||||
#define __atomic_increase(p) __sync_add_and_fetch(p, 1) |
||||
#define __sync_cmpswap(p, v, n) __sync_bool_compare_and_swap(p, v, n) |
||||
#define __predict_true(exp) __builtin_expect((exp) != 0, 1) |
||||
#define __make_rwx(p, n) ::mprotect(__ptr_align(p), \ |
||||
__page_align(__uintval(p) + n) != __page_align(__uintval(p)) ? __page_align(n) + __page_size : __page_align(n), \
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC) |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static __attribute((aligned(__page_size))) uint32_t __insns_pool[A64_MAX_BACKUPS][A64_MAX_INSTRUCTIONS * 10]; |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class A64HookInit |
||||
{ |
||||
public: |
||||
A64HookInit() |
||||
{ |
||||
__make_rwx(__insns_pool, sizeof(__insns_pool)); |
||||
} |
||||
}; |
||||
static A64HookInit __init; |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static uint32_t *FastAllocateTrampoline() |
||||
{ |
||||
static_assert((A64_MAX_INSTRUCTIONS * 10 * sizeof(uint32_t)) % 8 == 0, "8-byte align"); |
||||
static volatile int32_t __index = -1; |
||||
|
||||
int32_t i = __atomic_increase(&__index); |
||||
if (__predict_true(i >= 0 && i < __countof(__insns_pool))) { |
||||
return __insns_pool[i]; |
||||
} //if
|
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
A64_JNIEXPORT void *A64HookFunctionV(void *const symbol, void *const replace, |
||||
void *const rwx, const uintptr_t rwx_size) |
||||
{ |
||||
static constexpr uint_fast64_t mask = 0x03ffffffu; // 0b00000011111111111111111111111111
|
||||
|
||||
uint32_t *trampoline = static_cast<uint32_t *>(rwx), *original = static_cast<uint32_t *>(symbol); |
||||
|
||||
static_assert(A64_MAX_INSTRUCTIONS >= 5, "please fix A64_MAX_INSTRUCTIONS!"); |
||||
auto pc_offset = static_cast<int64_t>(__intval(replace) - __intval(symbol)) >> 2; |
||||
if (llabs(pc_offset) >= (mask >>1)) { |
||||
int32_t count = (reinterpret_cast<uint64_t>(original + 2) & 7u) != 0u ? 5 : 4; |
||||
if (trampoline) { |
||||
if (rwx_size < count * 10u) { |
||||
return NULL; |
||||
} //if
|
||||
__fix_instructions(original, count, trampoline); |
||||
} //if
|
||||
|
||||
if (__make_rwx(original, 5 * sizeof(uint32_t)) == 0) { |
||||
if (count == 5) { |
||||
original[0] = A64_NOP; |
||||
++original; |
||||
} //if
|
||||
original[0] = 0x58000051u; // LDR X17, #0x8
|
||||
original[1] = 0xd61f0220u; // BR X17
|
||||
*reinterpret_cast<int64_t *>(original + 2) = __intval(replace); |
||||
__flush_cache(symbol, 5 * sizeof(uint32_t)); |
||||
|
||||
} else { |
||||
trampoline = NULL; |
||||
} //if
|
||||
} else { |
||||
if (trampoline) { |
||||
if (rwx_size < 1u * 10u) { |
||||
return NULL; |
||||
} //if
|
||||
__fix_instructions(original, 1, trampoline); |
||||
} //if
|
||||
|
||||
if (__make_rwx(original, 1 * sizeof(uint32_t)) == 0) { |
||||
__sync_cmpswap(original, *original, 0x14000000u | (pc_offset & mask)); // "B" ADDR_PCREL26
|
||||
__flush_cache(symbol, 1 * sizeof(uint32_t)); |
||||
|
||||
} else { |
||||
trampoline = NULL; |
||||
} //if
|
||||
} //if
|
||||
|
||||
return trampoline; |
||||
} |
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
A64_JNIEXPORT void A64HookFunction(void *const symbol, void *const replace, void **result) |
||||
{ |
||||
void *trampoline = NULL; |
||||
if (result != NULL) { |
||||
trampoline = FastAllocateTrampoline(); |
||||
*result = trampoline; |
||||
if (trampoline == NULL) return; |
||||
} //if
|
||||
assert(__make_rwx(symbol, 4096) == 0); |
||||
trampoline = A64HookFunctionV(symbol, replace, trampoline, A64_MAX_INSTRUCTIONS * 10u); |
||||
if (trampoline == NULL && result != NULL) { |
||||
*result = NULL; |
||||
} //if
|
||||
} |
||||
} |
||||
|
||||
#endif // defined(__aarch64__)
|
@ -1,45 +0,0 @@ |
||||
/*
|
||||
* @date : 2018/04/18 |
||||
* @author : Rprop (r_prop@outlook.com) |
||||
* https://github.com/Rprop/And64InlineHook
|
||||
*/ |
||||
/*
|
||||
MIT License |
||||
|
||||
Copyright (c) 2018 Rprop (r_prop@outlook.com) |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
||||
*/ |
||||
#pragma once |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#define A64_MAX_BACKUPS 256 |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
void A64HookFunction(void *const symbol, void *const replace, void **result); |
||||
void *A64HookFunctionV(void *const symbol, void *const replace, |
||||
void *const rwx, const uintptr_t rwx_size); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
@ -1,38 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#ifndef SUBSTRATE_BUFFER_HPP |
||||
#define SUBSTRATE_BUFFER_HPP |
||||
|
||||
#include <string.h> |
||||
|
||||
template <typename Type_> |
||||
_disused static _finline void MSWrite(uint8_t *&buffer, Type_ value) { |
||||
*reinterpret_cast<Type_ *>(buffer) = value; |
||||
buffer += sizeof(Type_); |
||||
} |
||||
|
||||
_disused static _finline void MSWrite(uint8_t *&buffer, uint8_t *data, size_t size) { |
||||
memcpy(buffer, data, size); |
||||
buffer += size; |
||||
} |
||||
|
||||
#endif//SUBSTRATE_BUFFER_HPP
|
@ -1,152 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#ifndef SUBSTRATE_H_ |
||||
#define SUBSTRATE_H_ |
||||
|
||||
#ifdef __APPLE__ |
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
#include <mach-o/nlist.h> |
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#include <objc/runtime.h> |
||||
#include <objc/message.h> |
||||
#endif |
||||
|
||||
#include <dlfcn.h> |
||||
#include <stdlib.h> |
||||
|
||||
#define _finline \ |
||||
inline __attribute__((__always_inline__)) |
||||
#define _disused \ |
||||
__attribute__((__unused__)) |
||||
|
||||
#define _extern \ |
||||
extern "C" __attribute__((__visibility__("default"))) |
||||
|
||||
#ifdef __cplusplus |
||||
#define _default(value) = value |
||||
#else |
||||
#define _default(value) |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
bool MSHookProcess(pid_t pid, const char *library); |
||||
|
||||
typedef const void *MSImageRef; |
||||
|
||||
MSImageRef MSGetImageByName(const char *file); |
||||
void *MSFindSymbol(MSImageRef image, const char *name); |
||||
|
||||
void MSHookFunction(void *symbol, void *replace, void **result); |
||||
|
||||
#ifdef __APPLE__ |
||||
#ifdef __arm__ |
||||
__attribute__((__deprecated__)) |
||||
IMP MSHookMessage(Class _class, SEL sel, IMP imp, const char *prefix _default(NULL)); |
||||
#endif |
||||
void MSHookMessageEx(Class _class, SEL sel, IMP imp, IMP *result); |
||||
#endif |
||||
|
||||
#ifdef SubstrateInternal |
||||
typedef void *SubstrateAllocatorRef; |
||||
typedef struct __SubstrateProcess *SubstrateProcessRef; |
||||
typedef struct __SubstrateMemory *SubstrateMemoryRef; |
||||
|
||||
SubstrateProcessRef SubstrateProcessCreate(SubstrateAllocatorRef allocator, pid_t pid); |
||||
void SubstrateProcessRelease(SubstrateProcessRef process); |
||||
|
||||
SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size); |
||||
void SubstrateMemoryRelease(SubstrateMemoryRef memory); |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#ifdef __cplusplus |
||||
|
||||
#ifdef SubstrateInternal |
||||
struct SubstrateHookMemory { |
||||
SubstrateMemoryRef handle_; |
||||
|
||||
SubstrateHookMemory(SubstrateProcessRef process, void *data, size_t size) : |
||||
handle_(SubstrateMemoryCreate(NULL, NULL, data, size)) |
||||
{ |
||||
} |
||||
|
||||
~SubstrateHookMemory() { |
||||
if (handle_ != NULL) |
||||
SubstrateMemoryRelease(handle_); |
||||
} |
||||
}; |
||||
#endif |
||||
|
||||
|
||||
template<typename Type_> |
||||
static inline void MSHookFunction(Type_ *symbol, Type_ *replace, Type_ **result) { |
||||
MSHookFunction( |
||||
reinterpret_cast<void *>(symbol), |
||||
reinterpret_cast<void *>(replace), |
||||
reinterpret_cast<void **>(result) |
||||
); |
||||
} |
||||
|
||||
template<typename Type_> |
||||
static inline void MSHookFunction(Type_ *symbol, Type_ *replace) { |
||||
return MSHookFunction(symbol, replace, reinterpret_cast<Type_ **>(NULL)); |
||||
} |
||||
|
||||
template<typename Type_> |
||||
static inline void MSHookSymbol(Type_ *&value, const char *name, MSImageRef image = NULL) { |
||||
value = reinterpret_cast<Type_ *>(MSFindSymbol(image, name)); |
||||
} |
||||
|
||||
template<typename Type_> |
||||
static inline void MSHookFunction(const char *name, Type_ *replace, Type_ **result = NULL) { |
||||
Type_ *symbol; |
||||
MSHookSymbol(symbol, name); |
||||
return MSHookFunction(symbol, replace, result); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
#define MSHook(type, name, args...) \ |
||||
_disused static type (*_ ## name)(args); \
|
||||
static type $ ## name(args) |
||||
|
||||
#ifdef __cplusplus |
||||
#define MSHake(name) \ |
||||
&$ ## name, &_ ## name |
||||
#else |
||||
#define MSHake(name) \ |
||||
&$ ## name, (void **) &_ ## name |
||||
#endif |
||||
|
||||
|
||||
#endif//SUBSTRATE_H_
|
@ -1,67 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#ifndef SUBSTRATE_ARM_HPP |
||||
#define SUBSTRATE_ARM_HPP |
||||
|
||||
enum A$r { |
||||
A$r0, A$r1, A$r2, A$r3, |
||||
A$r4, A$r5, A$r6, A$r7, |
||||
A$r8, A$r9, A$r10, A$r11, |
||||
A$r12, A$r13, A$r14, A$r15, |
||||
A$sp = A$r13, |
||||
A$lr = A$r14, |
||||
A$pc = A$r15 |
||||
}; |
||||
|
||||
enum A$c { |
||||
A$eq, A$ne, A$cs, A$cc, |
||||
A$mi, A$pl, A$vs, A$vc, |
||||
A$hi, A$ls, A$ge, A$lt, |
||||
A$gt, A$le, A$al, |
||||
A$hs = A$cs, |
||||
A$lo = A$cc |
||||
}; |
||||
|
||||
#define _abs(im) abs((int)im) |
||||
|
||||
#define A$mrs_rm_cpsr(rd) /* mrs rd, cpsr */ \ |
||||
(0xe10f0000 | ((rd) << 12)) |
||||
#define A$msr_cpsr_f_rm(rm) /* msr cpsr_f, rm */ \ |
||||
(0xe128f000 | (rm)) |
||||
#define A$ldr_rd_$rn_im$(rd, rn, im) /* ldr rd, [rn, #im] */ \ |
||||
(0xe5100000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | _abs(im)) |
||||
#define A$str_rd_$rn_im$(rd, rn, im) /* sr rd, [rn, #im] */ \ |
||||
(0xe5000000 | ((im) < 0 ? 0 : 1 << 23) | ((rn) << 16) | ((rd) << 12) | _abs(im)) |
||||
#define A$sub_rd_rn_$im(rd, rn, im) /* sub, rd, rn, #im */ \ |
||||
(0xe2400000 | ((rn) << 16) | ((rd) << 12) | (im & 0xff)) |
||||
#define A$blx_rm(rm) /* blx rm */ \ |
||||
(0xe12fff30 | (rm)) |
||||
#define A$mov_rd_rm(rd, rm) /* mov rd, rm */ \ |
||||
(0xe1a00000 | ((rd) << 12) | (rm)) |
||||
#define A$ldmia_sp$_$rs$(rs) /* ldmia sp!, {rs} */ \ |
||||
(0xe8b00000 | (A$sp << 16) | (rs)) |
||||
#define A$stmdb_sp$_$rs$(rs) /* stmdb sp!, {rs} */ \ |
||||
(0xe9200000 | (A$sp << 16) | (rs)) |
||||
#define A$stmia_sp$_$r0$ 0xe8ad0001 /* stmia sp!, {r0} */ |
||||
#define A$bx_r0 0xe12fff10 /* bx r0 */ |
||||
|
||||
#endif//SUBSTRATE_ARM_HPP
|
@ -1,96 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#include "SubstrateHook.h" |
||||
#include "SubstrateDebug.hpp" |
||||
|
||||
#include <stdint.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
|
||||
_extern bool MSDebug; |
||||
bool MSDebug = false; |
||||
|
||||
static char _MSHexChar(uint8_t value) { |
||||
return value < 0x20 || value >= 0x80 ? '.' : value; |
||||
} |
||||
|
||||
#define HexWidth_ 16 |
||||
#define HexDepth_ 4 |
||||
|
||||
void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark) { |
||||
const uint8_t *data((const uint8_t *) vdata); |
||||
|
||||
size_t i(0), j; |
||||
|
||||
char d[256]; |
||||
size_t b(0); |
||||
d[0] = '\0'; |
||||
|
||||
while (i != size) { |
||||
if (i % HexWidth_ == 0) { |
||||
if (mark != NULL) |
||||
b += sprintf(d + b, "\n[%s] ", mark); |
||||
b += sprintf(d + b, "0x%.3zx:", i); |
||||
} |
||||
|
||||
b += sprintf(d + b, " "); |
||||
|
||||
for (size_t q(0); q != stride; ++q) |
||||
b += sprintf(d + b, "%.2x", data[i + stride - q - 1]); |
||||
|
||||
i += stride; |
||||
|
||||
for (size_t q(1); q != stride; ++q) |
||||
b += sprintf(d + b, " "); |
||||
|
||||
if (i % HexDepth_ == 0) |
||||
b += sprintf(d + b, " "); |
||||
|
||||
if (i % HexWidth_ == 0) { |
||||
b += sprintf(d + b, " "); |
||||
for (j = i - HexWidth_; j != i; ++j) |
||||
b += sprintf(d + b, "%c", _MSHexChar(data[j])); |
||||
|
||||
lprintf("%s", d); |
||||
b = 0; |
||||
d[0] = '\0'; |
||||
} |
||||
} |
||||
|
||||
if (i % HexWidth_ != 0) { |
||||
for (j = i % HexWidth_; j != HexWidth_; ++j) |
||||
b += sprintf(d + b, " "); |
||||
for (j = 0; j != (HexWidth_ - i % HexWidth_ + HexDepth_ - 1) / HexDepth_; ++j) |
||||
b += sprintf(d + b, " "); |
||||
b += sprintf(d + b, " "); |
||||
for (j = i / HexWidth_ * HexWidth_; j != i; ++j) |
||||
b += sprintf(d + b, "%c", _MSHexChar(data[j])); |
||||
|
||||
lprintf("%s", d); |
||||
b = 0; |
||||
d[0] = '\0'; |
||||
} |
||||
} |
||||
|
||||
void MSLogHex(const void *vdata, size_t size, const char *mark) { |
||||
return MSLogHexEx(vdata, size, 1, mark); |
||||
} |
@ -1,33 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#ifndef SUBSTRATE_DEBUG_HPP |
||||
#define SUBSTRATE_DEBUG_HPP |
||||
|
||||
#include "SubstrateLog.hpp" |
||||
#define lprintf(format, ...) \ |
||||
MSLog(MSLogLevelNotice, format, ## __VA_ARGS__) |
||||
|
||||
extern "C" bool MSDebug; |
||||
void MSLogHexEx(const void *vdata, size_t size, size_t stride, const char *mark = 0); |
||||
void MSLogHex(const void *vdata, size_t size, const char *mark = 0); |
||||
|
||||
#endif//SUBSTRATE_DEBUG_HPP
|
@ -1,962 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#define SubstrateInternal |
||||
|
||||
#include "And64InlineHook.hpp" |
||||
|
||||
#include <sys/mman.h> |
||||
|
||||
#define _trace() do { \ |
||||
MSLog(MSLogLevelNotice, "_trace(%u)", __LINE__); \
|
||||
} while (false) |
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) |
||||
#include "hde64.h" |
||||
#endif |
||||
|
||||
#include "SubstrateDebug.hpp" |
||||
#include "And64InlineHook.hpp" |
||||
#include "CydiaSubstrate.h" |
||||
|
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#ifdef __arm__ |
||||
/* WebCore (ARM) PC-Relative:
|
||||
X 1 ldr r*,[pc,r*] != |
||||
2 fldd d*,[pc,#*] |
||||
X 5 str r*,[pc,r*] != |
||||
8 flds s*,[pc,#*] |
||||
400 ldr r*,[pc,r*] == |
||||
515 add r*, pc,r* == |
||||
X 4790 ldr r*,[pc,#*] */ |
||||
|
||||
// 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.asm >WebCore.pc
|
||||
// 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
|
||||
|
||||
#include "SubstrateARM.hpp" |
||||
#include "And64InlineHook.hpp" |
||||
|
||||
#define T$Label(l, r) \ |
||||
(((r) - (l)) * 2 - 4 + ((l) % 2 == 0 ? 0 : 2)) |
||||
|
||||
#define T$pop_$r0$ 0xbc01 // pop {r0}
|
||||
#define T$b(im) /* b im */ \ |
||||
(0xde00 | (im & 0xff)) |
||||
#define T$blx(rm) /* blx rm */ \ |
||||
(0x4780 | (rm << 3)) |
||||
#define T$bx(rm) /* bx rm */ \ |
||||
(0x4700 | (rm << 3)) |
||||
#define T$nop /* nop */ \ |
||||
(0x46c0) |
||||
|
||||
#define T$add_rd_rm(rd, rm) /* add rd, rm */ \ |
||||
(0x4400 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) |
||||
#define T$push_r(r) /* push r... */ \ |
||||
(0xb400 | (((r) & (1 << A$lr)) >> A$lr << 8) | ((r) & 0xff)) |
||||
#define T$pop_r(r) /* pop r... */ \ |
||||
(0xbc00 | (((r) & (1 << A$pc)) >> A$pc << 8) | ((r) & 0xff)) |
||||
#define T$mov_rd_rm(rd, rm) /* mov rd, rm */ \ |
||||
(0x4600 | (((rd) & 0x8) >> 3 << 7) | (((rm) & 0x8) >> 3 << 6) | (((rm) & 0x7) << 3) | ((rd) & 0x7)) |
||||
#define T$ldr_rd_$rn_im_4$(rd, rn, im) /* ldr rd, [rn, #im * 4] */ \ |
||||
(0x6800 | (((im) & 0x1f) << 6) | ((rn) << 3) | (rd)) |
||||
#define T$ldr_rd_$pc_im_4$(rd, im) /* ldr rd, [PC, #im * 4] */ \ |
||||
(0x4800 | ((rd) << 8) | ((im) & 0xff)) |
||||
#define T$cmp_rn_$im(rn, im) /* cmp rn, #im */ \ |
||||
(0x2000 | ((rn) << 8) | ((im) & 0xff)) |
||||
#define T$it$_cd(cd, ms) /* it<ms>, cd */ \ |
||||
(0xbf00 | ((cd) << 4) | (ms)) |
||||
#define T$cbz$_rn_$im(op, rn, im) /* cb<op>z rn, #im */ \ |
||||
(0xb100 | ((op) << 11) | (((im) & 0x40) >> 6 << 9) | (((im) & 0x3e) >> 1 << 3) | (rn)) |
||||
#define T$b$_$im(cond, im) /* b<cond> #im */ \ |
||||
(cond == A$al ? 0xe000 | (((im) >> 1) & 0x7ff) : 0xd000 | ((cond) << 8) | (((im) >> 1) & 0xff)) |
||||
|
||||
#define T1$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ |
||||
(0xf850 | ((im < 0 ? 0 : 1) << 7) | (rn)) |
||||
#define T2$ldr_rt_$rn_im$(rt, rn, im) /* ldr rt, [rn, #im] */ \ |
||||
(((rt) << 12) | _abs(im)) |
||||
|
||||
#define T1$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ |
||||
(0xf3ef) |
||||
#define T2$mrs_rd_apsr(rd) /* mrs rd, apsr */ \ |
||||
(0x8000 | ((rd) << 8)) |
||||
|
||||
#define T1$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ |
||||
(0xf380 | (rn)) |
||||
#define T2$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ |
||||
(0x8c00) |
||||
#define T$msr_apsr_nzcvqg_rn(rn) /* msr apsr, rn */ \ |
||||
(T2$msr_apsr_nzcvqg_rn(rn) << 16 | T1$msr_apsr_nzcvqg_rn(rn)) |
||||
|
||||
static inline bool A$pcrel$r(uint32_t ic) { |
||||
return (ic & 0x0c000000) == 0x04000000 && (ic & 0xf0000000) != 0xf0000000 && |
||||
(ic & 0x000f0000) == 0x000f0000; |
||||
} |
||||
|
||||
static inline bool T$32bit$i(uint16_t ic) { |
||||
return ((ic & 0xe000) == 0xe000 && (ic & 0x1800) != 0x0000); |
||||
} |
||||
|
||||
static inline bool T$pcrel$cbz(uint16_t ic) { |
||||
return (ic & 0xf500) == 0xb100; |
||||
} |
||||
|
||||
static inline bool T$pcrel$b(uint16_t ic) { |
||||
return (ic & 0xf000) == 0xd000 && (ic & 0x0e00) != 0x0e00; |
||||
} |
||||
|
||||
static inline bool T2$pcrel$b(uint16_t *ic) { |
||||
return (ic[0] & 0xf800) == 0xf000 && |
||||
((ic[1] & 0xd000) == 0x9000 || ((ic[1] & 0xd000) == 0x8000 && (ic[0] & 0x0380) != 0x0380)); |
||||
} |
||||
|
||||
static inline bool T$pcrel$bl(uint16_t *ic) { |
||||
return (ic[0] & 0xf800) == 0xf000 && ((ic[1] & 0xd000) == 0xd000 || (ic[1] & 0xd001) == 0xc000); |
||||
} |
||||
|
||||
static inline bool T$pcrel$ldr(uint16_t ic) { |
||||
return (ic & 0xf800) == 0x4800; |
||||
} |
||||
|
||||
static inline bool T$pcrel$add(uint16_t ic) { |
||||
return (ic & 0xff78) == 0x4478; |
||||
} |
||||
|
||||
static inline bool T$pcrel$ldrw(uint16_t ic) { |
||||
return (ic & 0xff7f) == 0xf85f; |
||||
} |
||||
|
||||
static size_t MSGetInstructionWidthThumb(void *start) { |
||||
uint16_t *thumb(reinterpret_cast<uint16_t *>(start)); |
||||
return T$32bit$i(thumb[0]) ? 4 : 2; |
||||
} |
||||
|
||||
static size_t MSGetInstructionWidthARM(void *start) { |
||||
return 4; |
||||
} |
||||
|
||||
extern "C" size_t MSGetInstructionWidth(void *start) { |
||||
if ((reinterpret_cast<uintptr_t>(start) & 0x1) == 0) |
||||
return MSGetInstructionWidthARM(start); |
||||
else |
||||
return MSGetInstructionWidthThumb( |
||||
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(start) & ~0x1)); |
||||
} |
||||
|
||||
static size_t SubstrateHookFunctionThumb(SubstrateProcessRef process, void *symbol, void *replace, |
||||
void **result) { |
||||
if (symbol == NULL) |
||||
return 0; |
||||
printf("SubstrateHookFunctionThumb\n"); |
||||
uint16_t *area(reinterpret_cast<uint16_t *>(symbol)); |
||||
|
||||
unsigned align((reinterpret_cast<uintptr_t>(area) & 0x2) == 0 ? 0 : 1); |
||||
uint16_t *thumb(area + align); |
||||
|
||||
uint32_t *arm(reinterpret_cast<uint32_t *>(thumb + 2)); |
||||
uint16_t *trail(reinterpret_cast<uint16_t *>(arm + 2)); |
||||
|
||||
if ( |
||||
(align == 0 || area[0] == T$nop) && |
||||
thumb[0] == T$bx(A$pc) && |
||||
thumb[1] == T$nop && |
||||
arm[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8) |
||||
) { |
||||
if (result != NULL) |
||||
*result = reinterpret_cast<void *>(arm[1]); |
||||
|
||||
SubstrateHookMemory code(process, arm + 1, sizeof(uint32_t) * 1); |
||||
|
||||
arm[1] = reinterpret_cast<uint32_t>(replace); |
||||
|
||||
return sizeof(arm[0]); |
||||
} |
||||
|
||||
size_t required((trail - area) * sizeof(uint16_t)); |
||||
|
||||
size_t used(0); |
||||
while (used < required) |
||||
used += MSGetInstructionWidthThumb(reinterpret_cast<uint8_t *>(area) + used); |
||||
used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t); |
||||
|
||||
size_t blank((used - required) / sizeof(uint16_t)); |
||||
|
||||
uint16_t backup[used / sizeof(uint16_t)]; |
||||
memcpy(backup, area, used); |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHexEx(area, used + sizeof(uint16_t), 2, name); |
||||
} |
||||
|
||||
if (result != NULL) { |
||||
|
||||
size_t length(used); |
||||
for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) |
||||
if (T$pcrel$ldr(backup[offset])) |
||||
length += 3 * sizeof(uint16_t); |
||||
else if (T$pcrel$b(backup[offset])) |
||||
length += 6 * sizeof(uint16_t); |
||||
else if (T2$pcrel$b(backup + offset)) { |
||||
length += 5 * sizeof(uint16_t); |
||||
++offset; |
||||
} else if (T$pcrel$bl(backup + offset)) { |
||||
length += 5 * sizeof(uint16_t); |
||||
++offset; |
||||
} else if (T$pcrel$cbz(backup[offset])) { |
||||
length += 16 * sizeof(uint16_t); |
||||
} else if (T$pcrel$ldrw(backup[offset])) { |
||||
length += 4 * sizeof(uint16_t); |
||||
++offset; |
||||
} else if (T$pcrel$add(backup[offset])) |
||||
length += 6 * sizeof(uint16_t); |
||||
else if (T$32bit$i(backup[offset])) |
||||
++offset; |
||||
|
||||
unsigned pad((length & 0x2) == 0 ? 0 : 1); |
||||
length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t); |
||||
|
||||
uint16_t *buffer(reinterpret_cast<uint16_t *>(mmap( |
||||
NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 |
||||
))); |
||||
|
||||
if (buffer == MAP_FAILED) { |
||||
MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); |
||||
*result = NULL; |
||||
return 0; |
||||
} |
||||
|
||||
if (false) |
||||
fail: |
||||
{ |
||||
munmap(buffer, length); |
||||
*result = NULL; |
||||
return 0; |
||||
} |
||||
|
||||
size_t start(pad), end(length / sizeof(uint16_t)); |
||||
uint32_t *trailer(reinterpret_cast<uint32_t *>(buffer + end)); |
||||
for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) { |
||||
if (T$pcrel$ldr(backup[offset])) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t immediate : 8; |
||||
uint16_t rd : 3; |
||||
uint16_t : 5; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
buffer[start + 0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start + 0, end - 2) / 4); |
||||
buffer[start + 1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0); |
||||
|
||||
// XXX: this code "works", but is "wrong": the mechanism is more complex than this
|
||||
*--trailer = ((reinterpret_cast<uint32_t>(area + offset) + 4) & ~0x2) + |
||||
bits.immediate * 4; |
||||
|
||||
start += 2; |
||||
end -= 2; |
||||
} else if (T$pcrel$b(backup[offset])) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t imm8 : 8; |
||||
uint16_t cond : 4; |
||||
uint16_t /*1101*/ : 4; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
intptr_t jump(bits.imm8 << 1); |
||||
jump |= 1; |
||||
jump <<= 23; |
||||
jump >>= 23; |
||||
|
||||
buffer[start + 0] = T$b$_$im(bits.cond, (end - 6 - (start + 0)) * 2 - 4); |
||||
|
||||
*--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump; |
||||
*--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
*--trailer = T$nop << 16 | T$bx(A$pc); |
||||
|
||||
start += 1; |
||||
end -= 6; |
||||
} else if (T2$pcrel$b(backup + offset)) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t imm6 : 6; |
||||
uint16_t cond : 4; |
||||
uint16_t s : 1; |
||||
uint16_t : 5; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t imm11 : 11; |
||||
uint16_t j2 : 1; |
||||
uint16_t a : 1; |
||||
uint16_t j1 : 1; |
||||
uint16_t : 2; |
||||
}; |
||||
} exts = {backup[offset + 1]}; |
||||
|
||||
intptr_t jump(1); |
||||
jump |= exts.imm11 << 1; |
||||
jump |= bits.imm6 << 12; |
||||
|
||||
if (exts.a) { |
||||
jump |= bits.s << 24; |
||||
jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; |
||||
jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; |
||||
jump |= bits.cond << 18; |
||||
jump <<= 7; |
||||
jump >>= 7; |
||||
} else { |
||||
jump |= bits.s << 20; |
||||
jump |= exts.j2 << 19; |
||||
jump |= exts.j1 << 18; |
||||
jump <<= 11; |
||||
jump >>= 11; |
||||
} |
||||
|
||||
buffer[start + 0] = T$b$_$im(exts.a ? A$al : bits.cond, |
||||
(end - 6 - (start + 0)) * 2 - 4); |
||||
|
||||
*--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump; |
||||
*--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
*--trailer = T$nop << 16 | T$bx(A$pc); |
||||
|
||||
++offset; |
||||
start += 1; |
||||
end -= 6; |
||||
} else if (T$pcrel$bl(backup + offset)) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t immediate : 10; |
||||
uint16_t s : 1; |
||||
uint16_t : 5; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t immediate : 11; |
||||
uint16_t j2 : 1; |
||||
uint16_t x : 1; |
||||
uint16_t j1 : 1; |
||||
uint16_t : 2; |
||||
}; |
||||
} exts = {backup[offset + 1]}; |
||||
|
||||
int32_t jump(0); |
||||
jump |= bits.s << 24; |
||||
jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; |
||||
jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; |
||||
jump |= bits.immediate << 12; |
||||
jump |= exts.immediate << 1; |
||||
jump |= exts.x; |
||||
jump <<= 7; |
||||
jump >>= 7; |
||||
|
||||
buffer[start + 0] = T$push_r(1 << A$r7); |
||||
buffer[start + 1] = T$ldr_rd_$pc_im_4$(A$r7, |
||||
((end - 2 - (start + 1)) * 2 - 4 + 2) / 4); |
||||
buffer[start + 2] = T$mov_rd_rm(A$lr, A$r7); |
||||
buffer[start + 3] = T$pop_r(1 << A$r7); |
||||
buffer[start + 4] = T$blx(A$lr); |
||||
|
||||
*--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump; |
||||
|
||||
++offset; |
||||
start += 5; |
||||
end -= 2; |
||||
} else if (T$pcrel$cbz(backup[offset])) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t rn : 3; |
||||
uint16_t immediate : 5; |
||||
uint16_t : 1; |
||||
uint16_t i : 1; |
||||
uint16_t : 1; |
||||
uint16_t op : 1; |
||||
uint16_t : 4; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
intptr_t jump(1); |
||||
jump |= bits.i << 6; |
||||
jump |= bits.immediate << 1; |
||||
|
||||
//jump <<= 24;
|
||||
//jump >>= 24;
|
||||
|
||||
unsigned rn(bits.rn); |
||||
unsigned rt(rn == A$r7 ? A$r6 : A$r7); |
||||
|
||||
buffer[start + 0] = T$push_r(1 << rt); |
||||
buffer[start + 1] = T1$mrs_rd_apsr(rt); |
||||
buffer[start + 2] = T2$mrs_rd_apsr(rt); |
||||
buffer[start + 3] = T$cbz$_rn_$im(bits.op, rn, (end - 10 - (start + 3)) * 2 - 4); |
||||
buffer[start + 4] = T1$msr_apsr_nzcvqg_rn(rt); |
||||
buffer[start + 5] = T2$msr_apsr_nzcvqg_rn(rt); |
||||
buffer[start + 6] = T$pop_r(1 << rt); |
||||
|
||||
*--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump; |
||||
*--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
*--trailer = T$nop << 16 | T$bx(A$pc); |
||||
*--trailer = T$nop << 16 | T$pop_r(1 << rt); |
||||
*--trailer = T$msr_apsr_nzcvqg_rn(rt); |
||||
|
||||
#if 0 |
||||
if ((start & 0x1) == 0) |
||||
buffer[start++] = T$nop; |
||||
buffer[start++] = T$bx(A$pc); |
||||
buffer[start++] = T$nop; |
||||
|
||||
uint32_t *arm(reinterpret_cast<uint32_t *>(buffer + start)); |
||||
arm[0] = A$add(A$lr, A$pc, 1); |
||||
arm[1] = A$ldr_rd_$rn_im$(A$pc, A$pc, (trailer - arm) * sizeof(uint32_t) - 8); |
||||
#endif |
||||
|
||||
start += 7; |
||||
end -= 10; |
||||
} else if (T$pcrel$ldrw(backup[offset])) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t : 7; |
||||
uint16_t u : 1; |
||||
uint16_t : 8; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t immediate : 12; |
||||
uint16_t rt : 4; |
||||
}; |
||||
} exts = {backup[offset + 1]}; |
||||
|
||||
buffer[start + 0] = T1$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start + 0, end - 2)); |
||||
buffer[start + 1] = T2$ldr_rt_$rn_im$(exts.rt, A$pc, T$Label(start + 0, end - 2)); |
||||
|
||||
buffer[start + 2] = T1$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); |
||||
buffer[start + 3] = T2$ldr_rt_$rn_im$(exts.rt, exts.rt, 0); |
||||
|
||||
// XXX: this code "works", but is "wrong": the mechanism is more complex than this
|
||||
*--trailer = ((reinterpret_cast<uint32_t>(area + offset) + 4) & ~0x2) + |
||||
(bits.u == 0 ? -exts.immediate : exts.immediate); |
||||
|
||||
++offset; |
||||
start += 4; |
||||
end -= 2; |
||||
} else if (T$pcrel$add(backup[offset])) { |
||||
union { |
||||
uint16_t value; |
||||
|
||||
struct { |
||||
uint16_t rd : 3; |
||||
uint16_t rm : 3; |
||||
uint16_t h2 : 1; |
||||
uint16_t h1 : 1; |
||||
uint16_t : 8; |
||||
}; |
||||
} bits = {backup[offset + 0]}; |
||||
|
||||
if (bits.h1) { |
||||
MSLog(MSLogLevelError, "MS:Error:pcrel(%u):add (rd > r7)", offset); |
||||
goto fail; |
||||
} |
||||
|
||||
unsigned rt(bits.rd == A$r7 ? A$r6 : A$r7); |
||||
|
||||
buffer[start + 0] = T$push_r(1 << rt); |
||||
buffer[start + 1] = T$mov_rd_rm(rt, (bits.h1 << 3) | bits.rd); |
||||
buffer[start + 2] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start + 2, end - 2) / 4); |
||||
buffer[start + 3] = T$add_rd_rm((bits.h1 << 3) | bits.rd, rt); |
||||
buffer[start + 4] = T$pop_r(1 << rt); |
||||
*--trailer = reinterpret_cast<uint32_t>(area + offset) + 4; |
||||
|
||||
start += 5; |
||||
end -= 2; |
||||
} else if (T$32bit$i(backup[offset])) { |
||||
buffer[start++] = backup[offset]; |
||||
buffer[start++] = backup[++offset]; |
||||
} else { |
||||
buffer[start++] = backup[offset]; |
||||
} |
||||
} |
||||
|
||||
buffer[start++] = T$bx(A$pc); |
||||
buffer[start++] = T$nop; |
||||
|
||||
uint32_t *transfer = reinterpret_cast<uint32_t *>(buffer + start); |
||||
transfer[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
transfer[1] = reinterpret_cast<uint32_t>(area + used / sizeof(uint16_t)) + 1; |
||||
|
||||
if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { |
||||
MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); |
||||
return 0; |
||||
} |
||||
|
||||
*result = reinterpret_cast<uint8_t *>(buffer + pad) + 1; |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", *result); |
||||
MSLogHexEx(buffer, length, 2, name); |
||||
} |
||||
|
||||
} |
||||
|
||||
{ |
||||
SubstrateHookMemory code(process, area, used); |
||||
|
||||
if (align != 0) |
||||
area[0] = T$nop; |
||||
|
||||
thumb[0] = T$bx(A$pc); |
||||
thumb[1] = T$nop; |
||||
|
||||
arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
arm[1] = reinterpret_cast<uint32_t>(replace); |
||||
|
||||
for (unsigned offset(0); offset != blank; ++offset) |
||||
trail[offset] = T$nop; |
||||
} |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHexEx(area, used + sizeof(uint16_t), 2, name); |
||||
} |
||||
|
||||
return used; |
||||
} |
||||
|
||||
static size_t |
||||
SubstrateHookFunctionARM(SubstrateProcessRef process, void *symbol, void *replace, void **result) { |
||||
if (symbol == NULL) |
||||
return 0; |
||||
printf("SubstrateHookFunctionARM\n"); |
||||
uint32_t *area(reinterpret_cast<uint32_t *>(symbol)); |
||||
uint32_t *arm(area); |
||||
|
||||
const size_t used(8); |
||||
|
||||
uint32_t backup[used / sizeof(uint32_t)] = {arm[0], arm[1]}; |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHexEx(area, used + sizeof(uint32_t), 4, name); |
||||
} |
||||
|
||||
if (result != NULL) { |
||||
|
||||
if (backup[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8)) { |
||||
*result = reinterpret_cast<void *>(backup[1]); |
||||
|
||||
return sizeof(backup[0]); |
||||
} |
||||
|
||||
size_t length(used); |
||||
for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) |
||||
if (A$pcrel$r(backup[offset])) { |
||||
if ((backup[offset] & 0x02000000) == 0 || |
||||
(backup[offset] & 0x0000f000 >> 12) != (backup[offset] & 0x0000000f)) |
||||
length += 2 * sizeof(uint32_t); |
||||
else |
||||
length += 4 * sizeof(uint32_t); |
||||
} |
||||
|
||||
length += 2 * sizeof(uint32_t); |
||||
|
||||
uint32_t *buffer(reinterpret_cast<uint32_t *>(mmap( |
||||
NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 |
||||
))); |
||||
|
||||
if (buffer == MAP_FAILED) { |
||||
MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); |
||||
*result = NULL; |
||||
return 0; |
||||
} |
||||
|
||||
if (false) |
||||
fail: |
||||
{ |
||||
munmap(buffer, length); |
||||
*result = NULL; |
||||
return 0; |
||||
} |
||||
|
||||
size_t start(0), end(length / sizeof(uint32_t)); |
||||
uint32_t *trailer(reinterpret_cast<uint32_t *>(buffer + end)); |
||||
for (unsigned offset(0); offset != used / sizeof(uint32_t); ++offset) |
||||
if (A$pcrel$r(backup[offset])) { |
||||
union { |
||||
uint32_t value; |
||||
|
||||
struct { |
||||
uint32_t rm : 4; |
||||
uint32_t : 1; |
||||
uint32_t shift : 2; |
||||
uint32_t shiftamount : 5; |
||||
uint32_t rd : 4; |
||||
uint32_t rn : 4; |
||||
uint32_t l : 1; |
||||
uint32_t w : 1; |
||||
uint32_t b : 1; |
||||
uint32_t u : 1; |
||||
uint32_t p : 1; |
||||
uint32_t mode : 1; |
||||
uint32_t type : 2; |
||||
uint32_t cond : 4; |
||||
}; |
||||
} bits = {backup[offset + 0]}, copy(bits); |
||||
|
||||
bool guard; |
||||
if (bits.mode == 0 || bits.rd != bits.rm) { |
||||
copy.rn = bits.rd; |
||||
guard = false; |
||||
} else { |
||||
copy.rn = bits.rm != A$r0 ? A$r0 : A$r1; |
||||
guard = true; |
||||
} |
||||
|
||||
if (guard) |
||||
buffer[start++] = A$stmdb_sp$_$rs$((1 << copy.rn)); |
||||
|
||||
buffer[start + 0] = A$ldr_rd_$rn_im$(copy.rn, A$pc, |
||||
(end - 1 - (start + 0)) * 4 - 8); |
||||
buffer[start + 1] = copy.value; |
||||
|
||||
start += 2; |
||||
|
||||
if (guard) |
||||
buffer[start++] = A$ldmia_sp$_$rs$((1 << copy.rn)); |
||||
|
||||
*--trailer = reinterpret_cast<uint32_t>(area + offset) + 8; |
||||
end -= 1; |
||||
} else |
||||
buffer[start++] = backup[offset]; |
||||
|
||||
buffer[start + 0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
buffer[start + 1] = reinterpret_cast<uint32_t>(area + used / sizeof(uint32_t)); |
||||
|
||||
if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { |
||||
MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); |
||||
goto fail; |
||||
} |
||||
|
||||
*result = buffer; |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", *result); |
||||
MSLogHexEx(buffer, length, 4, name); |
||||
} |
||||
|
||||
} |
||||
|
||||
{ |
||||
SubstrateHookMemory code(process, symbol, used); |
||||
|
||||
arm[0] = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); |
||||
arm[1] = reinterpret_cast<uint32_t>(replace); |
||||
} |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHexEx(area, used + sizeof(uint32_t), 4, name); |
||||
} |
||||
|
||||
return used; |
||||
} |
||||
|
||||
static size_t |
||||
SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { |
||||
if (MSDebug) |
||||
MSLog(MSLogLevelNotice, "SubstrateHookFunction(%p, %p, %p, %p)\n", process, symbol, replace, |
||||
result); |
||||
|
||||
if ((reinterpret_cast<uintptr_t>(symbol) & 0x1) == 0) |
||||
return SubstrateHookFunctionARM(process, symbol, replace, result); |
||||
else |
||||
return SubstrateHookFunctionThumb(process, reinterpret_cast<void *>( |
||||
reinterpret_cast<uintptr_t>(symbol) & ~0x1), replace, result); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) |
||||
|
||||
#include "SubstrateX86.hpp" |
||||
|
||||
static size_t MSGetInstructionWidthIntel(void *start) { |
||||
hde64s decode; |
||||
return hde64_disasm(start, &decode); |
||||
} |
||||
|
||||
static void SubstrateHookFunction(SubstrateProcessRef process, void *symbol, void *replace, void **result) { |
||||
if (MSDebug) |
||||
MSLog(MSLogLevelNotice, "MSHookFunction(%p, %p, %p)\n", symbol, replace, result); |
||||
if (symbol == NULL) |
||||
return; |
||||
|
||||
uintptr_t source(reinterpret_cast<uintptr_t>(symbol)); |
||||
uintptr_t target(reinterpret_cast<uintptr_t>(replace)); |
||||
|
||||
uint8_t *area(reinterpret_cast<uint8_t *>(symbol)); |
||||
|
||||
size_t required(MSSizeOfJump(target, source)); |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHex(area, 32, name); |
||||
} |
||||
|
||||
size_t used(0); |
||||
while (used < required) { |
||||
size_t width(MSGetInstructionWidthIntel(area + used)); |
||||
if (width == 0) { |
||||
MSLog(MSLogLevelError, "MS:Error:MSGetInstructionWidthIntel(%p) == 0", area + used); |
||||
return; |
||||
} |
||||
|
||||
used += width; |
||||
} |
||||
|
||||
size_t blank(used - required); |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHex(area, used + sizeof(uint16_t), name); |
||||
} |
||||
|
||||
uint8_t backup[used]; |
||||
memcpy(backup, area, used); |
||||
|
||||
if (result != NULL) { |
||||
|
||||
if (backup[0] == 0xe9) { |
||||
*result = reinterpret_cast<void *>(source + 5 + *reinterpret_cast<uint32_t *>(backup + 1)); |
||||
return; |
||||
} |
||||
|
||||
if (!ia32 && backup[0] == 0xff && backup[1] == 0x25) { |
||||
*result = *reinterpret_cast<void **>(source + 6 + *reinterpret_cast<uint32_t *>(backup + 2)); |
||||
return; |
||||
} |
||||
|
||||
size_t length(used + MSSizeOfJump(source + used)); |
||||
|
||||
for (size_t offset(0), width; offset != used; offset += width) { |
||||
hde64s decode; |
||||
hde64_disasm(backup + offset, &decode); |
||||
width = decode.len; |
||||
//_assert(width != 0 && offset + width <= used);
|
||||
|
||||
#ifdef __LP64__ |
||||
if ((decode.modrm & 0xc7) == 0x05) { |
||||
if (decode.opcode == 0x8b) { |
||||
void *destiny(area + offset + width + int32_t(decode.disp.disp32)); |
||||
uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); |
||||
length -= decode.len; |
||||
length += MSSizeOfPushPointer(destiny); |
||||
length += MSSizeOfPop(reg); |
||||
length += MSSizeOfMove64(); |
||||
} else { |
||||
MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); |
||||
continue; |
||||
} |
||||
} else |
||||
#endif |
||||
|
||||
if (backup[offset] == 0xe8) { |
||||
int32_t relative(*reinterpret_cast<int32_t *>(backup + offset + 1)); |
||||
void *destiny(area + offset + decode.len + relative); |
||||
|
||||
if (relative == 0) { |
||||
length -= decode.len; |
||||
length += MSSizeOfPushPointer(destiny); |
||||
} else { |
||||
length += MSSizeOfSkip(); |
||||
length += MSSizeOfJump(destiny); |
||||
} |
||||
} else if (backup[offset] == 0xeb) { |
||||
length -= decode.len; |
||||
length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1)); |
||||
} else if (backup[offset] == 0xe9) { |
||||
length -= decode.len; |
||||
length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast<int32_t *>(backup + offset + 1)); |
||||
} else if ( |
||||
backup[offset] == 0xe3 || |
||||
(backup[offset] & 0xf0) == 0x70 |
||||
// XXX: opcode2 & 0xf0 is 0x80?
|
||||
) { |
||||
length += decode.len; |
||||
length += MSSizeOfJump(area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1)); |
||||
} |
||||
} |
||||
|
||||
uint8_t *buffer(reinterpret_cast<uint8_t *>(mmap( |
||||
NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 |
||||
))); |
||||
|
||||
if (buffer == MAP_FAILED) { |
||||
MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); |
||||
*result = NULL; |
||||
return; |
||||
} |
||||
|
||||
if (false) fail: { |
||||
munmap(buffer, length); |
||||
*result = NULL; |
||||
return; |
||||
} |
||||
|
||||
{ |
||||
uint8_t *current(buffer); |
||||
|
||||
for (size_t offset(0), width; offset != used; offset += width) { |
||||
hde64s decode; |
||||
hde64_disasm(backup + offset, &decode); |
||||
width = decode.len; |
||||
//_assert(width != 0 && offset + width <= used);
|
||||
|
||||
#ifdef __LP64__ |
||||
if ((decode.modrm & 0xc7) == 0x05) { |
||||
if (decode.opcode == 0x8b) { |
||||
void *destiny(area + offset + width + int32_t(decode.disp.disp32)); |
||||
uint8_t reg(decode.rex_r << 3 | decode.modrm_reg); |
||||
MSPushPointer(current, destiny); |
||||
MSWritePop(current, reg); |
||||
MSWriteMove64(current, reg, reg); |
||||
} else { |
||||
MSLog(MSLogLevelError, "MS:Error: Unknown RIP-Relative (%.2x %.2x)", decode.opcode, decode.opcode2); |
||||
goto copy; |
||||
} |
||||
} else |
||||
#endif |
||||
|
||||
if (backup[offset] == 0xe8) { |
||||
int32_t relative(*reinterpret_cast<int32_t *>(backup + offset + 1)); |
||||
if (relative == 0) |
||||
MSPushPointer(current, area + offset + decode.len); |
||||
else { |
||||
MSWrite<uint8_t>(current, 0xe8); |
||||
MSWrite<int32_t>(current, MSSizeOfSkip()); |
||||
void *destiny(area + offset + decode.len + relative); |
||||
MSWriteSkip(current, MSSizeOfJump(destiny, current + MSSizeOfSkip())); |
||||
MSWriteJump(current, destiny); |
||||
} |
||||
} else if (backup[offset] == 0xeb) |
||||
MSWriteJump(current, area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1)); |
||||
else if (backup[offset] == 0xe9) |
||||
MSWriteJump(current, area + offset + decode.len + *reinterpret_cast<int32_t *>(backup + offset + 1)); |
||||
else if ( |
||||
backup[offset] == 0xe3 || |
||||
(backup[offset] & 0xf0) == 0x70 |
||||
) { |
||||
MSWrite<uint8_t>(current, backup[offset]); |
||||
MSWrite<uint8_t>(current, 2); |
||||
MSWrite<uint8_t>(current, 0xeb); |
||||
void *destiny(area + offset + decode.len + *reinterpret_cast<int8_t *>(backup + offset + 1)); |
||||
MSWrite<uint8_t>(current, MSSizeOfJump(destiny, current + 1)); |
||||
MSWriteJump(current, destiny); |
||||
} else |
||||
#ifdef __LP64__ |
||||
copy: |
||||
#endif |
||||
{ |
||||
MSWrite(current, backup + offset, width); |
||||
} |
||||
} |
||||
|
||||
MSWriteJump(current, area + used); |
||||
} |
||||
|
||||
if (mprotect(buffer, length, PROT_READ | PROT_EXEC) == -1) { |
||||
MSLog(MSLogLevelError, "MS:Error:mprotect():%d", errno); |
||||
goto fail; |
||||
} |
||||
|
||||
*result = buffer; |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", *result); |
||||
MSLogHex(buffer, length, name); |
||||
} |
||||
|
||||
} |
||||
|
||||
{ |
||||
SubstrateHookMemory code(process, area, used); |
||||
|
||||
uint8_t *current(area); |
||||
MSWriteJump(current, target); |
||||
for (unsigned offset(0); offset != blank; ++offset) |
||||
MSWrite<uint8_t>(current, 0x90); |
||||
} |
||||
|
||||
if (MSDebug) { |
||||
char name[16]; |
||||
sprintf(name, "%p", area); |
||||
MSLogHex(area, used + sizeof(uint16_t), name); |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
_extern void MSHookFunction(void *symbol, void *replace, void **result) { |
||||
#ifdef __aarch64__ |
||||
A64HookFunction(symbol, replace, result); |
||||
#else |
||||
SubstrateHookFunction(NULL, symbol, replace, result); |
||||
#endif |
||||
} |
||||
|
||||
#if defined(__APPLE__) && defined(__arm__) |
||||
_extern void _Z14MSHookFunctionPvS_PS_(void *symbol, void *replace, void **result) { |
||||
return MSHookFunction(symbol, replace, result); |
||||
} |
||||
#endif |
@ -1,19 +0,0 @@ |
||||
#ifndef __SUBSTRATEHOOK_H__ |
||||
#define __SUBSTRATEHOOK_H__ |
||||
|
||||
|
||||
#include <stdlib.h> |
||||
|
||||
#define _extern extern "C" __attribute__((__visibility__("default"))) |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
void MSHookFunction(void *symbol, void *replace, void **result); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif |
@ -1,40 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#ifndef SUBSTRATE_LOG_HPP |
||||
#define SUBSTRATE_LOG_HPP |
||||
|
||||
#if 0 |
||||
#include <android/log.h> |
||||
|
||||
#define MSLog(level, format, ...) ((void)__android_log_print(level, "NNNN", format, __VA_ARGS__)) |
||||
|
||||
#define MSLogLevelNotice ANDROID_LOG_INFO |
||||
#define MSLogLevelWarning ANDROID_LOG_WARN |
||||
#define MSLogLevelError ANDROID_LOG_ERROR |
||||
|
||||
#else |
||||
|
||||
#define MSLog(level, format, ...) printf(format, __VA_ARGS__) |
||||
|
||||
#endif |
||||
|
||||
#endif//SUBSTRATE_LOG_HPP
|
@ -1,75 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#define SubstrateInternal |
||||
#include "CydiaSubstrate.h" |
||||
#include "SubstrateLog.hpp" |
||||
|
||||
#include <sys/mman.h> |
||||
|
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
|
||||
extern "C" void __clear_cache (void *beg, void *end); |
||||
|
||||
struct __SubstrateMemory { |
||||
void *address_; |
||||
size_t width_; |
||||
|
||||
__SubstrateMemory(void *address, size_t width) : |
||||
address_(address), |
||||
width_(width) |
||||
{ |
||||
} |
||||
}; |
||||
|
||||
extern "C" SubstrateMemoryRef SubstrateMemoryCreate(SubstrateAllocatorRef allocator, SubstrateProcessRef process, void *data, size_t size) { |
||||
if (allocator != NULL) { |
||||
MSLog(MSLogLevelError, "MS:Error:allocator != %d", 0); |
||||
return NULL; |
||||
} |
||||
|
||||
if (size == 0) |
||||
return NULL; |
||||
|
||||
long page(sysconf(_SC_PAGESIZE)); // Portable applications should employ sysconf(_SC_PAGESIZE) instead of getpagesize
|
||||
|
||||
uintptr_t base(reinterpret_cast<uintptr_t>(data) / page * page); |
||||
size_t width(((reinterpret_cast<uintptr_t>(data) + size - 1) / page + 1) * page - base); |
||||
void *address(reinterpret_cast<void *>(base)); |
||||
|
||||
if (mprotect(address, width, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) { |
||||
MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); |
||||
return NULL; |
||||
} |
||||
|
||||
return new __SubstrateMemory(address, width); |
||||
} |
||||
|
||||
extern "C" void SubstrateMemoryRelease(SubstrateMemoryRef memory) { |
||||
if (mprotect(memory->address_, memory->width_, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) |
||||
MSLog(MSLogLevelError, "MS:Error:mprotect() = %d", errno); |
||||
|
||||
__clear_cache(reinterpret_cast<char *>(memory->address_), reinterpret_cast<char *>(memory->address_) + memory->width_); |
||||
|
||||
delete memory; |
||||
} |
@ -1,200 +0,0 @@ |
||||
/* Cydia Substrate - Powerful Code Insertion Platform
|
||||
* Copyright (C) 2008-2011 Jay Freeman (saurik) |
||||
*/ |
||||
|
||||
/* GNU Lesser General Public License, Version 3 {{{ */ |
||||
/*
|
||||
* Substrate is free software: you can redistribute it and/or modify it under |
||||
* the terms of the GNU Lesser General Public License as published by the |
||||
* Free Software Foundation, either version 3 of the License, or (at your |
||||
* option) any later version. |
||||
* |
||||
* Substrate is distributed in the hope that it will be useful, but WITHOUT |
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
||||
* License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Lesser General Public License |
||||
* along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/ |
||||
/* }}} */ |
||||
|
||||
#ifndef SUBSTRATE_X86_HPP |
||||
#define SUBSTRATE_X86_HPP |
||||
|
||||
#include "Buffer.hpp" |
||||
|
||||
#ifdef __LP64__ |
||||
static const bool ia32 = false; |
||||
#else |
||||
static const bool ia32 = true; |
||||
#endif |
||||
|
||||
enum I$r { |
||||
I$rax, I$rcx, I$rdx, I$rbx, |
||||
I$rsp, I$rbp, I$rsi, I$rdi, |
||||
I$r8, I$r9, I$r10, I$r11, |
||||
I$r12, I$r13, I$r14, I$r15, |
||||
}; |
||||
|
||||
_disused static bool MSIs32BitOffset(uintptr_t target, uintptr_t source) { |
||||
intptr_t offset(target - source); |
||||
return int32_t(offset) == offset; |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfSkip() { |
||||
return 5; |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfPushPointer(uintptr_t target) { |
||||
return uint64_t(target) >> 32 == 0 ? 5 : 13; |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfPushPointer(void *target) { |
||||
return MSSizeOfPushPointer(reinterpret_cast<uintptr_t>(target)); |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfJump(bool blind, uintptr_t target, uintptr_t source = 0) { |
||||
if (ia32 || (!blind && MSIs32BitOffset(target, source + 5))) |
||||
return MSSizeOfSkip(); |
||||
else |
||||
return MSSizeOfPushPointer(target) + 1; |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfJump(uintptr_t target, uintptr_t source) { |
||||
return MSSizeOfJump(false, target, source); |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfJump(uintptr_t target) { |
||||
return MSSizeOfJump(true, target); |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfJump(void *target, void *source) { |
||||
return MSSizeOfJump(reinterpret_cast<uintptr_t>(target), reinterpret_cast<uintptr_t>(source)); |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfJump(void *target) { |
||||
return MSSizeOfJump(reinterpret_cast<uintptr_t>(target)); |
||||
} |
||||
|
||||
_disused static void MSWriteSkip(uint8_t *¤t, ssize_t size) { |
||||
MSWrite<uint8_t>(current, 0xe9); |
||||
MSWrite<uint32_t>(current, size); |
||||
} |
||||
|
||||
_disused static void MSPushPointer(uint8_t *¤t, uintptr_t target) { |
||||
MSWrite<uint8_t>(current, 0x68); |
||||
MSWrite<uint32_t>(current, target); |
||||
|
||||
if (uint32_t high = uint64_t(target) >> 32) { |
||||
MSWrite<uint8_t>(current, 0xc7); |
||||
MSWrite<uint8_t>(current, 0x44); |
||||
MSWrite<uint8_t>(current, 0x24); |
||||
MSWrite<uint8_t>(current, 0x04); |
||||
MSWrite<uint32_t>(current, high); |
||||
} |
||||
} |
||||
|
||||
_disused static void MSPushPointer(uint8_t *¤t, void *target) { |
||||
return MSPushPointer(current, reinterpret_cast<uintptr_t>(target)); |
||||
} |
||||
|
||||
_disused static void MSWriteCall(uint8_t *¤t, I$r target) { |
||||
if (target >> 3 != 0) |
||||
MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3); |
||||
MSWrite<uint8_t>(current, 0xff); |
||||
MSWrite<uint8_t>(current, 0xd0 | (target & 0x07)); |
||||
} |
||||
|
||||
_disused static void MSWriteCall(uint8_t *¤t, uintptr_t target) { |
||||
uintptr_t source(reinterpret_cast<uintptr_t>(current)); |
||||
|
||||
if (ia32 || MSIs32BitOffset(target, source + 5)) { |
||||
MSWrite<uint8_t>(current, 0xe8); |
||||
MSWrite<uint32_t>(current, target - (source + 5)); |
||||
} else { |
||||
MSPushPointer(current, target); |
||||
|
||||
MSWrite<uint8_t>(current, 0x83); |
||||
MSWrite<uint8_t>(current, 0xc4); |
||||
MSWrite<uint8_t>(current, 0x08); |
||||
|
||||
MSWrite<uint8_t>(current, 0x67); |
||||
MSWrite<uint8_t>(current, 0xff); |
||||
MSWrite<uint8_t>(current, 0x54); |
||||
MSWrite<uint8_t>(current, 0x24); |
||||
MSWrite<uint8_t>(current, 0xf8); |
||||
} |
||||
} |
||||
|
||||
template<typename Type_> |
||||
_disused static void MSWriteCall(uint8_t *¤t, Type_ *target) { |
||||
return MSWriteCall(current, reinterpret_cast<uintptr_t>(target)); |
||||
} |
||||
|
||||
_disused static void MSWriteJump(uint8_t *¤t, uintptr_t target) { |
||||
uintptr_t source(reinterpret_cast<uintptr_t>(current)); |
||||
|
||||
if (ia32 || MSIs32BitOffset(target, source + 5)) |
||||
MSWriteSkip(current, target - (source + 5)); |
||||
else { |
||||
MSPushPointer(current, target); |
||||
MSWrite<uint8_t>(current, 0xc3); |
||||
} |
||||
} |
||||
|
||||
_disused static void MSWriteJump(uint8_t *¤t, void *target) { |
||||
return MSWriteJump(current, reinterpret_cast<uintptr_t>(target)); |
||||
} |
||||
|
||||
_disused static void MSWriteJump(uint8_t *¤t, I$r target) { |
||||
if (target >> 3 != 0) |
||||
MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3); |
||||
MSWrite<uint8_t>(current, 0xff); |
||||
MSWrite<uint8_t>(current, 0xe0 | (target & 0x07)); |
||||
} |
||||
|
||||
_disused static void MSWritePop(uint8_t *¤t, uint8_t target) { |
||||
if (target >> 3 != 0) |
||||
MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3); |
||||
MSWrite<uint8_t>(current, 0x58 | (target & 0x07)); |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfPop(uint8_t target) { |
||||
return target >> 3 != 0 ? 2 : 1; |
||||
} |
||||
|
||||
_disused static void MSWritePush(uint8_t *¤t, I$r target) { |
||||
if (target >> 3 != 0) |
||||
MSWrite<uint8_t>(current, 0x40 | (target & 0x08) >> 3); |
||||
MSWrite<uint8_t>(current, 0x50 | (target & 0x07)); |
||||
} |
||||
|
||||
_disused static void MSWriteAdd(uint8_t *¤t, I$r target, uint8_t source) { |
||||
MSWrite<uint8_t>(current, 0x83); |
||||
MSWrite<uint8_t>(current, 0xc4 | (target & 0x07)); |
||||
MSWrite<uint8_t>(current, source); |
||||
} |
||||
|
||||
_disused static void MSWriteSet64(uint8_t *¤t, I$r target, uintptr_t source) { |
||||
MSWrite<uint8_t>(current, 0x48 | (target & 0x08) >> 3 << 2); |
||||
MSWrite<uint8_t>(current, 0xb8 | (target & 0x07)); |
||||
MSWrite<uint64_t>(current, source); |
||||
} |
||||
|
||||
template<typename Type_> |
||||
_disused static void MSWriteSet64(uint8_t *¤t, I$r target, Type_ *source) { |
||||
return MSWriteSet64(current, target, reinterpret_cast<uintptr_t>(source)); |
||||
} |
||||
|
||||
_disused static void MSWriteMove64(uint8_t *¤t, uint8_t source, uint8_t target) { |
||||
MSWrite<uint8_t>(current, 0x48 | (target & 0x08) >> 3 << 2 | (source & 0x08) >> 3); |
||||
MSWrite<uint8_t>(current, 0x8b); |
||||
MSWrite<uint8_t>(current, (target & 0x07) << 3 | (source & 0x07)); |
||||
} |
||||
|
||||
_disused static size_t MSSizeOfMove64() { |
||||
return 3; |
||||
} |
||||
|
||||
#endif//SUBSTRATE_X86_HPP
|
@ -1,332 +0,0 @@ |
||||
/*
|
||||
* Hacker Disassembler Engine 64 C |
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov. |
||||
* All rights reserved. |
||||
* |
||||
*/ |
||||
|
||||
#include <stdint.h> |
||||
#include <string.h> |
||||
|
||||
#include "hde64.h" |
||||
#include "table64.h" |
||||
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs) |
||||
{ |
||||
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0; |
||||
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; |
||||
uint8_t op64 = 0; |
||||
|
||||
memset(hs,0,sizeof(hde64s)); |
||||
char *tmp=(char*)hs; |
||||
|
||||
for (x = 16; x; x--) |
||||
switch (c = *p++) { |
||||
case 0xf3: |
||||
hs->p_rep = c; |
||||
pref |= PRE_F3; |
||||
break; |
||||
case 0xf2: |
||||
hs->p_rep = c; |
||||
pref |= PRE_F2; |
||||
break; |
||||
case 0xf0: |
||||
hs->p_lock = c; |
||||
pref |= PRE_LOCK; |
||||
break; |
||||
case 0x26: case 0x2e: case 0x36: |
||||
case 0x3e: case 0x64: case 0x65: |
||||
hs->p_seg = c; |
||||
pref |= PRE_SEG; |
||||
break; |
||||
case 0x66: |
||||
hs->p_66 = c; |
||||
pref |= PRE_66; |
||||
break; |
||||
case 0x67: |
||||
hs->p_67 = c; |
||||
pref |= PRE_67; |
||||
break; |
||||
default: |
||||
goto pref_done; |
||||
} |
||||
pref_done: |
||||
|
||||
hs->flags = (uint32_t)pref << 23; |
||||
|
||||
if (!pref) |
||||
pref |= PRE_NONE; |
||||
|
||||
if ((c & 0xf0) == 0x40) { |
||||
hs->flags |= F_PREFIX_REX; |
||||
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8) |
||||
op64++; |
||||
hs->rex_r = (c & 7) >> 2; |
||||
hs->rex_x = (c & 3) >> 1; |
||||
hs->rex_b = c & 1; |
||||
if (((c = *p++) & 0xf0) == 0x40) { |
||||
opcode = c; |
||||
goto error_opcode; |
||||
} |
||||
} |
||||
|
||||
if ((hs->opcode = c) == 0x0f) { |
||||
hs->opcode2 = c = *p++; |
||||
ht += DELTA_OPCODES; |
||||
} else if (c >= 0xa0 && c <= 0xa3) { |
||||
op64++; |
||||
if (pref & PRE_67) |
||||
pref |= PRE_66; |
||||
else |
||||
pref &= ~PRE_66; |
||||
} |
||||
|
||||
opcode = c; |
||||
cflags = ht[ht[opcode / 4] + (opcode % 4)]; |
||||
|
||||
if (cflags == C_ERROR) { |
||||
error_opcode: |
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE; |
||||
cflags = 0; |
||||
if ((opcode & -3) == 0x24) |
||||
cflags++; |
||||
} |
||||
|
||||
x = 0; |
||||
if (cflags & C_GROUP) { |
||||
uint16_t t; |
||||
t = *(uint16_t *)(ht + (cflags & 0x7f)); |
||||
cflags = (uint8_t)t; |
||||
x = (uint8_t)(t >> 8); |
||||
} |
||||
|
||||
if (hs->opcode2) { |
||||
ht = hde64_table + DELTA_PREFIXES; |
||||
if (ht[ht[opcode / 4] + (opcode % 4)] & pref) |
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE; |
||||
} |
||||
|
||||
if (cflags & C_MODRM) { |
||||
hs->flags |= F_MODRM; |
||||
hs->modrm = c = *p++; |
||||
hs->modrm_mod = m_mod = c >> 6; |
||||
hs->modrm_rm = m_rm = c & 7; |
||||
hs->modrm_reg = m_reg = (c & 0x3f) >> 3; |
||||
|
||||
if (x && ((x << m_reg) & 0x80)) |
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE; |
||||
|
||||
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { |
||||
uint8_t t = opcode - 0xd9; |
||||
if (m_mod == 3) { |
||||
ht = hde64_table + DELTA_FPU_MODRM + t*8; |
||||
t = ht[m_reg] << m_rm; |
||||
} else { |
||||
ht = hde64_table + DELTA_FPU_REG; |
||||
t = ht[t] << m_reg; |
||||
} |
||||
if (t & 0x80) |
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE; |
||||
} |
||||
|
||||
if (pref & PRE_LOCK) { |
||||
if (m_mod == 3) { |
||||
hs->flags |= F_ERROR | F_ERROR_LOCK; |
||||
} else { |
||||
uint8_t *table_end, op = opcode; |
||||
if (hs->opcode2) { |
||||
ht = hde64_table + DELTA_OP2_LOCK_OK; |
||||
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; |
||||
} else { |
||||
ht = hde64_table + DELTA_OP_LOCK_OK; |
||||
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; |
||||
op &= -2; |
||||
} |
||||
for (; ht != table_end; ht++) |
||||
if (*ht++ == op) { |
||||
if (!((*ht << m_reg) & 0x80)) |
||||
goto no_lock_error; |
||||
else |
||||
break; |
||||
} |
||||
hs->flags |= F_ERROR | F_ERROR_LOCK; |
||||
no_lock_error: |
||||
; |
||||
} |
||||
} |
||||
|
||||
if (hs->opcode2) { |
||||
switch (opcode) { |
||||
case 0x20: case 0x22: |
||||
m_mod = 3; |
||||
if (m_reg > 4 || m_reg == 1) |
||||
goto error_operand; |
||||
else |
||||
goto no_error_operand; |
||||
case 0x21: case 0x23: |
||||
m_mod = 3; |
||||
if (m_reg == 4 || m_reg == 5) |
||||
goto error_operand; |
||||
else |
||||
goto no_error_operand; |
||||
} |
||||
} else { |
||||
switch (opcode) { |
||||
case 0x8c: |
||||
if (m_reg > 5) |
||||
goto error_operand; |
||||
else |
||||
goto no_error_operand; |
||||
case 0x8e: |
||||
if (m_reg == 1 || m_reg > 5) |
||||
goto error_operand; |
||||
else |
||||
goto no_error_operand; |
||||
} |
||||
} |
||||
|
||||
if (m_mod == 3) { |
||||
uint8_t *table_end; |
||||
if (hs->opcode2) { |
||||
ht = hde64_table + DELTA_OP2_ONLY_MEM; |
||||
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM; |
||||
} else { |
||||
ht = hde64_table + DELTA_OP_ONLY_MEM; |
||||
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; |
||||
} |
||||
for (; ht != table_end; ht += 2) |
||||
if (*ht++ == opcode) { |
||||
if (*ht++ & pref && !((*ht << m_reg) & 0x80)) |
||||
goto error_operand; |
||||
else |
||||
break; |
||||
} |
||||
goto no_error_operand; |
||||
} else if (hs->opcode2) { |
||||
switch (opcode) { |
||||
case 0x50: case 0xd7: case 0xf7: |
||||
if (pref & (PRE_NONE | PRE_66)) |
||||
goto error_operand; |
||||
break; |
||||
case 0xd6: |
||||
if (pref & (PRE_F2 | PRE_F3)) |
||||
goto error_operand; |
||||
break; |
||||
case 0xc5: |
||||
goto error_operand; |
||||
} |
||||
goto no_error_operand; |
||||
} else |
||||
goto no_error_operand; |
||||
|
||||
error_operand: |
||||
hs->flags |= F_ERROR | F_ERROR_OPERAND; |
||||
no_error_operand: |
||||
|
||||
c = *p++; |
||||
if (m_reg <= 1) { |
||||
if (opcode == 0xf6) |
||||
cflags |= C_IMM8; |
||||
else if (opcode == 0xf7) |
||||
cflags |= C_IMM_P66; |
||||
} |
||||
|
||||
switch (m_mod) { |
||||
case 0: |
||||
if (pref & PRE_67) { |
||||
if (m_rm == 6) |
||||
disp_size = 2; |
||||
} else |
||||
if (m_rm == 5) |
||||
disp_size = 4; |
||||
break; |
||||
case 1: |
||||
disp_size = 1; |
||||
break; |
||||
case 2: |
||||
disp_size = 2; |
||||
if (!(pref & PRE_67)) |
||||
disp_size <<= 1; |
||||
} |
||||
|
||||
if (m_mod != 3 && m_rm == 4) { |
||||
hs->flags |= F_SIB; |
||||
p++; |
||||
hs->sib = c; |
||||
hs->sib_scale = c >> 6; |
||||
hs->sib_index = (c & 0x3f) >> 3; |
||||
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) |
||||
disp_size = 4; |
||||
} |
||||
|
||||
p--; |
||||
switch (disp_size) { |
||||
case 1: |
||||
hs->flags |= F_DISP8; |
||||
hs->disp.disp8 = *p; |
||||
break; |
||||
case 2: |
||||
hs->flags |= F_DISP16; |
||||
hs->disp.disp16 = *(uint16_t *)p; |
||||
break; |
||||
case 4: |
||||
hs->flags |= F_DISP32; |
||||
hs->disp.disp32 = *(uint32_t *)p; |
||||
} |
||||
p += disp_size; |
||||
} else if (pref & PRE_LOCK) |
||||
hs->flags |= F_ERROR | F_ERROR_LOCK; |
||||
|
||||
if (cflags & C_IMM_P66) { |
||||
if (cflags & C_REL32) { |
||||
if (pref & PRE_66) { |
||||
hs->flags |= F_IMM16 | F_RELATIVE; |
||||
hs->imm.imm16 = *(uint16_t *)p; |
||||
p += 2; |
||||
goto disasm_done; |
||||
} |
||||
goto rel32_ok; |
||||
} |
||||
if (op64) { |
||||
hs->flags |= F_IMM64; |
||||
hs->imm.imm64 = *(uint64_t *)p; |
||||
p += 8; |
||||
} else if (!(pref & PRE_66)) { |
||||
hs->flags |= F_IMM32; |
||||
hs->imm.imm32 = *(uint32_t *)p; |
||||
p += 4; |
||||
} else |
||||
goto imm16_ok; |
||||
} |
||||
|
||||
|
||||
if (cflags & C_IMM16) { |
||||
imm16_ok: |
||||
hs->flags |= F_IMM16; |
||||
hs->imm.imm16 = *(uint16_t *)p; |
||||
p += 2; |
||||
} |
||||
if (cflags & C_IMM8) { |
||||
hs->flags |= F_IMM8; |
||||
hs->imm.imm8 = *p++; |
||||
} |
||||
|
||||
if (cflags & C_REL32) { |
||||
rel32_ok: |
||||
hs->flags |= F_IMM32 | F_RELATIVE; |
||||
hs->imm.imm32 = *(uint32_t *)p; |
||||
p += 4; |
||||
} else if (cflags & C_REL8) { |
||||
hs->flags |= F_IMM8 | F_RELATIVE; |
||||
hs->imm.imm8 = *p++; |
||||
} |
||||
|
||||
disasm_done: |
||||
|
||||
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) { |
||||
hs->flags |= F_ERROR | F_ERROR_LENGTH; |
||||
hs->len = 15; |
||||
} |
||||
|
||||
return (unsigned int)hs->len; |
||||
} |
@ -1,112 +0,0 @@ |
||||
/*
|
||||
* Hacker Disassembler Engine 64 |
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov. |
||||
* All rights reserved. |
||||
* |
||||
* hde64.h: C/C++ header file |
||||
* |
||||
*/ |
||||
|
||||
#ifndef _HDE64_H_ |
||||
#define _HDE64_H_ |
||||
|
||||
/* stdint.h - C99 standard header
|
||||
* http://en.wikipedia.org/wiki/stdint.h
|
||||
* |
||||
* if your compiler doesn't contain "stdint.h" header (for |
||||
* example, Microsoft Visual C++), you can download file: |
||||
* http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
* and change next line to: |
||||
* #include "pstdint.h" |
||||
*/ |
||||
#include <stdint.h> |
||||
|
||||
#define F_MODRM 0x00000001 |
||||
#define F_SIB 0x00000002 |
||||
#define F_IMM8 0x00000004 |
||||
#define F_IMM16 0x00000008 |
||||
#define F_IMM32 0x00000010 |
||||
#define F_IMM64 0x00000020 |
||||
#define F_DISP8 0x00000040 |
||||
#define F_DISP16 0x00000080 |
||||
#define F_DISP32 0x00000100 |
||||
#define F_RELATIVE 0x00000200 |
||||
#define F_ERROR 0x00001000 |
||||
#define F_ERROR_OPCODE 0x00002000 |
||||
#define F_ERROR_LENGTH 0x00004000 |
||||
#define F_ERROR_LOCK 0x00008000 |
||||
#define F_ERROR_OPERAND 0x00010000 |
||||
#define F_PREFIX_REPNZ 0x01000000 |
||||
#define F_PREFIX_REPX 0x02000000 |
||||
#define F_PREFIX_REP 0x03000000 |
||||
#define F_PREFIX_66 0x04000000 |
||||
#define F_PREFIX_67 0x08000000 |
||||
#define F_PREFIX_LOCK 0x10000000 |
||||
#define F_PREFIX_SEG 0x20000000 |
||||
#define F_PREFIX_REX 0x40000000 |
||||
#define F_PREFIX_ANY 0x7f000000 |
||||
|
||||
#define PREFIX_SEGMENT_CS 0x2e |
||||
#define PREFIX_SEGMENT_SS 0x36 |
||||
#define PREFIX_SEGMENT_DS 0x3e |
||||
#define PREFIX_SEGMENT_ES 0x26 |
||||
#define PREFIX_SEGMENT_FS 0x64 |
||||
#define PREFIX_SEGMENT_GS 0x65 |
||||
#define PREFIX_LOCK 0xf0 |
||||
#define PREFIX_REPNZ 0xf2 |
||||
#define PREFIX_REPX 0xf3 |
||||
#define PREFIX_OPERAND_SIZE 0x66 |
||||
#define PREFIX_ADDRESS_SIZE 0x67 |
||||
|
||||
#pragma pack(push,1) |
||||
|
||||
typedef struct { |
||||
uint8_t len; |
||||
uint8_t p_rep; |
||||
uint8_t p_lock; |
||||
uint8_t p_seg; |
||||
uint8_t p_66; |
||||
uint8_t p_67; |
||||
uint8_t rex; |
||||
uint8_t rex_w; |
||||
uint8_t rex_r; |
||||
uint8_t rex_x; |
||||
uint8_t rex_b;
|
||||
uint8_t opcode; |
||||
uint8_t opcode2; |
||||
uint8_t modrm; |
||||
uint8_t modrm_mod; |
||||
uint8_t modrm_reg; |
||||
uint8_t modrm_rm; |
||||
uint8_t sib; |
||||
uint8_t sib_scale; |
||||
uint8_t sib_index; |
||||
uint8_t sib_base; |
||||
union { |
||||
uint8_t imm8; |
||||
uint16_t imm16; |
||||
uint32_t imm32; |
||||
uint64_t imm64; |
||||
} imm; |
||||
union { |
||||
uint8_t disp8; |
||||
uint16_t disp16; |
||||
uint32_t disp32; |
||||
} disp; |
||||
uint32_t flags; |
||||
} hde64s; |
||||
|
||||
#pragma pack(pop) |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/* __cdecl */ |
||||
unsigned int hde64_disasm(const void *code, hde64s *hs); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* _HDE64_H_ */ |
@ -1,74 +0,0 @@ |
||||
/*
|
||||
* Hacker Disassembler Engine 64 C |
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov. |
||||
* All rights reserved. |
||||
* |
||||
*/ |
||||
|
||||
#define C_NONE 0x00 |
||||
#define C_MODRM 0x01 |
||||
#define C_IMM8 0x02 |
||||
#define C_IMM16 0x04 |
||||
#define C_IMM_P66 0x10 |
||||
#define C_REL8 0x20 |
||||
#define C_REL32 0x40 |
||||
#define C_GROUP 0x80 |
||||
#define C_ERROR 0xff |
||||
|
||||
#define PRE_ANY 0x00 |
||||
#define PRE_NONE 0x01 |
||||
#define PRE_F2 0x02 |
||||
#define PRE_F3 0x04 |
||||
#define PRE_66 0x08 |
||||
#define PRE_67 0x10 |
||||
#define PRE_LOCK 0x20 |
||||
#define PRE_SEG 0x40 |
||||
#define PRE_ALL 0xff |
||||
|
||||
#define DELTA_OPCODES 0x4a |
||||
#define DELTA_FPU_REG 0xfd |
||||
#define DELTA_FPU_MODRM 0x104 |
||||
#define DELTA_PREFIXES 0x13c |
||||
#define DELTA_OP_LOCK_OK 0x1ae |
||||
#define DELTA_OP2_LOCK_OK 0x1c6 |
||||
#define DELTA_OP_ONLY_MEM 0x1d8 |
||||
#define DELTA_OP2_ONLY_MEM 0x1e7 |
||||
|
||||
unsigned char hde64_table[] = { |
||||
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5, |
||||
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1, |
||||
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea, |
||||
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0, |
||||
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab, |
||||
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92, |
||||
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90, |
||||
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b, |
||||
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b, |
||||
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc, |
||||
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20, |
||||
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff, |
||||
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00, |
||||
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01, |
||||
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10, |
||||
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00, |
||||
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00, |
||||
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00, |
||||
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00, |
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff, |
||||
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00, |
||||
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40, |
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43, |
||||
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, |
||||
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40, |
||||
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06, |
||||
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07, |
||||
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04, |
||||
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10, |
||||
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00, |
||||
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb, |
||||
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff, |
||||
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09, |
||||
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff, |
||||
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08, |
||||
0x00,0xf0,0x02,0x00 |
||||
}; |
Loading…
Reference in new issue