Commit 0c0d3112 authored by swift_gan's avatar swift_gan

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	nativehook/src/main/cpp/sandhook_native.cpp
parents f6870aeb 1b81d376
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (c) 2019 <copyright holders>
"Anti 996" License Version 1.0 (Draft)
Permission is hereby granted to any individual or legal entity
obtaining a copy of this licensed work (including the source code,
documentation and/or related items, hereinafter collectively referred
to as the "licensed work"), free of charge, to deal with the licensed
work for any purpose, including without limitation, the rights to use,
reproduce, modify, prepare derivative works of, distribute, publish
and sublicense the licensed work, subject to the following conditions:
1. The individual or the legal entity must conspicuously display,
without modification, this License and the notice on each redistributed
or derivative copy of the Licensed Work.
2. The individual or the legal entity must strictly comply with all
applicable laws, regulations, rules and standards of the jurisdiction
relating to labor and employment where the individual is physically
located or where the individual was born or naturalized; or where the
legal entity is registered or is operating (whichever is stricter). In
case that the jurisdiction has no such laws, regulations, rules and
standards or its laws, regulations, rules and standards are
unenforceable, the individual or the legal entity are required to
comply with Core International Labor Standards.
3. The individual or the legal entity shall not induce, suggest or force
its employee(s), whether full-time or part-time, or its independent
contractor(s), in any methods, to agree in oral or written form, to
directly or indirectly restrict, weaken or relinquish his or her
rights or remedies under such laws, regulations, rules and standards
relating to labor and employment as mentioned above, no matter whether
such written or oral agreements are enforceable under the laws of the
said jurisdiction, nor shall such individual or the legal entity
limit, in any methods, the rights of its employee(s) or independent
contractor(s) from reporting or complaining to the copyright holder or
relevant authorities monitoring the compliance of the license about
its violation(s) of the said license.
THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE
LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK.
\ No newline at end of file
# SandHook
Android ART Hook
- Android ART Hook
- Native Inline Hook
## Version
[ ![Version](https://api.bintray.com/packages/ganyao114/maven/hooklib/images/download.svg) ](https://bintray.com/ganyao114/maven/hooklib/_latestVersion)
......@@ -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(unstabitily)
#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.
//
#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