remove Substrate

pull/15/head
Milk 4 years ago
parent 20c2e96b75
commit 6583317f02
  1. 5
      Bcore/src/main/jni/Android.mk
  2. 567
      Bcore/src/main/jni/Substrate/And64InlineHook.cpp
  3. 45
      Bcore/src/main/jni/Substrate/And64InlineHook.hpp
  4. 38
      Bcore/src/main/jni/Substrate/Buffer.hpp
  5. 152
      Bcore/src/main/jni/Substrate/CydiaSubstrate.h
  6. 67
      Bcore/src/main/jni/Substrate/SubstrateARM.hpp
  7. 96
      Bcore/src/main/jni/Substrate/SubstrateDebug.cpp
  8. 33
      Bcore/src/main/jni/Substrate/SubstrateDebug.hpp
  9. 962
      Bcore/src/main/jni/Substrate/SubstrateHook.cpp
  10. 19
      Bcore/src/main/jni/Substrate/SubstrateHook.h
  11. 40
      Bcore/src/main/jni/Substrate/SubstrateLog.hpp
  12. 75
      Bcore/src/main/jni/Substrate/SubstratePosixMemory.cpp
  13. 200
      Bcore/src/main/jni/Substrate/SubstrateX86.hpp
  14. 332
      Bcore/src/main/jni/Substrate/hde64.c
  15. 112
      Bcore/src/main/jni/Substrate/hde64.h
  16. 74
      Bcore/src/main/jni/Substrate/table64.h

@ -22,11 +22,6 @@ LOCAL_SRC_FILES := JniHook/JniHook.cpp \
Utils/HexDump.cpp \
Utils/PointerCheck.cpp \
IO.cpp \
Substrate/hde64.c \
Substrate/SubstrateDebug.cpp \
Substrate/SubstrateHook.cpp \
Substrate/SubstratePosixMemory.cpp \
Substrate/And64InlineHook.cpp \
Hook/BaseHook.cpp \
Hook/RuntimeHook.cpp \
Hook/VMClassLoaderHook.cpp \

@ -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 *&current, ssize_t size) {
MSWrite<uint8_t>(current, 0xe9);
MSWrite<uint32_t>(current, size);
}
_disused static void MSPushPointer(uint8_t *&current, 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 *&current, void *target) {
return MSPushPointer(current, reinterpret_cast<uintptr_t>(target));
}
_disused static void MSWriteCall(uint8_t *&current, 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 *&current, 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 *&current, Type_ *target) {
return MSWriteCall(current, reinterpret_cast<uintptr_t>(target));
}
_disused static void MSWriteJump(uint8_t *&current, 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 *&current, void *target) {
return MSWriteJump(current, reinterpret_cast<uintptr_t>(target));
}
_disused static void MSWriteJump(uint8_t *&current, 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 *&current, 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 *&current, 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 *&current, 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 *&current, 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 *&current, I$r target, Type_ *source) {
return MSWriteSet64(current, target, reinterpret_cast<uintptr_t>(source));
}
_disused static void MSWriteMove64(uint8_t *&current, 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…
Cancel
Save