├── .gitignore ├── LICENSE.txt ├── README.md ├── annotation ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── swift │ └── sandhook │ └── annotation │ ├── HookClass.java │ ├── HookMethod.java │ ├── HookMethodBackup.java │ ├── HookMode.java │ ├── HookReflectClass.java │ ├── MethodParams.java │ ├── MethodReflectParams.java │ ├── Param.java │ ├── SkipParamCheck.java │ └── ThisObject.java ├── app ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── swift │ │ └── sandhook │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── swift │ │ │ └── sandhook │ │ │ ├── MainActivity.java │ │ │ ├── MyApp.java │ │ │ ├── test │ │ │ ├── Inter.java │ │ │ ├── InterImpl.java │ │ │ ├── PendingHookTest.java │ │ │ └── TestClass.java │ │ │ └── testHookers │ │ │ ├── ActivityHooker.java │ │ │ ├── CtrHook.java │ │ │ ├── CustmizeHooker.java │ │ │ ├── JniHooker.java │ │ │ ├── LogHooker.java │ │ │ ├── NewAnnotationApiHooker.java │ │ │ └── ObjectHooker.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── content_main.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── swift │ └── sandhook │ └── ExampleUnitTest.java ├── build.gradle ├── built ├── arm64-v8a │ ├── libsandhook-native.so │ └── libsandhook.so └── armeabi-v7a │ ├── libsandhook-native.so │ └── libsandhook.so ├── doc ├── doc.md └── res │ ├── inline_flow.png │ ├── pc_relate.png │ └── sandhook_arch.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── hookers ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── swift │ │ └── sandhook │ │ └── hookers │ │ ├── AbsHooker.java │ │ └── PluginHooker.java │ └── res │ └── values │ └── strings.xml ├── hooklib ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ ├── CMakeLists.txt │ ├── art │ │ ├── art_compiler_options.cpp │ │ └── art_method.cpp │ ├── casts │ │ ├── cast_art_method.cpp │ │ └── cast_compiler_options.cpp │ ├── includes │ │ ├── arch.h │ │ ├── arch_base.h │ │ ├── art_compiler_options.h │ │ ├── art_jit.h │ │ ├── art_method.h │ │ ├── art_runtime.h │ │ ├── cast.h │ │ ├── cast_art_method.h │ │ ├── cast_compiler_options.h │ │ ├── dlfcn_nougat.h │ │ ├── elf_util.h │ │ ├── hide_api.h │ │ ├── inst.h │ │ ├── log.h │ │ ├── native_hook.h │ │ ├── never_call.h │ │ ├── offset.h │ │ ├── sandhook.h │ │ ├── trampoline.h │ │ ├── trampoline_manager.h │ │ └── utils.h │ ├── inst │ │ ├── insts_arm32.cpp │ │ └── insts_arm64.cpp │ ├── nativehook │ │ └── native_hook.cpp │ ├── sandhook.cpp │ ├── trampoline │ │ ├── arch │ │ │ ├── arm32.S │ │ │ └── arm64.S │ │ ├── trampoline.cpp │ │ └── trampoline_manager.cpp │ └── utils │ │ ├── dlfcn_nougat.cpp │ │ ├── elf_util.cpp │ │ ├── hide_api.cpp │ │ ├── lock.h │ │ ├── offset.cpp │ │ └── utils.cpp │ ├── java │ └── com │ │ └── swift │ │ └── sandhook │ │ ├── ArtMethodSizeTest.java │ │ ├── ClassNeverCall.java │ │ ├── HookLog.java │ │ ├── PendingHookHandler.java │ │ ├── SandHook.java │ │ ├── SandHookConfig.java │ │ ├── SandHookMethodResolver.java │ │ ├── blacklist │ │ └── HookBlackList.java │ │ ├── utils │ │ ├── ArtDexOptimizer.java │ │ ├── ClassStatusUtils.java │ │ ├── FileUtils.java │ │ ├── ParamWrapper.java │ │ ├── ReflectionUtils.java │ │ └── Unsafe.java │ │ └── wrapper │ │ ├── HookErrorException.java │ │ ├── HookWrapper.java │ │ └── StubMethodsFactory.java │ └── res │ └── values │ └── strings.xml ├── nativehook ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── cpp │ ├── CMakeLists.txt │ ├── archs │ │ ├── arm │ │ │ ├── arm32 │ │ │ │ ├── assembler │ │ │ │ │ ├── assembler_arm32.cpp │ │ │ │ │ └── assembler_arm32.h │ │ │ │ ├── decoder │ │ │ │ │ ├── decoder_arm32.cpp │ │ │ │ │ └── decoder_arm32.h │ │ │ │ ├── hook │ │ │ │ │ ├── breakpoint_shellcode.S │ │ │ │ │ ├── hook_arm32.cpp │ │ │ │ │ └── hook_arm32.h │ │ │ │ ├── inst │ │ │ │ │ ├── arm32_base.h │ │ │ │ │ ├── inst_arm32.cpp │ │ │ │ │ ├── inst_arm32.h │ │ │ │ │ ├── inst_code_arm32.h │ │ │ │ │ ├── inst_struct_a32.h │ │ │ │ │ ├── inst_struct_t16.h │ │ │ │ │ ├── inst_struct_t32.h │ │ │ │ │ ├── inst_t16.cpp │ │ │ │ │ ├── inst_t16.h │ │ │ │ │ ├── inst_t32.cpp │ │ │ │ │ └── inst_t32.h │ │ │ │ ├── register │ │ │ │ │ ├── register_arm32.cpp │ │ │ │ │ ├── register_arm32.h │ │ │ │ │ ├── register_list_arm32.cpp │ │ │ │ │ └── register_list_arm32.h │ │ │ │ └── relocate │ │ │ │ │ ├── code_relocate_arm32.cpp │ │ │ │ │ └── code_relocate_arm32.h │ │ │ ├── arm64 │ │ │ │ ├── assembler │ │ │ │ │ ├── assembler_arm64.cpp │ │ │ │ │ └── assembler_arm64.h │ │ │ │ ├── decoder │ │ │ │ │ ├── decoder_arm64.cpp │ │ │ │ │ └── decoder_arm64.h │ │ │ │ ├── hook │ │ │ │ │ ├── hook_arm64.cpp │ │ │ │ │ └── hook_arm64.h │ │ │ │ ├── inst │ │ │ │ │ ├── inst_arm64.cpp │ │ │ │ │ ├── inst_arm64.h │ │ │ │ │ ├── inst_code_arm64.h │ │ │ │ │ └── inst_struct_aarch64.h │ │ │ │ ├── register │ │ │ │ │ ├── register_arm64.cpp │ │ │ │ │ ├── register_arm64.h │ │ │ │ │ ├── register_list_arm64.cpp │ │ │ │ │ └── register_list_arm64.h │ │ │ │ └── relocate │ │ │ │ │ ├── code_relocate_arm64.cpp │ │ │ │ │ └── code_relocate_arm64.h │ │ │ ├── arm_base.h │ │ │ └── shellcode_arm.h │ │ └── x86 │ │ │ └── place_holder.h │ ├── asm │ │ ├── cpu.h │ │ ├── data.h │ │ ├── instruction.h │ │ ├── label.h │ │ ├── ram.h │ │ ├── register.h │ │ └── unit.h │ ├── assembler │ │ └── assembler.cpp │ ├── buffer │ │ ├── code_buffer.cpp │ │ └── code_buffer.h │ ├── decoder │ │ └── decoder.cpp │ ├── elf │ │ └── elf.cpp │ ├── hook │ │ └── hook.cpp │ ├── includes │ │ ├── assembler.h │ │ ├── base.h │ │ ├── code_relocate.h │ │ ├── compiler.h │ │ ├── decoder.h │ │ ├── elf.h │ │ ├── exception.h │ │ └── hook.h │ ├── relocate │ │ └── code_relocate.cpp │ ├── sandhook_native.cpp │ ├── sandhook_native.h │ └── utils │ │ ├── lock.h │ │ ├── log.h │ │ ├── platform.cpp │ │ └── platform.h │ ├── java │ └── com │ │ └── swift │ │ └── sandhook │ │ └── nativehook │ │ └── NativeHook.java │ └── res │ └── values │ └── strings.xml ├── settings.gradle ├── xposedcompat ├── .gitignore ├── build.gradle ├── genhookstubs.py ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── com │ │ ├── android │ │ │ ├── dx │ │ │ │ ├── AnnotationId.java │ │ │ │ ├── AppDataDirGuesser.java │ │ │ │ ├── BinaryOp.java │ │ │ │ ├── Code.java │ │ │ │ ├── Comparison.java │ │ │ │ ├── Constants.java │ │ │ │ ├── DexMaker.java │ │ │ │ ├── FieldId.java │ │ │ │ ├── Label.java │ │ │ │ ├── Local.java │ │ │ │ ├── MethodId.java │ │ │ │ ├── TypeId.java │ │ │ │ ├── TypeList.java │ │ │ │ ├── UnaryOp.java │ │ │ │ └── stock │ │ │ │ │ └── ProxyBuilder.java │ │ │ └── internal │ │ │ │ └── util │ │ │ │ └── XmlUtils.java │ │ └── swift │ │ │ └── sandhook │ │ │ └── xposedcompat │ │ │ ├── XposedCompat.java │ │ │ ├── classloaders │ │ │ └── ProxyClassLoader.java │ │ │ ├── hookstub │ │ │ ├── CallOriginCallBack.java │ │ │ ├── HookMethodEntity.java │ │ │ ├── HookStubManager.java │ │ │ ├── MethodHookerStubs32.java │ │ │ └── MethodHookerStubs64.java │ │ │ ├── methodgen │ │ │ ├── DynamicBridge.java │ │ │ ├── ErrorCatch.java │ │ │ ├── HookMaker.java │ │ │ ├── HookerDexMaker.java │ │ │ └── HookerDexMakerNew.java │ │ │ └── utils │ │ │ ├── ApplicationUtils.java │ │ │ ├── DexLog.java │ │ │ ├── DexMakerUtils.java │ │ │ ├── FileUtils.java │ │ │ └── ProcessUtils.java │ ├── de │ │ └── robv │ │ │ └── android │ │ │ └── xposed │ │ │ ├── IXposedHookCmdInit.java │ │ │ ├── IXposedHookInitPackageResources.java │ │ │ ├── IXposedHookLoadPackage.java │ │ │ ├── IXposedHookZygoteInit.java │ │ │ ├── IXposedMod.java │ │ │ ├── SELinuxHelper.java │ │ │ ├── XC_MethodHook.java │ │ │ ├── XC_MethodReplacement.java │ │ │ ├── XSharedPreferences.java │ │ │ ├── XposedBridge.java │ │ │ ├── XposedHelpers.java │ │ │ ├── XposedInit.java │ │ │ ├── callbacks │ │ │ ├── IXUnhook.java │ │ │ ├── XC_InitPackageResources.java │ │ │ ├── XC_LayoutInflated.java │ │ │ ├── XC_LoadPackage.java │ │ │ ├── XCallback.java │ │ │ └── package-info.java │ │ │ └── services │ │ │ ├── BaseService.java │ │ │ ├── DirectAccessService.java │ │ │ └── FileResult.java │ └── external │ │ └── org │ │ └── apache │ │ └── commons │ │ └── lang3 │ │ ├── ArrayUtils.java │ │ ├── CharSequenceUtils.java │ │ ├── CharUtils.java │ │ ├── ClassUtils.java │ │ ├── JavaVersion.java │ │ ├── ObjectUtils.java │ │ ├── StringUtils.java │ │ ├── SystemUtils.java │ │ ├── Validate.java │ │ ├── builder │ │ ├── Builder.java │ │ ├── CompareToBuilder.java │ │ ├── EqualsBuilder.java │ │ ├── HashCodeBuilder.java │ │ ├── IDKey.java │ │ ├── ReflectionToStringBuilder.java │ │ ├── ToStringBuilder.java │ │ └── ToStringStyle.java │ │ ├── exception │ │ └── CloneFailedException.java │ │ ├── mutable │ │ ├── Mutable.java │ │ └── MutableInt.java │ │ ├── reflect │ │ ├── MemberUtils.java │ │ └── MethodUtils.java │ │ └── tuple │ │ ├── ImmutablePair.java │ │ └── Pair.java │ └── res │ └── values │ └── strings.xml └── xposedcompat_new ├── .gitignore ├── CMakeLists.txt ├── build.gradle ├── proguard-rules.pro └── src └── main ├── AndroidManifest.xml ├── cpp ├── art_jni_trampoline.cpp ├── art_jni_trampoline.h └── libffi │ ├── aarch64 │ ├── ffi_arm64.c │ ├── internal.h │ └── sysv_arm64.S │ ├── arm │ ├── ffi_armv7.c │ ├── internal.h │ └── sysv_armv7.S │ ├── closures.c │ ├── debug.c │ ├── dlmalloc.c │ ├── ffi.h │ ├── ffi_cfi.h │ ├── ffi_common.h │ ├── ffi_cxx.cc │ ├── ffi_cxx.h │ ├── fficonfig.h │ ├── ffitarget.h │ ├── java_raw_api.c │ ├── platform_include │ ├── ffi_arm64.h │ ├── ffi_armv7.h │ ├── ffi_i386.h │ ├── ffi_x86_64.h │ ├── fficonfig_arm64.h │ ├── fficonfig_armv7.h │ ├── fficonfig_i386.h │ ├── fficonfig_x86_64.h │ ├── ffitarget_arm64.h │ ├── ffitarget_armv7.h │ ├── ffitarget_i386.h │ └── ffitarget_x86_64.h │ ├── prep_cif.c │ ├── raw_api.c │ └── types.c ├── java ├── com │ ├── android │ │ └── internal │ │ │ └── util │ │ │ └── XmlUtils.java │ └── swift │ │ └── sandhook │ │ └── xposedcompat │ │ ├── HookInfo.java │ │ ├── XposedCompat.java │ │ └── utils │ │ ├── ApplicationUtils.java │ │ ├── ClassUtils.java │ │ ├── ProcessUtils.java │ │ └── ProxyClassLoader.java ├── de │ └── robv │ │ └── android │ │ └── xposed │ │ ├── IXposedHookCmdInit.java │ │ ├── IXposedHookInitPackageResources.java │ │ ├── IXposedHookLoadPackage.java │ │ ├── IXposedHookZygoteInit.java │ │ ├── IXposedMod.java │ │ ├── SELinuxHelper.java │ │ ├── XC_MethodHook.java │ │ ├── XC_MethodReplacement.java │ │ ├── XSharedPreferences.java │ │ ├── XposedBridge.java │ │ ├── XposedHelpers.java │ │ ├── XposedInit.java │ │ ├── callbacks │ │ ├── IXUnhook.java │ │ ├── XC_InitPackageResources.java │ │ ├── XC_LayoutInflated.java │ │ ├── XC_LoadPackage.java │ │ ├── XCallback.java │ │ └── package-info.java │ │ └── services │ │ ├── BaseService.java │ │ ├── DirectAccessService.java │ │ └── FileResult.java └── external │ └── org │ └── apache │ └── commons │ └── lang3 │ ├── ArrayUtils.java │ ├── CharSequenceUtils.java │ ├── CharUtils.java │ ├── ClassUtils.java │ ├── JavaVersion.java │ ├── ObjectUtils.java │ ├── StringUtils.java │ ├── SystemUtils.java │ ├── Validate.java │ ├── builder │ ├── Builder.java │ ├── CompareToBuilder.java │ ├── EqualsBuilder.java │ ├── HashCodeBuilder.java │ ├── IDKey.java │ ├── ReflectionToStringBuilder.java │ ├── ToStringBuilder.java │ └── ToStringStyle.java │ ├── exception │ └── CloneFailedException.java │ ├── mutable │ ├── Mutable.java │ └── MutableInt.java │ ├── reflect │ ├── MemberUtils.java │ └── MethodUtils.java │ └── tuple │ ├── ImmutablePair.java │ └── Pair.java ├── jniLibs ├── arm64-v8a │ └── libsandhook-native.so └── armeabi-v7a │ └── libsandhook-native.so └── res └── values └── strings.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/libraries 5 | /.idea/modules.xml 6 | /.idea/workspace.xml 7 | .DS_Store 8 | /build 9 | /captures 10 | .externalNativeBuild 11 | -------------------------------------------------------------------------------- /annotation/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /annotation/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java-library' 2 | 3 | dependencies { 4 | implementation fileTree(dir: 'libs', include: ['*.jar']) 5 | } 6 | 7 | sourceCompatibility = "1.7" 8 | targetCompatibility = "1.7" 9 | 10 | ext { 11 | bintrayRepo = 'maven' 12 | bintrayName = 'swift-sandhook-annotation' 13 | } 14 | 15 | apply plugin: 'com.novoda.bintray-release' 16 | 17 | publish { 18 | userOrg = rootProject.userOrg 19 | groupId = rootProject.groupId 20 | artifactId = 'hookannotation' 21 | publishVersion = rootProject.publishVersion 22 | desc = rootProject.desc 23 | website = rootProject.website 24 | licences = rootProject.licences 25 | } 26 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/HookClass.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.TYPE}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface HookClass { 11 | Class value(); 12 | } 13 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/HookMethod.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface HookMethod { 11 | String value() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/HookMethodBackup.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD,ElementType.FIELD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface HookMethodBackup { 11 | String value() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/HookMode.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface HookMode { 11 | 12 | int AUTO = 0; 13 | int INLINE = 1; 14 | int REPLACE = 2; 15 | 16 | int value() default AUTO; 17 | } 18 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/HookReflectClass.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.TYPE}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface HookReflectClass { 11 | String value(); 12 | } 13 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/MethodParams.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD,ElementType.FIELD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface MethodParams { 11 | Class[] value(); 12 | } -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/MethodReflectParams.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD,ElementType.FIELD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface MethodReflectParams { 11 | 12 | String BOOLEAN = "boolean"; 13 | String BYTE = "byte"; 14 | String CHAR = "char"; 15 | String DOUBLE = "double"; 16 | String FLOAT = "float"; 17 | String INT = "int"; 18 | String LONG = "long"; 19 | String SHORT = "short"; 20 | 21 | String[] value(); 22 | } -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/Param.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface Param { 11 | String value() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/SkipParamCheck.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.METHOD, ElementType.FIELD}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface SkipParamCheck { 11 | } 12 | -------------------------------------------------------------------------------- /annotation/src/main/java/com/swift/sandhook/annotation/ThisObject.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target({ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ThisObject { 11 | } 12 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # For more information about using CMake with Android Studio, read the 2 | # documentation: https://d.android.com/studio/projects/add-native-code.html 3 | 4 | # Sets the minimum version of CMake required to build the native library. 5 | 6 | cmake_minimum_required(VERSION 3.4.1) 7 | 8 | # Creates and names a library, sets it as either STATIC 9 | # or SHARED, and provides the relative paths to its source code. 10 | # You can define multiple libraries, and CMake builds them for you. 11 | # Gradle automatically packages shared libraries with your APK. 12 | 13 | add_library( # Sets the name of the library. 14 | native-lib 15 | 16 | # Sets the library as a shared library. 17 | SHARED 18 | 19 | # Provides a relative path to your source file(s). 20 | src/main/cpp/native-lib.cpp 21 | src/main/cpp/trampoline/trampoline.cpp 22 | src/main/cpp/trampoline/trampoline_manager.cpp 23 | src/main/cpp/utils/fake_dlfcn.cpp 24 | src/main/cpp/trampoline/arch/arm32.S 25 | src/main/cpp/trampoline/arch/arm64.S 26 | ) 27 | 28 | # Searches for a specified prebuilt library and stores the path as a 29 | # variable. Because CMake includes system libraries in the search path by 30 | # default, you only need to specify the name of the public NDK library 31 | # you want to add. CMake verifies that the library exists before 32 | # completing its build. 33 | 34 | find_library( # Sets the name of the path variable. 35 | log-lib 36 | 37 | # Specifies the name of the NDK library that 38 | # you want CMake to locate. 39 | log ) 40 | 41 | # Specifies libraries CMake should link to your target library. You 42 | # can link multiple libraries, such as libraries you define in this 43 | # build script, prebuilt third-party libraries, or system libraries. 44 | 45 | target_link_libraries( # Specifies the target library. 46 | native-lib 47 | 48 | # Links the target library to the log library 49 | # included in the NDK. 50 | ${log-lib} ) 51 | 52 | 53 | add_definitions(-std=c++11) 54 | 55 | ENABLE_LANGUAGE(ASM) -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | defaultConfig { 6 | applicationId "com.swift.sandhook" 7 | minSdkVersion 19 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | debug { 15 | debuggable true 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(include: ['*.jar'], dir: 'libs') 24 | implementation 'com.android.support:appcompat-v7:28.0.0' 25 | implementation 'com.android.support.constraint:constraint-layout:1.1.3' 26 | implementation 'com.android.support:design:28.0.0' 27 | testImplementation 'junit:junit:4.12' 28 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 29 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 30 | implementation project(':hooklib') 31 | implementation project(':nativehook') 32 | implementation project(':xposedcompat') 33 | //implementation project(':xposedcompat_new') 34 | } 35 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/swift/sandhook/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.swift.sandhook", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/test/Inter.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.test; 2 | 3 | public interface Inter { 4 | void dosth(); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/test/InterImpl.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.test; 2 | 3 | import android.util.Log; 4 | 5 | public class InterImpl implements Inter { 6 | @Override 7 | public void dosth() { 8 | Log.e("dosth", "sasa"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/test/PendingHookTest.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.test; 2 | 3 | import android.util.Log; 4 | 5 | import com.swift.sandhook.MyApp; 6 | 7 | public class PendingHookTest { 8 | 9 | static { 10 | if (!MyApp.initedTest) { 11 | throw new RuntimeException("PendingHookTest.class may can not init this time!"); 12 | } 13 | } 14 | 15 | public static void test() { 16 | Log.e("PendingHookTest", "hook failure!"); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/test/TestClass.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.test; 2 | 3 | import com.swift.sandhook.MainActivity; 4 | 5 | public class TestClass { 6 | 7 | public int a = 1; 8 | int b = 2; 9 | 10 | public TestClass(int a) { 11 | this.a = a + 1; 12 | } 13 | 14 | public void add1 () { 15 | a++; 16 | b++; 17 | throw new RuntimeException("test exception"); 18 | } 19 | 20 | public void add2 () { 21 | a++; 22 | b++; 23 | } 24 | 25 | public void testNewHookApi (MainActivity activity, int x) { 26 | x++; 27 | a++; 28 | b++; 29 | } 30 | 31 | public native void jni_test(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/ActivityHooker.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | 7 | import com.swift.sandhook.SandHook; 8 | import com.swift.sandhook.annotation.HookClass; 9 | import com.swift.sandhook.annotation.HookMethod; 10 | import com.swift.sandhook.annotation.HookMethodBackup; 11 | import com.swift.sandhook.annotation.MethodParams; 12 | import com.swift.sandhook.annotation.ThisObject; 13 | import com.swift.sandhook.wrapper.HookWrapper; 14 | 15 | import java.lang.reflect.Method; 16 | 17 | @HookClass(Activity.class) 18 | public class ActivityHooker { 19 | 20 | @HookMethodBackup("onCreate") 21 | @MethodParams(Bundle.class) 22 | static Method onCreateBackup; 23 | 24 | @HookMethodBackup("onPause") 25 | static HookWrapper.HookEntity onPauseBackup; 26 | 27 | @HookMethod("onCreate") 28 | @MethodParams(Bundle.class) 29 | public static void onCreate(Activity thiz, Bundle bundle) throws Throwable { 30 | Log.e("ActivityHooker", "hooked onCreate success " + thiz); 31 | SandHook.callOriginByBackup(onCreateBackup, thiz, bundle); 32 | } 33 | 34 | @HookMethod("onPause") 35 | public static void onPause(@ThisObject Activity thiz) throws Throwable { 36 | Log.e("ActivityHooker", "hooked onPause success " + thiz); 37 | onPauseBackup.callOrigin(thiz); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/CtrHook.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.util.Log; 4 | 5 | import com.swift.sandhook.SandHook; 6 | import com.swift.sandhook.annotation.HookClass; 7 | import com.swift.sandhook.annotation.HookMethod; 8 | import com.swift.sandhook.annotation.HookMethodBackup; 9 | import com.swift.sandhook.annotation.HookMode; 10 | import com.swift.sandhook.annotation.SkipParamCheck; 11 | import com.swift.sandhook.annotation.ThisObject; 12 | import com.swift.sandhook.test.TestClass; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | @HookClass(TestClass.class) 17 | public class CtrHook { 18 | 19 | @HookMethodBackup 20 | @SkipParamCheck 21 | static Method ctrbackup; 22 | 23 | @HookMethodBackup("add1") 24 | @SkipParamCheck 25 | static Method add1backup; 26 | 27 | @HookMethodBackup("add2") 28 | @SkipParamCheck 29 | static Method add2backup; 30 | 31 | @HookMethod 32 | public static void onCtr(@ThisObject TestClass thiz, int a) throws Throwable { 33 | Log.e("TestClassHook", "TestClass(int) been hooked"); 34 | SandHook.callOriginByBackup(ctrbackup, thiz, a); 35 | } 36 | 37 | @HookMethod("add1") 38 | @HookMode(HookMode.INLINE) 39 | public static void onAdd1(TestClass thiz) throws Throwable { 40 | Log.e("TestClassHook", "add1 been hooked"); 41 | try { 42 | SandHook.callOriginByBackup(add1backup, thiz); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | } 47 | 48 | @HookMethod("add2") 49 | public static void onAdd2(TestClass thiz) throws Throwable { 50 | SandHook.callOriginByBackup(add2backup, thiz); 51 | } 52 | 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/CustmizeHooker.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.util.Log; 4 | 5 | import com.swift.sandhook.MainActivity; 6 | import com.swift.sandhook.annotation.HookClass; 7 | import com.swift.sandhook.annotation.HookMethod; 8 | import com.swift.sandhook.annotation.HookMethodBackup; 9 | import com.swift.sandhook.annotation.MethodParams; 10 | 11 | import java.lang.reflect.Method; 12 | 13 | @HookClass(MainActivity.class) 14 | public class CustmizeHooker { 15 | 16 | @HookMethodBackup("methodBeHooked") 17 | @MethodParams({int.class, int.class}) 18 | static Method backup; 19 | 20 | @HookMethod("methodBeHooked") 21 | @MethodParams({int.class, int.class}) 22 | public static int staticMethodHooked(int a, int b) { 23 | Log.e("CustmizeHooker", "methodBeHooked be hooked"); 24 | try { 25 | return (int) backup.invoke(null, a, b); 26 | } catch (Exception e) { 27 | e.printStackTrace(); 28 | } 29 | return 0; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/JniHooker.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.os.Build; 4 | import android.util.Log; 5 | 6 | import com.swift.sandhook.SandHook; 7 | import com.swift.sandhook.annotation.HookClass; 8 | import com.swift.sandhook.annotation.HookMethod; 9 | import com.swift.sandhook.annotation.HookMethodBackup; 10 | import com.swift.sandhook.annotation.SkipParamCheck; 11 | import com.swift.sandhook.annotation.ThisObject; 12 | import com.swift.sandhook.test.TestClass; 13 | 14 | import java.lang.reflect.Method; 15 | 16 | @HookClass(TestClass.class) 17 | public class JniHooker { 18 | 19 | @HookMethodBackup("jni_test") 20 | @SkipParamCheck 21 | static Method backup; 22 | 23 | @HookMethod("jni_test") 24 | public static void onJni(@ThisObject TestClass thiz) throws Throwable { 25 | Log.e("JniHooker", "hooked success "); 26 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { 27 | SandHook.callOriginByBackup(backup, thiz); 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/LogHooker.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.util.Log; 4 | 5 | import com.swift.sandhook.SandHook; 6 | import com.swift.sandhook.annotation.HookClass; 7 | import com.swift.sandhook.annotation.HookMethod; 8 | import com.swift.sandhook.annotation.HookMethodBackup; 9 | import com.swift.sandhook.annotation.Param; 10 | import com.swift.sandhook.annotation.SkipParamCheck; 11 | 12 | import java.lang.reflect.Method; 13 | 14 | @HookClass(Log.class) 15 | public class LogHooker { 16 | 17 | @HookMethodBackup("w") 18 | @SkipParamCheck 19 | static Method backup; 20 | 21 | @HookMethod("w") 22 | public static int onCreate(String tag, @Param("java.lang.String") Object msg) throws Throwable { 23 | Log.e("LogHooker", "hooked success " + tag); 24 | return (int) SandHook.callOriginByBackup(backup, null, tag, msg); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/NewAnnotationApiHooker.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | 6 | import com.swift.sandhook.SandHook; 7 | import com.swift.sandhook.annotation.HookClass; 8 | import com.swift.sandhook.annotation.HookMethod; 9 | import com.swift.sandhook.annotation.HookMethodBackup; 10 | import com.swift.sandhook.annotation.Param; 11 | import com.swift.sandhook.annotation.SkipParamCheck; 12 | import com.swift.sandhook.annotation.ThisObject; 13 | import com.swift.sandhook.test.TestClass; 14 | 15 | import java.lang.reflect.Method; 16 | 17 | @HookClass(TestClass.class) 18 | public class NewAnnotationApiHooker { 19 | 20 | @HookMethodBackup("testNewHookApi") 21 | @SkipParamCheck 22 | static Method backup; 23 | 24 | @HookMethod("testNewHookApi") 25 | public static void onTestNewHookApi(@ThisObject TestClass thiz, @Param("com.swift.sandhook.MainActivity") Activity activity, int a) throws Throwable { 26 | Log.e("TestClassHook", "testNewHookApi been hooked"); 27 | SandHook.callOriginByBackup(backup, thiz, activity, a); 28 | } 29 | 30 | @HookMethodBackup("testNewHookApi") 31 | public static void onTestNewHookApiBackup(@ThisObject TestClass thiz, @Param("com.swift.sandhook.MainActivity") Activity activity, int a) { 32 | onTestNewHookApiBackup(thiz, activity, a); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/swift/sandhook/testHookers/ObjectHooker.java: -------------------------------------------------------------------------------- 1 | package com.swift.sandhook.testHookers; 2 | 3 | import android.util.Log; 4 | 5 | import com.swift.sandhook.annotation.HookClass; 6 | import com.swift.sandhook.annotation.HookMethod; 7 | import com.swift.sandhook.annotation.HookMethodBackup; 8 | import com.swift.sandhook.annotation.HookMode; 9 | import com.swift.sandhook.wrapper.HookWrapper; 10 | 11 | @HookClass(Object.class) 12 | public class ObjectHooker { 13 | 14 | @HookMethodBackup("toString") 15 | static HookWrapper.HookEntity toStrHook; 16 | 17 | @HookMethod("toString") 18 | @HookMode(HookMode.INLINE) 19 | public static String toStr(Object thiz) throws Throwable { 20 | Log.e("ObjectHooker", "hooked success "); 21 | return (String) toStrHook.callOrigin(thiz); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asLody/SandHook/16a59fa0eef011ca202814311b362a8a3bcda412/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | SandHook 3 | Settings 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |