Unverified Commit e862404d authored by ganyao114's avatar ganyao114 Committed by GitHub

Merge pull request #15 from ganyao114/native_hook

Native hook
parents 75214784 e4bab752
......@@ -200,11 +200,22 @@ To bypass hidden api on P & Q
# Native Hook
## simple hook(no backup)
#include "includes/sandhook.h"
// can not call origin method now
bool nativeHookNoBackup(void* origin, void* hook);
## need backup origin method
#include "sanhook_native.h"
void* SandInlineHook(void* origin, void* replace);
void* SandInlineHookSym(const char* so, const char* symb, void* replace);
return is backup method
## more
- disassembler (only implement important instructions)
- assembler (only implement important instructions)
# Demo
## SandVXPosed
......
......@@ -27,5 +27,6 @@ dependencies {
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':hooklib')
implementation project(':nativehook')
implementation project(':xposedcompat')
}
......@@ -5,6 +5,7 @@ import android.app.Application;
import android.os.Build;
import android.util.Log;
import com.swift.sandhook.nativehook.NativeHook;
import com.swift.sandhook.test.TestClass;
import com.swift.sandhook.testHookers.ActivityHooker;
import com.swift.sandhook.testHookers.CtrHook;
......@@ -29,6 +30,8 @@ public class MyApp extends Application {
public void onCreate() {
super.onCreate();
NativeHook.test();
SandHookConfig.DEBUG = BuildConfig.DEBUG;
if (testAndroidQ) {
......
......@@ -45,7 +45,7 @@ namespace SandHook {
private:
const char* elf = nullptr;
uint8_t * base = nullptr;
void* base = nullptr;
char* buffer = nullptr;
off_t size = 0;
off_t bias = -4396;
......
......@@ -31,10 +31,10 @@ ElfImg::ElfImg(const char *elf) {
Elf_Off symtab_entsize = 0;
section_header = reinterpret_cast<Elf_Shdr *>(((uint8_t *) header) + header->e_shoff);
section_header = reinterpret_cast<Elf_Shdr *>(((size_t) header) + header->e_shoff);
uint8_t* shoff = reinterpret_cast<uint8_t *>(section_header);
char* section_str = reinterpret_cast<char *>(section_header[header->e_shstrndx].sh_offset + ((uint8_t *) header));
size_t shoff = reinterpret_cast<size_t>(section_header);
char* section_str = reinterpret_cast<char *>(section_header[header->e_shstrndx].sh_offset + ((size_t) header));
bool has_strtab = false;
bool has_dynsym = false;
......@@ -75,10 +75,10 @@ ElfImg::ElfImg(const char *elf) {
LOGW("can't find symtab from sections\n");
}
sym_start = reinterpret_cast<Elf_Sym *>(((uint8_t *) header) + symtab_offset);
sym_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + symtab_offset);
//load module base
base = reinterpret_cast<uint8_t *>(getModuleBase(elf));
base = getModuleBase(elf);
}
ElfImg::~ElfImg() {
......@@ -97,7 +97,7 @@ Elf_Addr ElfImg::getSymbOffset(const char *name) {
Elf_Addr _offset = 0;
for(int i = 0 ; i < symtab_count; i++) {
unsigned int st_type = ELF_ST_TYPE(sym_start[i].st_info);
char* st_name = reinterpret_cast<char *>(((uint8_t *) header) + symstr_offset + sym_start[i].st_name);
char* st_name = reinterpret_cast<char *>(((size_t) header) + symstr_offset + sym_start[i].st_name);
if (st_type == STT_FUNC && sym_start[i].st_size) {
if(strcmp(st_name, name) == 0) {
_offset = sym_start[i].st_value;
......@@ -112,7 +112,7 @@ Elf_Addr ElfImg::getSymbOffset(const char *name) {
Elf_Addr ElfImg::getSymbAddress(const char *name) {
Elf_Addr offset = getSymbOffset(name);
if (offset > 0 && base != nullptr) {
return reinterpret_cast<Elf_Addr>(base + offset - bias);
return static_cast<Elf_Addr>((size_t)base + offset - bias);
} else {
return 0;
}
......
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
if(${CMAKE_ANDROID_ARCH_ABI} STREQUAL "arm64-v8a")
set(OS_DEPENDENDED_SRC
src/main/cpp/archs/arm/arm64/assembler/assembler_arm64.cpp
src/main/cpp/archs/arm/arm64/inst/inst_arm64.cpp
src/main/cpp/archs/arm/arm64/register/register_arm64.cpp
src/main/cpp/archs/arm/arm64/register/register_list_arm64.cpp
src/main/cpp/archs/arm/arm64/decoder/decoder_arm64.cpp
src/main/cpp/archs/arm/arm64/relocate/code_relocate_arm64.cpp
src/main/cpp/archs/arm/arm64/hook/hook_arm64.cpp)
elseif (${CMAKE_ANDROID_ARCH_ABI} STREQUAL "armeabi-v7a")
set(OS_DEPENDENDED_SRC
src/main/cpp/archs/arm/arm32/inst/inst_arm32.cpp
src/main/cpp/archs/arm/arm32/inst/inst_t32.cpp
src/main/cpp/archs/arm/arm32/inst/inst_t16.cpp
src/main/cpp/archs/arm/arm32/register/register_arm32.cpp
src/main/cpp/archs/arm/arm32/register/register_list_arm32.cpp
src/main/cpp/archs/arm/arm32/assembler/assembler_arm32.cpp
src/main/cpp/archs/arm/arm32/decoder/decoder_arm32.cpp
src/main/cpp/archs/arm/arm32/hook/hook_arm32.cpp
src/main/cpp/archs/arm/arm32/relocate/code_relocate_arm32.cpp)
endif()
add_library( # Sets the name of the library.
sandhook-native
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/cpp/sandhook_native.cpp
src/main/cpp/decoder/decoder.cpp
src/main/cpp/relocate/code_relocate.cpp
src/main/cpp/elf/elf.cpp
src/main/cpp/assembler/assembler.cpp
src/main/cpp/buffer/code_buffer.cpp
src/main/cpp/utils/platform.cpp
src/main/cpp/hook/hook.cpp
${OS_DEPENDENDED_SRC})
include_directories(
src/main/cpp/asm
src/main/cpp/decoder
src/main/cpp/elf
src/main/cpp/utils
src/main/cpp/includes
src/main/cpp/buffer
src/main/cpp/archs/arm
src/main/cpp/archs/arm/arm64/inst
src/main/cpp/archs/arm/arm64/register
src/main/cpp/archs/arm/arm64/decoder
src/main/cpp/archs/arm/arm64/assembler
src/main/cpp/archs/arm/arm64/relocate
src/main/cpp/archs/arm/arm64/hook
src/main/cpp/archs/arm/arm32/inst
src/main/cpp/archs/arm/arm32/register
src/main/cpp/archs/arm/arm32/assembler
src/main/cpp/archs/arm/arm32/decoder
src/main/cpp/archs/arm/arm32/hook
src/main/cpp/archs/arm/arm32/relocate
)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
sandhook-native
# Links the target library to the log library
# included in the NDK.
${log-lib})
add_definitions(-std=c++11)
ENABLE_LANGUAGE(ASM)
\ No newline at end of file
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
arguments '-DBUILD_TESTING=OFF'
cppFlags "-frtti -fexceptions -Wpointer-arith"
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
package com.swift.sandhook.nativehook;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.swift.sandhook.nativehook.test", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.swift.sandhook.nativehook" />
//
// Created by swift on 2019/5/22.
//
#include "assembler_arm32.h"
#include "exception.h"
using namespace SandHook::Assembler;
using namespace SandHook::RegistersA32;
using namespace SandHook::AsmA32;
AssemblerA32::AssemblerA32(CodeBuffer* codeBuffer) {
codeContainer.setCodeBuffer(codeBuffer);
}
void *AssemblerA32::getPC() {
return reinterpret_cast<void *>(codeContainer.curPc);
}
void *AssemblerA32::getStartPC() {
return reinterpret_cast<void *>(codeContainer.startPc);
}
void AssemblerA32::allocBufferFirst(U32 size) {
codeContainer.allocBufferFirst(size);
}
void *AssemblerA32::finish() {
codeContainer.commit();
return reinterpret_cast<void *>(codeContainer.startPc);
}
void AssemblerA32::Emit(U32 data32) {
Emit(reinterpret_cast<Unit<Base>*>(new Data32(data32)));
}
void AssemblerA32::Emit(Unit<Base> *unit) {
codeContainer.append(unit);
}
void AssemblerA32::Mov(RegisterA32 &rd, U16 imm16) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(MOV_MOVT_IMM)(INST_T32(MOV_MOVT_IMM)::MOV, rd, imm16)));
}
void AssemblerA32::Movt(RegisterA32 &rd, U16 imm16) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(MOV_MOVT_IMM)(INST_T32(MOV_MOVT_IMM)::MOVT, rd, imm16)));
}
void AssemblerA32::Mov(RegisterA32 &rd, U32 imm32) {
U16 immL = BITS16L(imm32);
U16 immH = BITS16H(imm32);
Mov(rd, immL);
Movt(rd, immH);
}
void AssemblerA32::Ldr(RegisterA32 &rt, Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_LIT)(INST_T32(LDR_LIT)::LDR, INST_T32(LDR_LIT)::UnSign, rt, *label)));
}
void AssemblerA32::Ldrb(RegisterA32 &rt, Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_LIT)(INST_T32(LDR_LIT)::LDRB, INST_T32(LDR_LIT)::UnSign,rt, *label)));
}
void AssemblerA32::Ldrh(RegisterA32 &rt, Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_LIT)(INST_T32(LDR_LIT)::LDRH, INST_T32(LDR_LIT)::UnSign,rt, *label)));
}
void AssemblerA32::Ldrsb(RegisterA32 &rt, Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_LIT)(INST_T32(LDR_LIT)::LDRB, INST_T32(LDR_LIT)::Sign,rt, *label)));
}
void AssemblerA32::Ldrsh(RegisterA32 &rt, Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_LIT)(INST_T32(LDR_LIT)::LDRH, INST_T32(LDR_LIT)::Sign,rt, *label)));
}
void AssemblerA32::Ldr(RegisterA32 &rt, const MemOperand &operand) {
if (operand.addr_mode == Offset && operand.offset >= 0) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_UIMM)(rt, *operand.rn, operand.addr_mode)));
} else {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_IMM)(INST_T32(LDR_IMM)::LDR, rt, operand)));
}
}
void AssemblerA32::Ldrb(RegisterA32 &rt, const MemOperand &operand) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_IMM)(INST_T32(LDR_IMM)::LDRB, rt, operand)));
}
void AssemblerA32::Ldrh(RegisterA32 &rt, const MemOperand &operand) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_IMM)(INST_T32(LDR_IMM)::LDRH, rt, operand)));
}
void AssemblerA32::Ldrsb(RegisterA32 &rt, const MemOperand &operand) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_IMM)(INST_T32(LDR_IMM)::LDRSB, rt, operand)));
}
void AssemblerA32::Ldrsh(RegisterA32 &rt, const MemOperand &operand) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(LDR_IMM)(INST_T32(LDR_IMM)::LDRSH, rt, operand)));
}
void AssemblerA32::B(Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(B)(*label)));
}
void AssemblerA32::Bl(Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(B32)(INST_T32(B32)::BL, INST_T32(B32)::arm, *label)));
}
void AssemblerA32::Blx(Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(B32)(INST_T32(B32)::BL, INST_T32(B32)::thumb, *label)));
}
void AssemblerA32::Bx(Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T32(B32)(INST_T32(B32)::B, INST_T32(B32)::thumb, *label)));
}
void AssemblerA32::Mov(RegisterA32 &rd, RegisterA32 &rm) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(MOV_REG)(rd, rm)));
}
void AssemblerA32::Bx(RegisterA32 &rm) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(BX_BLX)(INST_T16(BX_BLX)::BX, rm)));
}
void AssemblerA32::Blx(RegisterA32 &rm) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(BX_BLX)(INST_T16(BX_BLX)::BLX, rm)));
}
void AssemblerA32::B(Condition condition, Label* label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(B_COND)(condition, *label)));
}
void AssemblerA32::Add(RegisterA32 &rdn, U8 imm8) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(ADD_IMM_RDN)(&rdn, imm8)));
}
void AssemblerA32::Add(RegisterA32 &rd, RegisterA32 &rn, RegisterA32 &rm) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(ADD_REG)(&rd, &rn, &rm)));
}
void AssemblerA32::Cmp(RegisterA32 &rd, RegisterA32 &rn) {
if (rd.getCode() < 8 && rn.getCode() < 8) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(CMP_REG)(rd, rn)));
} else {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(CMP_REG_EXT)(rd, rn)));
}
}
void AssemblerA32::Pop(RegisterA32 &rt) {
if (rt.getCode() < 8 || rt == PC) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(POP)(RegisterList(rt))));
} else {
throw ErrorCodeException("error pop inst");
}
}
void AssemblerA32::Push(RegisterA32 &rt) {
if (rt.getCode() < 8 || rt == PC) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(PUSH)(RegisterList(rt))));
} else {
throw ErrorCodeException("error pop inst");
}
}
void AssemblerA32::Adr(RegisterA32 &rd, Label *label) {
Emit(reinterpret_cast<Unit<Base>*>(new INST_T16(ADR)(rd, *label)));
}
void AssemblerA32::Nop16() {
Mov(IP, IP);
}
//
// Created by swift on 2019/5/22.
//
#ifndef SANDHOOK_ASSEMBLER_A32_H
#define SANDHOOK_ASSEMBLER_A32_H
#include "assembler.h"
#include "register_arm32.h"
#include "inst_t16.h"
#include "inst_t32.h"
using namespace SandHook::AsmA32;
namespace SandHook {
namespace Assembler {
class AssemblerA32 {
public:
AssemblerA32(CodeBuffer* codeBuffer);
void allocBufferFirst(U32 size);
void* getStartPC();
void* getPC();
void* finish();
void Emit(U32 data32);
void Emit(Unit<Base>* unit);
void Mov(RegisterA32 &rd, U16 imm16);
void Movt(RegisterA32 &rd, U16 imm16);
void Mov(RegisterA32 &rd, U32 imm32);
void Mov(RegisterA32 &rd, RegisterA32 &rm);
void Ldr(RegisterA32 &rt, Label* label);
void Ldrb(RegisterA32 &rt, Label* label);
void Ldrh(RegisterA32 &rt, Label* label);
void Ldrsb(RegisterA32 &rt, Label* label);
void Ldrsh(RegisterA32 &rt, Label* label);
void Ldr(RegisterA32 &rt, const MemOperand& operand);
void Ldrb(RegisterA32 &rt, const MemOperand& operand);
void Ldrh(RegisterA32 &rt, const MemOperand& operand);
void Ldrsb(RegisterA32 &rt, const MemOperand& operand);
void Ldrsh(RegisterA32 &rt, const MemOperand& operand);
void B(Label* label);
void Bl(Label* label);
void Blx(Label* label);
void Bx(Label* label);
void Blx(RegisterA32 &rm);
void Bx(RegisterA32 &rm);
void B(Condition condition, Label* label);
void Add(RegisterA32 &rdn, U8 imm8);
void Add(RegisterA32 &rd, RegisterA32 &rn, RegisterA32& rm);
void Cmp(RegisterA32 &rn, RegisterA32 &rm);
void Pop(RegisterA32& rt);
void Push(RegisterA32& rt);
void Adr(RegisterA32& rd, Label* label);
void Nop16();
public:
CodeContainer codeContainer = CodeContainer(nullptr);
};
}
}
#endif //SANDHOOK_ASSEMBLER_A32_H
//
// Created by swift on 2019/5/23.
//
#include "inst_t16.h"
#include "inst_t32.h"
#include "decoder_arm32.h"
using namespace SandHook::Decoder;
using namespace SandHook::AsmA32;
#define CASE(T, X) \
if (IS_OPCODE_##T(*reinterpret_cast<Inst##T *>(pc), X)) { \
STRUCT_##T(X) *s = reinterpret_cast<STRUCT_##T(X) *>(pc); \
unit = reinterpret_cast<Unit<Base> *>(new INST_##T(X)(s)); \
goto label_matched; \
}
#define CASE_A32(X) CASE(A32, X)
#define CASE_T16(X) CASE(T16, X)
#define CASE_T32(X) CASE(T32, X)
Arm32Decoder* Arm32Decoder::instant = new Arm32Decoder();
void Arm32Decoder::decode(void *codeStart, Addr codeLen, InstVisitor &visitor) {
bool thumb = isThumbCode(reinterpret_cast<Addr>(codeStart));
if (thumb) {
codeStart = getThumbCodeAddress(codeStart);
}
void *pc = codeStart;
Addr endAddr = (Addr) codeStart + codeLen;
Unit<Base>* unit = nullptr;
while((Addr) pc < endAddr) {
bool thumb32 = isThumb32(*reinterpret_cast<InstT16*>(pc));
if (thumb && thumb32) {
CASE_T32(B32)
CASE_T32(LDR_LIT)
CASE_T32(LDR_IMM)
CASE_T32(LDR_UIMM)
CASE_T32(MOV_MOVT_IMM)
if (unit == nullptr) {
unit = reinterpret_cast<Unit<Base> *>(new INST_T32(UNKNOW)(*reinterpret_cast<STRUCT_T32(UNKNOW) *>(pc)));
}
} else if (thumb) {
CASE_T16(B)
CASE_T16(B_COND)
CASE_T16(BX_BLX)
CASE_T16(CBZ_CBNZ)
CASE_T16(LDR_LIT)
CASE_T16(ADD_IMM_RDN)
CASE_T16(ADR)
CASE_T16(ADD_REG)
CASE_T16(CMP_REG)
CASE_T16(CMP_REG_EXT)
CASE_T16(MOV_REG)
CASE_T16(POP)
CASE_T16(PUSH)
if (unit == nullptr) {
unit = reinterpret_cast<Unit<Base> *>(new INST_T16(UNKNOW)(*reinterpret_cast<STRUCT_T16(UNKNOW) *>(pc)));
}
} else {
//TODO
unit = reinterpret_cast<Unit<Base> *>(new INST_T32(UNKNOW)(*reinterpret_cast<STRUCT_T32(UNKNOW) *>(pc)));
}
label_matched:
if (!visitor.visit(unit, pc)) {
break;
}
pc = reinterpret_cast<InstA64 *>((Addr)pc + unit->size());
unit = nullptr;
}
}
//
// Created by swift on 2019/5/23.
//
#ifndef SANDHOOK_DECODER_A32_H
#define SANDHOOK_DECODER_A32_H
#include "decoder.h"
namespace SandHook {
namespace Decoder {
class Arm32Decoder : public InstDecoder {
public:
void decode(void *codeStart, Addr codeLen, InstVisitor &visitor) override;
public:
static Arm32Decoder* instant;
};
}
}
#endif //SANDHOOK_DECODER_A32_H
//
// Created by swift on 2019/5/23.
//
#include "code_relocate_arm32.h"
#include "hook_arm32.h"
#include "code_buffer.h"
#include "lock.h"
using namespace SandHook::Hook;
using namespace SandHook::Decoder;
using namespace SandHook::Asm;
using namespace SandHook::Assembler;
using namespace SandHook::Utils;
#include "assembler_arm32.h"
using namespace SandHook::RegistersA32;
void *InlineHookArm32Android::inlineHook(void *origin, void *replace) {
AutoLock lock(hookLock);
void* originCode = origin;
if (isThumbCode((Addr)origin)) {
originCode = getThumbCodeAddress(origin);
}
if (isThumbCode((Addr)origin)) {
replace = getThumbPC(replace);
}
void* backup = nullptr;
AssemblerA32 assemblerBackup(backupBuffer);
StaticCodeBuffer inlineBuffer = StaticCodeBuffer(reinterpret_cast<Addr>(originCode));
AssemblerA32 assemblerInline(&inlineBuffer);
CodeContainer* codeContainerInline = &assemblerInline.codeContainer;
//build inline trampoline
#define __ assemblerInline.
Label* target_addr_label = new Label();
__ Ldr(PC, target_addr_label);
__ Emit(target_addr_label);
__ Emit((Addr)replace);
#undef __
//build backup method
CodeRelocateA32 relocate = CodeRelocateA32(assemblerBackup);
backup = relocate.relocate(origin, codeContainerInline->size(), nullptr);
#define __ assemblerBackup.
__ Mov(IP ,(Addr) getThumbPC(reinterpret_cast<void *>((Addr)originCode + relocate.curOffset)));
__ Bx(IP);
__ finish();
#undef __
//commit inline trampoline
assemblerInline.finish();
return getThumbPC(backup);
}
\ No newline at end of file
//
// Created by swift on 2019/5/23.
//
#ifndef SANDHOOK_HOOK_ARM32_H
#define SANDHOOK_HOOK_ARM32_H
#include "hook.h"
namespace SandHook {
namespace Hook {
class InlineHookArm32Android : public InlineHook {
public:
inline InlineHookArm32Android() {
hookLock = new std::mutex();
};
inline ~InlineHookArm32Android() {
delete hookLock;
}
void *inlineHook(void *origin, void *replace) override;
protected:
std::mutex* hookLock;
};
}
}
#endif //SANDHOOK_HOOK_ARM32_H
//
// Created by swift on 2019/5/16.
//
#ifndef SANDHOOK_ARM32_BASE_H
#define SANDHOOK_ARM32_BASE_H
#include <ostream>
#include "arm_base.h"
#include "register_list_arm32.h"
#include "instruction.h"
#define DECODE_OFFSET(bits, ext) signExtend32(bits + ext, COMBINE(get()->imm##bits, 0, ext))
#define ENCODE_OFFSET(bits, ext) get()->imm##bits = TruncateToUint##bits(offset >> ext)
#define CODE_OFFSET(I) I->offset + I->instType() == A32 ? 2 * 4 : 2 * 2
using namespace SandHook::RegistersA32;
namespace SandHook {
namespace AsmA32 {
enum Sign { Plus, Minus };
class MemOperand {
public:
explicit MemOperand()
: rn(&UnknowRegiser), rm(&UnknowRegiser), offset(0), addr_mode(Offset) {}
explicit MemOperand(RegisterA32* rn, S32 offset = 0, AddrMode am = Offset)
: rn(rn), rm(&UnknowRegiser), offset(offset), addr_mode(am) {}
explicit MemOperand(RegisterA32* rn, RegisterA32* rm, AddrMode am = Offset)
: rn(rn), rm(rm), shift(LSL), shift_imm(0), addr_mode(am) {
}
explicit MemOperand(RegisterA32* rn, RegisterA32* rm, Shift shift, int shift_imm, AddrMode am = Offset)
: rn(rn), rm(rm), shift(shift), shift_imm(shift_imm & 31), addr_mode(am) {
}
// =====
bool IsImmediateOffset() const { return (addr_mode == Offset); }
bool IsRegisterOffset() const { return (addr_mode == Offset); }
bool IsPreIndex() const { return addr_mode == PreIndex; }
bool IsPostIndex() const { return addr_mode == PostIndex; }
public:
RegisterA32* rn; // base
RegisterA32* rm; // register offset
S32 offset; // valid if rm_ == no_reg
Shift shift;
Sign sign;
int shift_imm; // valid if rm_ != no_reg && rs_ == no_reg
AddrMode addr_mode; // bits P, U, and W
};
class RegisterList {
public:
RegisterList() : list_(0) {}
RegisterList(RegisterA32& reg) // NOLINT(runtime/explicit)
: list_(RegisterToList(reg)) {}
RegisterList(RegisterA32& reg1, RegisterA32& reg2)
: list_(RegisterToList(reg1) | RegisterToList(reg2)) {}
RegisterList(RegisterA32& reg1, RegisterA32& reg2, RegisterA32& reg3)
: list_(RegisterToList(reg1) | RegisterToList(reg2) |
RegisterToList(reg3)) {}
RegisterList(RegisterA32& reg1, RegisterA32& reg2, RegisterA32& reg3, RegisterA32& reg4)
: list_(RegisterToList(reg1) | RegisterToList(reg2) |
RegisterToList(reg3) | RegisterToList(reg4)) {}
explicit RegisterList(U16 list) : list_(list) {}
U16 GetList() const { return list_; }
void SetList(U16 list) { list_ = list; }
bool Includes(RegisterA32& reg) const {
return (list_ & RegisterToList(reg)) != 0;
}
void Combine(RegisterList& other) { list_ |= other.GetList(); }
void Combine(RegisterA32& reg) { list_ |= RegisterToList(reg); }
void Remove(RegisterList& other) { list_ &= ~other.GetList(); }
void Remove(RegisterA32& reg) { list_ &= ~RegisterToList(reg); }
bool Overlaps(RegisterList& other) const {
return (list_ & other.list_) != 0;
}
bool IsR0toR7orPC() const {
// True if all the registers from the list are not from r8-r14.
return (list_ & 0x7f00) == 0;
}
bool IsR0toR7orLR() const {
// True if all the registers from the list are not from r8-r13 nor from r15.
return (list_ & 0xbf00) == 0;
}
bool IsEmpty() const { return list_ == 0; }
static RegisterList Union(const RegisterList& list_1,
const RegisterList& list_2) {
return RegisterList(list_1.list_ | list_2.list_);
}
static RegisterList Union(const RegisterList& list_1,
const RegisterList& list_2,
const RegisterList& list_3) {
return Union(list_1, Union(list_2, list_3));
}
static RegisterList Union(const RegisterList& list_1,
const RegisterList& list_2,
const RegisterList& list_3,
const RegisterList& list_4) {
return Union(Union(list_1, list_2), Union(list_3, list_4));
}
static RegisterList Intersection(const RegisterList& list_1,
const RegisterList& list_2) {
return RegisterList(list_1.list_ & list_2.list_);
}
static RegisterList Intersection(const RegisterList& list_1,
const RegisterList& list_2,
const RegisterList& list_3) {
return Intersection(list_1, Intersection(list_2, list_3));
}
static RegisterList Intersection(const RegisterList& list_1,
const RegisterList& list_2,
const RegisterList& list_3,
const RegisterList& list_4) {
return Intersection(Intersection(list_1, list_2),
Intersection(list_3, list_4));
}
private:
static U16 RegisterToList(RegisterA32& reg) {
if (reg.getCode() == UnknowRegiser.getCode()) {
return 0;
} else {
return static_cast<U16>(UINT16_C(1) << reg.getCode());
}
}
// Bitfield representation of all registers in the list
// (1 for r0, 2 for r1, 4 for r2, ...).
U16 list_;
};
inline uint32_t GetRegisterListEncoding(const RegisterList& registers,
int first,
int count) {
return (registers.GetList() >> first) & ((1 << count) - 1);
}
inline bool isThumbCode(Addr codeAddr) {
return (codeAddr & 0x1) == 0x1;
}
inline bool isThumb32(InstT16 code) {
return ((code & 0xF000) == 0xF000) || ((code & 0xF800) == 0xE800);
}
inline void* getThumbCodeAddress(void* code) {
Addr addr = reinterpret_cast<Addr>(code) & (~0x1);
return reinterpret_cast<void*>(addr);
}
inline void* getThumbPC(void* code) {
Addr addr = reinterpret_cast<Addr>(code) & (~0x1);
return reinterpret_cast<void*>(addr + 1);
}
std::ostream& operator<<(std::ostream& os, RegisterList registers);
}
}
#endif //SANDHOOK_ARM32_BASE_H
//
// Created by swift on 2019/5/12.
//
#include "inst_arm32.h"
//// STR IMM
//A64_STR_IMM::A64_STR_IMM() {}
//
//A64_STR_IMM::A64_STR_IMM(STRUCT_A64(STR_IMM) *inst) : InstructionA64(inst) {
// decode(inst);
//}
//
//A64_STR_IMM::A64_STR_IMM(RegisterA64 &rt, const MemOperand &operand) : rt(&rt), operand(operand) {}
//
//A64_STR_IMM::A64_STR_IMM(Condition condition, RegisterA64 &rt, const MemOperand &operand)
// : condition(condition), rt(&rt), operand(operand) {}
//
//AddrMode A64_STR_IMM::decodeAddrMode() {
// if (get()->P == 1 && get()->W == 0) {
// return Offset;
// } else if (get()->P == 0 && get()->W == 0) {
// return PostIndex;
// } else if (get()->P == 1 && get()->W == 1) {
// return PreIndex;
// } else {
// valid = false;
// return NonAddrMode;
// }
//}
//
//void A64_STR_IMM::decode(STRUCT_A64(STR_IMM) *inst) {
// imm32 = zeroExtend32(12, inst->imm12);
// condition = Condition(inst->cond);
// operand.addr_mode = decodeAddrMode();
// index = inst->P == 1;
// wback = inst->P == 1 || inst->W == 0;
// add = inst->U == 0;
// rt = XReg(static_cast<U8>(inst->rt));
// operand.base = XReg(static_cast<U8>(inst->rn));
// operand.offset = add ? imm32 : -imm32;
//}
//
//
//void A64_STR_IMM::assembler() {
// INST_DCHECK(condition, Condition::nv)
//
//}
\ No newline at end of file
//
// Created by swift on 2019/5/12.
//
#ifndef SANDHOOK_NH_INST_ARM32_H
#define SANDHOOK_NH_INST_ARM32_H
namespace SandHook {
namespace Asm {
// class INST_A64(STR_IMM) : public InstructionA64<STRUCT_A64(STR_IMM)> {
// public:
// A64_STR_IMM();
//
// A64_STR_IMM(STRUCT_A64(STR_IMM) *inst);
//
// A64_STR_IMM(RegisterA64 &rt, const MemOperand &operand);
//
// A64_STR_IMM(Condition condition, RegisterA64 &rt, const MemOperand &operand);
//
// DEFINE_IS_EXT(STR_IMM, TEST_INST_FIELD(opcode, OPCODE_A64(STR_IMM)) && TEST_INST_FIELD(unkown1_0, 0) && TEST_INST_FIELD(unkown2_0, 0))
//
// inline U32 instCode() override {
// return STR_x;
// }
//
// void decode(STRUCT_A64(STR_IMM) *inst) override;
//
// void assembler() override;
//
// AddrMode getAddrMode() {
// return operand.addr_mode;
// }
//
// private:
// AddrMode decodeAddrMode();
//
// public:
// Condition condition = Condition::al;
// RegisterA64* rt;
// MemOperand operand = MemOperand(nullptr);
// private:
// bool wback;
// U32 imm32;
// bool add;
// bool index;
//};
}
}
#endif //SANDHOOK_NH_INST_ARM32_H
//
// Created by swift on 2019/5/16.
//
#ifndef SANDHOOK_INST_CODE_ARM32_H
#define SANDHOOK_INST_CODE_ARM32_H
enum class InstCodeA32 {
};
enum class InstCodeT16 {
UNKNOW,
BASE_SASMC,
DATA_PROC,
SPDIABE,
MISC,
B,
B_COND,
BX_BLX,
CBZ_CBNZ,
LDR_LIT,
ADD_IMM_RDN,
//rn = pc
ADR,
ADD_REG,
CMP_REG,
CMP_REG_EXT,
MOV_IMM,
MOV_REG,
POP,
PUSH
};
enum class InstCodeT32 {
UNKNOW,
B32,
LDR_LIT,
LDR_IMM,
LDR_UIMM,
MOV_MOVT_IMM
};
#endif //SANDHOOK_INST_CODE_ARM32_H
//
// Created by swift on 2019/5/12.
//
#ifndef SANDHOOK_NH_INST_STRUCT_ARM32_H
#define SANDHOOK_NH_INST_STRUCT_ARM32_H
#include "instruction.h"
#define STRUCT_A32(X) A32_STRUCT_##X
#define OPCODE_A32(X) A32_OPCODE_##X
#define DEFINE_OPCODE(X, V) const U32 OPCODE_A32(X) = V;
#define DEFINE_STRUCT_A32(X) struct STRUCT_A32(X) : public Base
DEFINE_OPCODE(STR_IMM, 0b010)
DEFINE_STRUCT_A32(STR_IMM) {
InstA64 imm12:12;
InstA64 rt:4;
InstA64 rn:4;
InstA64 unkown2_0:1;
InstA64 W:1;
InstA64 unkown1_0:1;
InstA64 U:1;
InstA64 P:1;
InstA64 opcode:3;
InstA64 cond:4;
};
#endif //SANDHOOK_NH_INST_STRCUT_ARM32_H
//
// Created by swift on 2019/5/12.
//
#ifndef SANDHOOK_NH_INST_STRUCT_T16_H
#define SANDHOOK_NH_INST_STRUCT_T16_H
#include "instruction.h"
#include "inst_code_arm32.h"
#define STRUCT_T16(X) T16_STRUCT_##X
#define OPCODE_T16(X) T16_OPCODE_##X
#define DEFINE_OPCODE_T16(X, V) const U32 OPCODE_T16(X) = V;
#define DEFINE_STRUCT_T16(X) struct STRUCT_T16(X) : public Base
#define DEFINE_STRCUT_BASE_T16(w_base, w_op) \
InstT16 opcode:w_op; \
InstT16 opcode_base:w_base;
//Shift (immediate), add, subtract, move, and compare
//opcode_base == 0b00
DEFINE_OPCODE_T16(BASE_SASMC, 0b00)
//Data-processing
DEFINE_OPCODE_T16(DATA_PROC, 0b010000)
DEFINE_OPCODE_T16(SPDIABE, 0b010001)
DEFINE_OPCODE_T16(MISC, 0b1011)
#define DATA_PROC_FIELDS DEFINE_STRCUT_BASE_T16(6, 4)
#define T16_REG_WIDE 3
//unknow inst
DEFINE_STRUCT_T16(UNKNOW) {
InstT16 raw;
};
DEFINE_OPCODE_T16(B, 0b11100)
DEFINE_STRUCT_T16(B) {
InstT16 imm11:11;
InstT16 opcode:5;
};
DEFINE_OPCODE_T16(B_COND, 0b1101)
DEFINE_STRUCT_T16(B_COND) {
InstT16 imm8:8;
InstT16 cond:4;
InstT16 opcode:4;
};
DEFINE_OPCODE_T16(BX_BLX_1, 0b01000111)
DEFINE_OPCODE_T16(BX_BLX_2, 0b000)
DEFINE_STRUCT_T16(BX_BLX) {
InstT16 opcode2:3;
InstT16 rm:4;
InstT16 op:1;
InstT16 opcode1:8;
};
DEFINE_OPCODE_T16(CBZ_CBNZ_1, 0b1011)
DEFINE_OPCODE_T16(CBZ_CBNZ_2, 0b0)
DEFINE_OPCODE_T16(CBZ_CBNZ_3, 0b1)
DEFINE_STRUCT_T16(CBZ_CBNZ) {
InstT16 rn:T16_REG_WIDE;
InstT16 imm5:5;
InstT16 opcode3:1;
InstT16 i:1;
InstT16 opcode2:1;
InstT16 op:1;
InstT16 opcode1:4;
};
DEFINE_OPCODE_T16(LDR_LIT, 0b01001)
DEFINE_STRUCT_T16(LDR_LIT) {
InstT16 imm8:8;
InstT16 rt:T16_REG_WIDE;
InstT16 opcode:5;
};
DEFINE_OPCODE_T16(ADD_IMM_RDN, 0b00110)
DEFINE_STRUCT_T16(ADD_IMM_RDN) {
InstT16 imm8:8;
InstT16 rdn:T16_REG_WIDE;
InstT16 opcode:5;
};
DEFINE_OPCODE_T16(ADR, 0b10100)
DEFINE_STRUCT_T16(ADR) {
InstT16 imm8:8;
InstT16 rd:T16_REG_WIDE;
InstT16 opcode:5;
};
DEFINE_OPCODE_T16(CMP_REG, 0b1010)
DEFINE_STRUCT_T16(CMP_REG) {
InstT16 rn:T16_REG_WIDE;
InstT16 rm:T16_REG_WIDE;
DATA_PROC_FIELDS
};
DEFINE_OPCODE_T16(CMP_REG_EXT, 0b1010)
DEFINE_STRUCT_T16(CMP_REG_EXT) {
InstT16 rn:4;
InstT16 rm:4;
InstT16 N:1;
InstT16 opcode:8;
};
DEFINE_OPCODE_T16(MOV_REG, 0b10)
DEFINE_STRUCT_T16(MOV_REG) {
InstT16 rd:T16_REG_WIDE;
InstT16 rm:4;
InstT16 D:1;
DEFINE_STRCUT_BASE_T16(6, 2)
};
DEFINE_OPCODE_T16(MOV_IMM, 0b00100)
DEFINE_STRUCT_T16(MOV_IMM) {
InstT16 imm8:8;
InstT16 rd:T16_REG_WIDE;
InstT16 opcode:5;
};
DEFINE_OPCODE_T16(ADD_REG, 0b0001100)
DEFINE_STRUCT_T16(ADD_REG) {
InstT16 rd:T16_REG_WIDE;
InstT16 rn:T16_REG_WIDE;
InstT16 rm:T16_REG_WIDE;
InstT16 opcode:7;
};
DEFINE_OPCODE_T16(POP, 0b1011110)
DEFINE_STRUCT_T16(POP) {
InstT16 regs:8;
InstT16 P:1;
InstT16 opcode:7;
};
DEFINE_OPCODE_T16(PUSH, 0b1011010)
DEFINE_STRUCT_T16(PUSH) {
InstT16 regs:8;
InstT16 M:1;
InstT16 opcode:7;
};
#endif //SANDHOOK_NH_INST_STRUCT_T16_H
//
// Created by swift on 2019/5/12.
//
#ifndef SANDHOOK_NH_INST_STRUCT_T32_H
#define SANDHOOK_NH_INST_STRUCT_T32_H
#include "instruction.h"
#define STRUCT_T32(X) T32_STRUCT_##X
#define OPCODE_T32(X) T32_OPCODE_##X
#define DEFINE_OPCODE_T32(X, V) const U32 OPCODE_T32(X) = V;
#define DEFINE_STRUCT_T32(X) struct STRUCT_T32(X) : public Base
#define T32_REG_WIDE 4
//unknow inst
DEFINE_STRUCT_T32(UNKNOW) {
InstT32 raw;
};
DEFINE_OPCODE_T32(B32, 0b11110)
DEFINE_STRUCT_T32(B32) {
InstT32 imm10:10;
InstT32 S:1;
InstT32 opcode:5;
InstT32 imm11:11;
InstT32 J2:1;
InstT32 X:1;
InstT32 J1:1;
InstT32 op:2;
};
DEFINE_OPCODE_T32(LDR_LIT, 0b1111100)
DEFINE_STRUCT_T32(LDR_LIT) {
InstT32 op:7;
InstT32 U:1;
InstT32 S:1;
InstT32 opcode:7;
InstT32 imm12:12;
InstT32 rt:T32_REG_WIDE;
};
//ldr imm T3
DEFINE_OPCODE_T32(LDR_UIMM, 0b111110001101)
DEFINE_STRUCT_T32(LDR_UIMM) {
InstT32 rn:T32_REG_WIDE;
InstT32 opcode:12;
InstT32 imm12:12;
InstT32 rt:T32_REG_WIDE;
};
//ldr imm T4
DEFINE_OPCODE_T32(LDR_IMM_1, 0b11111000)
DEFINE_OPCODE_T32(LDR_IMM_2, 0b1)
DEFINE_STRUCT_T32(LDR_IMM) {
InstT32 rn:T32_REG_WIDE;
InstT32 op:4;
InstT32 opcode1:8;
InstT32 imm8:8;
InstT32 W:1;
InstT32 U:1;
InstT32 P:1;
InstT32 opcode2:1;
InstT32 rt:T32_REG_WIDE;
};
DEFINE_OPCODE_T32(MOV_MOVT_IMM_1, 0b11110)
DEFINE_OPCODE_T32(MOV_MOVT_IMM_2, 0b0)
DEFINE_STRUCT_T32(MOV_MOVT_IMM) {
InstT32 imm4:4;
InstT32 op:6;
InstT32 i:1;
InstT32 opcode1:5;
InstT32 imm8:8;
InstT32 rd:4;
InstT32 imm3:3;
InstT32 opcode2:1;
};
#endif //SANDHOOK_NH_INST_STRUCT_T32_H
//
// Created by swift on 2019/5/16.
//
#include "inst_t16.h"
#include "arm32_base.h"
#include "register_list_arm32.h"
#define SET_BASE_OPCODE(X) get()->opcode_base = OPCODE_T16(X)
#define SET_OPCODE(X) get()->opcode = OPCODE_T16(X)
#define SET_OPCODE_MULTI(X, INDEX) get()->opcode##INDEX = OPCODE_T16(X##_##INDEX)
using namespace SandHook::AsmA32;
using namespace SandHook::RegistersA32;
//Unknow
T16_UNKNOW::T16_UNKNOW(STRUCT_T16(UNKNOW) &inst) : InstructionT16(&inst) {
decode(&inst);
}
void T16_UNKNOW::decode(T16_STRUCT_UNKNOW *inst) {
inst_backup = *inst;
}
void T16_UNKNOW::assembler() {
set(inst_backup);
}
//B
T16_B::T16_B() {}
T16_B::T16_B(T16_STRUCT_B *inst) : T16_INST_PC_REL(inst) {
decode(inst);
}
T16_B::T16_B(Off offset) : offset(offset) {}
T16_B::T16_B(Label &label) {
bindLabel(label);
}
Off T16_B::getImmPCOffset() {
return DECODE_OFFSET(11, 1);
}
void T16_B::decode(T16_STRUCT_B *inst) {
offset = getImmPCOffset();
}
void T16_B::assembler() {
SET_OPCODE(B);
DECODE_OFFSET(11, 1);
}
void T16_B::onOffsetApply(Off offset) {
this->offset = offset;
DECODE_OFFSET(11, 1);
}
//B Cond
T16_B_COND::T16_B_COND() {}
T16_B_COND::T16_B_COND(STRUCT_T16(B_COND) *inst) : T16_INST_PC_REL(inst) {
decode(inst);
}
T16_B_COND::T16_B_COND(Condition condition, Off offset) : condition(condition), offset(offset) {}
T16_B_COND::T16_B_COND(Condition condition, Label &label) {
bindLabel(label);
}
void T16_B_COND::decode(STRUCT_T16(B_COND) *inst) {
DECODE_COND;
offset = getImmPCOffset();
}
void T16_B_COND::assembler() {
SET_OPCODE(B_COND);
ENCODE_COND;
ENCODE_OFFSET(8, 1);
}
void T16_B_COND::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(8, 1);
}
Off T16_B_COND::getImmPCOffset() {
return DECODE_OFFSET(8, 1);
}
//BX BLX
T16_BX_BLX::T16_BX_BLX(T16_BX_BLX::OP op, RegisterA32 &rm) : op(op), rm(&rm) {}
T16_BX_BLX::T16_BX_BLX(T16_STRUCT_BX_BLX *inst) : T16_INST_PC_REL(inst) {
decode(inst);
}
void T16_BX_BLX::decode(STRUCT_T16(BX_BLX) *inst) {
DECODE_OP;
DECODE_RM(Reg);
}
void T16_BX_BLX::assembler() {
SET_OPCODE_MULTI(BX_BLX, 1);
SET_OPCODE_MULTI(BX_BLX, 2);
ENCODE_OP;
ENCODE_RM;
}
//CBZ CBNZ
T16_CBZ_CBNZ::T16_CBZ_CBNZ(T16_STRUCT_CBZ_CBNZ *inst) : T16_INST_PC_REL(inst) {
decode(inst);
}
T16_CBZ_CBNZ::T16_CBZ_CBNZ(T16_CBZ_CBNZ::OP op, Off offset, RegisterA32 &rn) : op(op), offset(offset),
rn(&rn) {}
T16_CBZ_CBNZ::T16_CBZ_CBNZ(T16_CBZ_CBNZ::OP op, Label& label, RegisterA32 &rn) : op(op),
rn(&rn) {
bindLabel(label);
}
Off T16_CBZ_CBNZ::getImmPCOffset() {
return COMBINE(get()->i, get()->imm5, 5) << 2;
}
void T16_CBZ_CBNZ::decode(T16_STRUCT_CBZ_CBNZ *inst) {
offset = getImmPCOffset();
DECODE_RN(Reg);
DECODE_OP;
}
void T16_CBZ_CBNZ::assembler() {
SET_OPCODE_MULTI(CBZ_CBNZ, 1);
SET_OPCODE_MULTI(CBZ_CBNZ, 2);
SET_OPCODE_MULTI(CBZ_CBNZ, 3);
ENCODE_OP;
ENCODE_RN;
ENCODE_OFFSET(5, 2);
}
void T16_CBZ_CBNZ::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(5, 2);
}
//LDR_LIT
T16_LDR_LIT::T16_LDR_LIT(T16_STRUCT_LDR_LIT *inst) : T16_INST_PC_REL(inst) {
decode(inst);
}
T16_LDR_LIT::T16_LDR_LIT(Off offset, RegisterA32 &rt) : offset(offset), rt(&rt) {
}
Off T16_LDR_LIT::getImmPCOffset() {
return get()->imm8 << 2;
}
Addr T16_LDR_LIT::getImmPCOffsetTarget() {
return ALIGN((Addr) getPC() + offset, 4);
}
void T16_LDR_LIT::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(8, 2);
}
void T16_LDR_LIT::decode(T16_STRUCT_LDR_LIT *inst) {
DECODE_RT(Reg);
offset = getImmPCOffset();
}
void T16_LDR_LIT::assembler() {
SET_OPCODE(LDR_LIT);
ENCODE_RT;
ENCODE_OFFSET(8, 2);
}
//ADD IMM RD = RN
T16_ADD_IMM_RDN::T16_ADD_IMM_RDN(T16_STRUCT_ADD_IMM_RDN *inst) : InstructionT16(inst) {
decode(inst);
}
T16_ADD_IMM_RDN::T16_ADD_IMM_RDN(RegisterA32 *rdn, U8 imm8) : rdn(rdn), imm8(imm8) {}
void T16_ADD_IMM_RDN::decode(T16_STRUCT_ADD_IMM_RDN *inst) {
rdn = Reg(inst->rdn);
imm8 = inst->imm8;
}
void T16_ADD_IMM_RDN::assembler() {
SET_OPCODE(ADD_IMM_RDN);
get()->imm8 = imm8;
get()->rdn = rdn->getCode();
}
//ADR
T16_ADR::T16_ADR(T16_STRUCT_ADR *inst) : T16_INST_PC_REL(inst) {
decode(inst);
}
T16_ADR::T16_ADR(RegisterA32 &rd, Off offset) : rd(&rd), offset(offset) {}
T16_ADR::T16_ADR(RegisterA32 &rd, Label &label) : rd(&rd) {
bindLabel(label);
}
Off T16_ADR::getImmPCOffset() {
return COMBINE(get()->imm8, 0 ,2);
}
Addr T16_ADR::getImmPCOffsetTarget() {
return RoundDown((Addr) getPC() + offset, 4);
}
void T16_ADR::onOffsetApply(Off offset) {
this->offset = offset;
get()->imm8 = (U32)offset >> 2;
}
void T16_ADR::decode(T16_STRUCT_ADR *inst) {
offset = getImmPCOffset();
DECODE_RD(Reg);
}
void T16_ADR::assembler() {
SET_OPCODE(ADR);
ENCODE_RD;
get()->imm8 = (U32)offset >> 2;
}
T16_CMP_REG::T16_CMP_REG() {}
T16_CMP_REG::T16_CMP_REG(T16_STRUCT_CMP_REG *inst) : InstructionT16(inst) {
decode(inst);
}
T16_CMP_REG::T16_CMP_REG(RegisterA32 &rm, RegisterA32 &rn) : rm(&rm), rn(&rn) {}
void T16_CMP_REG::decode(T16_STRUCT_CMP_REG *inst) {
DECODE_RM(Reg);
DECODE_RN(Reg);
}
void T16_CMP_REG::assembler() {
SET_BASE_OPCODE(DATA_PROC);
SET_OPCODE(CMP_REG);
ENCODE_RM;
ENCODE_RN;
}
//MOV REG
T16_MOV_REG::T16_MOV_REG(T16_STRUCT_MOV_REG *inst) : InstructionT16(inst) {
decode(inst);
}
T16_MOV_REG::T16_MOV_REG(RegisterA32 &rd, RegisterA32 &rm) : rm(&rm), rd(&rd) {
}
void T16_MOV_REG::decode(T16_STRUCT_MOV_REG *inst) {
DECODE_RM(Reg);
rd = Reg(static_cast<U8>(COMBINE(inst->D, inst->rd, 3)));
}
void T16_MOV_REG::assembler() {
SET_BASE_OPCODE(DATA_PROC);
SET_OPCODE(MOV_REG);
ENCODE_RM;
get()->rd = BITS(rd->getCode(), 0, 2);
get()->D = BIT(rd->getCode(), 3);
}
bool T16_MOV_REG::pcRelate() {
return rd == &PC || rm == &PC;
}
T16_ADD_REG::T16_ADD_REG() {}
T16_ADD_REG::T16_ADD_REG(T16_STRUCT_ADD_REG *inst) : InstructionT16(inst) {
decode(inst);
}
T16_ADD_REG::T16_ADD_REG(RegisterA32 *rd, RegisterA32 *rn, RegisterA32 *rm) : rd(rd), rn(rn),
rm(rm) {}
void T16_ADD_REG::decode(T16_STRUCT_ADD_REG *inst) {
DECODE_RD(Reg);
DECODE_RN(Reg);
DECODE_RM(Reg);
}
void T16_ADD_REG::assembler() {
SET_OPCODE(ADD_REG);
INST_ASSERT(rd->getCode() > 7);
INST_ASSERT(rn->getCode() > 7);
INST_ASSERT(rm->getCode() > 7);
ENCODE_RD;
ENCODE_RN;
ENCODE_RM;
}
T16_CMP_REG_EXT::T16_CMP_REG_EXT(T16_STRUCT_CMP_REG_EXT *inst) : InstructionT16(inst) {
decode(inst);
}
T16_CMP_REG_EXT::T16_CMP_REG_EXT(RegisterA32 &rn, RegisterA32 &rm) : rn(&rn), rm(&rm) {}
void T16_CMP_REG_EXT::decode(T16_STRUCT_CMP_REG_EXT *inst) {
rn = Reg(COMBINE(inst->N, inst->rn, 3));
DECODE_RM(Reg);
}
void T16_CMP_REG_EXT::assembler() {
SET_OPCODE(CMP_REG_EXT);
ENCODE_RM;
get()->rn = BITS(rn->getCode(), 0, 2);
get()->N = BIT(rn->getCode(), 3);
}
//POP
T16_POP::T16_POP(T16_STRUCT_POP *inst) : InstructionT16(inst) {
decode(inst);
}
T16_POP::T16_POP(const RegisterList &registerList) : registerList(registerList) {}
void T16_POP::decode(T16_STRUCT_POP *inst) {
registerList.SetList(COMBINE(inst->P << 7, inst->regs, 8));
}
void T16_POP::assembler() {
SET_OPCODE(POP);
U16 regs = registerList.GetList();
get()->regs = BITS(regs, 0, 7);
get()->P = BIT(regs, 15);
}
//PUSH
T16_PUSH::T16_PUSH(T16_STRUCT_PUSH *inst) : InstructionT16(inst) {
decode(inst);
}
T16_PUSH::T16_PUSH(const RegisterList &registerList) : registerList(registerList) {}
void T16_PUSH::decode(T16_STRUCT_PUSH *inst) {
registerList.SetList(COMBINE(inst->M << 6, inst->regs, 8));
}
void T16_PUSH::assembler() {
SET_OPCODE(PUSH);
U16 regs = registerList.GetList();
get()->regs = BITS(regs, 0, 7);
get()->M = BIT(regs, 14);
}
\ No newline at end of file
//
// Created by swift on 2019/5/16.
//
#ifndef SANDHOOK_INST_T16_H
#define SANDHOOK_INST_T16_H
#include "arm_base.h"
#include "register_list_arm32.h"
#include "inst_struct_t16.h"
#include "inst_code_arm32.h"
#include "arm32_base.h"
#define INST_T16(X) T16_##X
#define IS_OPCODE_T16(RAW, OP) INST_T16(OP)::is(RAW)
#define DEFINE_IS_EXT(X, COND) \
inline static bool is(InstT16& inst) { \
union { \
InstT16 raw; \
STRUCT_T16(X) inst; \
} inst_test; \
inst_test.raw = inst; \
return COND; \
}
#define DEFINE_IS(X) DEFINE_IS_EXT(X, TEST_INST_FIELD(opcode,OPCODE_T16(X)))
#define TEST_INST_FIELD(F, V) inst_test.inst.F == V
#define INST_FIELD(F) inst_test.inst.F
#define TEST_INST_OPCODE(X, INDEX) inst_test.inst.opcode##INDEX == OPCODE_T16(X##_##INDEX)
#define DEFINE_INST_CODE(X) \
inline U32 instCode() override { \
return ENUM_VALUE(InstCodeT16, InstCodeT16::X); \
}
using namespace SandHook::RegistersA32;
namespace SandHook {
namespace AsmA32 {
template<typename Inst>
class InstructionT16 : public Instruction<Inst> {
public:
InstructionT16() {}
InstructionT16(Inst *inst) : Instruction<Inst>(inst) {}
Inst mask(Inst raw) {
return raw & *(this->get());
}
U32 size() override {
return 2;
}
void *getPC() override {
return reinterpret_cast<void *>((Addr) Instruction<Inst>::getPC() + 2 * 2);
}
Addr getVPC() override {
return Instruction<Inst>::getVPC() + 2 * 2;
}
static inline S32 signExtend32(unsigned int bits, U32 value) {
return ExtractSignedBitfield32(bits - 1, 0, value);
}
InstType instType() override {
return thumb16;
}
Arch arch() override {
return arm32;
}
};
template<typename Inst>
class T16_INST_PC_REL : public InstructionT16<Inst> {
public:
T16_INST_PC_REL() {};
T16_INST_PC_REL(Inst *inst) : InstructionT16<Inst>(inst) {};
virtual Off getImmPCOffset() {
return 0;
};
virtual Addr getImmPCOffsetTarget() {
return (Addr) this->getPC() + getImmPCOffset();
};
inline bool pcRelate() override {
return true;
};
};
class INST_T16(UNKNOW) : public InstructionT16<STRUCT_T16(UNKNOW)> {
public:
T16_UNKNOW(STRUCT_T16(UNKNOW) &inst);
DEFINE_INST_CODE(UNKNOW)
inline bool unknow() override {
return true;
}
void decode(T16_STRUCT_UNKNOW *inst) override;
void assembler() override;
private:
STRUCT_T16(UNKNOW) inst_backup;
};
class INST_T16(B) : public T16_INST_PC_REL<STRUCT_T16(B)> {
public:
T16_B();
T16_B(STRUCT_T16(B) *inst);
T16_B(Off offset);
T16_B(Label &label);
DEFINE_IS(B)
DEFINE_INST_CODE(B)
void onOffsetApply(Off offset) override;
Off getImmPCOffset() override;
void decode(STRUCT_T16(B) *inst) override;
void assembler() override;
public:
Off offset;
};
class INST_T16(B_COND) : public T16_INST_PC_REL<STRUCT_T16(B_COND)> {
public:
T16_B_COND();
T16_B_COND(STRUCT_T16(B_COND) *inst);
T16_B_COND(Condition condition, Off offset);
T16_B_COND(Condition condition, Label &label);
DEFINE_IS_EXT(B_COND, TEST_INST_FIELD(opcode, OPCODE_T16(B_COND)) &&
INST_FIELD(cond) != 0b1110 && INST_FIELD(cond) != 0b1111)
DEFINE_INST_CODE(B_COND)
Off getImmPCOffset() override;
void onOffsetApply(Off offset) override;
void decode(STRUCT_T16(B_COND) *inst) override;
void assembler() override;
public:
Condition condition;
Off offset;
};
class INST_T16(BX_BLX) : public T16_INST_PC_REL<STRUCT_T16(BX_BLX)> {
public:
enum OP {
BX = 0b0,
BLX = 0b1
};
T16_BX_BLX(T16_STRUCT_BX_BLX *inst);
T16_BX_BLX(OP op, RegisterA32 &rm);
DEFINE_IS_EXT(BX_BLX, TEST_INST_OPCODE(BX_BLX, 1) && TEST_INST_OPCODE(BX_BLX, 2))
DEFINE_INST_CODE(BX_BLX)
void decode(T16_STRUCT_BX_BLX *inst) override;
void assembler() override;
public:
OP op;
RegisterA32 *rm;
};
class INST_T16(CBZ_CBNZ) : public T16_INST_PC_REL<STRUCT_T16(CBZ_CBNZ)> {
public:
enum OP {
CBZ = 0b0,
CBNZ = 0b1
};
T16_CBZ_CBNZ(T16_STRUCT_CBZ_CBNZ *inst);
T16_CBZ_CBNZ(OP op, Off offset, RegisterA32 &rn);
T16_CBZ_CBNZ(OP op, Label &label, RegisterA32 &rn);
DEFINE_IS_EXT(CBZ_CBNZ,
TEST_INST_OPCODE(CBZ_CBNZ, 1) && TEST_INST_OPCODE(CBZ_CBNZ, 2) &&
TEST_INST_OPCODE(CBZ_CBNZ, 3))
DEFINE_INST_CODE(CBZ_CBNZ)
void onOffsetApply(Off offset) override;
Off getImmPCOffset() override;
void decode(T16_STRUCT_CBZ_CBNZ *inst) override;
void assembler() override;
public:
OP op;
Off offset;
RegisterA32 *rn;
};
class INST_T16(LDR_LIT) : public T16_INST_PC_REL<STRUCT_T16(LDR_LIT)> {
public:
T16_LDR_LIT(T16_STRUCT_LDR_LIT *inst);
T16_LDR_LIT(Off offset, RegisterA32 &rt);
DEFINE_IS(LDR_LIT)
DEFINE_INST_CODE(LDR_LIT)
Addr getImmPCOffsetTarget() override;
Off getImmPCOffset() override;
void onOffsetApply(Off offset) override;
void decode(T16_STRUCT_LDR_LIT *inst) override;
void assembler() override;
public:
Off offset;
RegisterA32 *rt;
};
class INST_T16(ADD_IMM_RDN) : public InstructionT16<STRUCT_T16(ADD_IMM_RDN)> {
public:
T16_ADD_IMM_RDN(T16_STRUCT_ADD_IMM_RDN *inst);
T16_ADD_IMM_RDN(RegisterA32 *rdn, U8 imm8);
DEFINE_IS(ADD_IMM_RDN)
DEFINE_INST_CODE(ADD_IMM_RDN)
void decode(T16_STRUCT_ADD_IMM_RDN *inst) override;
void assembler() override;
public:
RegisterA32 *rdn;
U8 imm8;
};
class INST_T16(ADR) : public T16_INST_PC_REL<STRUCT_T16(ADR)> {
public:
T16_ADR(T16_STRUCT_ADR *inst);
T16_ADR(RegisterA32 &rd, Off offset);
T16_ADR(RegisterA32 &rd, Label &label);
DEFINE_IS(ADR)
DEFINE_INST_CODE(ADR)
Off getImmPCOffset() override;
Addr getImmPCOffsetTarget() override;
void onOffsetApply(Off offset) override;
void decode(T16_STRUCT_ADR *inst) override;
void assembler() override;
public:
RegisterA32 *rd;
Off offset;
};
class INST_T16(CMP_REG) : public InstructionT16<STRUCT_T16(CMP_REG)> {
public:
T16_CMP_REG();
T16_CMP_REG(T16_STRUCT_CMP_REG *inst);
T16_CMP_REG(RegisterA32 &rm, RegisterA32 &rn);
DEFINE_INST_CODE(CMP_REG)
DEFINE_IS_EXT(CMP_REG, TEST_INST_FIELD(opcode_base, OPCODE_T16(DATA_PROC)) &&
TEST_INST_FIELD(opcode, OPCODE_T16(CMP_REG)))
void decode(T16_STRUCT_CMP_REG *inst) override;
void assembler() override;
public:
RegisterA32 *rm;
RegisterA32 *rn;
};
class INST_T16(MOV_REG) : public InstructionT16<STRUCT_T16(MOV_REG)> {
public:
T16_MOV_REG(T16_STRUCT_MOV_REG *inst);
T16_MOV_REG(RegisterA32 &rd, RegisterA32 &rm);
DEFINE_INST_CODE(MOV_REG)
DEFINE_IS_EXT(MOV_REG, TEST_INST_FIELD(opcode_base, OPCODE_T16(DATA_PROC)) &&
TEST_INST_FIELD(opcode, OPCODE_T16(MOV_REG)))
void decode(T16_STRUCT_MOV_REG *inst) override;
void assembler() override;
bool pcRelate() override;
public:
RegisterA32 *rd;
RegisterA32 *rm;
};
class INST_T16(ADD_REG) : public InstructionT16<STRUCT_T16(ADD_REG)> {
public:
T16_ADD_REG();
T16_ADD_REG(T16_STRUCT_ADD_REG *inst);
T16_ADD_REG(RegisterA32 *rd, RegisterA32 *rn, RegisterA32 *rm);
DEFINE_IS(ADD_REG)
DEFINE_INST_CODE(ADD_REG)
void decode(T16_STRUCT_ADD_REG *inst) override;
void assembler() override;
public:
RegisterA32 *rd;
RegisterA32 *rn;
RegisterA32 *rm;
};
class INST_T16(CMP_REG_EXT) : public InstructionT16<STRUCT_T16(CMP_REG_EXT)> {
public:
T16_CMP_REG_EXT(T16_STRUCT_CMP_REG_EXT *inst);
T16_CMP_REG_EXT(RegisterA32 &rn, RegisterA32 &rm);
DEFINE_IS(CMP_REG_EXT)
DEFINE_INST_CODE(CMP_REG_EXT)
void decode(T16_STRUCT_CMP_REG_EXT *inst) override;
void assembler() override;
public:
RegisterA32 *rn;
RegisterA32 *rm;
};
class INST_T16(POP) : public InstructionT16<STRUCT_T16(POP)> {
public:
T16_POP(T16_STRUCT_POP *inst);
T16_POP(const RegisterList &registerList);
DEFINE_IS(POP)
DEFINE_INST_CODE(POP)
void decode(T16_STRUCT_POP *inst) override;
void assembler() override;
public:
RegisterList registerList;
};
class INST_T16(PUSH) : public InstructionT16<STRUCT_T16(PUSH)> {
public:
T16_PUSH(T16_STRUCT_PUSH *inst);
T16_PUSH(const RegisterList &registerList);
DEFINE_IS(PUSH)
DEFINE_INST_CODE(PUSH)
void decode(T16_STRUCT_PUSH *inst) override;
void assembler() override;
public:
RegisterList registerList;
};
}
}
#undef DEFINE_IS_EXT
#undef DEFINE_IS
#undef TEST_INST_FIELD
#undef TEST_INST_OPCODE
#undef DEFINE_INST_CODE
#endif //SANDHOOK_INST_T16_H
//
// Created by swift on 2019/5/16.
//
#include "inst_t32.h"
#include "inst_struct_t32.h"
#define SET_BASE_OPCODE(X) get()->opcode_base = OPCODE_T32(X)
#define SET_OPCODE(X) get()->opcode = OPCODE_T32(X)
#define SET_OPCODE_MULTI(X, INDEX) get()->opcode##INDEX = OPCODE_T32(X##_##INDEX)
using namespace SandHook::Asm;
using namespace SandHook::AsmA32;
//Unknow
T32_UNKNOW::T32_UNKNOW(STRUCT_T32(UNKNOW) &inst) : InstructionT32(&inst) {
decode(&inst);
}
void T32_UNKNOW::decode(T32_STRUCT_UNKNOW *inst) {
inst_backup = *inst;
}
void T32_UNKNOW::assembler() {
set(inst_backup);
}
T32_B32::T32_B32(T32_STRUCT_B32 *inst) : T32_INST_PC_REL(inst) {
decode(inst);
}
T32_B32::T32_B32(T32_B32::OP op, T32_B32::X x, Off offset) : op(op), x(x), offset(offset) {}
T32_B32::T32_B32(T32_B32::OP op, T32_B32::X x, Label &label) : op(op), x(x) {
bindLabel(label);
}
Off T32_B32::getImmPCOffset() {
U32 S = get()->S;
U32 imm21 = COMBINE(get()->imm10, get()->imm11, 11);
if (get()->X == 0) {
imm21 &= ~(1 << 0);
}
U32 i1 = !(get()->J1 ^ S);
U32 i2 = !(get()->J2 ^ S);
U32 i1i2 = COMBINE(i1, i2, 1);
U32 Si1i2 = COMBINE(-S, i1i2, 2);
return signExtend32(25, COMBINE(Si1i2, imm21, 21) << 1);
}
void T32_B32::decode(T32_STRUCT_B32 *inst) {
DECODE_OP;
x = X(inst->X);
offset = getImmPCOffset();
}
void T32_B32::assembler() {
SET_OPCODE(B32);
ENCODE_OP;
get()->X = x;
U32 imm24 = TruncateToUint25(offset) >> 1;
get()->imm11 = BITS(imm24, 0, 10);
get()->imm10 = BITS(imm24, 11, 20);
if (get()->X == 0) {
get()->imm11 |= (1 << 0);
}
get()->S = BIT(imm24, 23);
U32 i1 = BIT(imm24, 22);
U32 i2 = BIT(imm24, 21);
if (i1 == 1) {
get()->J1 = get()->S;
} else {
get()->J1 = !get()->S;
}
if (i2 == 1) {
get()->J2 = get()->S;
} else {
get()->J2 = !get()->S;
}
}
Addr T32_B32::getImmPCOffsetTarget() {
if (x == arm) {
void* base = reinterpret_cast<void *>(ALIGN((Addr) getPC(), 4));
return offset + reinterpret_cast<Addr>(base);
} else {
return T32_INST_PC_REL::getImmPCOffsetTarget();
}
}
T32_LDR_UIMM::T32_LDR_UIMM(T32_STRUCT_LDR_UIMM *inst) : InstructionT32(inst) {}
T32_LDR_UIMM::T32_LDR_UIMM(RegisterA32 &rt, RegisterA32 &rn, U32 offset) : rt(&rt), rn(&rn),
offset(offset) {}
void T32_LDR_UIMM::decode(T32_STRUCT_LDR_UIMM *inst) {
DECODE_RN(Reg);
DECODE_RT(Reg);
INST_ASSERT(rn == &PC);
offset = inst->imm12;
}
void T32_LDR_UIMM::assembler() {
SET_OPCODE(LDR_UIMM);
ENCODE_RN;
ENCODE_RT;
INST_ASSERT(rn == &PC);
get()->imm12 = offset;
}
T32_LDR_LIT::T32_LDR_LIT() {}
T32_LDR_LIT::T32_LDR_LIT(T32_STRUCT_LDR_LIT *inst) : T32_INST_PC_REL(inst) {
decode(inst);
}
T32_LDR_LIT::T32_LDR_LIT(OP op, S s, RegisterA32 &rt, Off offset) : op(op), s(s), rt(&rt), offset(offset) {}
T32_LDR_LIT::T32_LDR_LIT(OP op, S s, RegisterA32 &rt, Label& label) : op(op), s(s), rt(&rt) {
bindLabel(label);
}
Off T32_LDR_LIT::getImmPCOffset() {
return get()->U == add ? get()->imm12 : -get()->imm12;
}
void T32_LDR_LIT::onOffsetApply(Off offset) {
this->offset = offset;
if (offset >= 0) {
get()->U = add;
get()->imm12 = static_cast<InstT32>(offset);
} else {
get()->U = cmp;
get()->imm12 = static_cast<InstT32>(-offset);
}
}
void T32_LDR_LIT::decode(T32_STRUCT_LDR_LIT *inst) {
DECODE_OP;
DECODE_RT(Reg);
s = S(inst->S);
offset = getImmPCOffset();
}
void T32_LDR_LIT::assembler() {
SET_OPCODE(LDR_LIT);
ENCODE_OP;
ENCODE_RT;
get()->S = s;
if (offset >= 0) {
get()->U = add;
get()->imm12 = static_cast<InstT32>(offset);
} else {
get()->U = cmp;
get()->imm12 = static_cast<InstT32>(-offset);
}
}
T32_MOV_MOVT_IMM::T32_MOV_MOVT_IMM() {}
T32_MOV_MOVT_IMM::T32_MOV_MOVT_IMM(T32_STRUCT_MOV_MOVT_IMM *inst) : InstructionT32(inst) {
decode(inst);
}
T32_MOV_MOVT_IMM::T32_MOV_MOVT_IMM(T32_MOV_MOVT_IMM::OP op, RegisterA32 &rd, U16 imm16) : op(op),
rd(&rd),
imm16(imm16) {}
void T32_MOV_MOVT_IMM::decode(T32_STRUCT_MOV_MOVT_IMM *inst) {
DECODE_OP;
DECODE_RD(Reg);
U16 imm4i = COMBINE(inst->imm4, inst->i, 1);
U16 imm38 = COMBINE(inst->imm3, inst->imm8, 8);
imm16 = COMBINE(imm4i, imm38, 11);
}
void T32_MOV_MOVT_IMM::assembler() {
SET_OPCODE_MULTI(MOV_MOVT_IMM, 1);
SET_OPCODE_MULTI(MOV_MOVT_IMM, 2);
ENCODE_OP;
ENCODE_RD;
get()->imm8 = BITS(imm16, 0, 7);
get()->imm3 = BITS(imm16, 8 ,10);
get()->i = BIT(imm16, 11);
get()->imm4 = BITS(imm16, 12, 15);
}
T32_LDR_IMM::T32_LDR_IMM(T32_STRUCT_LDR_IMM *inst) : InstructionT32(inst) {
decode(inst);
}
T32_LDR_IMM::T32_LDR_IMM(T32_LDR_IMM::OP op, RegisterA32 &rt, const MemOperand &operand) : op(op),
rt(&rt),
operand(operand) {}
void T32_LDR_IMM::decode(T32_STRUCT_LDR_IMM *inst) {
DECODE_OP;
DECODE_RT(Reg);
operand.rn = Reg(static_cast<U8>(inst->rn));
if (inst->P == 1 && inst->U == 0 && inst->W == 0) {
operand.addr_mode = Offset;
} else if (inst->P == 0 && inst->W == 1) {
operand.addr_mode = PostIndex;
} else if (inst->P == 1 && inst->W == 1) {
operand.addr_mode = PreIndex;
} else {
valid = false;
}
operand.offset = inst->U == 0 ? -inst->imm8 : inst->imm8;
}
void T32_LDR_IMM::assembler() {
SET_OPCODE_MULTI(LDR_IMM, 1);
SET_OPCODE_MULTI(LDR_IMM, 2);
ENCODE_OP;
get()->rn = operand.rn->getCode();
if (operand.offset < 0) {
get()->imm8 = static_cast<InstT32>(-operand.offset);
get()->U = 0;
} else {
get()->imm8 = static_cast<InstT32>(operand.offset);
get()->U = 1;
}
switch (operand.addr_mode) {
case Offset:
get()->P = 1;
get()->U = 0;
get()->W = 0;
break;
case PostIndex:
get()->P = 0;
get()->W = 1;
break;
case PreIndex:
get()->P = 1;
get()->W = 1;
break;
default:
valid = false;
}
}
//
// Created by swift on 2019/5/16.
//
#ifndef SANDHOOK_INST_T32_H
#define SANDHOOK_INST_T32_H
#include "arm_base.h"
#include "arm32_base.h"
#include "register_list_arm32.h"
#include "inst_struct_t16.h"
#include "inst_code_arm32.h"
#include "inst_struct_t32.h"
#define INST_T32(X) T32_##X
#define IS_OPCODE_T32(RAW,OP) INST_T32(OP)::is(RAW)
#define DEFINE_IS_EXT(X, COND) \
inline static bool is(InstT32& inst) { \
union { \
InstT32 raw; \
STRUCT_T32(X) inst; \
} inst_test; \
inst_test.raw = inst; \
return COND; \
}
#define DEFINE_IS(X) DEFINE_IS_EXT(X, TEST_INST_FIELD(opcode,OPCODE_T32(X)))
#define TEST_INST_FIELD(F,V) inst_test.inst.F == V
#define INST_FIELD(F) inst_test.inst.F
#define TEST_INST_OPCODE(X, INDEX) inst_test.inst.opcode##INDEX == OPCODE_T32(X##_##INDEX)
#define DEFINE_INST_CODE(X) \
inline U32 instCode() override { \
return ENUM_VALUE(InstCodeT32, InstCodeT32::X); \
}
using namespace SandHook::RegistersA32;
namespace SandHook {
namespace AsmA32 {
template<typename Inst>
class InstructionT32 : public Instruction<Inst> {
public:
InstructionT32() {}
InstructionT32(Inst *inst) : Instruction<Inst>(inst) {}
Inst mask(Inst raw) {
return raw & *(this->get());
}
U32 size() override {
return 4;
}
void *getPC() override {
return reinterpret_cast<void *>((Addr) Instruction<Inst>::getPC() + 2 * 2);
}
Addr getVPC() override {
return Instruction<Inst>::getVPC() + 2 * 2;
}
static inline S32 signExtend32(unsigned int bits, U32 value) {
return ExtractSignedBitfield32(bits - 1, 0, value);
}
InstType instType() override {
return thumb32;
}
Arch arch() override {
return arm32;
}
};
template <typename Inst>
class T32_INST_PC_REL : public InstructionT32<Inst> {
public:
T32_INST_PC_REL() {};
T32_INST_PC_REL(Inst *inst) : InstructionT32<Inst>(inst) {};
virtual Off getImmPCOffset() {
return 0;
};
virtual Addr getImmPCOffsetTarget() {
return (Addr) this->getPC() + getImmPCOffset();
};
inline bool pcRelate() override {
return true;
};
};
class INST_T32(UNKNOW) : public InstructionT32<STRUCT_T32(UNKNOW)> {
public:
T32_UNKNOW(STRUCT_T32(UNKNOW) &inst);
DEFINE_INST_CODE(UNKNOW)
inline bool unknow() override {
return true;
}
void decode(T32_STRUCT_UNKNOW *inst) override;
void assembler() override;
private:
STRUCT_T32(UNKNOW) inst_backup;
};
class INST_T32(B32) : public T32_INST_PC_REL<STRUCT_T32(B32)> {
public:
enum OP {
B = 0b10,
BL = 0b11
};
enum X {
arm = 0b0,
thumb = 0b1
};
T32_B32(T32_STRUCT_B32 *inst);
T32_B32(OP op, X x, Off offset);
T32_B32(OP op, X x, Label& label);
DEFINE_INST_CODE(B32)
DEFINE_IS(B32)
Addr getImmPCOffsetTarget() override;
Off getImmPCOffset() override;
void decode(T32_STRUCT_B32 *inst) override;
void assembler() override;
public:
OP op;
X x;
Off offset;
};
class INST_T32(LDR_UIMM) : public InstructionT32<STRUCT_T32(LDR_UIMM)> {
public:
T32_LDR_UIMM(T32_STRUCT_LDR_UIMM *inst);
T32_LDR_UIMM(RegisterA32 &rt, RegisterA32 &rn, U32 offset);
DEFINE_INST_CODE(LDR_UIMM)
DEFINE_IS(LDR_UIMM)
void decode(T32_STRUCT_LDR_UIMM *inst) override;
void assembler() override;
public:
RegisterA32* rt;
RegisterA32* rn;
U32 offset;
};
class INST_T32(LDR_LIT) : public T32_INST_PC_REL<STRUCT_T32(LDR_LIT)> {
public:
enum OP {
LDR = 0b1011111,
LDRB = 0b0011111,
LDRH = 0b0111111
};
enum U {
cmp = 0b0,
add = 0b1
};
enum S {
UnSign = 0b0,
Sign = 0b1
};
T32_LDR_LIT();
T32_LDR_LIT(T32_STRUCT_LDR_LIT *inst);
T32_LDR_LIT(OP op, S s, RegisterA32 &rt, Off offset);
T32_LDR_LIT(OP op, S s, RegisterA32 &rt, Label& label);
DEFINE_IS(LDR_LIT)
DEFINE_INST_CODE(LDR_LIT)
Off getImmPCOffset() override;
void onOffsetApply(Off offset) override;
void decode(T32_STRUCT_LDR_LIT *inst) override;
void assembler() override;
public:
OP op;
S s;
RegisterA32* rt;
Off offset;
};
class INST_T32(MOV_MOVT_IMM) : public InstructionT32<STRUCT_T32(MOV_MOVT_IMM)> {
public:
enum OP {
MOV = 0b100100,
MOVT = 0b101100
};
T32_MOV_MOVT_IMM();
T32_MOV_MOVT_IMM(T32_STRUCT_MOV_MOVT_IMM *inst);
T32_MOV_MOVT_IMM(OP op, RegisterA32 &rd, U16 imm16);
DEFINE_IS_EXT(MOV_MOVT_IMM, TEST_INST_OPCODE(MOV_MOVT_IMM, 1) && TEST_INST_OPCODE(MOV_MOVT_IMM, 2))
DEFINE_INST_CODE(MOV_MOVT_IMM)
void decode(T32_STRUCT_MOV_MOVT_IMM *inst) override;
void assembler() override;
public:
OP op;
RegisterA32* rd;
U16 imm16;
};
class INST_T32(LDR_IMM) : public InstructionT32<STRUCT_T32(LDR_IMM)> {
public:
enum OP {
LDR = 0b0101,
LDRB = 0b1001,
LDRH = 0b1011,
LDRSB = 0b0001,
LDRSH = 0b0011
};
T32_LDR_IMM(T32_STRUCT_LDR_IMM *inst);
T32_LDR_IMM(OP op, RegisterA32 &rt, const MemOperand &operand);
DEFINE_IS_EXT(LDR_IMM, TEST_INST_OPCODE(LDR_IMM, 1) && TEST_INST_OPCODE(LDR_IMM, 2))
DEFINE_INST_CODE(LDR_IMM)
void decode(T32_STRUCT_LDR_IMM *inst) override;
void assembler() override;
public:
OP op;
RegisterA32* rt;
MemOperand operand;
};
}
}
#undef DEFINE_IS_EXT
#undef DEFINE_IS
#undef TEST_INST_FIELD
#undef TEST_INST_OPCODE
#undef DEFINE_INST_CODE
#endif //SANDHOOK_INST_T32_H
//
// Created by swift on 2019/5/12.
//
#include "register_arm32.h"
#include "register_list_arm32.h"
using namespace SandHook::RegistersA32;
SandHook::Asm::RegisterA32::RegisterA32(U8 code) : Register(code) {
}
SandHook::Asm::RegisterA32::RegisterA32() {
}
U8 SandHook::Asm::RegisterA32::getWide() {
return 4;
}
RegisterA32* RegisterA32::registers[ARM32_REGISTER_COUNT] = {
#define DEFINE_REGISTERS_X(N) \
&R##N,
ARM32_REGISTER_CODE_LIST(DEFINE_REGISTERS_X)
#undef DEFINE_REGISTERS_X
};
\ No newline at end of file
//
// Created by swift on 2019/5/12.
//
#ifndef SANDHOOK_NH_REGISTER_A32_H
#define SANDHOOK_NH_REGISTER_A32_H
#include "base.h"
#include "register.h"
namespace SandHook {
namespace Asm {
union A32RegisterStruct {
struct {
U8 b3;
U8 b2;
U8 b1;
U8 b0;
} u8;
struct {
U16 h;
U16 l;
} u16;
};
class RegisterA32 : public Register<A32RegisterStruct> {
public:
RegisterA32();
RegisterA32(U8 code);
U8 getWide() override;
virtual bool isUnkonw () {
return getCode() == 38;
}
static RegisterA32* get(U8 code) {
return registers[code];
}
private:
static RegisterA32* registers[];
};
}
}
#endif //SANDHOOK_NH_REGISTER_A32_H
//
// Created by swift on 2019/5/16.
//
#include "register_list_arm32.h"
namespace SandHook {
namespace RegistersA32 {
#define INIT_REGISTERS(N) \
RegisterA32 R##N = RegisterA32(N);
ARM32_REGISTER_CODE_LIST(INIT_REGISTERS)
#undef INIT_REGISTERS
enum RegNum {
kIPRegNum = 12, kSPRegNum = 13, kLRRegNum = 14, kPCRegNum = 15
};
RegisterA32 SP = *Reg(kSPRegNum);
RegisterA32 IP = *Reg(kIPRegNum);
RegisterA32 LR = *Reg(kLRRegNum);
RegisterA32 PC = *Reg(kPCRegNum);
RegisterA32 UnknowRegiser = RegisterA32(38);
}}
\ No newline at end of file
//
// Created by swift on 2019/5/8.
//
#ifndef SANDHOOK_NH_REGISTER_LIST_A32_H
#define SANDHOOK_NH_REGISTER_LIST_A32_H
#include "register_arm32.h"
using namespace SandHook::Asm;
// clang-format off
#define ARM32_REGISTER_COUNT 16
#define ARM32_REGISTER_CODE_LIST(R) \
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15)
namespace SandHook {
namespace RegistersA32 {
#define DEFINE_REGISTERS(N) \
extern RegisterA32 R##N;
ARM32_REGISTER_CODE_LIST(DEFINE_REGISTERS)
#undef DEFINE_REGISTERS
extern RegisterA32 SP;
extern RegisterA32 IP;
extern RegisterA32 LR;
extern RegisterA32 PC;
extern RegisterA32 UnknowRegiser;
}}
#define Reg(N) RegisterA32::get(N)
#endif //SANDHOOK_NH_REGISTER_LIST_A32_H
//
// Created by swift on 2019/5/23.
//
#include "code_relocate_arm32.h"
#include "decoder.h"
#include "lock.h"
using namespace SandHook::RegistersA32;
using namespace SandHook::AsmA32;
using namespace SandHook::Utils;
using namespace SandHook::Decoder;
#define __ assemblerA32->
#define IMPL_RELOCATE(T, X) void CodeRelocateA32::relocate_##T##_##X (INST_##T(X)* inst, void* toPc) throw(ErrorCodeException)
#define CASE(T, X) \
case ENUM_VALUE(InstCode##T, InstCode##T::X): \
relocate_##T##_##X(reinterpret_cast<INST_##T(X)*>(instruction), toPc); \
break;
CodeRelocateA32::CodeRelocateA32(AssemblerA32 &assembler) : CodeRelocate(assembler.codeContainer) {
this->assemblerA32 = &assembler;
}
bool CodeRelocateA32::visit(Unit<Base> *unit, void *pc) {
relocate(reinterpret_cast<Instruction<Base> *>(unit), __ getPC());
curOffset += unit->size();
if (unit->refcount() == 0) {
delete unit;
}
return true;
}
void* CodeRelocateA32::relocate(void *startPc, Addr len, void *toPc = nullptr) throw(ErrorCodeException) {
AutoLock autoLock(relocateLock);
startAddr = reinterpret_cast<Addr>(startPc);
if (isThumbCode(startAddr)) {
startAddr = reinterpret_cast<Addr>(getThumbCodeAddress(startPc));
}
length = len;
curOffset = 0;
__ allocBufferFirst(static_cast<U32>(len * 8));
void* curPc = __ getPC();
if (toPc == nullptr) {
Disassembler::get()->decode(startPc, len, *this);
} else {
//TODO
}
return curPc;
}
void* CodeRelocateA32::relocate(Instruction<Base> *instruction, void *toPc) throw(ErrorCodeException) {
void* curPc = __ getPC();
//insert later bind labels
__ Emit(getLaterBindLabel(curOffset));
if (!instruction->pcRelate()) {
__ Emit(instruction);
instruction->ref();
return curPc;
}
if (instruction->instType() == thumb32) {
switch (instruction->instCode()) {
CASE(T32, B32)
CASE(T32, LDR_LIT)
default:
__ Emit(instruction);
instruction->ref();
}
} else if (instruction->instType() == thumb16) {
switch (instruction->instCode()) {
CASE(T16, B)
CASE(T16, B_COND)
CASE(T16, BX_BLX)
CASE(T16, CBZ_CBNZ)
CASE(T16, ADR)
CASE(T16, LDR_LIT)
default:
__ Emit(instruction);
instruction->ref();
}
} else {
__ Emit(instruction);
instruction->ref();
}
return curPc;
}
IMPL_RELOCATE(T16, B_COND) {
if (inRelocateRange(CODE_OFFSET(inst), sizeof(InstT16))) {
__ B(inst->condition, getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
if (inst->condition == al) {
Label* target_label = new Label;
__ Ldr(PC, target_label);
__ Emit(target_label);
__ Emit(targetAddr);
} else {
Label* true_label = new Label();
Label* false_label = new Label();
Label* target_label = new Label;
__ B(inst->condition, true_label);
__ B(false_label);
__ Emit(true_label);
__ Ldr(PC, target_label);
__ Emit(target_label);
__ Emit(targetAddr);
__ Emit(false_label);
}
}
IMPL_RELOCATE(T16, B) {
if (inRelocateRange(CODE_OFFSET(inst), sizeof(InstT16))) {
__ B(getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
Label* target_label = new Label();
__ Ldr(PC, target_label);
__ Emit(target_label);
__ Emit((Addr) getThumbPC(reinterpret_cast<void *>(targetAddr)));
}
IMPL_RELOCATE(T16, BX_BLX) {
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
inst->ref();
}
IMPL_RELOCATE(T16, CBZ_CBNZ) {
inst->ref();
if (inRelocateRange(CODE_OFFSET(inst), sizeof(InstT16))) {
inst->bindLabel(*getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
Label* true_label = new Label;
Label* false_label = new Label;
Label* target_label = new Label();
inst->bindLabel(*true_label);
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
__ B(false_label);
__ Emit(true_label);
__ Ldr(PC, target_label);
__ Emit(target_label);
__ Emit((Addr) getThumbPC(reinterpret_cast<void *>(targetAddr)));
__ Emit(false_label);
}
IMPL_RELOCATE(T16, LDR_LIT) {
if (inRelocateRange(CODE_OFFSET(inst), inst->rt->getWide())) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
__ Mov(*inst->rt, targetAddr);
__ Ldr(*inst->rt, MemOperand(inst->rt, 0));
}
IMPL_RELOCATE(T16, ADR) {
if (inRelocateRange(CODE_OFFSET(inst), inst->rd->getWide())) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
__ Mov(*inst->rd, targetAddr);
}
IMPL_RELOCATE(T32, B32) {
if (inRelocateRange(CODE_OFFSET(inst), sizeof(InstT16))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
if (inst->x == T32_B32::thumb) {
//Thumb mode
if (inst->op == T32_B32::BL) {
__ Mov(LR, U32((Addr) toPc + inst->size() + 2 * 2));
}
targetAddr = reinterpret_cast<Addr>(getThumbPC(reinterpret_cast<void *>(targetAddr)));
Label* target_label = new Label();
__ Ldr(PC, target_label);
__ Emit(target_label);
__ Emit(reinterpret_cast<Addr>(targetAddr));
} else {
//to A32 mode
__ Mov(IP, targetAddr);
if (inst->op == T32_B32::BL) {
__ Blx(IP);
} else {
__ Bx(IP);
}
}
}
IMPL_RELOCATE(T32, LDR_LIT) {
if (inRelocateRange(CODE_OFFSET(inst), sizeof(InstT16))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(CODE_OFFSET(inst) + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
__ Mov(*inst->rt, targetAddr);
switch (inst->op) {
case T32_LDR_LIT::LDR:
__ Ldr(*inst->rt, MemOperand(inst->rt, 0));
break;
case T32_LDR_LIT::LDRB:
if (inst->s == T32_LDR_LIT::UnSign) {
__ Ldrb(*inst->rt, MemOperand(inst->rt, 0));
} else {
__ Ldrsb(*inst->rt, MemOperand(inst->rt, 0));
}
break;
case T32_LDR_LIT::LDRH:
if (inst->s == T32_LDR_LIT::UnSign) {
__ Ldrh(*inst->rt, MemOperand(inst->rt, 0));
} else {
__ Ldrsh(*inst->rt, MemOperand(inst->rt, 0));
}
break;
default:
inst->ref();
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
}
}
\ No newline at end of file
//
// Created by swift on 2019/5/23.
//
#ifndef SANDHOOK_CODE_RELOCATE_ARM32_H
#define SANDHOOK_CODE_RELOCATE_ARM32_H
#include <mutex>
#include <map>
#include "code_relocate.h"
#include "assembler_arm32.h"
using namespace SandHook::Assembler;
using namespace SandHook::Decoder;
using namespace SandHook::AsmA32;
#define DEFINE_RELOCATE(T, X) void relocate_##T##_##X (INST_##T(X)* inst, void* toPc) throw(ErrorCodeException);
namespace SandHook {
namespace Asm {
class CodeRelocateA32 : public CodeRelocate {
public:
CodeRelocateA32(AssemblerA32 &assembler);
void* relocate(Instruction<Base> *instruction, void *toPc) throw(ErrorCodeException) override;
void* relocate(void *startPc, Addr len, void *toPc) throw(ErrorCodeException) override;
bool visit(Unit<Base> *unit, void *pc) override;
DEFINE_RELOCATE(T16, B_COND)
DEFINE_RELOCATE(T16, B)
DEFINE_RELOCATE(T16, BX_BLX)
DEFINE_RELOCATE(T16, CBZ_CBNZ)
DEFINE_RELOCATE(T16, LDR_LIT)
DEFINE_RELOCATE(T16, ADR)
DEFINE_RELOCATE(T32, B32)
DEFINE_RELOCATE(T32, LDR_LIT)
private:
AssemblerA32* assemblerA32;
};
}
}
#undef DEFINE_RELOCATE
#endif //SANDHOOK_CODE_RELOCATE_ARM32_H
//
// Created by swift on 2019/5/11.
//
#include "assembler_arm64.h"
using namespace SandHook::Assembler;
using namespace SandHook::RegistersA64;
using namespace SandHook::AsmA64;
AssemblerA64::AssemblerA64(CodeBuffer* codeBuffer) {
codeContainer.setCodeBuffer(codeBuffer);
}
void *AssemblerA64::getPC() {
return reinterpret_cast<void *>(codeContainer.curPc);
}
void *AssemblerA64::getStartPC() {
return reinterpret_cast<void *>(codeContainer.startPc);
}
void AssemblerA64::allocBufferFirst(U32 size) {
codeContainer.allocBufferFirst(size);
}
void *AssemblerA64::finish() {
codeContainer.commit();
return reinterpret_cast<void *>(codeContainer.startPc);
}
void AssemblerA64::Emit(U64 data64) {
Emit(reinterpret_cast<Unit<Base>*>(new Data64(data64)));
}
void AssemblerA64::Emit(U32 data32) {
Emit(reinterpret_cast<Unit<Base>*>(new Data32(data32)));
}
void AssemblerA64::Emit(Unit<Base> *unit) {
codeContainer.append(unit);
}
void AssemblerA64::MoveWide(RegisterA64 &rd, INST_A64(MOV_WIDE)::OP op, U64 imme,
INST_A64(MOV_WIDE)::Shift shift) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(MOV_WIDE)(op, &rd, imme, shift)));
}
void AssemblerA64::Mov(WRegister &rd, U32 imme) {
const U16 h0 = BITS16L(imme);
const U16 h1 = BITS16H(imme);
Movz(rd, h0, INST_A64(MOV_WIDE)::Shift0);
Movk(rd, h1, INST_A64(MOV_WIDE)::Shift1);
}
void AssemblerA64::Mov(XRegister &rd, U64 imme) {
const U32 wl = BITS32L(imme);
const U32 wh = BITS32H(imme);
const U16 h0 = BITS16L(wl);
const U16 h1 = BITS16H(wl);
const U16 h2 = BITS16L(wh);
const U16 h3 = BITS16H(wh);
Movz(rd, h0, INST_A64(MOV_WIDE)::Shift0);
Movk(rd, h1, INST_A64(MOV_WIDE)::Shift1);
Movk(rd, h2, INST_A64(MOV_WIDE)::Shift2);
Movk(rd, h3, INST_A64(MOV_WIDE)::Shift3);
}
void AssemblerA64::Movz(RegisterA64 &rd, U64 imme,
INST_A64(MOV_WIDE)::Shift shift) {
MoveWide(rd, INST_A64(MOV_WIDE)::MOV_WideOp_Z, imme, shift);
}
void AssemblerA64::Movk(RegisterA64 &rd, U64 imme,
INST_A64(MOV_WIDE)::Shift shift) {
MoveWide(rd, INST_A64(MOV_WIDE)::MOV_WideOp_K, imme, shift);
}
void AssemblerA64::Movn(RegisterA64 &rd, U64 imme,
INST_A64(MOV_WIDE)::Shift shift) {
MoveWide(rd, INST_A64(MOV_WIDE)::MOV_WideOp_N, imme, shift);
}
void AssemblerA64::Br(XRegister &rn) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(BR_BLR_RET)(INST_A64(BR_BLR_RET)::BR, rn)));
}
void AssemblerA64::B(Off offset) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(B_BL)(INST_A64(B_BL)::B, offset)));
}
void AssemblerA64::B(Label *label) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(B_BL)(INST_A64(B_BL)::B, *label)));
}
void AssemblerA64::Bl(Off offset) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(B_BL)(INST_A64(B_BL)::BL, offset)));
}
void AssemblerA64::Bl(Label *label) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(B_BL)(INST_A64(B_BL)::BL, *label)));
}
void AssemblerA64::B(Condition condition, Off offset) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(B_COND)(condition, offset)));
}
void AssemblerA64::B(Condition condition, Label *label) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(B_COND)(condition, *label)));
}
void AssemblerA64::Tbz(RegisterA64 &rt, U32 bit, Label *label) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(TBZ_TBNZ)(INST_A64(TBZ_TBNZ)::TBZ, rt, bit, *label))));
}
void AssemblerA64::Tbz(RegisterA64 &rt, U32 bit, Off offset) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(TBZ_TBNZ)(INST_A64(TBZ_TBNZ)::TBZ, rt, bit, offset))));
}
void AssemblerA64::Tbnz(RegisterA64 &rt, U32 bit, Off offset) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(TBZ_TBNZ)(INST_A64(TBZ_TBNZ)::TBNZ, rt, bit, offset))));
}
void AssemblerA64::Tbnz(RegisterA64 &rt, U32 bit, Label *label) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(TBZ_TBNZ)(INST_A64(TBZ_TBNZ)::TBNZ, rt, bit, *label))));
}
void AssemblerA64::Cbz(RegisterA64 &rt, Off offset) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(CBZ_CBNZ)(INST_A64(CBZ_CBNZ)::CBZ, offset, rt))));
}
void AssemblerA64::Cbz(RegisterA64 &rt, Label *label) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(CBZ_CBNZ)(INST_A64(CBZ_CBNZ)::CBZ, *label, rt))));
}
void AssemblerA64::Cbnz(RegisterA64 &rt, Off offset) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(CBZ_CBNZ)(INST_A64(CBZ_CBNZ)::CBNZ, offset, rt))));
}
void AssemblerA64::Cbnz(RegisterA64 &rt, Label *label) {
Emit((reinterpret_cast<Unit<Base> *>(new INST_A64(CBZ_CBNZ)(INST_A64(CBZ_CBNZ)::CBNZ, *label, rt))));
}
void AssemblerA64::Str(RegisterA64 &rt, const MemOperand& memOperand) {
if (memOperand.addr_mode == Offset) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(STR_UIMM)(rt, memOperand)));
} else {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(STR_IMM)(rt, memOperand)));
}
}
void AssemblerA64::Ldr(RegisterA64 &rt, const MemOperand &memOperand) {
if (memOperand.addr_mode == Offset) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(LDR_UIMM)(rt, memOperand)));
} else {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(LDR_IMM)(rt, memOperand)));
}
}
void AssemblerA64::Ldr(RegisterA64 &rt, Label* label) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(LDR_LIT)(rt.isX() ? INST_A64(LDR_LIT)::LDR_X : INST_A64(LDR_LIT)::LDR_W, rt, *label)));
}
void AssemblerA64::Ldrsw(RegisterA64 &rt, Label* label) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(LDR_LIT)(INST_A64(LDR_LIT)::LDR_SW, rt, *label)));
}
void AssemblerA64::Ldrsw(XRegister &rt, const MemOperand& memOperand) {
if (memOperand.addr_mode == Offset) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(LDRSW_UIMM)(rt, memOperand)));
} else {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(LDRSW_IMM)(rt, memOperand)));
}
}
// If the current stack pointer is sp, then it must be aligned to 16 bytes
// on entry and the total size of the specified registers must also be a
// multiple of 16 bytes.
void AssemblerA64::Pop(RegisterA64 &rd) {
if (rd.isX()) {
Ldr(rd, MemOperand(&SP, 16, PostIndex));
} else {
Ldr(rd, MemOperand(&WSP, 16, PostIndex));
}
}
// If the current stack pointer is sp, then it must be aligned to 16 bytes
// on entry and the total size of the specified registers must also be a
// multiple of 16 bytes.
void AssemblerA64::Push(RegisterA64 &rt) {
if (rt.isX()) {
Str(rt, MemOperand(&SP, -16, PreIndex));
} else {
Str(rt, MemOperand(&WSP, -16, PreIndex));
}
}
void AssemblerA64::Cmp(RegisterA64 &rn, const Operand &operand) {
Subs(*zeroRegFor(rn), rn, operand);
}
void AssemblerA64::Subs(RegisterA64 &rd, RegisterA64 &rn, const Operand &operand) {
Emit(reinterpret_cast<Unit<Base> *>(new INST_A64(SUB_EXT_REG)(rd, rn, operand, SetFlags)));
}
//
// Created by swift on 2019/5/11.
//
#ifndef SANDHOOK_NH_ASSEMBLER_A64_H
#define SANDHOOK_NH_ASSEMBLER_A64_H
#include "assembler.h"
#include "register_arm64.h"
#include "inst_arm64.h"
using namespace SandHook::AsmA64;
namespace SandHook {
namespace Assembler {
class AssemblerA64 {
public:
AssemblerA64(CodeBuffer* codeBuffer);
void allocBufferFirst(U32 size);
void* getStartPC();
void* getPC();
void* finish();
void Emit(U32 data32);
void Emit(U64 data64);
void Emit(Unit<Base>* unit);
void MoveWide(RegisterA64& rd, INST_A64(MOV_WIDE)::OP op, U64 imme, INST_A64(MOV_WIDE)::Shift shift);
void Movz(RegisterA64& rd, U64 imme, INST_A64(MOV_WIDE)::Shift shift);
void Movk(RegisterA64& rd, U64 imme, INST_A64(MOV_WIDE)::Shift shift);
void Movn(RegisterA64& rd, U64 imme, INST_A64(MOV_WIDE)::Shift shift);
void Mov(WRegister& rd, U32 imme);
void Mov(XRegister& rd, U64 imme);
void Br(XRegister& rn);
void B(Off offset);
void B(Label* label);
void Bl(Off offset);
void Bl(Label* label);
void B(Condition condition, Off offset);
void B(Condition condition, Label* label);
void Tbz(RegisterA64 &rt, U32 bit, Off offset);
void Tbz(RegisterA64 &rt, U32 bit, Label* label);
void Tbnz(RegisterA64 &rt, U32 bit, Off offset);
void Tbnz(RegisterA64 &rt, U32 bit, Label* label);
void Cbz(RegisterA64 &rt, Off offset);
void Cbz(RegisterA64 &rt, Label* label);
void Cbnz(RegisterA64 &rt, Off offset);
void Cbnz(RegisterA64 &rt, Label* label);
void Str(RegisterA64& rt, const MemOperand& memOperand);
void Ldr(RegisterA64& rt, const MemOperand& memOperand);
void Ldr(RegisterA64& rt, Label* label);
void Ldrsw(RegisterA64 &rt, Label* label);
void Ldrsw(XRegister& rt, const MemOperand& memOperand);
void Pop(RegisterA64& rt);
void Push(RegisterA64& rt);
void Subs(RegisterA64& rd, RegisterA64& rn, const Operand& operand);
void Cmp(RegisterA64& rn, const Operand& operand);
public:
CodeContainer codeContainer = CodeContainer(nullptr);
};
}
}
#endif //SANDHOOK_NH_ASSEMBLER_A64_H
//
// Created by swift on 2019/5/6.
//
#include "inst_arm64.h"
#include "decoder_arm64.h"
using namespace SandHook::Decoder;
using namespace SandHook::AsmA64;
#define CASE(X) \
if (IS_OPCODE_A64(*pc, X)) { \
STRUCT_A64(X) *s = reinterpret_cast<STRUCT_A64(X) *>(pc); \
unit = reinterpret_cast<Unit<Base> *>(new INST_A64(X)(*s)); \
goto label_matched; \
}
Arm64Decoder* Arm64Decoder::instant = new Arm64Decoder();
void Arm64Decoder::decode(void *codeStart, Addr codeLen, InstVisitor &visitor) {
InstA64 *pc = reinterpret_cast<InstA64 *>(codeStart);
Addr endAddr = (Addr) codeStart + codeLen;
Unit<Base>* unit = nullptr;
while((Addr) pc < endAddr) {
CASE(MOV_WIDE)
CASE(MOV_REG)
CASE(ADR_ADRP)
CASE(LDR_LIT)
CASE(LDR_IMM)
CASE(LDR_UIMM)
CASE(LDRSW_IMM)
CASE(LDRSW_UIMM)
CASE(STR_UIMM)
CASE(STR_IMM)
CASE(B_BL)
CASE(B_COND)
CASE(BR_BLR_RET)
CASE(CBZ_CBNZ)
CASE(TBZ_TBNZ)
CASE(SUB_EXT_REG)
CASE(SVC)
CASE(EXCEPTION_GEN)
label_matched:
if (unit == nullptr) {
unit = reinterpret_cast<Unit<Base> *>(new INST_A64(UNKNOW)(*reinterpret_cast<STRUCT_A64(UNKNOW) *>(pc)));
}
if (!visitor.visit(unit, pc)) {
break;
}
pc = reinterpret_cast<InstA64 *>((Addr)pc + unit->size());
unit = nullptr;
}
}
//
// Created by swift on 2019/5/6.
//
#ifndef SANDHOOK_NH_DECODER_ARM64_H
#define SANDHOOK_NH_DECODER_ARM64_H
#include "decoder.h"
namespace SandHook {
namespace Decoder {
class Arm64Decoder : public InstDecoder {
public:
void decode(void *codeStart, Addr codeLen, InstVisitor &visitor) override;
public:
static Arm64Decoder* instant;
};
}
}
#endif //SANDHOOK_NH_DECODER_ARM64_H
//
// Created by swift on 2019/5/23.
//
#include "hook_arm64.h"
#include "code_buffer.h"
#include "lock.h"
using namespace SandHook::Hook;
using namespace SandHook::Decoder;
using namespace SandHook::Asm;
using namespace SandHook::Assembler;
using namespace SandHook::Utils;
#include "assembler_arm64.h"
#include "code_relocate_arm64.h"
using namespace SandHook::RegistersA64;
void *InlineHookArm64Android::inlineHook(void *origin, void *replace) {
AutoLock lock(hookLock);
void* backup = nullptr;
AssemblerA64 assemblerBackup(backupBuffer);
StaticCodeBuffer inlineBuffer = StaticCodeBuffer(reinterpret_cast<Addr>(origin));
AssemblerA64 assemblerInline(&inlineBuffer);
CodeContainer* codeContainerInline = &assemblerInline.codeContainer;
//build inline trampoline
#define __ assemblerInline.
Label* target_addr_label = new Label();
__ Ldr(IP1, target_addr_label);
__ Br(IP1);
__ Emit(target_addr_label);
__ Emit((Addr) replace);
#undef __
//build backup method
CodeRelocateA64 relocate = CodeRelocateA64(assemblerBackup);
backup = relocate.relocate(origin, codeContainerInline->size(), nullptr);
#define __ assemblerBackup.
Label* origin_addr_label = new Label();
__ Ldr(IP1, origin_addr_label);
__ Br(IP1);
__ Emit(origin_addr_label);
__ Emit((Addr) origin + codeContainerInline->size());
__ finish();
#undef __
//commit inline trampoline
assemblerInline.finish();
return backup;
}
\ No newline at end of file
//
// Created by swift on 2019/5/23.
//
#ifndef SANDHOOK_HOOK_ARM64_H
#define SANDHOOK_HOOK_ARM64_H
#include "hook.h"
namespace SandHook {
namespace Hook {
class InlineHookArm64Android : public InlineHook {
public:
inline InlineHookArm64Android() {
hookLock = new std::mutex();
};
inline ~InlineHookArm64Android() {
delete hookLock;
}
void *inlineHook(void *origin, void *replace) override;
protected:
std::mutex* hookLock;
};
}
}
#endif //SANDHOOK_HOOK_ARM64_H
//
// Created by swift on 2019/5/6.
//
#include "inst_arm64.h"
#define SET_OPCODE(X) get()->opcode = OPCODE_A64(X)
#define SET_OPCODE_MULTI(X, INDEX) get()->opcode##INDEX = OPCODE_A64(X##_##INDEX)
#define DECODE_OFFSET(bits, ext) signExtend64(bits + ext, COMBINE(get()->imm##bits, 0, ext))
#define ENCODE_OFFSET(bits, ext) get()->imm##bits = TruncateToUint##bits(offset >> ext)
using namespace SandHook::Asm;
using namespace SandHook::AsmA64;
template<typename InstStruct>
U32 InstructionA64<InstStruct>::size() {
return sizeof(InstA64);
}
//Unknow
A64_UNKNOW::A64_UNKNOW(STRUCT_A64(UNKNOW) &inst) : InstructionA64(&inst) {
decode(&inst);
}
void A64_UNKNOW::decode(A64_STRUCT_UNKNOW *inst) {
inst_backup = *inst;
}
void A64_UNKNOW::assembler() {
set(inst_backup);
}
//PC Rel Inst
template<typename Inst>
A64_INST_PC_REL<Inst>::A64_INST_PC_REL(Inst *inst):InstructionA64<Inst>(inst) {
}
template<typename Inst>
A64_INST_PC_REL<Inst>::A64_INST_PC_REL() {}
template<typename Inst>
Addr A64_INST_PC_REL<Inst>::getImmPCOffsetTarget() {
return this->getImmPCOffset() + reinterpret_cast<Addr>(this->getPC());
}
template<typename Inst>
bool A64_INST_PC_REL<Inst>::pcRelate() {
return true;
}
//ADR ADRP
A64_ADR_ADRP::A64_ADR_ADRP() {}
A64_ADR_ADRP::A64_ADR_ADRP(STRUCT_A64(ADR_ADRP) &inst) : A64_INST_PC_REL(&inst) {
decode(&inst);
}
A64_ADR_ADRP::A64_ADR_ADRP(A64_ADR_ADRP::OP op, XRegister &rd, S64 offset) : op(op), rd(&rd),
offset(offset) {
}
A64_ADR_ADRP::A64_ADR_ADRP(A64_ADR_ADRP::OP op, XRegister &rd, Label &label) {
bindLabel(label);
}
Off A64_ADR_ADRP::getImmPCOffset() {
U32 hi = get()->immhi;
U32 lo = get()->immlo;
U64 imm = COMBINE(hi, lo, IMM_LO_W);
if (isADRP()) {
return signExtend64(IMM_HI_W + IMM_LO_W + PAGE_OFFSET, imm << PAGE_OFFSET);
} else {
return signExtend64(IMM_HI_W + IMM_LO_W, imm);
}
}
Addr A64_ADR_ADRP::getImmPCOffsetTarget() {
void* base = AlignDown(getPC(), P_SIZE);
return offset + reinterpret_cast<Addr>(base);
}
void A64_ADR_ADRP::assembler() {
SET_OPCODE(ADR_ADRP);
}
void A64_ADR_ADRP::decode(STRUCT_A64(ADR_ADRP) *inst) {
offset = getImmPCOffset();
DECODE_RD(XReg);
DECODE_OP;
}
//Mov Wide
A64_MOV_WIDE::A64_MOV_WIDE() {}
A64_MOV_WIDE::A64_MOV_WIDE(STRUCT_A64(MOV_WIDE) &inst) : InstructionA64(&inst) {
decode(&inst);
}
A64_MOV_WIDE::A64_MOV_WIDE(A64_MOV_WIDE::OP op,RegisterA64* rd, U16 imme, U8 shift)
: shift(shift), op(op), imme(imme), rd(rd) {}
void A64_MOV_WIDE::assembler() {
SET_OPCODE(MOV_WIDE);
get()->imm16 = imme;
get()->hw = static_cast<InstA64>(shift / 16);
ENCODE_OP;
get()->sf = rd->isX() ? 1 : 0;
ENCODE_RD;
}
void A64_MOV_WIDE::decode(STRUCT_A64(MOV_WIDE) *inst) {
imme = static_cast<U16>(inst->imm16);
shift = static_cast<U8>(inst->hw * 16);
op = OP(inst->op);
if (inst->sf == 1) {
DECODE_RD(XReg);
} else {
DECODE_RD(WReg);
}
}
//B BL
A64_B_BL::A64_B_BL() {}
A64_B_BL::A64_B_BL(STRUCT_A64(B_BL) &inst) : A64_INST_PC_REL(&inst) {
decode(&inst);
}
A64_B_BL::A64_B_BL(A64_B_BL::OP op, Off offset) : op(op), offset(offset) {
}
A64_B_BL::A64_B_BL(A64_B_BL::OP op, Label &l) : op(op) {
bindLabel(l);
}
Off A64_B_BL::getImmPCOffset() {
return DECODE_OFFSET(26, 2);
}
void A64_B_BL::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(26, 2);
}
void A64_B_BL::decode(STRUCT_A64(B_BL) *inst) {
DECODE_OP;
offset = getImmPCOffset();
}
void A64_B_BL::assembler() {
SET_OPCODE(B_BL);
ENCODE_OP;
ENCODE_OFFSET(26, 2);
}
//CBZ CBNZ
A64_CBZ_CBNZ::A64_CBZ_CBNZ() {}
A64_CBZ_CBNZ::A64_CBZ_CBNZ(STRUCT_A64(CBZ_CBNZ) &inst) : A64_INST_PC_REL(&inst) {
decode(&inst);
}
A64_CBZ_CBNZ::A64_CBZ_CBNZ(A64_CBZ_CBNZ::OP op, Off offset, RegisterA64 &rt) : op(op),
offset(offset),
rt(&rt) {}
A64_CBZ_CBNZ::A64_CBZ_CBNZ(A64_CBZ_CBNZ::OP op, Label& label, RegisterA64 &rt) : op(op),
rt(&rt) {
bindLabel(label);
}
Off A64_CBZ_CBNZ::getImmPCOffset() {
return DECODE_OFFSET(19, 2);
}
void A64_CBZ_CBNZ::decode(STRUCT_A64(CBZ_CBNZ) *inst) {
DECODE_OP;
if (inst->sf == 1) {
DECODE_RT(XReg);
} else {
DECODE_RT(WReg);
}
offset = getImmPCOffset();
}
void A64_CBZ_CBNZ::assembler() {
SET_OPCODE(CBZ_CBNZ);
ENCODE_OP;
ENCODE_RT;
get()->sf = rt->isX() ? 1 : 0;
ENCODE_OFFSET(19, 2);
}
void A64_CBZ_CBNZ::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(19, 2);
}
//B.Cond
A64_B_COND::A64_B_COND() {}
A64_B_COND::A64_B_COND(STRUCT_A64(B_COND) &inst) : A64_INST_PC_REL(&inst) {
decode(&inst);
}
A64_B_COND::A64_B_COND(Condition condition, Off offset) : condition(condition), offset(offset) {}
Off A64_B_COND::getImmPCOffset() {
return DECODE_OFFSET(19, 2);
}
void A64_B_COND::decode(STRUCT_A64(B_COND) *inst) {
DECODE_COND;
offset = getImmPCOffset();
}
void A64_B_COND::assembler() {
SET_OPCODE(B_COND);
ENCODE_COND;
ENCODE_OFFSET(19, 2);
}
A64_B_COND::A64_B_COND(Condition condition, Label &label) {
bindLabel(label);
}
void A64_B_COND::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(19, 2);
}
//TBZ TBNZ
A64_TBZ_TBNZ::A64_TBZ_TBNZ() {}
A64_TBZ_TBNZ::A64_TBZ_TBNZ(STRUCT_A64(TBZ_TBNZ) &inst) : A64_INST_PC_REL(&inst) {
decode(&inst);
}
A64_TBZ_TBNZ::A64_TBZ_TBNZ(A64_TBZ_TBNZ::OP op, RegisterA64 &rt, U32 bit, Off offset) : op(op),
rt(&rt),
bit(bit),
offset(offset) {}
A64_TBZ_TBNZ::A64_TBZ_TBNZ(A64_TBZ_TBNZ::OP op, RegisterA64 &rt, U32 bit, Label &label) : op(op),
rt(&rt),
bit(bit) {
bindLabel(label);
}
Off A64_TBZ_TBNZ::getImmPCOffset() {
return DECODE_OFFSET(14, 2);
}
void A64_TBZ_TBNZ::decode(STRUCT_A64(TBZ_TBNZ) *inst) {
bit = COMBINE(inst->b5, inst->b40, 5);
if (inst->b5 == 1) {
DECODE_RT(XReg);
} else {
DECODE_RT(WReg);
}
DECODE_OP;
offset = getImmPCOffset();
}
void A64_TBZ_TBNZ::assembler() {
SET_OPCODE(TBZ_TBNZ);
ENCODE_OP;
get()->b5 = rt->isX() ? 1 : 0;
ENCODE_RT;
get()->b40 = static_cast<InstA64>(BITS(bit, sizeof(InstA64) - 5, sizeof(InstA64)));
ENCODE_OFFSET(14, 2);
}
void A64_TBZ_TBNZ::onOffsetApply(Off offset) {
this->offset = offset;
get()->imm14 = TruncateToUint14(offset >> 2);
}
// LDR(literal)
A64_LDR_LIT::A64_LDR_LIT() {}
A64_LDR_LIT::A64_LDR_LIT(STRUCT_A64(LDR_LIT) &inst) : A64_INST_PC_REL(&inst) {
decode(&inst);
}
A64_LDR_LIT::A64_LDR_LIT(A64_LDR_LIT::OP op, RegisterA64 &rt, Off offset) : op(op), rt(&rt),
offset(offset) {}
A64_LDR_LIT::A64_LDR_LIT(A64_LDR_LIT::OP op, RegisterA64 &rt, Label& label) : op(op), rt(&rt) {
bindLabel(label);
}
Off A64_LDR_LIT::getImmPCOffset() {
return DECODE_OFFSET(19, 2);
}
void A64_LDR_LIT::onOffsetApply(Off offset) {
this->offset = offset;
ENCODE_OFFSET(19, 2);
}
void A64_LDR_LIT::decode(STRUCT_A64(LDR_LIT) *inst) {
DECODE_OP;
offset = getImmPCOffset();
ENCODE_OFFSET(19, 2);
if (op == LDR_W) {
DECODE_RT(WReg);
} else {
DECODE_RT(XReg);
}
}
void A64_LDR_LIT::assembler() {
SET_OPCODE(LDR_LIT);
ENCODE_OP;
ENCODE_RT;
ENCODE_OFFSET(19, 2);
}
A64_BR_BLR_RET::A64_BR_BLR_RET() {}
A64_BR_BLR_RET::A64_BR_BLR_RET(STRUCT_A64(BR_BLR_RET) &inst) : InstructionA64(&inst) {
decode(&inst);
}
A64_BR_BLR_RET::A64_BR_BLR_RET(A64_BR_BLR_RET::OP op, XRegister &rn) : op(op), rn(&rn) {}
void A64_BR_BLR_RET::decode(A64_STRUCT_BR_BLR_RET *inst) {
DECODE_RN(XReg);
DECODE_OP;
}
void A64_BR_BLR_RET::assembler() {
SET_OPCODE_MULTI(BR_BLR_RET, 1);
SET_OPCODE_MULTI(BR_BLR_RET, 2);
SET_OPCODE_MULTI(BR_BLR_RET, 3);
ENCODE_RN;
ENCODE_OP;
}
A64_STR_IMM::A64_STR_IMM() {}
A64_STR_IMM::A64_STR_IMM(STRUCT_A64(STR_IMM) &inst) : A64LoadAndStoreImm(&inst) {
decode(&inst);
}
A64_STR_IMM::A64_STR_IMM(RegisterA64 &rt, const MemOperand &operand) : A64LoadAndStoreImm(&rt, operand) {
}
void A64_STR_IMM::decode(STRUCT_A64(STR_IMM) *inst) {
regSize = Size(inst->size);
switch (regSize) {
case Size64:
rt = XReg(static_cast<U8>(inst->rt));
operand.base = XReg(static_cast<U8>(inst->rn));
break;
case Size32:
rt = WReg(static_cast<U8>(inst->rt));
operand.base = WReg(static_cast<U8>(inst->rn));
break;
default:
valid = false;
return;
}
addrMode = AdMod(inst->addrmode);
switch (addrMode) {
case PostIndex:
wback = true;
postindex = true;
operand.addr_mode = AddrMode::PostIndex;
break;
case PreIndex:
wback = true;
postindex = false;
operand.addr_mode = AddrMode::PreIndex;
break;
default:
operand.addr_mode = AddrMode::Offset;
valid = false;
}
scale = static_cast<U8>(inst->size);
offset = signExtend64(9, inst->imm9);
operand.offset = offset;
}
void A64_STR_IMM::assembler() {
SET_OPCODE(STR_IMM);
get()->rt = rt->getCode();
get()->rn = operand.base->getCode();
get()->imm9 = TruncateToUint9(operand.offset);
if (rt->isX()) {
get()->size = Size64;
} else if (rt->isW()) {
get()->size = Size32;
} else {
valid = false;
return;
}
switch (operand.addr_mode) {
case AddrMode::PostIndex:
wback = true;
postindex = true;
get()->addrmode = PostIndex;
break;
case AddrMode::PreIndex:
wback = true;
postindex = false;
get()->addrmode = PreIndex;
break;
default:
get()->addrmode = Offset;
valid = false;
}
}
A64_STR_UIMM::A64_STR_UIMM() {}
A64_STR_UIMM::A64_STR_UIMM(STRUCT_A64(STR_UIMM) &inst) : A64LoadAndStoreImm(&inst) {
decode(&inst);
}
A64_STR_UIMM::A64_STR_UIMM(RegisterA64 &rt, const MemOperand &operand) : A64LoadAndStoreImm(&rt, operand) {
}
void A64_STR_UIMM::decode(STRUCT_A64(STR_UIMM) *inst) {
regSize = Size(inst->size);
switch (regSize) {
case Size64:
rt = XReg(static_cast<U8>(inst->rt));
operand.base = XReg(static_cast<U8>(inst->rn));
break;
case Size32:
rt = WReg(static_cast<U8>(inst->rt));
operand.base = WReg(static_cast<U8>(inst->rn));
break;
default:
valid = false;
return;
}
operand.addr_mode = AddrMode::Offset;
scale = static_cast<U8>(inst->size);
offset = inst->imm12 << regSize;
operand.offset = offset;
}
void A64_STR_UIMM::assembler() {
SET_OPCODE(STR_UIMM);
ENCODE_RT;
get()->rn = operand.base->getCode();
if (rt->isX()) {
get()->size = Size64;
} else if (rt->isW()) {
get()->size = Size32;
} else {
valid = false;
return;
}
get()->imm12 = operand.offset >> get()->size;
}
A64_MOV_REG::A64_MOV_REG() {}
A64_MOV_REG::A64_MOV_REG(STRUCT_A64(MOV_REG) &inst) : InstructionA64(&inst) {
decode(&inst);
}
A64_MOV_REG::A64_MOV_REG(RegisterA64 &rd, RegisterA64 &rm) : rd(&rd), rm(&rm) {
}
void A64_MOV_REG::decode(A64_STRUCT_MOV_REG *inst) {
if (inst->sf == 1) {
DECODE_RD(XReg);
DECODE_RM(XReg);
} else {
DECODE_RD(WReg);
DECODE_RM(WReg);
}
}
void A64_MOV_REG::assembler() {
SET_OPCODE_MULTI(MOV_REG, 1);
SET_OPCODE_MULTI(MOV_REG, 2);
get()->sf = rd->isX() ? 1 : 0;
ENCODE_RD;
ENCODE_RM;
}
A64_SUB_EXT_REG::A64_SUB_EXT_REG() {}
A64_SUB_EXT_REG::A64_SUB_EXT_REG(STRUCT_A64(SUB_EXT_REG) &inst) : InstructionA64(&inst) {
decode(&inst);
}
A64_SUB_EXT_REG::A64_SUB_EXT_REG(RegisterA64 &rd, RegisterA64 &rn, const Operand &operand,
FlagsUpdate flagsUpdate) : rd(&rd), rn(&rn), operand(operand),
flagsUpdate(flagsUpdate) {}
void A64_SUB_EXT_REG::decode(STRUCT_A64(SUB_EXT_REG) *inst) {
flagsUpdate = FlagsUpdate(inst->S);
if (inst->sf == 1) {
DECODE_RD(XReg);
DECODE_RN(XReg);
operand.reg = XReg(static_cast<U8>(inst->rm));
} else {
DECODE_RD(WReg);
DECODE_RN(WReg);
operand.reg = XReg(static_cast<U8>(inst->rm));
}
operand.extend = Extend(inst->option);
INST_ASSERT(inst->imm3 > 4);
operand.shift = Shift(inst->imm3);
}
void A64_SUB_EXT_REG::assembler() {
SET_OPCODE_MULTI(SUB_EXT_REG, 1);
SET_OPCODE_MULTI(SUB_EXT_REG, 2);
get()->S = flagsUpdate;
get()->sf = rd->isX() ? 1 : 0;
get()->option = operand.extend;
get()->imm3 = operand.shift;
get()->rm = operand.reg->getCode();
ENCODE_RN;
ENCODE_RD;
}
A64_EXCEPTION_GEN::A64_EXCEPTION_GEN() {}
A64_EXCEPTION_GEN::A64_EXCEPTION_GEN(STRUCT_A64(EXCEPTION_GEN) &inst) : InstructionA64(&inst) {
decode(&inst);
}
A64_EXCEPTION_GEN::A64_EXCEPTION_GEN(A64_EXCEPTION_GEN::OP op, ExceptionLevel el, U16 imme) : op(
op), el(el), imme(imme) {}
void A64_EXCEPTION_GEN::decode(STRUCT_A64(EXCEPTION_GEN) *inst) {
DECODE_OP;
el = ExceptionLevel(inst->ll);
imme = static_cast<U16>(inst->imm16);
}
void A64_EXCEPTION_GEN::assembler() {
SET_OPCODE_MULTI(EXCEPTION_GEN, 1);
SET_OPCODE_MULTI(EXCEPTION_GEN, 2);
ENCODE_OP;
get()->ll = el;
get()->imm16 = imme;
}
A64_SVC::A64_SVC(U16 imme) : A64_EXCEPTION_GEN(XXC, EL1,imme) {}
A64_SVC::A64_SVC() {}
A64_SVC::A64_SVC(STRUCT_A64(SVC) &inst) : A64_EXCEPTION_GEN(inst) {}
A64_LDR_IMM::A64_LDR_IMM() {}
A64_LDR_IMM::A64_LDR_IMM(STRUCT_A64(LDR_IMM) &inst) : A64LoadAndStoreImm(&inst) {
decode(&inst);
}
A64_LDR_IMM::A64_LDR_IMM(RegisterA64 &rt, const MemOperand &operand) : A64LoadAndStoreImm(&rt,
operand) {}
void A64_LDR_IMM::decode(STRUCT_A64(LDR_IMM) *inst) {
regSize = Size(inst->size);
switch (regSize) {
case Size64:
rt = XReg(static_cast<U8>(inst->rt));
operand.base = XReg(static_cast<U8>(inst->rn));
break;
case Size32:
rt = WReg(static_cast<U8>(inst->rt));
operand.base = WReg(static_cast<U8>(inst->rn));
break;
default:
valid = false;
return;
}
addrMode = AdMod(inst->addrmode);
switch (addrMode) {
case PostIndex:
wback = true;
postindex = true;
operand.addr_mode = AddrMode::PostIndex;
break;
case PreIndex:
wback = true;
postindex = false;
operand.addr_mode = AddrMode::PreIndex;
break;
default:
operand.addr_mode = AddrMode::Offset;
valid = false;
}
scale = static_cast<U8>(inst->size);
offset = signExtend64(9, inst->imm9);
operand.offset = offset;
}
void A64_LDR_IMM::assembler() {
SET_OPCODE(LDR_IMM);
get()->rt = rt->getCode();
get()->rn = operand.base->getCode();
get()->imm9 = TruncateToUint9(operand.offset);
if (rt->isX()) {
get()->size = Size64;
} else if (rt->isW()) {
get()->size = Size32;
} else {
valid = false;
return;
}
switch (operand.addr_mode) {
case AddrMode::PostIndex:
wback = true;
postindex = true;
get()->addrmode = PostIndex;
break;
case AddrMode::PreIndex:
wback = true;
postindex = false;
get()->addrmode = PreIndex;
break;
default:
get()->addrmode = Offset;
valid = false;
}
}
A64_LDR_UIMM::A64_LDR_UIMM() {}
A64_LDR_UIMM::A64_LDR_UIMM(STRUCT_A64(LDR_UIMM) &inst) : A64LoadAndStoreImm(&inst) {
decode(&inst);
}
A64_LDR_UIMM::A64_LDR_UIMM(RegisterA64 &rt, const MemOperand &operand) : A64LoadAndStoreImm(&rt,
operand) {}
void A64_LDR_UIMM::decode(STRUCT_A64(LDR_UIMM) *inst) {
regSize = Size(inst->size);
switch (regSize) {
case Size64:
rt = XReg(static_cast<U8>(inst->rt));
operand.base = XReg(static_cast<U8>(inst->rn));
break;
case Size32:
rt = WReg(static_cast<U8>(inst->rt));
operand.base = WReg(static_cast<U8>(inst->rn));
break;
default:
valid = false;
return;
}
operand.addr_mode = AddrMode::Offset;
scale = static_cast<U8>(inst->size);
offset = inst->imm12 << regSize;
operand.offset = offset;
}
void A64_LDR_UIMM::assembler() {
SET_OPCODE(LDR_UIMM);
get()->rt = rt->getCode();
get()->rn = operand.base->getCode();
if (rt->isX()) {
get()->size = Size64;
} else if (rt->isW()) {
get()->size = Size32;
} else {
valid = false;
return;
}
get()->imm12 = static_cast<InstA64>(operand.offset >> get()->size);
}
A64_LDRSW_IMM::A64_LDRSW_IMM() {}
A64_LDRSW_IMM::A64_LDRSW_IMM(STRUCT_A64(LDRSW_IMM) &inst) : A64_LDR_IMM(inst) {}
A64_LDRSW_IMM::A64_LDRSW_IMM(RegisterA64 &rt, const MemOperand &operand) : A64_LDR_IMM(rt,
operand) {}
void A64_LDRSW_IMM::decode(STRUCT_A64(LDR_IMM) *inst) {
rt = XReg(static_cast<U8>(inst->rt));
addrMode = AdMod(inst->addrmode);
switch (addrMode) {
case PostIndex:
wback = true;
postindex = true;
operand.addr_mode = AddrMode::PostIndex;
break;
case PreIndex:
wback = true;
postindex = false;
operand.addr_mode = AddrMode::PreIndex;
break;
default:
valid = false;
return;
}
scale = static_cast<U8>(inst->size);
offset = signExtend64(9, inst->imm9);
operand.offset = offset;
rt = XReg(static_cast<U8>(inst->rt));
operand.base = XReg(static_cast<U8>(inst->rn));
}
void A64_LDRSW_IMM::assembler() {
SET_OPCODE(LDRSW_IMM);
get()->size = Size32;
get()->rt = rt->getCode();
get()->rn = operand.base->getCode();
get()->imm9 = TruncateToUint9(operand.offset);
switch (operand.addr_mode) {
case AddrMode::PostIndex:
wback = true;
postindex = true;
get()->addrmode = PostIndex;
break;
case AddrMode::PreIndex:
wback = true;
postindex = false;
get()->addrmode = PreIndex;
break;
default:
valid = false;
return;
}
}
A64_LDRSW_UIMM::A64_LDRSW_UIMM() {}
A64_LDRSW_UIMM::A64_LDRSW_UIMM(STRUCT_A64(LDR_UIMM) &inst) : A64_LDR_UIMM(inst) {}
A64_LDRSW_UIMM::A64_LDRSW_UIMM(XRegister &rt, const MemOperand &operand) : A64_LDR_UIMM(rt,
operand) {}
void A64_LDRSW_UIMM::decode(STRUCT_A64(LDR_UIMM) *inst) {
DECODE_RT(XReg);
operand.base = XReg(static_cast<U8>(inst->rn));
operand.addr_mode = AddrMode::Offset;
scale = static_cast<U8>(inst->size);
offset = inst->imm12 << Size32;
operand.offset = offset;
}
void A64_LDRSW_UIMM::assembler() {
SET_OPCODE(LDRSW_UIMM);
get()->size = Size32;
ENCODE_RT;
get()->rn = operand.base->getCode();
get()->imm12 = operand.offset >> Size32;
}
//
// Created by swift on 2019/5/6.
//
#ifndef SANDHOOK_NH_INST_ARM64_H
#define SANDHOOK_NH_INST_ARM64_H
#include "inst_struct_aarch64.h"
#include "instruction.h"
#include "base.h"
#include "register_list_arm64.h"
#define INST_A64(X) A64_##X
#define IS_OPCODE_A64(RAW,OP) INST_A64(OP)::is(RAW)
#define DEFINE_IS_EXT(X, COND) \
inline static bool is(InstA64& inst) { \
union { \
InstA64 raw; \
STRUCT_A64(X) inst; \
} inst_test; \
inst_test.raw = inst; \
return COND; \
}
#define DEFINE_IS(X) DEFINE_IS_EXT(X, TEST_INST_FIELD(opcode,OPCODE_A64(X)))
#define TEST_INST_FIELD(F,V) inst_test.inst.F == V
#define TEST_INST_OPCODE(X, INDEX) inst_test.inst.opcode##INDEX == OPCODE_A64(X##_##INDEX)
#define DEFINE_INST_CODE(X) \
inline U32 instCode() override { \
return ENUM_VALUE(InstCodeA64, InstCodeA64::X); \
}
using namespace SandHook::RegistersA64;
using namespace SandHook::Asm;
namespace SandHook {
namespace AsmA64 {
template<typename Inst>
class InstructionA64 : public Instruction<Inst> {
public:
InstructionA64() {}
InstructionA64(Inst *inst) : Instruction<Inst>(inst) {}
Inst mask(Inst raw) {
return raw & *(this->get());
}
U32 size() override;
static inline S64 signExtend64(unsigned int bits, U64 value) {
return ExtractSignedBitfield64(bits - 1, 0, value);
}
static inline S32 signExtend32(unsigned int bits, U32 value) {
return ExtractSignedBitfield32(bits - 1, 0, value);
}
InstType instType() override {
return A64;
}
Arch arch() override {
return arm64;
}
};
enum MemOp {MemOp_LOAD, MemOp_STORE, MemOp_PREFETCH};
enum FPTrapFlags {
EnableTrap = 1,
DisableTrap = 0
};
enum FlagsUpdate {
SetFlags = 1,
LeaveFlags = 0
};
enum ExceptionLevel {
EL0 = 0b00,
EL1 = 0b01,
EL2 = 0b10,
EL3 = 0b11
};
class Operand {
public:
inline explicit Operand(){};
inline explicit Operand(S64 imm)
: immediate(imm), reg(&UnknowRegiser), shift(NO_SHIFT), extend(NO_EXTEND), shift_extend_imm(0) {}
inline Operand(RegisterA64* reg, Shift shift = LSL, int32_t imm = 0)
: immediate(0), reg(reg), shift(shift), extend(NO_EXTEND), shift_extend_imm(imm) {}
inline Operand(RegisterA64* reg, Extend extend, int32_t imm = 0)
: immediate(0), reg(reg), shift(NO_SHIFT), extend(extend), shift_extend_imm(imm) {}
// =====
bool IsImmediate() const { return reg->is(UnknowRegiser); }
bool IsShiftedRegister() const { return (shift != NO_SHIFT); }
bool IsExtendedRegister() const { return (extend != NO_EXTEND); }
public:
S64 immediate;
RegisterA64* reg;
Shift shift;
Extend extend;
int32_t shift_extend_imm;
};
class MemOperand {
public:
inline explicit MemOperand() {}
inline explicit MemOperand(RegisterA64* base, Off offset = 0, AddrMode addr_mode = Offset)
: base(base), reg_offset(&UnknowRegiser), offset(offset), addr_mode(addr_mode), shift(NO_SHIFT),
extend(NO_EXTEND), shift_extend_imm(0) {}
inline explicit MemOperand(RegisterA64* base, RegisterA64* reg_offset, Extend extend, unsigned extend_imm)
: base(base), reg_offset(reg_offset), offset(0), addr_mode(Offset), shift(NO_SHIFT), extend(extend),
shift_extend_imm(extend_imm) {}
inline explicit MemOperand(RegisterA64* base, RegisterA64* reg_offset, Shift shift = LSL, unsigned shift_imm = 0)
: base(base), reg_offset(reg_offset), offset(0), addr_mode(Offset), shift(shift), extend(NO_EXTEND),
shift_extend_imm(shift_imm) {}
inline explicit MemOperand(RegisterA64* base, const Operand &offset, AddrMode addr_mode = Offset)
: base(base), reg_offset(&UnknowRegiser), addr_mode(addr_mode) {
if (offset.IsShiftedRegister()) {
reg_offset = offset.reg;
shift = offset.shift;
shift_extend_imm = offset.shift_extend_imm;
extend = NO_EXTEND;
this->offset = 0;
} else if (offset.IsExtendedRegister()) {
reg_offset = offset.reg;
extend = offset.extend;
shift_extend_imm = offset.shift_extend_imm;
shift = NO_SHIFT;
this->offset = 0;
}
}
// =====
bool IsImmediateOffset() const { return (addr_mode == Offset); }
bool IsRegisterOffset() const { return (addr_mode == Offset); }
bool IsPreIndex() const { return addr_mode == PreIndex; }
bool IsPostIndex() const { return addr_mode == PostIndex; }
public:
RegisterA64* base;
RegisterA64* reg_offset;
Off offset;
AddrMode addr_mode;
Shift shift;
Extend extend;
S32 shift_extend_imm;
};
class INST_A64(UNKNOW) : public InstructionA64<STRUCT_A64(UNKNOW)> {
public:
A64_UNKNOW(STRUCT_A64(UNKNOW) &inst);
DEFINE_INST_CODE(UNKNOW)
inline bool unknow() override {
return true;
}
void decode(A64_STRUCT_UNKNOW *inst) override;
void assembler() override;
private:
STRUCT_A64(UNKNOW) inst_backup;
};
template <typename Inst>
class A64_INST_PC_REL : public InstructionA64<Inst> {
public:
A64_INST_PC_REL();
A64_INST_PC_REL(Inst *inst);
virtual Off getImmPCOffset() = 0;
virtual Addr getImmPCOffsetTarget();
bool pcRelate() override;
};
class INST_A64(ADR_ADRP) : public A64_INST_PC_REL<STRUCT_A64(ADR_ADRP)> {
public:
enum OP {
ADR = 0b0,
ADRP = 0b1,
};
A64_ADR_ADRP();
A64_ADR_ADRP(STRUCT_A64(ADR_ADRP) &inst);
A64_ADR_ADRP(OP op, XRegister &rd, S64 offset);
A64_ADR_ADRP(OP op, XRegister &rd, Label &label);
DEFINE_IS(ADR_ADRP)
DEFINE_INST_CODE(ADR_ADRP)
bool isADRP() {
return get()->op == OP::ADRP;
}
Off getImmPCOffset() override;
Addr getImmPCOffsetTarget() override;
void decode(A64_STRUCT_ADR_ADRP *inst) override;
void assembler() override;
public:
OP op;
XRegister* rd;
S64 offset;
};
class INST_A64(MOV_WIDE) : public InstructionA64<STRUCT_A64(MOV_WIDE)> {
public:
enum OP {
// Move and keep.
MOV_WideOp_K = 0b11,
// Move with zero.
MOV_WideOp_Z = 0b10,
// Move with non-zero.
MOV_WideOp_N = 0b00,
};
enum Shift {
Shift0 = 0,
Shift1 = 16,
Shift2 = 32,
Shift3 = 48
};
A64_MOV_WIDE();
A64_MOV_WIDE(STRUCT_A64(MOV_WIDE) &inst);
A64_MOV_WIDE(A64_MOV_WIDE::OP op, RegisterA64* rd, U16 imme, U8 shift);
DEFINE_IS(MOV_WIDE)
DEFINE_INST_CODE(MOV_WIDE)
void assembler() override;
void decode(STRUCT_A64(MOV_WIDE) *decode) override;
public:
//can be 16/32/64/128
//hw = shift / 16
U8 shift;
OP op;
U16 imme;
RegisterA64* rd;
};
class INST_A64(B_BL) : public A64_INST_PC_REL<STRUCT_A64(B_BL)> {
public:
enum OP {
B = 0b0,
BL = 0b1
};
A64_B_BL();
A64_B_BL(STRUCT_A64(B_BL) &inst);
A64_B_BL(OP op, Off offset);
A64_B_BL(OP op, Label &l);
DEFINE_IS(B_BL)
inline Off getOffset() {
return offset;
}
inline OP getOP() {
return op;
}
DEFINE_INST_CODE(B_BL)
Off getImmPCOffset() override;
void onOffsetApply(Off offset) override;
void decode(STRUCT_A64(B_BL) *decode) override;
void assembler() override;
public:
OP op;
Off offset;
};
class INST_A64(CBZ_CBNZ) : public A64_INST_PC_REL<STRUCT_A64(CBZ_CBNZ)> {
public:
enum OP {
CBZ = 0,
CBNZ = 1
};
A64_CBZ_CBNZ();
A64_CBZ_CBNZ(STRUCT_A64(CBZ_CBNZ) &inst);
A64_CBZ_CBNZ(OP op, Off offset, RegisterA64 &rt);
A64_CBZ_CBNZ(OP op, Label& label, RegisterA64 &rt);
DEFINE_IS(CBZ_CBNZ)
DEFINE_INST_CODE(CBZ_CBNZ)
void onOffsetApply(Off offset) override;
Off getImmPCOffset() override;
void decode(STRUCT_A64(CBZ_CBNZ) *inst) override;
void assembler() override;
public:
OP op;
Off offset;
RegisterA64* rt;
};
class INST_A64(B_COND) : public A64_INST_PC_REL<STRUCT_A64(B_COND)> {
public:
A64_B_COND();
A64_B_COND(STRUCT_A64(B_COND) &inst);
A64_B_COND(Condition condition, Off offset);
A64_B_COND(Condition condition, Label& label);
DEFINE_IS(B_COND)
DEFINE_INST_CODE(B_COND)
Off getImmPCOffset() override;
void onOffsetApply(Off offset) override;
void decode(STRUCT_A64(B_COND) *inst) override;
void assembler() override;
public:
Condition condition;
Off offset;
};
class INST_A64(TBZ_TBNZ) : public A64_INST_PC_REL<STRUCT_A64(TBZ_TBNZ)> {
public:
enum OP {
TBZ = 0,
TBNZ = 1
};
A64_TBZ_TBNZ();
A64_TBZ_TBNZ(STRUCT_A64(TBZ_TBNZ) &inst);
A64_TBZ_TBNZ(OP op, RegisterA64 &rt, U32 bit, Off offset);
A64_TBZ_TBNZ(OP op, RegisterA64 &rt, U32 bit, Label& label);
DEFINE_IS(TBZ_TBNZ)
DEFINE_INST_CODE(TBZ_TBNZ)
void onOffsetApply(Off offset) override;
Off getImmPCOffset() override;
void decode(STRUCT_A64(TBZ_TBNZ) *inst) override;
void assembler() override;
public:
OP op;
RegisterA64* rt;
U32 bit;
Off offset;
};
class INST_A64(LDR_LIT) : public A64_INST_PC_REL<STRUCT_A64(LDR_LIT)> {
public:
enum OP {
LDR_W = 0b00,
LDR_X = 0b01,
LDR_SW = 0b10,
LDR_PRFM = 0b11
};
A64_LDR_LIT();
A64_LDR_LIT(STRUCT_A64(LDR_LIT) &inst);
A64_LDR_LIT(OP op, RegisterA64 &rt, Off offset);
A64_LDR_LIT(OP op, RegisterA64 &rt, Label& label);
DEFINE_IS(LDR_LIT)
DEFINE_INST_CODE(LDR_LIT)
Off getImmPCOffset() override;
void onOffsetApply(Off offset) override;
void decode(STRUCT_A64(LDR_LIT) *inst) override;
void assembler() override;
public:
OP op;
RegisterA64* rt;
Off offset;
};
class INST_A64(BR_BLR_RET) : public InstructionA64<STRUCT_A64(BR_BLR_RET)> {
public:
enum OP {
BR = 0b00,
BLR = 0b01,
RET = 0b11
};
A64_BR_BLR_RET();
A64_BR_BLR_RET(STRUCT_A64(BR_BLR_RET) &inst);
A64_BR_BLR_RET(OP op, XRegister &rn);
DEFINE_IS_EXT(BR_BLR_RET, TEST_INST_OPCODE(BR_BLR_RET, 1) && TEST_INST_OPCODE(BR_BLR_RET, 2) && TEST_INST_OPCODE(BR_BLR_RET,3))
DEFINE_INST_CODE(BR_BLR_RET)
void decode(A64_STRUCT_BR_BLR_RET *inst) override;
void assembler() override;
public:
OP op;
XRegister* rn;
};
template <typename Inst>
class A64LoadAndStoreImm : public InstructionA64<Inst> {
public:
enum AdMod {
Offset = 0b00,
PostIndex = 0b01,
PreIndex = 0b11
};
enum Size {
Size32 = 0b10,
Size64 = 0b11
};
A64LoadAndStoreImm() {}
A64LoadAndStoreImm(Inst *inst) : InstructionA64<Inst>(inst) {}
A64LoadAndStoreImm(RegisterA64 *rt, const MemOperand &operand) : rt(rt),
operand(operand) {}
RegisterA64* rt;
MemOperand operand = MemOperand();
protected:
AdMod addrMode;
Size regSize;
U8 scale;
bool wback;
bool postindex;
Off offset;
};
class INST_A64(STR_IMM) : public A64LoadAndStoreImm<STRUCT_A64(STR_IMM)> {
public:
A64_STR_IMM();
A64_STR_IMM(STRUCT_A64(STR_IMM)& inst);
A64_STR_IMM(RegisterA64 &rt, const MemOperand &operand);
DEFINE_IS(STR_IMM)
DEFINE_INST_CODE(MOV_REG)
void decode(STRUCT_A64(STR_IMM) *inst) override;
void assembler() override;
};
class INST_A64(STR_UIMM) : public A64LoadAndStoreImm<STRUCT_A64(STR_UIMM)> {
public:
A64_STR_UIMM();
A64_STR_UIMM(STRUCT_A64(STR_UIMM)& inst);
A64_STR_UIMM(RegisterA64 &rt, const MemOperand &operand);
DEFINE_IS(STR_UIMM)
DEFINE_INST_CODE(STR_UIMM)
void decode(STRUCT_A64(STR_UIMM) *inst) override;
void assembler() override;
};
class INST_A64(MOV_REG) : public InstructionA64<STRUCT_A64(MOV_REG)> {
public:
A64_MOV_REG();
A64_MOV_REG(STRUCT_A64(MOV_REG) &inst);
A64_MOV_REG(RegisterA64 &rd, RegisterA64 &rm);
DEFINE_IS_EXT(MOV_REG, TEST_INST_OPCODE(MOV_REG, 1) && TEST_INST_OPCODE(MOV_REG, 2))
DEFINE_INST_CODE(MOV_REG)
void decode(A64_STRUCT_MOV_REG *inst) override;
void assembler() override;
public:
RegisterA64* rd;
RegisterA64* rm;
};
class INST_A64(SUB_EXT_REG) : public InstructionA64<STRUCT_A64(SUB_EXT_REG)> {
public:
A64_SUB_EXT_REG();
A64_SUB_EXT_REG(STRUCT_A64(SUB_EXT_REG) &inst);
A64_SUB_EXT_REG(RegisterA64 &rd, RegisterA64 &rn, const Operand &operand,
FlagsUpdate flagsUpdate);
DEFINE_IS_EXT(SUB_EXT_REG, TEST_INST_OPCODE(SUB_EXT_REG, 1) && TEST_INST_OPCODE(SUB_EXT_REG, 2))
DEFINE_INST_CODE(SUB_EXT_REG)
void decode(A64_STRUCT_SUB_EXT_REG *inst) override;
void assembler() override;
public:
RegisterA64* rd;
RegisterA64* rn;
Operand operand = Operand();
FlagsUpdate flagsUpdate;
};
class INST_A64(EXCEPTION_GEN) : public InstructionA64<STRUCT_A64(EXCEPTION_GEN)> {
public:
enum OP {
XXC = 0b000,
BRK = 0b001,
HLT = 0b010,
DCP = 0b101
};
A64_EXCEPTION_GEN();
A64_EXCEPTION_GEN(STRUCT_A64(EXCEPTION_GEN) &inst);
A64_EXCEPTION_GEN(OP op, ExceptionLevel el, U16 imme);
DEFINE_IS_EXT(EXCEPTION_GEN, TEST_INST_OPCODE(EXCEPTION_GEN, 1) && TEST_INST_OPCODE(EXCEPTION_GEN, 2))
DEFINE_INST_CODE(EXCEPTION_GEN)
void decode(STRUCT_A64(EXCEPTION_GEN) *inst) override;
void assembler() override;
public:
OP op;
ExceptionLevel el;
U16 imme;
};
class INST_A64(SVC) : public INST_A64(EXCEPTION_GEN) {
public:
A64_SVC(U16 imme);
A64_SVC();
A64_SVC(STRUCT_A64(SVC) &inst);
DEFINE_IS_EXT(EXCEPTION_GEN, TEST_INST_OPCODE(EXCEPTION_GEN, 1) && TEST_INST_OPCODE(EXCEPTION_GEN, 2) && TEST_INST_FIELD(op, XXC) && TEST_INST_FIELD(ll, EL1))
DEFINE_INST_CODE(SVC)
};
class INST_A64(LDR_IMM) : public A64LoadAndStoreImm<STRUCT_A64(LDR_IMM)> {
public:
A64_LDR_IMM();
A64_LDR_IMM(STRUCT_A64(LDR_IMM) &inst);
A64_LDR_IMM(RegisterA64 &rt, const MemOperand &operand);
DEFINE_IS(LDR_IMM)
DEFINE_INST_CODE(LDR_IMM)
void decode(STRUCT_A64(LDR_IMM) *inst) override;
void assembler() override;
};
class INST_A64(LDR_UIMM) : public A64LoadAndStoreImm<STRUCT_A64(LDR_UIMM)> {
public:
A64_LDR_UIMM();
A64_LDR_UIMM(STRUCT_A64(LDR_UIMM) &inst);
A64_LDR_UIMM(RegisterA64 &rt, const MemOperand &operand);
DEFINE_IS(LDR_UIMM)
DEFINE_INST_CODE(LDR_UIMM)
void decode(STRUCT_A64(LDR_UIMM) *inst) override;
void assembler() override;
};
class INST_A64(LDRSW_IMM) : public INST_A64(LDR_IMM) {
public:
A64_LDRSW_IMM();
A64_LDRSW_IMM(STRUCT_A64(LDRSW_IMM) &inst);
A64_LDRSW_IMM(RegisterA64 &rt, const MemOperand &operand);
DEFINE_IS_EXT(LDRSW_IMM, TEST_INST_FIELD(opcode, OPCODE_A64(LDRSW_IMM)) && TEST_INST_FIELD(size, Size32))
DEFINE_INST_CODE(LDRSW_IMM)
void decode(STRUCT_A64(LDR_IMM) *inst) override;
void assembler() override;
};
class INST_A64(LDRSW_UIMM) : public INST_A64(LDR_UIMM) {
public:
A64_LDRSW_UIMM();
A64_LDRSW_UIMM(STRUCT_A64(LDR_UIMM) &inst);
A64_LDRSW_UIMM(XRegister &rt, const MemOperand &operand);
DEFINE_IS_EXT(LDRSW_UIMM, TEST_INST_FIELD(opcode, OPCODE_A64(LDRSW_UIMM)) && TEST_INST_FIELD(size, Size32))
DEFINE_INST_CODE(LDRSW_UIMM)
void decode(STRUCT_A64(LDR_UIMM) *inst) override;
void assembler() override;
};
}
}
#undef DEFINE_IS_EXT
#undef DEFINE_IS
#undef TEST_INST_FIELD
#undef TEST_INST_OPCODE
#undef DEFINE_INST_CODE
#endif //SANDHOOK_NH_INST_ARM64_H
//
// Created by swift on 2019/5/8.
//
#ifndef SANDHOOK_NH_INST_CODE_ARM64_H
#define SANDHOOK_NH_INST_CODE_ARM64_H
#include "inst_struct_aarch64.h"
enum class InstCodeA64 {
UNKNOW,
MOV_WIDE,
MOV_REG,
ADR_ADRP,
LDR_LIT,
LDR_UIMM,
LDR_IMM,
LDRSW_UIMM,
LDRSW_IMM,
STR_IMM,
STR_UIMM,
B_BL,
B_COND,
BR_BLR_RET,
CBZ_CBNZ,
TBZ_TBNZ,
SUB_EXT_REG,
EXCEPTION_GEN,
SVC
};
#endif //SANDHOOK_NH_INST_CODE_ARM64_H
//
// Created by swift on 2019/5/5.
//
#ifndef SANDHOOK_NH_INST_AARCH64_H
#define SANDHOOK_NH_INST_AARCH64_H
#include "instruction.h"
#include "inst_code_arm64.h"
#include "arm_base.h"
#define STRUCT_A64(X) A64_STRUCT_##X
#define OPCODE_A64(X) A64_OPCODE_##X
#define DEFINE_OPCODE_A64(X, V) const U32 OPCODE_A64(X) = V;
#define DEFINE_STRUCT_A64(X) struct STRUCT_A64(X) : public Base
enum ImmBranchType {
UnknownBranchType = 0,
CondBranchType = 1,
UncondBranchType = 2,
CompareBranchType = 3,
TestBranchType = 4
};
enum Extend {
NO_EXTEND = -1,
UXTB = 0,
UXTH = 1,
UXTW = 2,
UXTX = 3,
SXTB = 4,
SXTH = 5,
SXTW = 6,
SXTX = 7
};
enum FieldWide {
WideReg = 5,
};
//unknow inst
DEFINE_STRUCT_A64(UNKNOW) {
InstA64 raw;
};
#define IMM_LO_W 2
#define IMM_HI_W 19
DEFINE_OPCODE_A64(ADR_ADRP, 0b10000)
struct STRUCT_A64(ADR_ADRP) {
InstA64 rd:WideReg;
InstA64 immhi:IMM_HI_W;
InstA64 opcode:5;
InstA64 immlo:IMM_LO_W;
InstA64 op:1;
};
DEFINE_OPCODE_A64(MOV_WIDE, 0b100101)
DEFINE_STRUCT_A64(MOV_WIDE) {
InstA64 rd:WideReg;
InstA64 imm16:16;
InstA64 hw:2;
InstA64 opcode:6;
InstA64 op:2;
InstA64 sf:1;
};
DEFINE_OPCODE_A64(MOV_REG_1, 0b0101010000)
DEFINE_OPCODE_A64(MOV_REG_2, 0b00000011111)
DEFINE_STRUCT_A64(MOV_REG) {
InstA64 rd:WideReg;
InstA64 opcode2:11;
InstA64 rm:WideReg;
InstA64 opcode1:10;
InstA64 sf:1;
};
DEFINE_OPCODE_A64(B_BL, 0b00101)
DEFINE_STRUCT_A64(B_BL) {
InstA64 imm26:26;
InstA64 opcode:5;
InstA64 op:1;
};
DEFINE_OPCODE_A64(CBZ_CBNZ, 0b011010)
DEFINE_STRUCT_A64(CBZ_CBNZ) {
InstA64 rt:WideReg;
InstA64 imm19:19;
InstA64 op:1;
InstA64 opcode:6;
InstA64 sf:1;
};
DEFINE_OPCODE_A64(B_COND, 0b01010100)
DEFINE_STRUCT_A64(B_COND) {
InstA64 cond:4;
InstA64 unkown_0:1;
InstA64 imm19:19;
InstA64 opcode:8;
};
DEFINE_OPCODE_A64(TBZ_TBNZ, 0b011011)
DEFINE_STRUCT_A64(TBZ_TBNZ) {
InstA64 rt:WideReg;
InstA64 imm14:14;
InstA64 b40:5;
InstA64 op:1;
InstA64 opcode:6;
InstA64 b5:1;
};
DEFINE_OPCODE_A64(LDR_LIT, 0b011000)
DEFINE_STRUCT_A64(LDR_LIT) {
InstA64 rt:WideReg;
InstA64 imm19:19;
InstA64 opcode:6;
InstA64 op:2;
};
DEFINE_OPCODE_A64(LDR_UIMM, 0b11100101)
DEFINE_STRUCT_A64(LDR_UIMM) {
InstA64 rt:WideReg;
InstA64 rn:WideReg;
InstA64 imm12:12;
InstA64 opcode:8;
InstA64 size:2;
};
DEFINE_OPCODE_A64(LDR_IMM, 0b111000010)
DEFINE_STRUCT_A64(LDR_IMM) {
InstA64 rt:WideReg;
InstA64 rn:WideReg;
InstA64 addrmode:2;
InstA64 imm9:9;
InstA64 opcode:9;
InstA64 size:2;
};
DEFINE_OPCODE_A64(LDRSW_UIMM, 0b11100110)
struct STRUCT_A64(LDRSW_UIMM) : public STRUCT_A64(LDR_UIMM) {
};
DEFINE_OPCODE_A64(LDRSW_IMM, 0b111000100)
struct STRUCT_A64(LDRSW_IMM) : public STRUCT_A64(LDR_IMM) {
};
DEFINE_OPCODE_A64(BR_BLR_RET_1, 0b110101100)
DEFINE_OPCODE_A64(BR_BLR_RET_2, 0b11111000000)
DEFINE_OPCODE_A64(BR_BLR_RET_3, 0b00000)
DEFINE_STRUCT_A64(BR_BLR_RET) {
InstA64 opcode3:5;
InstA64 rn:WideReg;
InstA64 opcode2:11;
InstA64 op:2;
InstA64 opcode1:9;
};
DEFINE_OPCODE_A64(STR_IMM, 0b111000000)
DEFINE_STRUCT_A64(STR_IMM) {
InstA64 rt:WideReg;
InstA64 rn:WideReg;
InstA64 addrmode:2;
InstA64 imm9:9;
InstA64 opcode:9;
InstA64 size:2;
};
DEFINE_OPCODE_A64(STR_UIMM, 0b11100100)
DEFINE_STRUCT_A64(STR_UIMM) {
InstA64 rt:WideReg;
InstA64 rn:WideReg;
InstA64 imm12:12;
InstA64 opcode:8;
InstA64 size:2;
};
DEFINE_OPCODE_A64(SUB_EXT_REG_1, 0b1)
DEFINE_OPCODE_A64(SUB_EXT_REG_2, 0b01011001)
DEFINE_STRUCT_A64(SUB_EXT_REG) {
InstA64 rd:WideReg;
InstA64 rn:WideReg;
InstA64 imm3:3;
InstA64 option:3;
InstA64 rm:WideReg;
InstA64 opcode2:8;
InstA64 S:1;
InstA64 opcode1:1;
InstA64 sf:1;
};
DEFINE_OPCODE_A64(EXCEPTION_GEN_1, 0b11010100)
DEFINE_OPCODE_A64(EXCEPTION_GEN_2, 0b000)
DEFINE_STRUCT_A64(EXCEPTION_GEN) {
InstA64 ll:2;
InstA64 opcode2:3;
InstA64 imm16:16;
InstA64 op:3;
InstA64 opcode1:8;
};
struct STRUCT_A64(SVC) : STRUCT_A64(EXCEPTION_GEN) {
};
#endif //SANDHOOK_NH_INST_AARCH64_H
//
// Created by swift on 2019/5/8.
//
#include "register_arm64.h"
#include "register_list_arm64.h"
using namespace SandHook::Asm;
using namespace SandHook::RegistersA64;
RegisterA64::RegisterA64() {}
RegisterA64::RegisterA64(U8 code) : Register(code) {}
XRegister* XRegister::registers[AARCH64_REGISTER_COUNT] = {
#define DEFINE_REGISTERS_X(N) \
&X##N,
AARCH64_REGISTER_CODE_LIST(DEFINE_REGISTERS_X)
#undef DEFINE_REGISTERS_X
};
XRegister::XRegister(U8 code) : RegisterA64(code) {}
XRegister::XRegister() {}
U8 XRegister::getWide() {
return Reg64Bit;
}
WRegister* WRegister::registers[AARCH64_REGISTER_COUNT] = {
#define DEFINE_REGISTERS_W(N) \
&W##N,
AARCH64_REGISTER_CODE_LIST(DEFINE_REGISTERS_W)
#undef DEFINE_REGISTERS_W
};
WRegister::WRegister(U8 code) : RegisterA64(code) {}
WRegister::WRegister() {}
U8 WRegister::getWide() {
return Reg32Bit;
}
//
// Created by swift on 2019/5/8.
//
#ifndef SANDHOOK_NH_REGISTER_A64_H
#define SANDHOOK_NH_REGISTER_A64_H
#include "register.h"
namespace SandHook {
namespace Asm {
union A64RegisterStruct {
struct {
U16 d3;
U16 d2;
U16 d1;
U16 d0;
} u16;
struct {
U32 h;
U32 l;
} u32;
};
class RegisterA64 : public Register<A64RegisterStruct> {
public:
enum RegisterType {
// The kInvalid value is used to detect uninitialized static instances,
// which are always zero-initialized before any constructors are called.
kInvalid = 0,
kRegister,
kVRegister,
kFPRegister = kVRegister,
kNoRegister
};
enum SpecialRegisters {
kFpRegCode = 29,
kLinkRegCode = 30,
kSpRegCode = 31,
kZeroRegCode = 31,
kSPRegInternalCode = 63
};
RegisterA64();
RegisterA64(U8 code);
inline bool isX() {
return is64Bit();
}
inline bool isW() {
return is32Bit();
}
};
class XRegister : public RegisterA64 {
public:
XRegister();
XRegister(U8 code);
U8 getWide() override;
static XRegister* get(U8 code) {
return registers[code];
}
private:
static XRegister* registers[];
};
class WRegister : public RegisterA64 {
public:
WRegister();
WRegister(U8 code);
U8 getWide() override;
static WRegister* get(U8 code) {
return registers[code];
}
private:
static WRegister* registers[];
};
}
}
#endif //SANDHOOK_NH_REGISTER_A64_H
//
// Created by swift on 2019/5/9.
//
#include "register_list_arm64.h"
namespace SandHook {
namespace RegistersA64 {
#define INIT_REGISTERS(N) \
WRegister W##N = WRegister(N); \
XRegister X##N = XRegister(N);
AARCH64_REGISTER_CODE_LIST(INIT_REGISTERS)
#undef INIT_REGISTERS
WRegister WSP = WRegister(RegisterA64::kSPRegInternalCode);
XRegister SP = XRegister(RegisterA64::kSPRegInternalCode);
XRegister IP0 = X16;
XRegister IP1 = X17;
XRegister LR = X30;
//zero reg
XRegister XZR = X31;
WRegister WZR = W31;
RegisterA64 UnknowRegiser = RegisterA64(38);
}
}
\ No newline at end of file
//
// Created by swift on 2019/5/8.
//
#ifndef SANDHOOK_NH_REGISTER_LIST_A64_H
#define SANDHOOK_NH_REGISTER_LIST_A64_H
#include "register_arm64.h"
#include "base.h"
using namespace SandHook::Asm;
// clang-format off
#define AARCH64_REGISTER_COUNT 32
#define AARCH64_REGISTER_CODE_LIST(R) \
R(0) R(1) R(2) R(3) R(4) R(5) R(6) R(7) \
R(8) R(9) R(10) R(11) R(12) R(13) R(14) R(15) \
R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23) \
R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
namespace SandHook {
namespace RegistersA64 {
#define DEFINE_REGISTERS(N) \
extern WRegister W##N; \
extern XRegister X##N;
AARCH64_REGISTER_CODE_LIST(DEFINE_REGISTERS)
#undef DEFINE_REGISTERS
extern WRegister WSP;
extern XRegister SP;
extern XRegister IP0;
extern XRegister IP1;
extern XRegister LR;
//zero reg
extern XRegister XZR;
extern WRegister WZR;
extern RegisterA64 UnknowRegiser;
//cmp....
inline RegisterA64 *zeroRegFor(RegisterA64& registerA64) {
if (registerA64.isX()) {
return &XZR;
} else {
return &WZR;
}
}
}
}
#define XReg(N) XRegister::get(N)
#define WReg(N) WRegister::get(N)
#endif //SANDHOOK_NH_REGISTER_LIST_A64_H
//
// Created by swift on 2019/5/12.
//
#include "code_relocate_arm64.h"
#include "decoder.h"
#include "lock.h"
using namespace SandHook::Decoder;
using namespace SandHook::RegistersA64;
using namespace SandHook::AsmA64;
using namespace SandHook::Utils;
#define __ assemblerA64->
#define IMPL_RELOCATE(X) void CodeRelocateA64::relocate_##X (INST_A64(X)* inst, void* toPc) throw(ErrorCodeException)
#define CASE(X) \
case ENUM_VALUE(InstCodeA64, InstCodeA64::X): \
relocate_##X(reinterpret_cast<INST_A64(X)*>(instruction), toPc); \
break;
CodeRelocateA64::CodeRelocateA64(AssemblerA64 &assembler) : CodeRelocate(assembler.codeContainer) {
assemblerA64 = &assembler;
}
bool CodeRelocateA64::visit(Unit<Base> *unit, void *pc) {
relocate(reinterpret_cast<Instruction<Base> *>(unit), __ getPC());
curOffset += unit->size();
if (unit->refcount() == 0) {
delete unit;
}
return true;
}
void* CodeRelocateA64::relocate(void *startPc, Addr len, void *toPc = nullptr) throw(ErrorCodeException) {
AutoLock autoLock(relocateLock);
startAddr = reinterpret_cast<Addr>(startPc);
length = len;
curOffset = 0;
__ allocBufferFirst(static_cast<U32>(len * 8));
void* curPc = __ getPC();
if (toPc == nullptr) {
Disassembler::get()->decode(startPc, len, *this);
} else {
//TODO
}
return curPc;
}
void* CodeRelocateA64::relocate(Instruction<Base> *instruction, void *toPc) throw(ErrorCodeException) {
void* curPc = __ getPC();
//insert later bind labels
__ Emit(getLaterBindLabel(curOffset));
if (!instruction->pcRelate()) {
__ Emit(instruction);
instruction->ref();
return curPc;
}
switch (instruction->instCode()) {
CASE(B_BL)
CASE(B_COND)
CASE(TBZ_TBNZ)
CASE(CBZ_CBNZ)
CASE(LDR_LIT)
CASE(ADR_ADRP)
default:
__ Emit(instruction);
instruction->ref();
}
return curPc;
}
IMPL_RELOCATE(B_BL) {
if (inRelocateRange(inst->offset, sizeof(InstA64))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(inst->offset + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
if (inst->op == inst->BL) {
__ Mov(LR, (Addr)inst->getPC() + inst->size());
}
__ Mov(IP1, targetAddr);
__ Br(IP1);
}
IMPL_RELOCATE(B_COND) {
if (inRelocateRange(inst->offset, sizeof(InstA64))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(inst->offset + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
Label *true_label = new Label();
Label *false_label = new Label();
__ B(inst->condition, true_label);
__ B(false_label);
__ Emit(true_label);
__ Mov(IP1, targetAddr);
__ Br(IP1);
__ Emit(false_label);
}
IMPL_RELOCATE(TBZ_TBNZ) {
if (inRelocateRange(inst->offset, sizeof(InstA64))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(inst->offset + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
Label *true_label = new Label();
Label *false_label = new Label();
if (inst->op == INST_A64(TBZ_TBNZ)::TBNZ) {
__ Tbnz(*inst->rt, inst->bit, true_label);
} else {
__ Tbz(*inst->rt, inst->bit, true_label);
}
__ B(false_label);
__ Emit(true_label);
__ Mov(IP1, targetAddr);
__ Br(IP1);
__ Emit(false_label);
}
IMPL_RELOCATE(CBZ_CBNZ) {
if (inRelocateRange(inst->offset, sizeof(InstA64))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(inst->offset + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
Addr targetAddr = inst->getImmPCOffsetTarget();
Label *true_label = new Label();
Label *false_label = new Label();
if (inst->op == INST_A64(CBZ_CBNZ)::CBNZ) {
__ Cbnz(*inst->rt, true_label);
} else {
__ Cbz(*inst->rt, true_label);
}
__ B(false_label);
__ Emit(true_label);
__ Mov(IP1, targetAddr);
__ Br(IP1);
__ Emit(false_label);
}
IMPL_RELOCATE(LDR_LIT) {
Addr targetAddr = inst->getImmPCOffsetTarget();
XRegister* rtX = XReg(inst->rt->getCode());
WRegister* rtW = WReg(inst->rt->getCode());
if (inRelocateRange(inst->offset, sizeof(Addr))) {
inst->ref();
inst->bindLabel(*getLaterBindLabel(inst->offset + curOffset));
__ Emit(reinterpret_cast<Instruction<Base>*>(inst));
return;
}
switch (inst->op) {
case INST_A64(LDR_LIT)::LDR_X:
__ Mov(*rtX, targetAddr);
__ Ldr(*rtX, MemOperand(rtX, 0, Offset));
break;
case INST_A64(LDR_LIT)::LDR_W:
__ Mov(*rtX, targetAddr);
__ Ldr(*rtW, MemOperand(rtX, 0, Offset));
break;
case INST_A64(LDR_LIT)::LDR_SW:
__ Mov(*rtX, targetAddr);
__ Ldrsw(*rtX, MemOperand(rtX, 0, Offset));
break;
case INST_A64(LDR_LIT)::LDR_PRFM:
__ Push(X0);
__ Mov(X0, targetAddr);
__ Ldrsw(X0, MemOperand(rtX, 0, Offset));
__ Pop(X0);
break;
}
}
IMPL_RELOCATE(ADR_ADRP) {
__ Mov(*inst->rd, inst->getImmPCOffsetTarget());
}
//
// Created by swift on 2019/5/12.
//
#ifndef SANDHOOK_NH_CODE_RELOCATE_A64_H
#define SANDHOOK_NH_CODE_RELOCATE_A64_H
#include <mutex>
#include <map>
#include "code_relocate.h"
#include "assembler_arm64.h"
using namespace SandHook::Assembler;
using namespace SandHook::Decoder;
using namespace SandHook::AsmA64;
#define DEFINE_RELOCATE(X) void relocate_##X (INST_A64(X)* inst, void* toPc) throw(ErrorCodeException);
namespace SandHook {
namespace Asm {
class CodeRelocateA64 : public CodeRelocate {
public:
CodeRelocateA64(AssemblerA64 &assembler);
void* relocate(Instruction<Base> *instruction, void *toPc) throw(ErrorCodeException) override;
void* relocate(void *startPc, Addr len, void *toPc) throw(ErrorCodeException) override;
bool visit(Unit<Base> *unit, void *pc) override;
DEFINE_RELOCATE(B_BL)
DEFINE_RELOCATE(B_COND)
DEFINE_RELOCATE(TBZ_TBNZ)
DEFINE_RELOCATE(CBZ_CBNZ)
DEFINE_RELOCATE(LDR_LIT)
DEFINE_RELOCATE(ADR_ADRP)
private:
AssemblerA64* assemblerA64;
};
}
}
#undef DEFINE_RELOCATE
#endif //SANDHOOK_NH_CODE_RELOCATE_A64_H
//
// Created by swift on 2019/5/16.
//
#ifndef SANDHOOK_ARM_BASE_H
#define SANDHOOK_ARM_BASE_H
// Condition codes.
enum Condition {
eq = 0, // Z set Equal.
ne = 1, // Z clear Not equal.
cs = 2, // C set Carry set.
cc = 3, // C clear Carry clear.
mi = 4, // N set Negative.
pl = 5, // N clear Positive or zero.
vs = 6, // V set Overflow.
vc = 7, // V clear No overflow.
hi = 8, // C set, Z clear Unsigned higher.
ls = 9, // C clear or Z set Unsigned lower or same.
ge = 10, // N == V Greater or equal.
lt = 11, // N != V Less than.
gt = 12, // Z clear, N == V Greater than.
le = 13, // Z set or N != V Less then or equal
al = 14, // Always.
nv = 15, // Behaves as always/al.
// Aliases.
hs = cs, // C set Unsigned higher or same.
lo = cc // C clear Unsigned lower.
};
enum Shift {
NO_SHIFT = -1,
LSL = 0x0,
LSR = 0x1,
ASR = 0x2,
ROR = 0x3,
MSL = 0x4,
RRX = 0x4
};
enum AddrMode { Offset, PreIndex, PostIndex, NonAddrMode};
//decode field & encode field
//condition
#define DECODE_COND condition = Condition(inst->cond)
#define ENCODE_COND get()->cond = condition
//reg
#define DECODE_RD(Type) rd = Type(static_cast<U8>(get()->rd))
#define ENCODE_RD get()->rd = rd->getCode()
#define DECODE_RT(Type) rt = Type(static_cast<U8>(get()->rt))
#define ENCODE_RT get()->rt = rt->getCode()
#define DECODE_RM(Type) rm = Type(static_cast<U8>(get()->rm))
#define ENCODE_RM get()->rm = rm->getCode()
#define DECODE_RN(Type) rn = Type(static_cast<U8>(get()->rn))
#define ENCODE_RN get()->rn = rn->getCode()
//op
#define DECODE_OP op = OP(inst->op)
#define ENCODE_OP get()->op = op
#endif //SANDHOOK_ARM_BASE_H
//
// Created by swift on 2019/5/16.
//
#ifndef SANDHOOK_PLACE_HOLDER_H
#define SANDHOOK_PLACE_HOLDER_H
#endif //SANDHOOK_PLACE_HOLDER_H
//
// Created by SwiftGan on 2019/4/15.
//
#ifndef SANDHOOK_CPU_H
#define SANDHOOK_CPU_H
#include "register.h"
namespace SandHook {
namespace VM {
class CPU {
public:
};
}
}
#endif //SANDHOOK_CPU_H
//
// Created by swift on 2019/5/10.
//
#ifndef SANDHOOK_NH_DATA_H
#define SANDHOOK_NH_DATA_H
#include "unit.h"
#define DATA(BITS) STRUCT_DATA_##BITS
#define DEFINE_DATA(BITS) \
struct DATA(BITS) : public Base { \
U##BITS raw_; \
public: \
DATA(BITS)(U##BITS r) { \
raw_ = r; \
} \
};
namespace SandHook {
namespace Asm {
template <typename DType>
class Data : public Unit<DType> {
public:
Data(DType raw) : Unit<DType>() {
this->set(raw);
}
inline UnitType unitType() override {
return UnitType::UnitData;
};
};
DEFINE_DATA(16)
class Data16 : public Data<DATA(16)> {
public:
Data16(U16 raw) : Data(DATA(16)(raw)) {}
};
DEFINE_DATA(32)
class Data32 : public Data<DATA(32)> {
public:
Data32(U32 raw) : Data(DATA(32)(raw)) {}
};
DEFINE_DATA(64)
class Data64 : public Data<DATA(64)> {
public:
Data64(U64 raw) : Data(DATA(64)(raw)) {}
};
}
}
#endif //SANDHOOK_NH_DATA_H
//
// Created by SwiftGan on 2019/4/15.
//
#ifndef SANDHOOK_IMME_H
#define SANDHOOK_IMME_H
#include "../includes/base.h"
namespace SandHook {
namespace Asm {
template <typename ImmeType>
class Imme {
public:
virtual ImmeType get() = 0;
virtual void set(ImmeType imme) = 0;
U8 size() {
return immeSize;
};
private:
//byte
U8 immeSize;
ImmeType value;
Arch arch;
InstType instType;
};
}
}
#endif //SANDHOOK_IMME_H
//
// Created by SwiftGan on 2019/4/15.
//
#ifndef SANDHOOK_INSTRUCTION_H
#define SANDHOOK_INSTRUCTION_H
#include "unit.h"
#include "label.h"
//aarch64
typedef U32 InstA64;
//arm32
typedef U32 InstA32;
//thumb16
typedef U16 InstT16;
//thumb32
typedef U32 InstT32;
#if defined(__aarch64__)
typedef U32 InstRaw;
#endif
#define INST_CHECK(X,V) \
CHECK(X,V, valid = false;)
#define INST_DCHECK(X,V) \
DCHECK(X,V, valid = false;)
#define INST_ASSERT(COND) \
if (COND) { \
valid = false; \
}
namespace SandHook {
namespace Asm {
template <typename Inst>
class Instruction : public Unit<Inst>, public LabelBinder {
public:
Instruction() {}
Instruction(Inst *inst) : Unit<Inst>(inst) {}
UnitType unitType() override {
return UnitType::UnitInst;
};
virtual InstType instType() {
return unknowInst;
}
virtual Arch arch() {
return unknowArch;
}
virtual U32 instCode() {
return 0;
};
virtual bool pcRelate() {
return false;
}
virtual bool unknow() {
return false;
}
inline bool isValid() const {
return valid;
}
virtual void onOffsetApply(Off offset) {}
void onLabelApply(Addr pc) override {
onOffsetApply(pc - this->getVPC());
}
inline void bindLabel(Label &l) {
label = &l;
l.addBinder(this);
}
virtual void decode(Inst* inst) {}
virtual void assembler() {}
protected:
bool valid = true;
Label* label = nullptr;
};
class Void : public Unit<Base> {
public:
Void(U32 size) : size_(size) {}
U32 size() override {
return size_;
}
private:
U32 size_;
};
}
}
#endif //SANDHOOK_INSTRUCTION_H
//
// Created by swift on 2019/5/10.
//
#ifndef SANDHOOK_NH_LABEL_H
#define SANDHOOK_NH_LABEL_H
#include "unit.h"
#include <list>
namespace SandHook {
namespace Asm {
class LabelBinder {
public:
virtual void onLabelApply(Addr pc) = 0;
};
class Label : public Unit<Base> {
public:
Label() {}
Label(void *pc) : pc(pc) {}
inline UnitType unitType() override {
return UnitType::UnitLabel;
}
inline U32 size() override {
return 0;
}
inline void setPC(void* pc) {
this->pc = pc;
}
inline void *getPC() override {
return pc;
}
inline void addBinder(LabelBinder* binder) {
binders.push_back(binder);
}
inline void removeBinder(LabelBinder* binder) {
binders.push_back(binder);
}
inline void bindLabel() {
std::list<LabelBinder*>::iterator binder;
for(binder = binders.begin();binder != binders.end(); ++binder) {
(*binder)->onLabelApply(getVPC());
}
}
private:
void* pc;
std::list<LabelBinder*> binders = std::list<LabelBinder*>();
};
}
}
#endif //SANDHOOK_NH_LABEL_H
//
// Created by swift on 2019/5/23.
//
#ifndef SANDHOOK_MEMORY_H
#define SANDHOOK_MEMORY_H
namespace SandHook {
namespace VM {
class Memory {
};
}
}
#endif //SANDHOOK_MEMORY_H
//
// Created by SwiftGan on 2019/4/15.
//
#ifndef SANDHOOK_REGISTER_H
#define SANDHOOK_REGISTER_H
#include "../includes/base.h"
namespace SandHook {
namespace Asm {
enum RegVariant {
Reg32Bit = 32,
Reg64Bit = 64,
Reg128Bit = 128
};
template <typename Data>
class Register {
public:
Register() {}
Register(U8 code) : code(code) {}
inline U8 getCode() {
return code;
}
virtual bool isFP() {
return false;
};
virtual U8 getWide() {
return 0;
};
inline U8 getWideInBytes() {
return static_cast<U8>(getWide() / BITS_OF_BYTE);
};
inline bool is32Bit() {
return getWide() == Reg32Bit;
}
inline bool is64Bit() {
return getWide() == Reg64Bit;
}
inline bool is128Bit() {
return getWide() == Reg128Bit;
}
virtual bool is(const Register &rhs) {
return rhs.code == code;
}
bool operator==(const Register &rhs) const {
return code == rhs.code;
}
bool operator!=(const Register &rhs) const {
return !(rhs == *this);
}
virtual void setData(Data data) {
this->data = data;
}
virtual Data& getData() {
return data;
}
private:
U8 code;
Data data;
};
}
}
#endif //SANDHOOK_REGISTER_H
//
// Created by swift on 2019/5/10.
//
#ifndef SANDHOOK_NH_UNIT_H
#define SANDHOOK_NH_UNIT_H
#include <malloc.h>
#include "../includes/base.h"
namespace SandHook {
namespace Asm {
template <typename Raw>
class Unit {
public:
Unit() {
if (unitType() != UnitVoid) {
raw = reinterpret_cast<Raw *>(malloc(size()));
memset(raw, 0, size());
auto_alloc = true;
}
}
Unit<Raw>(Raw *raw) : raw(raw) {}
Unit<Raw>(Raw raw) {
Unit();
*this->raw = raw;
}
virtual void* getPC() {
return auto_alloc ? nullptr : raw;
}
virtual Addr getVPC() {
return vPos;
}
inline void setVPos(Addr vPos) {
this->vPos = vPos;
}
inline Raw* get() const {
return raw;
}
inline void set(Raw raw) const {
*this->raw = raw;
}
inline void set(Raw* raw) {
if (auto_alloc) {
free(this->raw);
auto_alloc = false;
}
this->raw = raw;
}
inline void copy(void* dest) {
memcpy(dest, getPC(), size());
}
inline void move(Raw* dest) {
memcpy(dest, raw, size());
if (auto_alloc) {
free(raw);
auto_alloc = false;
}
raw = dest;
}
virtual UnitType unitType() {
return UnitType::UnitUnknow;
};
virtual U32 size() {
return sizeof(Raw);
}
inline U8 ref() {
return ++ref_count;
}
inline U8 release() {
return --ref_count;
}
inline U8 refcount() {
return ref_count;
}
virtual ~Unit() {
if (auto_alloc) {
free(raw);
}
}
private:
Raw* raw = nullptr;
Addr vPos = 0;
bool auto_alloc = false;
U8 ref_count = 0;
};
}
}
#endif //SANDHOOK_NH_UNIT_H
//
// Created by swift on 2019/5/10.
//
#include <assembler.h>
#include <platform.h>
using namespace SandHook::Assembler;
using namespace SandHook::Asm;
CodeContainer::CodeContainer(CodeBuffer *codeBuffer) : codeBuffer(codeBuffer) {}
void CodeContainer::setCodeBuffer(CodeBuffer *codeBuffer) {
this->codeBuffer = codeBuffer;
}
void CodeContainer::append(Unit<Base> *unit) {
units.push_back(unit);
unit->setVPos(curPc);
switch (unit->unitType()) {
case UnitLabel:
labels.push_back((Label*)unit);
break;
default:
curPc += unit->size();
}
}
void CodeContainer::commit() {
U32 bufferSize = static_cast<U32>(curPc - startPc);
void* bufferStart;
if (startPc > 0) {
bufferStart = reinterpret_cast<void *>(startPc);
codeBuffer->resetLastBufferSize(bufferSize);
} else {
bufferStart = codeBuffer->getBuffer(bufferSize);
}
Addr pcNow = reinterpret_cast<Addr>(bufferStart);
//commit to code buffer & assembler inst
std::list<Unit<Base>*>::iterator unit;
for(unit = units.begin();unit != units.end(); ++unit) {
if ((*unit)->unitType() == UnitData) {
(*unit)->move(reinterpret_cast<Base *>(pcNow));
} else if ((*unit)->unitType() != UnitLabel) {
(*unit)->set(reinterpret_cast<Base *>(pcNow));
}
if ((*unit)->unitType() == UnitInst) {
reinterpret_cast<Instruction<Base>*>(*unit)->assembler();
}
pcNow += (*unit)->size();
}
//bind labels
std::list<Label*>::iterator label;
for(label = labels.begin();label != labels.end(); ++label) {
(*label)->bindLabel();
}
//flush I cache
flushCache(reinterpret_cast<Addr>(bufferStart), pcNow - reinterpret_cast<Addr>(bufferStart));
//set pc
startPc = reinterpret_cast<Addr>(bufferStart);
curPc = pcNow;
}
void CodeContainer::allocBufferFirst(U32 size) {
startPc = reinterpret_cast<Addr>(codeBuffer->getBuffer(size));
curPc = startPc;
}
CodeContainer::~CodeContainer() {
std::list<Unit<Base>*>::iterator unit;
for(unit = units.begin();unit != units.end(); ++unit) {
delete (*unit);
}
}
Addr CodeContainer::size() {
return curPc - startPc;
}
//
// Created by swift on 2019/5/11.
//
#include <sys/mman.h>
#include <platform.h>
#include "log.h"
#include "code_buffer.h"
#include "lock.h"
using namespace SandHook::Assembler;
using namespace SandHook::Utils;
void *AndroidCodeBuffer::getBuffer(U32 size) {
AutoLock autoLock(allocSpaceLock);
void* mmapRes;
Addr exeSpace = 0;
if (executeSpaceList.size() == 0) {
goto label_alloc_new_space;
} else if (executePageOffset + size > currentExecutePageSize) {
goto label_alloc_new_space;
} else {
exeSpace = reinterpret_cast<Addr>(executeSpaceList.back());
Addr retSpace = exeSpace + executePageOffset;
executePageOffset += size;
return reinterpret_cast<void *>(retSpace);
}
label_alloc_new_space:
currentExecutePageSize = static_cast<U32>(FIT(size, P_SIZE));
mmapRes = mmap(NULL, currentExecutePageSize, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (mmapRes == MAP_FAILED) {
return 0;
}
memset(mmapRes, 0, currentExecutePageSize);
executeSpaceList.push_back(mmapRes);
executePageOffset = size;
return mmapRes;
}
AndroidCodeBuffer::AndroidCodeBuffer() {}
StaticCodeBuffer::StaticCodeBuffer(Addr pc) : pc(pc) {}
void *StaticCodeBuffer::getBuffer(U32 bufferSize) {
if (!memUnprotect(pc, bufferSize)) {
LOGE("error memUnprotect!");
}
return reinterpret_cast<void *>(pc);
}
void AndroidRellocBufferUnsafe::resetLastBufferSize(U32 size) {
if (executePageOffset + (size - lastAllocSize) <= currentExecutePageSize) {
executePageOffset += size - lastAllocSize;
lastAllocSize = size;
}
}
void *AndroidRellocBufferUnsafe::getBuffer(U32 bufferSize) {
void* res = AndroidCodeBuffer::getBuffer(bufferSize);
if (res) {
lastAllocSize = bufferSize;
}
return res;
}
//
// Created by swift on 2019/5/11.
//
#ifndef SANDHOOK_NH_CODE_BUFFER_H
#define SANDHOOK_NH_CODE_BUFFER_H
#include <mutex>
#include "assembler.h"
namespace SandHook {
namespace Assembler {
class AndroidCodeBuffer : public CodeBuffer {
public:
AndroidCodeBuffer();
void *getBuffer(U32 bufferSize) override;
protected:
std::list<void*> executeSpaceList = std::list<void*>();
std::mutex allocSpaceLock;
Addr executePageOffset = 0;
U32 currentExecutePageSize = 0;
};
//thread unsafe
class AndroidRellocBufferUnsafe : public AndroidCodeBuffer {
public:
public:
void resetLastBufferSize(U32 size) override;
void *getBuffer(U32 bufferSize) override;
private:
U32 lastAllocSize;
};
class StaticCodeBuffer : public CodeBuffer {
public:
StaticCodeBuffer(Addr pc);
void *getBuffer(U32 bufferSize) override;
private:
Addr pc;
};
}
}
#endif //SANDHOOK_NH_CODE_BUFFER_H
//
// Created by swift on 2019/5/6.
//
#include "decoder.h"
#if defined(__arm__)
#include "decoder_arm32.h"
#elif defined(__aarch64__)
#include "decoder_arm64.h"
#endif
using namespace SandHook::Decoder;
//do not support now
InstDecoder* Disassembler::get(Arch arch) {
switch (arch) {
case arm32:
return get();
case arm64:
return get();
default:
return nullptr;
}
}
InstDecoder *Disassembler::get() {
#if defined(__arm__)
return Arm32Decoder::instant;
#elif defined(__aarch64__)
return Arm64Decoder::instant;
#else
return nullptr;
#endif
}
//
// Created by swift on 2019/5/10.
//
#include "elf.h"
#include <malloc.h>
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "log.h"
using namespace SandHook::Elf;
ElfImg::ElfImg(const char *elf) {
this->elf = elf;
//load elf
int fd = open(elf, O_RDONLY);
if (fd < 0) {
LOGE("failed to open %s", elf);
return;
}
size = lseek(fd, 0, SEEK_END);
if (size <= 0) {
LOGE("lseek() failed for %s", elf);
}
header = reinterpret_cast<Elf_Ehdr *>(mmap(0, size, PROT_READ, MAP_SHARED, fd, 0));
close(fd);
Elf_Off symtab_entsize = 0;
section_header = reinterpret_cast<Elf_Shdr *>(((size_t) header) + header->e_shoff);
size_t shoff = reinterpret_cast<size_t>(section_header);
char* section_str = reinterpret_cast<char *>(section_header[header->e_shstrndx].sh_offset + ((size_t) header));
bool has_strtab = false;
bool has_dynsym = false;
for (int i = 0; i < header->e_shnum; i++, shoff += header->e_shentsize) {
Elf_Shdr *section_h = (Elf_Shdr *) shoff;
char* sname = section_h->sh_name + section_str;
switch (section_h->sh_type) {
case SHT_DYNSYM:
has_dynsym = true;
dynsym = section_h;
break;
case SHT_SYMTAB:
if (strcmp(sname, ".symtab") == 0) {
symtab = section_h;
symtab_offset = section_h->sh_offset;
symtab_size = section_h->sh_size;
symtab_entsize = section_h->sh_entsize;
symtab_count = symtab_size / symtab_entsize;
}
break;
case SHT_STRTAB:
has_strtab = true;
if (strcmp(sname, ".strtab") == 0) {
strtab = section_h;
symstr_offset = section_h->sh_offset;
}
break;
case SHT_PROGBITS:
if (has_dynsym && has_strtab && bias == -4396) {
bias = (off_t) section_h->sh_addr - (off_t) section_h->sh_offset;
}
break;
}
}
if(!symtab_offset) {
LOGW("can't find symtab from sections\n");
}
sym_start = reinterpret_cast<Elf_Sym *>(((size_t) header) + symtab_offset);
//load module base
base = getModuleBase(elf);
}
ElfImg::~ElfImg() {
//open elf file local
if (buffer) {
free(buffer);
buffer = nullptr;
}
//use mmap
if (header) {
munmap(header, size);
}
}
Elf_Addr ElfImg::getSymbOffset(const char *name) {
Elf_Addr _offset = 0;
for(int i = 0 ; i < symtab_count; i++) {
unsigned int st_type = ELF_ST_TYPE(sym_start[i].st_info);
char* st_name = reinterpret_cast<char *>(((size_t) header) + symstr_offset + sym_start[i].st_name);
if (st_type == STT_FUNC && sym_start[i].st_size) {
if(strcmp(st_name, name) == 0) {
_offset = sym_start[i].st_value;
LOGD("find %s: %x\n", elf ,_offset);
break;
}
}
}
return _offset;
}
Elf_Addr ElfImg::getSymbAddress(const char *name) {
Elf_Addr offset = getSymbOffset(name);
if (offset > 0 && base != nullptr) {
return static_cast<Elf_Addr>((size_t)base + offset - bias);
} else {
return 0;
}
}
void *ElfImg::getModuleBase(const char *name) {
FILE *maps;
char buff[256];
off_t load_addr;
int found = 0;
maps = fopen("/proc/self/maps", "r");
while (fgets(buff, sizeof(buff), maps)) {
if ((strstr(buff, "r-xp") || strstr(buff, "r--p")) && strstr(buff, name)) {
found = 1;
__android_log_print(ANDROID_LOG_DEBUG, "dlopen", "%s\n", buff);
break;
}
}
if (!found) {
LOGE("failed to read load address for %s", name);
return nullptr;
}
if (sscanf(buff, "%lx", &load_addr) != 1)
LOGE("failed to read load address for %s", name);
fclose(maps);
LOGD("get module base %s: %lu", name, load_addr);
return reinterpret_cast<void *>(load_addr);
}
//
// Created by swift on 2019/5/14.
//
#include "hook.h"
#if defined(__arm__)
#include "hook_arm32.h"
#elif defined(__aarch64__)
#include "hook_arm64.h"
#endif
using namespace SandHook::Hook;
AndroidCodeBuffer* InlineHook::backupBuffer = new AndroidCodeBuffer();
#if defined(__arm__)
InlineHook* InlineHook::instance = new InlineHookArm32Android();
#elif defined(__aarch64__)
InlineHook* InlineHook::instance = new InlineHookArm64Android();
#endif
\ No newline at end of file
//
// Created by swift on 2019/5/7.
//
#ifndef SANDHOOK_NH_ASSEMBLER_H
#define SANDHOOK_NH_ASSEMBLER_H
#include "label.h"
#include "instruction.h"
#include "data.h"
namespace SandHook {
using namespace Asm;
namespace Assembler {
class Assembler {
};
class CodeBuffer {
public:
virtual void* getBuffer(U32 size) = 0;
virtual void resetLastBufferSize(U32 size){};
};
class CodeContainer {
public:
CodeContainer(CodeBuffer *codeBuffer);
void setCodeBuffer(CodeBuffer *codeBuffer);
//allow code relocate to get new pc first
void allocBufferFirst(U32 size);
void append(Unit<Base>* unit);
void commit();
Addr size();
virtual ~CodeContainer();
public:
//before commit is virtual address so = 0, after commit is real address
Addr startPc = 0;
Addr curPc = 0;
private:
Addr maxSize = 0;
std::list<Unit<Base>*> units = std::list<Unit<Base>*>();
std::list<Label*> labels = std::list<Label*>();
CodeBuffer* codeBuffer = nullptr;
};
}
}
#endif //SANDHOOK_NH_ASSEMBLER_H
//
// Created by SwiftGan on 2019/4/15.
//
#ifndef SANDHOOK_BASE_H
#define SANDHOOK_BASE_H
#include <cstdint>
#include <cstring>
#include <type_traits>
#include "compiler.h"
typedef uint8_t U8;
typedef uint16_t U16;
typedef uint32_t U32;
typedef uint64_t U64;
typedef int8_t S8;
typedef int16_t S16;
typedef int32_t S32;
typedef int64_t S64;
typedef size_t Addr;
//32bit
#if defined(__i386__) || defined(__arm__)
typedef S32 Off;
//64bit
#elif defined(__aarch64__) || defined(__x86_64__)
typedef S64 Off;
#endif
const int PTR_BYTE = sizeof(void*);
#define PAGE_OFFSET 12
const int BITS_OF_BYTE = 8;
const Addr P_SIZE = 2 << PAGE_OFFSET;
enum Arch {
arm32,
arm64,
unknowArch
};
enum UnitType {
UnitInst,
UnitData,
UnitLabel,
UnitVoid,
UnitUnknow
};
enum InstType {
A32,
thumb16,
thumb32,
A64,
unknowInst
};
template <int SizeInBits>
struct Unsigned;
template <>
struct Unsigned<16> {
typedef U16 type;
};
template <>
struct Unsigned<32> {
typedef U32 type;
};
template <>
struct Unsigned<64> {
typedef U64 type;
};
struct Base {};
template <typename T>
T AlignDown(T pointer,
typename Unsigned<sizeof(T) * BITS_OF_BYTE>::type alignment) {
// Use C-style casts to get static_cast behaviour for integral types (T), and
// reinterpret_cast behaviour for other types.
typename Unsigned<sizeof(T)* BITS_OF_BYTE>::type pointer_raw =
(typename Unsigned<sizeof(T) * BITS_OF_BYTE>::type)pointer;
size_t mask = alignment - 1;
return (T)(pointer_raw & ~mask);
}
#define ALIGN(value, align) ((uintptr_t)value & ~((uintptr_t)align - 1))
template<typename T>
struct Identity {
using type = T;
};
template<typename T>
constexpr T RoundDown(T x, typename Identity<T>::type n) {
return (x & -n);
}
template<typename T>
constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) {
return RoundDown(x + n - 1, n);
}
#define FIT(value, align) value <= align ? align : ((value / align) + align)
#define OFFSET(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
//data covert
// Macros for compile-time format checking.
#if GCC_VERSION_OR_NEWER(4, 4, 0)
#define PRINTF_CHECK(format_index, varargs_index) \
__attribute__((format(gnu_printf, format_index, varargs_index)))
#else
#define PRINTF_CHECK(format_index, varargs_index)
#endif
#ifdef __GNUC__
#define VIXL_HAS_DEPRECATED_WITH_MSG
#elif defined(__clang__)
#ifdef __has_extension(attribute_deprecated_with_message)
#define VIXL_HAS_DEPRECATED_WITH_MSG
#endif
#endif
#ifdef VIXL_HAS_DEPRECATED_WITH_MSG
#define VIXL_DEPRECATED(replaced_by, declarator) \
__attribute__((deprecated("Use \"" replaced_by "\" instead"))) declarator
#else
#define VIXL_DEPRECATED(replaced_by, declarator) declarator
#endif
//只保留低N位
inline uint64_t TruncateToUintN(unsigned n, uint64_t x) {
return static_cast<uint64_t>(x) & ((UINT64_C(1) << n) - 1);
}
VIXL_DEPRECATED("TruncateToUintN",
inline uint64_t truncate_to_intn(unsigned n, int64_t x)) {
return TruncateToUintN(n, x);
}
// clang-format off
#define INT_1_TO_32_LIST(V) \
V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \
V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \
V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \
V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32)
#define INT_33_TO_63_LIST(V) \
V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \
V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \
V(57) V(58) V(59) V(60) V(61) V(62) V(63)
#define INT_1_TO_63_LIST(V) INT_1_TO_32_LIST(V) INT_33_TO_63_LIST(V)
#define DECLARE_TRUNCATE_TO_UINT_32(N) \
inline uint32_t TruncateToUint##N(uint64_t x) { \
return static_cast<uint32_t>(TruncateToUintN(N, x)); \
} \
VIXL_DEPRECATED("TruncateToUint" #N, \
inline uint32_t truncate_to_int##N(int64_t x)) { \
return TruncateToUint##N(x); \
}
INT_1_TO_32_LIST(DECLARE_TRUNCATE_TO_UINT_32)
#undef DECLARE_TRUNCATE_TO_INT_N
//位提取
// Bit field extraction.
inline uint64_t ExtractUnsignedBitfield64(int msb, int lsb, uint64_t x) {
if ((msb == 63) && (lsb == 0)) return x;
return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
}
inline int64_t ExtractSignedBitfield64(int msb, int lsb, U64 x) {
uint64_t temp = ExtractUnsignedBitfield64(msb, lsb, x);
// If the highest extracted bit is set, sign extend.
if ((temp >> (msb - lsb)) == 1) {
temp |= ~UINT64_C(0) << (msb - lsb);
}
int64_t result;
memcpy(&result, &temp, sizeof(result));
return result;
}
inline int32_t ExtractSignedBitfield32(int msb, int lsb, U32 x) {
uint32_t temp = TruncateToUint32(ExtractSignedBitfield64(msb, lsb, x));
int32_t result;
memcpy(&result, &temp, sizeof(result));
return result;
}
template <typename T>
inline T SignExtend(T val, int bitSize) {
T mask = (T(2) << (bitSize - 1)) - T(1);
val &= mask;
T sign_bits = -((val >> (bitSize - 1)) << bitSize);
val |= sign_bits;
return val;
}
inline U16 BITS16L(U32 value) {
return static_cast<U16>(value & 0xffff);
}
inline U16 BITS16H(U32 value) {
return static_cast<U16>(value >> 16);
}
inline U32 BITS32L(U64 value) {
return static_cast<U32>(value);
}
inline U32 BITS32H(U64 value) {
return static_cast<U32>(value >> 32);
}
#define COMBINE(hi, lo, lowide) (hi << lowide) | lo
/* borrow from gdb, refer: binutils-gdb/gdb/arch/arm.h */
#define SUB_MASK(x) ((1L << ((x) + 1)) - 1)
#define BITS(obj, st, fn) (((obj) >> (st)) & SUB_MASK((fn) - (st)))
#define BIT(obj, st) (((obj) >> (st)) & 1)
#define SBITS(obj, st, fn) ((long)(BITS(obj, st, fn) | ((long)BIT(obj, fn) * ~SUB_MASK(fn - st))))
#define DCHECK(X,V, ACTION) \
if (X == V) { \
ACTION \
}
#define CHECK(X,V, ACTION) \
if (X != V) { \
ACTION \
}
#define ENUM_VALUE(Type, Value) static_cast<std::underlying_type<Type>::type>(Value)
#endif //SANDHOOK_BASE_H
//
// Created by swift on 2019/5/10.
//
#ifndef SANDHOOK_NH_CODE_RELOCATE_H
#define SANDHOOK_NH_CODE_RELOCATE_H
#include <mutex>
#include <map>
#include "exception.h"
#include "instruction.h"
#include "assembler.h"
#include "decoder.h"
using namespace SandHook::Assembler;
using namespace SandHook::Decoder;
namespace SandHook {
namespace Asm {
class CodeRelocate : public InstVisitor {
public:
CodeRelocate(CodeContainer &codeContainer) : codeContainer(&codeContainer) {}
virtual void* relocate(Instruction<Base> *instruction, void* toPc) throw(ErrorCodeException) = 0;
virtual void* relocate(void *startPc, Addr len, void *toPc) throw(ErrorCodeException) = 0;
bool inRelocateRange(Off targetOffset, Addr targetLen);
Label* getLaterBindLabel(Addr offset);
virtual ~CodeRelocate() {
delete relocateLock;
delete laterBindlabels;
}
public:
CodeContainer* codeContainer;
std::mutex* relocateLock = new std::mutex();
std::map<Addr, Label*>* laterBindlabels = new std::map<Addr, Label*>();
Addr startAddr = 0;
Addr length = 0;
Addr curOffset = 0;
};
}
}
#endif //SANDHOOK_NH_CODE_RELOCATE_H
//
// Created by swift on 2019/5/6.
//
#ifndef SANDHOOK_NH_COMPILER_H
#define SANDHOOK_NH_COMPILER_H
// Helper to check whether the version of GCC used is greater than the specified
// requirement.
#define MAJOR 1000000
#define MINOR 1000
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \
((__GNUC__ * (MAJOR) + __GNUC_MINOR__ * (MINOR) + __GNUC_PATCHLEVEL__) >= \
((major) * (MAJOR) + ((minor)) * (MINOR) + (patchlevel)))
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) \
((__GNUC__ * (MAJOR) + __GNUC_MINOR__ * (MINOR)) >= \
((major) * (MAJOR) + ((minor)) * (MINOR) + (patchlevel)))
#else
#define GCC_VERSION_OR_NEWER(major, minor, patchlevel) 0
#endif
#if defined(__clang__) && !defined(VIXL_NO_COMPILER_BUILTINS)
// clang-format off
#define COMPILER_HAS_BUILTIN_CLRSB (__has_builtin(__builtin_clrsb))
#define COMPILER_HAS_BUILTIN_CLZ (__has_builtin(__builtin_clz))
#define COMPILER_HAS_BUILTIN_CTZ (__has_builtin(__builtin_ctz))
#define COMPILER_HAS_BUILTIN_FFS (__has_builtin(__builtin_ffs))
#define COMPILER_HAS_BUILTIN_POPCOUNT (__has_builtin(__builtin_popcount))
// clang-format on
#elif defined(__GNUC__) && !defined(VIXL_NO_COMPILER_BUILTINS)
// The documentation for these builtins is available at:
// https://gcc.gnu.org/onlinedocs/gcc-$MAJOR.$MINOR.$PATCHLEVEL/gcc//Other-Builtins.html
// clang-format off
# define COMPILER_HAS_BUILTIN_CLRSB (GCC_VERSION_OR_NEWER(4, 7, 0))
# define COMPILER_HAS_BUILTIN_CLZ (GCC_VERSION_OR_NEWER(3, 4, 0))
# define COMPILER_HAS_BUILTIN_CTZ (GCC_VERSION_OR_NEWER(3, 4, 0))
# define COMPILER_HAS_BUILTIN_FFS (GCC_VERSION_OR_NEWER(3, 4, 0))
# define COMPILER_HAS_BUILTIN_POPCOUNT (GCC_VERSION_OR_NEWER(3, 4, 0))
// clang-format on
#else
// One can define VIXL_NO_COMPILER_BUILTINS to force using the manually
// implemented C++ methods.
// clang-format off
#define COMPILER_HAS_BUILTIN_BSWAP false
#define COMPILER_HAS_BUILTIN_CLRSB false
#define COMPILER_HAS_BUILTIN_CLZ false
#define COMPILER_HAS_BUILTIN_CTZ false
#define COMPILER_HAS_BUILTIN_FFS false
#define COMPILER_HAS_BUILTIN_POPCOUNT false
// clang-format on
#endif
#endif //SANDHOOK_NH_COMPILER_H
//
// Created by swift on 2019/5/6.
//
#ifndef SANDHOOK_NH_DECODER_H
#define SANDHOOK_NH_DECODER_H
#include "base.h"
#include "instruction.h"
namespace SandHook {
namespace Decoder {
using namespace Asm;
class InstVisitor {
public:
//need free unit
virtual bool visit(Unit<Base>* unit, void* pc) = 0;
};
class InstDecoder {
public:
virtual void decode(void* codeStart, Addr codeLen, InstVisitor& visitor) = 0;
};
class Disassembler {
public:
static InstDecoder* get(Arch arch);
static InstDecoder* get();
};
}
}
#endif //SANDHOOK_NH_DECODER_H
//
// Created by swift on 2019/5/10.
//
#ifndef SANDHOOK_NH_ELF_H
#define SANDHOOK_NH_ELF_H
#include <linux/elf.h>
#include "base.h"
#if defined(__LP64__)
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Addr Elf_Addr;
typedef Elf64_Dyn Elf_Dyn;
typedef Elf64_Rela Elf_Rela;
typedef Elf64_Sym Elf_Sym;
typedef Elf64_Off Elf_Off;
#define ELF_R_SYM(i) ELF64_R_SYM(i)
#else
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Addr Elf_Addr;
typedef Elf32_Dyn Elf_Dyn;
typedef Elf32_Rel Elf_Rela;
typedef Elf32_Sym Elf_Sym;
typedef Elf32_Off Elf_Off;
#define ELF_R_SYM(i) ELF32_R_SYM(i)
#endif
namespace SandHook {
namespace Elf {
class ElfImg {
public:
ElfImg(const char* elf);
Elf_Addr getSymbOffset(const char* name);
void* getModuleBase(const char* name);
Elf_Addr getSymbAddress(const char* name);
~ElfImg();
private:
const char* elf = nullptr;
void* base = nullptr;
char* buffer = nullptr;
off_t size = 0;
off_t bias = -4396;
Elf_Ehdr* header = nullptr;
Elf_Shdr* section_header = nullptr;
Elf_Shdr* symtab = nullptr;
Elf_Shdr* strtab = nullptr;
Elf_Shdr* dynsym = nullptr;
Elf_Sym* sym_start = nullptr;
Elf_Off symtab_count = 0;
Elf_Off symstr_offset = 0;
Elf_Off symtab_offset = 0;
Elf_Off symtab_size = 0;
};
}
}
#endif //SANDHOOK_NH_ELF_H
//
// Created by swift on 2019/5/10.
//
#include "exception"
#ifndef SANDHOOK_NH_EXCEPTION_H
#define SANDHOOK_NH_EXCEPTION_H
namespace SandHook {
namespace Asm {
class ErrorCodeException : public std::exception {
public:
ErrorCodeException(const char *what_) : what_(what_) {}
const char *what() const noexcept override {
return what_;
}
private:
const char *what_;
};
}
}
#endif //SANDHOOK_NH_EXCEPTION_H
//
// Created by swift on 2019/5/14.
//
#ifndef SANDHOOK_NH_HOOK_H
#define SANDHOOK_NH_HOOK_H
#include <mutex>
#include "code_buffer.h"
#include "decoder.h"
#include "assembler.h"
#include "code_relocate.h"
namespace SandHook {
namespace Hook {
class InlineHook {
public:
//return == backup method
virtual void* inlineHook(void* origin, void* replace) = 0;
protected:
static AndroidCodeBuffer* backupBuffer;
public:
static InlineHook* instance;
};
}
}
#endif //SANDHOOK_NH_HOOK_H
//
// Created by swift on 2019/5/10.
//
#include "code_relocate.h"
using namespace SandHook::Asm;
//in range of copy
bool CodeRelocate::inRelocateRange(Off targetOffset, Addr targetLen) {
Off startP = curOffset + targetOffset;
Off endP = startP + targetLen;
return startP >= 0 && endP <= length;
}
Label *CodeRelocate::getLaterBindLabel(Addr offset) {
Label* label_per_unit = nullptr;
std::map<Addr,Label*>::iterator it = laterBindlabels->find(offset);
if (it != laterBindlabels->end()) {
label_per_unit = it->second;
}
if (label_per_unit == nullptr) {
label_per_unit = new Label();
laterBindlabels->insert(std::map<Addr, Label*>::value_type(offset, label_per_unit));
}
return label_per_unit;
}
\ No newline at end of file
//
// Created by SwiftGan on 2019/4/15.
//
#include <jni.h>
#include <sys/mman.h>
#include <log.h>
#include "sandhook_native.h"
#include "hook.h"
#include "elf.h"
using namespace SandHook::Hook;
using namespace SandHook::Elf;
int m1 = 5;
int m3 = 1036;
int m2 = 1035;
int m4 = 5;
void (*dosth3Backup)(int, int) = nullptr;
void (*dosth4Backup)() = nullptr;
void (*dosth4Backup2)() = nullptr;
void (*innerSuspendVM)() = nullptr;
void SuspendVMReplace() {
LOGE("VM Suspend!");
innerSuspendVM();
}
void do2() {
int a = 1 + 1;
int b = 1 + 1;
int c = 1 + 1;
int d = 1 + 1;
}
void do3(int x, int y) {
do2();
int a = 1 + 1;
int b = 1 + 1;
int c = 1 + 1;
int d = a + b + c;
LOGE("x = %d", x);
}
void do5() {
LOGE("x = %d", 5);
}
void do4() {
if (m3 > m2) {
return;
}
do5();
int a = 1 + 1;
int b = a + 1;
int d = a + 1;
int e = a + 1;
LOGE("x = %d", 7);
}
void do4replace() {
int a = 1 + 1;
int b = 1 + 1;
int c = 1 + 1;
int d = 1 + 1;
dosth4Backup();
}
void do4replace2() {
int a = 1 + 1;
int c = 1 + 1;
int d = 1 + 1;
dosth4Backup2();
}
void do3replace(int x, int y) {
int a = 1 + 1;
int b = 1 + 1;
int c = 1 + 1;
int d = 1 + 1;
dosth3Backup(x, y);
}
void do1() {
do2();
}
class Visitor : public InstVisitor {
bool visit(Unit<Base> *unit, void *pc) override {
Instruction<Base>* instruction = reinterpret_cast<Instruction<Base> *>(unit);
instruction->assembler();
return true;
}
};
extern "C"
JNIEXPORT void JNICALL
Java_com_swift_sandhook_nativehook_NativeHook_test(JNIEnv *env, jclass jclass1) {
dosth4Backup = reinterpret_cast<void (*)()>(InlineHook::instance->inlineHook(
reinterpret_cast<void *>(do4),
reinterpret_cast<void *>(do4replace)));
do4();
innerSuspendVM = reinterpret_cast<void (*)()>(SandInlineHookSym("/system/lib64/libart.so", "_ZN3art3Dbg9SuspendVMEv",
reinterpret_cast<void *>(SuspendVMReplace)));
}
extern "C"
EXPORT void* SandInlineHook(void* origin, void* replace) {
return InlineHook::instance->inlineHook(origin, replace);
}
extern "C"
EXPORT void* SandInlineHookSym(const char* so, const char* symb, void* replace) {
ElfImg elfImg(so);
void* origin = reinterpret_cast<void *>(elfImg.getSymbAddress(symb));
if (origin == nullptr)
return nullptr;
return InlineHook::instance->inlineHook(origin, replace);
}
\ No newline at end of file
//
// Created by SwiftGan on 2019/4/15.
//
#ifndef SANDHOOK_SANDHOOK_NATIVE_H
#define SANDHOOK_SANDHOOK_NATIVE_H
#define EXPORT __attribute__ ((visibility ("default")))
extern "C"
EXPORT void* SandInlineHook(void* origin, void* replace);
extern "C"
EXPORT void* SandInlineHookSym(const char* so, const char* symb, void* replace);
#endif //SANDHOOK_SANDHOOK_NATIVE_H
//
// Created by swift on 2019/5/11.
//
#ifndef SANDHOOK_NH_LOCK_H
#define SANDHOOK_NH_LOCK_H
#include <mutex>
namespace SandHook {
namespace Utils {
class AutoLock {
public:
inline AutoLock(std::mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline AutoLock(std::mutex* mutex) : mLock(*mutex) { mLock.lock(); }
inline ~AutoLock() { mLock.unlock(); }
private:
std::mutex& mLock;
};
}
}
#endif //SANDHOOK_NH_LOCK_H
//
// Created by SwiftGan on 2019/2/15.
//
#ifndef SANDHOOK_LOG_H
#define SANDHOOK_LOG_H
#include "android/log.h"
#define TAG "SandHook-Native"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#endif //SANDHOOK_LOG_H
//
// Created by swift on 2019/5/11.
//
#include <unistd.h>
#include <sys/mman.h>
#include "platform.h"
bool flushCache(Addr addr, Off len) {
#if defined(__arm__)
int i = cacheflush(addr, addr + len, 0);
if (i == -1) {
return false;
}
return true;
#elif defined(__aarch64__)
char *begin = reinterpret_cast<char *>(addr);
__builtin___clear_cache(begin, begin + len);
#endif
return true;
}
extern "C" bool memUnprotect(Addr addr, Addr len) {
long pagesize = P_SIZE;
unsigned alignment = (unsigned)((unsigned long long)addr % pagesize);
int i = mprotect((void *) (addr - alignment), (size_t) (alignment + len),
PROT_READ | PROT_WRITE | PROT_EXEC);
return i != -1;
}
\ No newline at end of file
//
// Created by swift on 2019/5/11.
//
#ifndef SANDHOOK_NH_PLATFORM_H
#define SANDHOOK_NH_PLATFORM_H
#include "base.h"
extern "C" bool flushCache(Addr addr, Off len);
extern "C" bool memUnprotect(Addr addr, Addr len);
#endif //SANDHOOK_NH_PLATFORM_H
package com.swift.sandhook.nativehook;
/**
* @author Swift Gan
* Create: 2019/5/10
* Desc:
*/
public class NativeHook {
static {
System.loadLibrary("sandhook-native");
}
public static void dosth() {}
public static native void test();
}
<resources>
<string name="app_name">nativehook</string>
</resources>
package com.swift.sandhook.nativehook;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
include ':app', ':hooklib', ':hookers', ':annotation', ':xposedcompat'
include ':app', ':hooklib', ':hookers', ':annotation', ':xposedcompat', ':nativehook'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment