├── .gitignore ├── WeChatPay.jpg ├── bsd ├── Makefile ├── arch │ ├── amd64 │ │ ├── distorm │ │ │ ├── config.h │ │ │ ├── decoder.c │ │ │ ├── decoder.h │ │ │ ├── distorm.c │ │ │ ├── distorm.h │ │ │ ├── instructions.c │ │ │ ├── instructions.h │ │ │ ├── insts.c │ │ │ ├── insts.h │ │ │ ├── mnemonics.c │ │ │ ├── mnemonics.h │ │ │ ├── operands.c │ │ │ ├── operands.h │ │ │ ├── prefix.c │ │ │ ├── prefix.h │ │ │ ├── textdefs.c │ │ │ ├── textdefs.h │ │ │ ├── wstring.h │ │ │ └── x86defs.h │ │ ├── hijack_amd64.c │ │ └── hijack_amd64.h │ └── arm64 │ │ ├── hijack_arm64.c │ │ └── hijack_arm64.h ├── framework │ ├── dev_interface.c │ ├── hijack_operation.c │ ├── include │ │ └── common_data.h │ ├── module.c │ └── symbol_resolve.c ├── readme_bsd.md └── sample │ ├── hook_fdrop.c │ └── replace_sys_open.c ├── demo.gif ├── linux ├── sample │ ├── Makefile │ ├── aftvermagic.sh │ ├── hook_fuse_open.c │ ├── hook_vfs_read.c │ ├── include │ │ ├── common_data.h │ │ ├── hijack_arm.h │ │ ├── hijack_arm64.h │ │ ├── hijack_powerpc.h │ │ ├── hijack_x86.h │ │ ├── hijack_x86_64.h │ │ └── hook_framework.h │ ├── module.c │ ├── prevermagic.sh │ └── replace_vfs_open.c └── src │ ├── Makefile │ ├── aftvermagic.sh │ ├── arch │ ├── arm │ │ ├── hijack_arm.c │ │ └── hijack_arm.h │ ├── arm64 │ │ ├── hijack_arm64.c │ │ └── hijack_arm64.h │ ├── powerpc │ │ ├── hijack_powerpc.c │ │ └── hijack_powerpc.h │ ├── x86 │ │ ├── common.c │ │ ├── hijack_x86.c │ │ └── hijack_x86.h │ └── x86_64 │ │ ├── common.c │ │ ├── hijack_x86_64.c │ │ └── hijack_x86_64.h │ ├── framework │ ├── hijack_operation.c │ ├── module.c │ ├── proc_interface.c │ ├── stack_safety_check.c │ ├── symbol_resolver.c │ ├── symbol_resolver_bak.c │ └── write_map_page.c │ ├── include │ └── common_data.h │ └── prevermagic.sh └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.cmd 2 | *.ko 3 | *.mod.c 4 | *.nam 5 | *.o 6 | *.til 7 | *.txt 8 | *.d 9 | .tmp_versions 10 | modules.order 11 | Module.symvers 12 | .vscode/* 13 | -------------------------------------------------------------------------------- /WeChatPay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiJiLab/kernel-inline-hook-framework/500c4f7f016e271c3c54a4f52df8a9cc117b002c/WeChatPay.jpg -------------------------------------------------------------------------------- /bsd/Makefile: -------------------------------------------------------------------------------- 1 | KMOD=hookFrame 2 | ARCH != echo $$(uname -m) 3 | 4 | SRCS+=framework/module.c 5 | SRCS+=framework/symbol_resolve.c 6 | SRCS+=framework/hijack_operation.c 7 | SRCS+=framework/dev_interface.c 8 | SRCS+=arch/$(ARCH)/hijack_$(ARCH).c 9 | SRCS+=vnode_if.h 10 | 11 | .if $(ARCH) == "amd64" 12 | SRCS+=arch/$(ARCH)/distorm/decoder.c 13 | SRCS+=arch/$(ARCH)/distorm/distorm.c 14 | SRCS+=arch/$(ARCH)/distorm/instructions.c 15 | SRCS+=arch/$(ARCH)/distorm/insts.c 16 | SRCS+=arch/$(ARCH)/distorm/mnemonics.c 17 | SRCS+=arch/$(ARCH)/distorm/operands.c 18 | SRCS+=arch/$(ARCH)/distorm/prefix.c 19 | SRCS+=arch/$(ARCH)/distorm/textdefs.c 20 | .endif 21 | 22 | SRCS+=sample/replace_sys_open.c 23 | SRCS+=sample/hook_fdrop.c 24 | 25 | CFLAGS+=-I$(PWD)/framework -I$(PWD)/arch/$(ARCH) -D"_$(ARCH)_" 26 | .include 27 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | config.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef CONFIG_H 13 | #define CONFIG_H 14 | 15 | /* diStorm version number. */ 16 | #define __DISTORMV__ 0x030503 17 | 18 | #include /* memset, memcpy - can be easily self implemented for libc independency. */ 19 | 20 | #include "distorm.h" 21 | 22 | 23 | /* 24 | * 64 bit offsets support: 25 | * This macro should be defined from compiler command line flags, e.g: -DSUPPORT_64BIT_OFFSET 26 | * Note: make sure that the caller (library user) defines it too! 27 | */ 28 | /* #define SUPPORT_64BIT_OFFSET */ 29 | 30 | /* 31 | * If you compile diStorm as a dynamic library (.dll or .so) file, make sure you uncomment the next line. 32 | * So the interface functions will be exported, otherwise they are useable only for static library. 33 | * For example, this macro is being set for compiling diStorm as a .dll for Python with CTypes. 34 | */ 35 | /* #define DISTORM_DYNAMIC */ 36 | 37 | /* 38 | * If DISTORM_LIGHT is defined, everything involved in formatting the instructions 39 | * as text will be excluded from compilation. 40 | * distorm_decode(..) and distorm_format(..) will not be available. 41 | * This will decrease the size of the executable and leave you with decomposition functionality only. 42 | * 43 | * Note: it should be either set in the preprocessor definitions manually or in command line -D switch. 44 | * #define DISTORM_LIGHT 45 | */ 46 | 47 | /* 48 | * diStorm now supports little/big endian CPU's. 49 | * It should detect the endianness according to predefined macro's of the compiler. 50 | * If you don't use GCC/MSVC you will have to define it on your own. 51 | */ 52 | 53 | /* These macros are used in order to make the code portable. */ 54 | #ifdef __GNUC__ 55 | 56 | // #include 57 | 58 | #define _DLLEXPORT_ 59 | #define _FASTCALL_ 60 | /* Keep inline as static (arrrrg) as it would break linux on some flavors otherwise. */ 61 | #define _INLINE_ static 62 | /* GCC ignores this directive... */ 63 | /*#define _FASTCALL_ __attribute__((__fastcall__))*/ 64 | 65 | /* Set endianity (supposed to be LE though): */ 66 | #ifdef __BIG_ENDIAN__ 67 | #define BE_SYSTEM 68 | #endif 69 | 70 | /* End of __GCC__ */ 71 | 72 | #elif __WATCOMC__ 73 | 74 | #include 75 | 76 | #define _DLLEXPORT_ 77 | #define _FASTCALL_ 78 | #define _INLINE_ __inline 79 | 80 | /* End of __WATCOMC__ */ 81 | 82 | #elif __DMC__ 83 | 84 | #include 85 | 86 | #define _DLLEXPORT_ 87 | #define _FASTCALL_ 88 | #define _INLINE_ __inline 89 | 90 | /* End of __DMC__ */ 91 | 92 | #elif __TINYC__ 93 | 94 | #include 95 | 96 | #define _DLLEXPORT_ 97 | #define _FASTCALL_ 98 | #define _INLINE_ static 99 | 100 | /* End of __TINYC__ */ 101 | 102 | #elif _MSC_VER 103 | 104 | /* stdint alternative is defined in distorm.h */ 105 | 106 | #define _DLLEXPORT_ __declspec(dllexport) 107 | #define _FASTCALL_ __fastcall 108 | #define _INLINE_ __inline 109 | 110 | /* Set endianity (supposed to be LE though): */ 111 | #if !defined(_M_IX86) && !defined(_M_X64) 112 | #define BE_SYSTEM 113 | #endif 114 | 115 | #endif /* #elif _MSC_VER */ 116 | 117 | /* If the library isn't compiled as a dynamic library don't export any functions. */ 118 | #ifndef DISTORM_DYNAMIC 119 | #undef _DLLEXPORT_ 120 | #define _DLLEXPORT_ 121 | #endif 122 | 123 | #ifndef FALSE 124 | #define FALSE 0 125 | #endif 126 | #ifndef TRUE 127 | #define TRUE 1 128 | #endif 129 | 130 | /* Define stream read functions for big endian systems. */ 131 | #ifdef BE_SYSTEM 132 | 133 | /* Avoid defining 'static static' for GCC. */ 134 | #ifndef __GNUC__ 135 | #define STATIC_INLINE static _INLINE_ 136 | #else 137 | #define STATIC_INLINE static 138 | #endif 139 | 140 | /* 141 | * Assumption: These functions can read from the stream safely! 142 | * Swap endianity of input to little endian. 143 | */ 144 | STATIC_INLINE int16_t RSHORT(const uint8_t *s) 145 | { 146 | return s[0] | (s[1] << 8); 147 | } 148 | STATIC_INLINE uint16_t RUSHORT(const uint8_t *s) 149 | { 150 | return s[0] | (s[1] << 8); 151 | } 152 | STATIC_INLINE int32_t RLONG(const uint8_t *s) 153 | { 154 | return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); 155 | } 156 | STATIC_INLINE uint32_t RULONG(const uint8_t *s) 157 | { 158 | return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24); 159 | } 160 | STATIC_INLINE int64_t RLLONG(const uint8_t *s) 161 | { 162 | return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) | ((uint64_t)s[4] << 32) | ((uint64_t)s[5] << 40) | ((uint64_t)s[6] << 48) | ((uint64_t)s[7] << 56); 163 | } 164 | STATIC_INLINE uint64_t RULLONG(const uint8_t *s) 165 | { 166 | return s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24) | ((uint64_t)s[4] << 32) | ((uint64_t)s[5] << 40) | ((uint64_t)s[6] << 48) | ((uint64_t)s[7] << 56); 167 | } 168 | 169 | #undef STATIC_INLINE 170 | 171 | #else 172 | /* Little endian macro's will just make the cast. */ 173 | #define RSHORT(x) *(int16_t *)x 174 | #define RUSHORT(x) *(uint16_t *)x 175 | #define RLONG(x) *(int32_t *)x 176 | #define RULONG(x) *(uint32_t *)x 177 | #define RLLONG(x) *(int64_t *)x 178 | #define RULLONG(x) *(uint64_t *)x 179 | #endif 180 | 181 | #endif /* CONFIG_H */ 182 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | decoder.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef DECODER_H 13 | #define DECODER_H 14 | 15 | #include "config.h" 16 | 17 | typedef unsigned int _iflags; 18 | 19 | _DecodeResult decode_internal(_CodeInfo* _ci, int supportOldIntr, _DInst result[], unsigned int maxResultCount, unsigned int* usedInstructionsCount); 20 | 21 | #endif /* DECODER_H */ 22 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/distorm.c: -------------------------------------------------------------------------------- 1 | /* 2 | distorm.c 3 | 4 | diStorm3 C Library Interface 5 | diStorm3 - Powerful disassembler for X86/AMD64 6 | http://ragestorm.net/distorm/ 7 | distorm at gmail dot com 8 | Copyright (C) 2003-2021 Gil Dabah 9 | This library is licensed under the BSD license. See the file COPYING. 10 | */ 11 | 12 | 13 | #include "distorm.h" 14 | #include "config.h" 15 | #include "decoder.h" 16 | #include "x86defs.h" 17 | #include "textdefs.h" 18 | #include "wstring.h" 19 | #include "mnemonics.h" 20 | 21 | /* C DLL EXPORTS */ 22 | #ifdef SUPPORT_64BIT_OFFSET 23 | _DLLEXPORT_ _DecodeResult distorm_decompose64(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount) 24 | #else 25 | _DLLEXPORT_ _DecodeResult distorm_decompose32(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount) 26 | #endif 27 | { 28 | if (usedInstructionsCount == NULL) { 29 | return DECRES_SUCCESS; 30 | } 31 | 32 | if ((ci == NULL) || 33 | (ci->codeLen < 0) || 34 | ((unsigned)ci->dt > (unsigned)Decode64Bits) || 35 | (ci->code == NULL) || 36 | (result == NULL) || 37 | (maxInstructions == 0) || 38 | ((ci->features & (DF_MAXIMUM_ADDR16 | DF_MAXIMUM_ADDR32)) == (DF_MAXIMUM_ADDR16 | DF_MAXIMUM_ADDR32))) 39 | { 40 | return DECRES_INPUTERR; 41 | } 42 | 43 | return decode_internal(ci, FALSE, result, maxInstructions, usedInstructionsCount); 44 | } 45 | 46 | #ifndef DISTORM_LIGHT 47 | 48 | /* Helper function to concatenate an explicit size when it's unknown from the operands. */ 49 | static void distorm_format_size(unsigned char** str, const _DInst* di, int opNum) 50 | { 51 | int isSizingRequired = 0; 52 | /* 53 | * We only have to output the size explicitly if it's not clear from the operands. 54 | * For example: 55 | * mov al, [0x1234] -> The size is 8, we know it from the AL register operand. 56 | * mov [0x1234], 0x11 -> Now we don't know the size. Pam pam pam 57 | * 58 | * If given operand number is higher than 2, then output the size anyways. 59 | */ 60 | isSizingRequired = ((opNum >= 2) || ((opNum == 0) && (di->ops[0].type != O_REG) && (di->ops[1].type != O_REG))); 61 | 62 | /* Still not sure? Try some special instructions. */ 63 | if (!isSizingRequired) { 64 | /* 65 | * INS/OUTS are exception, because DX is a port specifier and not a real src/dst register. 66 | * A few exceptions that always requires sizing: 67 | * MOVZX, MOVSX, MOVSXD. 68 | * ROL, ROR, RCL, RCR, SHL, SHR, SAL, SAR. 69 | * SHLD, SHRD. 70 | * CVTSI2SS is also an exception. 71 | */ 72 | switch (di->opcode) 73 | { 74 | case I_INS: 75 | case I_OUTS: 76 | case I_MOVZX: 77 | case I_MOVSX: 78 | case I_MOVSXD: 79 | case I_ROL: 80 | case I_ROR: 81 | case I_RCL: 82 | case I_RCR: 83 | case I_SHL: 84 | case I_SHR: 85 | case I_SAL: 86 | case I_SAR: 87 | case I_SHLD: 88 | case I_SHRD: 89 | case I_CVTSI2SS: 90 | isSizingRequired = 1; 91 | break; 92 | default: /* Instruction doesn't require sizing. */ break; 93 | } 94 | } 95 | 96 | if (isSizingRequired) 97 | { 98 | /*case 0: break; OT_MEM's unknown size. */ 99 | switch (di->ops[opNum].size / 8) 100 | { 101 | case 1: strcat_WS(*str, "BYTE ", 8, 5); break; 102 | case 2: strcat_WS(*str, "WORD ", 8, 5); break; 103 | case 4: strcat_WS(*str, "DWORD ", 8, 6); break; 104 | case 8: strcat_WS(*str, "QWORD ", 8, 6); break; 105 | case 10: strcat_WS(*str, "TBYTE ", 8, 6); break; 106 | case 16: strcat_WS(*str, "DQWORD ", 8, 7); break; 107 | case 32: strcat_WS(*str, "YWORD ", 8, 6); break; 108 | } 109 | } 110 | } 111 | 112 | static void distorm_format_signed_disp(unsigned char** str, const _DInst* di, uint64_t addrMask) 113 | { 114 | int64_t tmpDisp64; 115 | 116 | if (di->dispSize) { 117 | if (((int64_t)di->disp < 0)) { 118 | chrcat_WS(*str, MINUS_DISP_CHR); 119 | tmpDisp64 = -(int64_t)di->disp; 120 | tmpDisp64 &= addrMask; /* Verify only for neg numbers. */ 121 | } 122 | else { 123 | chrcat_WS(*str, PLUS_DISP_CHR); 124 | tmpDisp64 = di->disp; 125 | } 126 | str_int(str, tmpDisp64); 127 | } 128 | } 129 | 130 | static uint8_t prefixTable[6][8] = { "", "LOCK ", "REPNZ ", "REPNZ ", "REP ", "REPZ " }; 131 | static unsigned int prefixSizesTable[6] = { 0, 5, 6, 6, 4, 5 }; 132 | static uint8_t suffixTable[10] = { 0, 'B', 'W', 0, 'D', 0, 0, 0, 'Q' }; 133 | 134 | /* WARNING: This function is written carefully to be able to work with same input and output buffer in-place! */ 135 | #ifdef SUPPORT_64BIT_OFFSET 136 | _DLLEXPORT_ void distorm_format64(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result) 137 | #else 138 | _DLLEXPORT_ void distorm_format32(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result) 139 | #endif 140 | { 141 | unsigned char* str; 142 | int64_t tmpDisp64; 143 | uint64_t addrMask = (uint64_t)-1; 144 | const _WMnemonic* mnemonic; 145 | int suffixSize = -1; 146 | unsigned int i; 147 | 148 | /* Set address mask, when default is for 64bits addresses. */ 149 | if (ci->features & DF_USE_ADDR_MASK) addrMask = ci->addrMask; 150 | else { 151 | if (ci->features & DF_MAXIMUM_ADDR32) addrMask = 0xffffffff; 152 | else if (ci->features & DF_MAXIMUM_ADDR16) addrMask = 0xffff; 153 | } 154 | 155 | /* Gotta have full address for (di->addr - ci->codeOffset) to work in all modes. */ 156 | str_hex(&result->instructionHex, (const uint8_t*)&ci->code[(unsigned int)(di->addr - ci->codeOffset)], di->size); 157 | 158 | if ((int)((int16_t)di->flags) == -1) { 159 | /* In-place considerations: DI is RESULT. Deref fields first. */ 160 | unsigned int size = di->size; 161 | unsigned int byte = di->imm.byte; 162 | _OffsetType offset = di->addr & addrMask; 163 | 164 | result->offset = offset; 165 | result->size = size; 166 | str = (unsigned char*)&result->mnemonic.p; 167 | strcat_WS(str, "DB ", 4, 3); 168 | str_int(&str, byte); 169 | strfinalize_WS(result->mnemonic, str); 170 | *(uint64_t*)&result->operands = 0; /* Clears length and the string at once. */ 171 | return; /* Skip to next instruction. */ 172 | } 173 | 174 | str = (unsigned char*)&result->operands.p; 175 | 176 | /* Special treatment for String (movs, cmps, stos, lods, scas) instructions. */ 177 | if ((di->opcode >= I_MOVS) && (di->opcode <= I_SCAS)) { 178 | /* 179 | * No operands are needed if the address size is the default one, 180 | * and no segment is overridden, so add the suffix letter, 181 | * to indicate size of operation and continue to next instruction. 182 | */ 183 | if ((SEGMENT_IS_DEFAULT_OR_NONE(di->segment)) && (FLAG_GET_ADDRSIZE(di->flags) == ci->dt)) { 184 | suffixSize = di->ops[0].size / 8; 185 | goto skipOperands; 186 | } 187 | suffixSize = 0; /* Marks it's a string instruction. */ 188 | } 189 | 190 | for (i = 0; i < di->opsNo; i++) { 191 | unsigned int type = di->ops[i].type; 192 | if (i > 0) strcat_WS(str, ", ", 2, 2); 193 | if (type == O_REG) { 194 | strcat_WSR(&str, &_REGISTERS[di->ops[i].index]); 195 | } 196 | else if (type == O_IMM) { 197 | /* If the instruction is 'push', show explicit size (except byte imm). */ 198 | if ((di->opcode == I_PUSH) && (di->ops[i].size != 8)) distorm_format_size(&str, di, i); 199 | /* Special fix for negative sign extended immediates. */ 200 | if ((di->flags & FLAG_IMM_SIGNED) && (di->ops[i].size == 8) && (di->imm.sbyte < 0)) { 201 | chrcat_WS(str, MINUS_DISP_CHR); 202 | tmpDisp64 = -di->imm.sbyte; 203 | str_int(&str, tmpDisp64); 204 | } 205 | else { 206 | /* Notice signedness and size of the immediate. */ 207 | if (di->ops[i].size == 0x20) str_int(&str, di->imm.dword); 208 | else str_int(&str, di->imm.qword); 209 | } 210 | } 211 | else if (type == O_PC) { 212 | #ifdef SUPPORT_64BIT_OFFSET 213 | str_int(&str, (di->size + di->imm.sqword + di->addr) & addrMask); 214 | #else 215 | tmpDisp64 = ((_OffsetType)di->imm.sdword + di->addr + di->size) & (uint32_t)addrMask; 216 | str_int(&str, tmpDisp64); 217 | #endif 218 | } 219 | else if (type == O_DISP) { 220 | distorm_format_size(&str, di, i); 221 | chrcat_WS(str, OPEN_CHR); 222 | if (!SEGMENT_IS_DEFAULT_OR_NONE(di->segment)) { 223 | strcat_WSR(&str, &_REGISTERS[SEGMENT_GET_UNSAFE(di->segment)]); 224 | chrcat_WS(str, SEG_OFF_CHR); 225 | } 226 | tmpDisp64 = di->disp & addrMask; 227 | str_int(&str, tmpDisp64); 228 | chrcat_WS(str, CLOSE_CHR); 229 | } 230 | else if (type == O_SMEM) { 231 | int isDefault; 232 | int segment; 233 | distorm_format_size(&str, di, i); 234 | chrcat_WS(str, OPEN_CHR); 235 | 236 | segment = SEGMENT_GET(di->segment); 237 | isDefault = SEGMENT_IS_DEFAULT(di->segment); 238 | 239 | /* 240 | * This is where we need to take special care for String instructions. 241 | * If we got here, it means we need to explicitly show their operands. 242 | * The problem with CMPS and MOVS is that they have two(!) memory operands. 243 | * So we have to complement(!) them ourselves, since the isntruction structure supplies only the segment that can be overridden. 244 | * And make the rest of the String operations explicit. 245 | * We ignore default ES/DS in 64 bits. 246 | * ["MOVS"], [OPT.REGI_EDI, OPT.REGI_ESI] -- DS can be overridden. 247 | * ["CMPS"], [OPT.REGI_ESI, OPT.REGI_EDI] -- DS can be overriden. 248 | * 249 | * suffixSize == 0 was set above for string opcode already. 250 | */ 251 | if (suffixSize == 0) { 252 | if (((di->opcode == I_MOVS) && (i == 0)) || ((di->opcode == I_CMPS) && (i == 1))) { 253 | if (ci->dt != Decode64Bits) { 254 | segment = R_ES; 255 | isDefault = FALSE; 256 | } 257 | else isDefault = TRUE; 258 | } 259 | else if (isDefault && ((di->opcode == I_MOVS) || (di->opcode == I_CMPS))) { 260 | if (ci->dt != Decode64Bits) { 261 | segment = R_DS; 262 | isDefault = FALSE; 263 | } 264 | } 265 | } 266 | if (!isDefault && (segment != R_NONE)) { 267 | strcat_WSR(&str, &_REGISTERS[segment]); 268 | chrcat_WS(str, SEG_OFF_CHR); 269 | } 270 | 271 | strcat_WSR(&str, &_REGISTERS[di->ops[i].index]); 272 | 273 | distorm_format_signed_disp(&str, di, addrMask); 274 | chrcat_WS(str, CLOSE_CHR); 275 | } 276 | else if (type == O_MEM) { 277 | distorm_format_size(&str, di, i); 278 | chrcat_WS(str, OPEN_CHR); 279 | if (!SEGMENT_IS_DEFAULT_OR_NONE(di->segment)) { 280 | strcat_WSR(&str, &_REGISTERS[SEGMENT_GET_UNSAFE(di->segment)]); 281 | chrcat_WS(str, SEG_OFF_CHR); 282 | } 283 | if (di->base != R_NONE) { 284 | strcat_WSR(&str, &_REGISTERS[di->base]); 285 | chrcat_WS(str, PLUS_DISP_CHR); 286 | } 287 | strcat_WSR(&str, &_REGISTERS[di->ops[i].index]); 288 | if (di->scale != 0) { 289 | switch (di->scale) 290 | { 291 | case 2: strcat_WS(str, "*2", 2, 2); break; 292 | case 4: strcat_WS(str, "*4", 2, 2); break; 293 | case 8: strcat_WS(str, "*8", 2, 2); break; 294 | } 295 | } 296 | distorm_format_signed_disp(&str, di, addrMask); 297 | chrcat_WS(str, CLOSE_CHR); 298 | } 299 | else if (type == O_PTR) { 300 | str_int(&str, di->imm.ptr.seg); 301 | chrcat_WS(str, SEG_OFF_CHR); 302 | str_int(&str, di->imm.ptr.off); 303 | } 304 | else if (type == O_IMM1) { 305 | str_int(&str, di->imm.ex.i1); 306 | } 307 | else if (type == O_IMM2) { 308 | str_int(&str, di->imm.ex.i2); 309 | } 310 | } 311 | 312 | skipOperands: 313 | 314 | /* Finalize the operands string. */ 315 | strfinalize_WS(result->operands, str); 316 | 317 | /* Not used anymore. 318 | if (di->flags & FLAG_HINT_TAKEN) strcat_WSN(str, " ;TAKEN"); 319 | else if (di->flags & FLAG_HINT_NOT_TAKEN) strcat_WSN(str, " ;NOT TAKEN"); 320 | */ 321 | { 322 | /* In-place considerations: DI is RESULT. Deref fields first. */ 323 | unsigned int opcode = di->opcode; 324 | unsigned int prefix = FLAG_GET_PREFIX(di->flags); 325 | unsigned int size = di->size; 326 | _OffsetType offset = di->addr & addrMask; 327 | str = (unsigned char*)&result->mnemonic.p; 328 | mnemonic = (const _WMnemonic*)&_MNEMONICS[opcode]; 329 | 330 | if (prefix) { 331 | /* REP prefix for CMPS and SCAS is really a REPZ. */ 332 | prefix += (opcode == I_CMPS); 333 | prefix += (opcode == I_SCAS); 334 | memcpy(str, &prefixTable[prefix][0], 8); 335 | str += prefixSizesTable[prefix]; 336 | } 337 | 338 | /* 339 | * Always copy 16 bytes from the mnemonic, we have a sentinel padding so we can read past. 340 | * This helps the compiler to remove the call to memcpy and therefore makes this copying much faster. 341 | * The longest instruction is exactly 16 chars long, so we null terminate the string below. 342 | */ 343 | memcpy((int8_t*)str, mnemonic->p, 16); 344 | str += mnemonic->length; 345 | 346 | if (suffixSize > 0) { 347 | *str++ = suffixTable[suffixSize]; 348 | } 349 | strfinalize_WS(result->mnemonic, str); 350 | 351 | result->offset = offset; 352 | result->size = size; 353 | } 354 | } 355 | 356 | #ifdef SUPPORT_64BIT_OFFSET 357 | _DLLEXPORT_ _DecodeResult distorm_decode64(_OffsetType codeOffset, unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount) 358 | #else 359 | _DLLEXPORT_ _DecodeResult distorm_decode32(_OffsetType codeOffset, unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount) 360 | #endif 361 | { 362 | _DecodeResult res; 363 | _CodeInfo ci; 364 | unsigned int i, instsCount; 365 | 366 | *usedInstructionsCount = 0; 367 | 368 | /* I use codeLen as a signed variable in order to ease detection of underflow... and besides - */ 369 | if (codeLen < 0) { 370 | return DECRES_INPUTERR; 371 | } 372 | 373 | if ((unsigned)dt > (unsigned)Decode64Bits) { 374 | return DECRES_INPUTERR; 375 | } 376 | 377 | /* Make sure there's at least one instruction in the result buffer. */ 378 | if ((code == NULL) || (result == NULL) || (maxInstructions == 0)) { 379 | return DECRES_INPUTERR; 380 | } 381 | 382 | /* 383 | * We have to format the result into text. But the interal decoder works with the new structure of _DInst. 384 | * Therefore, we will pass the result array(!) from the caller and the interal decoder will fill it in with _DInst's. 385 | * Then we will copy each result to a temporary structure, and use it to reformat that specific result. 386 | * 387 | * This is all done to save memory allocation and to work on the same result array in-place!!! 388 | * It's a bit ugly, I have to admit, but worth it. 389 | */ 390 | 391 | ci.codeOffset = codeOffset; 392 | ci.code = code; 393 | ci.codeLen = codeLen; 394 | ci.dt = dt; 395 | ci.features = DF_USE_ADDR_MASK; 396 | if (dt == Decode16Bits) ci.addrMask = 0xffff; 397 | else if (dt == Decode32Bits) ci.addrMask = 0xffffffff; 398 | else ci.addrMask = (_OffsetType)-1; 399 | 400 | res = decode_internal(&ci, TRUE, (_DInst*)result, maxInstructions, usedInstructionsCount); 401 | instsCount = *usedInstructionsCount; 402 | for (i = 0; i < instsCount; i++) { 403 | /* distorm_format is optimized and can work with same input/output buffer in-place. */ 404 | #ifdef SUPPORT_64BIT_OFFSET 405 | distorm_format64(&ci, (_DInst*)&result[i], &result[i]); 406 | #else 407 | distorm_format32(&ci, (_DInst*)&result[i], &result[i]); 408 | #endif 409 | } 410 | 411 | return res; 412 | } 413 | 414 | #endif /* DISTORM_LIGHT */ 415 | 416 | _DLLEXPORT_ unsigned int distorm_version(void) 417 | { 418 | return __DISTORMV__; 419 | } 420 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/distorm.h: -------------------------------------------------------------------------------- 1 | /* diStorm 3.5.3 */ 2 | 3 | /* 4 | distorm.h 5 | 6 | diStorm3 - Powerful disassembler for X86/AMD64 7 | http://ragestorm.net/distorm/ 8 | distorm at gmail dot com 9 | Copyright (C) 2003-2021 Gil Dabah 10 | This library is licensed under the BSD license. See the file COPYING. 11 | */ 12 | 13 | 14 | #ifndef DISTORM_H 15 | #define DISTORM_H 16 | 17 | #include 18 | 19 | /* 20 | * 64 bit offsets support: 21 | * If the diStorm library you use was compiled with 64 bits offsets, 22 | * make sure you compile your own code with the following macro set: 23 | * SUPPORT_64BIT_OFFSET 24 | * Otherwise comment it out, or you will get a linker error of an unresolved symbol... 25 | * Turned on by default! 26 | */ 27 | 28 | #if !(defined(DISTORM_STATIC) || defined(DISTORM_DYNAMIC)) 29 | /* Define this macro for outer projects by default. */ 30 | #define SUPPORT_64BIT_OFFSET 31 | #endif 32 | 33 | /* TINYC has a problem with some 64bits library functions, so ignore 64 bit offsets. */ 34 | #ifdef __TINYC__ 35 | #undef SUPPORT_64BIT_OFFSET 36 | #endif 37 | 38 | #ifdef SUPPORT_64BIT_OFFSET 39 | #define OFFSET_INTEGER uint64_t 40 | #else 41 | /* 32 bit offsets are used. */ 42 | #define OFFSET_INTEGER uint32_t 43 | #endif 44 | 45 | /* Support C++ compilers */ 46 | #ifdef __cplusplus 47 | extern "C" { 48 | #endif 49 | 50 | 51 | /* *** Helper Macros *** */ 52 | 53 | /* Get the ISC of the instruction, used with the definitions below. */ 54 | #define META_GET_ISC(meta) (((meta) >> 8) & 0x1f) 55 | #define META_SET_ISC(di, isc) (((di)->meta) |= ((isc) << 8)) 56 | /* Get the flow control flags of the instruction, see 'features for decompose' below. */ 57 | #define META_GET_FC(meta) ((meta) & 0xf) 58 | 59 | /* Get the target address of a branching instruction. O_PC operand type. */ 60 | #define INSTRUCTION_GET_TARGET(di) ((_OffsetType)(((di)->addr + (di)->imm.addr + (di)->size))) 61 | /* Get the target address of a RIP-relative memory indirection. */ 62 | #define INSTRUCTION_GET_RIP_TARGET(di) ((_OffsetType)(((di)->addr + (di)->disp + (di)->size))) 63 | 64 | /* 65 | * Operand Size or Adderss size are stored inside the flags: 66 | * 00 - 16 bits 67 | * 01 - 32 bits 68 | * 10 - 64 bits 69 | * 11 - reserved 70 | * 71 | * If you call these set-macros more than once, you will have to clean the bits before doing so. 72 | */ 73 | #define FLAG_SET_OPSIZE(di, size) ((di->flags) |= (((size) & 3) << 8)) 74 | #define FLAG_SET_ADDRSIZE(di, size) ((di->flags) |= (((size) & 3) << 10)) 75 | #define FLAG_GET_OPSIZE(flags) (((flags) >> 8) & 3) 76 | #define FLAG_GET_ADDRSIZE(flags) (((flags) >> 10) & 3) 77 | /* To get the LOCK/REPNZ/REP prefixes. */ 78 | #define FLAG_GET_PREFIX(flags) (((unsigned int)((int16_t)flags)) & 7) 79 | /* Indicates whether the instruction is privileged. */ 80 | #define FLAG_GET_PRIVILEGED(flags) (((flags) & FLAG_PRIVILEGED_INSTRUCTION) != 0) 81 | 82 | /* 83 | * Macros to extract segment registers from 'segment': 84 | */ 85 | #define SEGMENT_DEFAULT 0x80 86 | #define SEGMENT_GET(segment) (((segment) == R_NONE) ? R_NONE : ((segment) & 0x7f)) 87 | #define SEGMENT_GET_UNSAFE(segment) ((segment) & 0x7f) 88 | #define SEGMENT_IS_DEFAULT(segment) (((int8_t)segment) < -1) /* Quick check it's a negative number that isn't -1, so it's (0x80 | SEGREG). */ 89 | #define SEGMENT_IS_DEFAULT_OR_NONE(segment) (((uint8_t)(segment)) > 0x80) 90 | 91 | /* Decodes modes of the disassembler, 16 bits or 32 bits or 64 bits for AMD64, x86-64. */ 92 | typedef enum { Decode16Bits = 0, Decode32Bits = 1, Decode64Bits = 2 } _DecodeType; 93 | 94 | typedef OFFSET_INTEGER _OffsetType; 95 | 96 | typedef struct { 97 | _OffsetType codeOffset, addrMask; 98 | _OffsetType nextOffset; /* nextOffset is OUT only. */ 99 | uint8_t* code; 100 | int codeLen; /* Using signed integer makes it easier to detect an underflow. */ 101 | _DecodeType dt; 102 | unsigned int features; 103 | } _CodeInfo; 104 | 105 | typedef enum { O_NONE, O_REG, O_IMM, O_IMM1, O_IMM2, O_DISP, O_SMEM, O_MEM, O_PC, O_PTR } _OperandType; 106 | 107 | typedef union { 108 | /* Used by O_IMM: */ 109 | int8_t sbyte; 110 | uint8_t byte; 111 | int16_t sword; 112 | uint16_t word; 113 | int32_t sdword; 114 | uint32_t dword; 115 | int64_t sqword; /* All immediates are SIGN-EXTENDED to 64 bits! */ 116 | uint64_t qword; 117 | 118 | /* Used by O_PC: (Use GET_TARGET_ADDR).*/ 119 | _OffsetType addr; /* It's a relative offset as for now. */ 120 | 121 | /* Used by O_PTR: */ 122 | struct { 123 | uint16_t seg; 124 | /* Can be 16 or 32 bits, size is in ops[n].size. */ 125 | uint32_t off; 126 | } ptr; 127 | 128 | /* Used by O_IMM1 (i1) and O_IMM2 (i2). ENTER instruction only. */ 129 | struct { 130 | uint32_t i1; 131 | uint32_t i2; 132 | } ex; 133 | } _Value; 134 | 135 | typedef struct { 136 | /* Type of operand: 137 | O_NONE: operand is to be ignored. 138 | O_REG: index holds global register index. 139 | O_IMM: instruction.imm. 140 | O_IMM1: instruction.imm.ex.i1. 141 | O_IMM2: instruction.imm.ex.i2. 142 | O_DISP: memory dereference with displacement only, instruction.disp. 143 | O_SMEM: simple memory dereference with optional displacement (a single register memory dereference). 144 | O_MEM: complex memory dereference (optional fields: s/i/b/disp). 145 | O_PC: the relative address of a branch instruction (instruction.imm.addr). 146 | O_PTR: the absolute target address of a far branch instruction (instruction.imm.ptr.seg/off). 147 | */ 148 | uint8_t type; /* _OperandType */ 149 | 150 | /* Index of: 151 | O_REG: holds global register index 152 | O_SMEM: holds the 'base' register. E.G: [ECX], [EBX+0x1234] are both in operand.index. 153 | O_MEM: holds the 'index' register. E.G: [EAX*4] is in operand.index. 154 | */ 155 | uint8_t index; 156 | 157 | /* Size in bits of: 158 | O_REG: register 159 | O_IMM: instruction.imm 160 | O_IMM1: instruction.imm.ex.i1 161 | O_IMM2: instruction.imm.ex.i2 162 | O_DISP: instruction.disp 163 | O_SMEM: size of indirection. 164 | O_MEM: size of indirection. 165 | O_PC: size of the relative offset 166 | O_PTR: size of instruction.imm.ptr.off (16 or 32) 167 | */ 168 | uint16_t size; 169 | } _Operand; 170 | 171 | #define OPCODE_ID_NONE 0 172 | /* Instruction could not be disassembled. */ 173 | #define FLAG_NOT_DECODABLE ((uint16_t)-1) 174 | /* The instruction locks memory access. */ 175 | #define FLAG_LOCK (1 << 0) 176 | /* The instruction is prefixed with a REPNZ. */ 177 | #define FLAG_REPNZ (1 << 1) 178 | /* The instruction is prefixed with a REP, this can be a REPZ, it depends on the specific instruction. */ 179 | #define FLAG_REP (1 << 2) 180 | /* Indicates there is a hint taken for Jcc instructions only. */ 181 | #define FLAG_HINT_TAKEN (1 << 3) 182 | /* Indicates there is a hint non-taken for Jcc instructions only. */ 183 | #define FLAG_HINT_NOT_TAKEN (1 << 4) 184 | /* The Imm value is signed extended (E.G in 64 bit decoding mode, a 32 bit imm is usually sign extended into 64 bit imm). */ 185 | #define FLAG_IMM_SIGNED (1 << 5) 186 | /* The destination operand is writable. */ 187 | #define FLAG_DST_WR (1 << 6) 188 | /* The instruction uses RIP-relative indirection. */ 189 | #define FLAG_RIP_RELATIVE (1 << 7) 190 | 191 | /* See flag FLAG_GET_XXX macros above. */ 192 | 193 | /* The instruction is privileged and can only be used from Ring0. */ 194 | #define FLAG_PRIVILEGED_INSTRUCTION (1 << 15) 195 | 196 | /* No register was defined. */ 197 | #define R_NONE ((uint8_t)-1) 198 | 199 | #define REGS64_BASE 0 200 | #define REGS32_BASE 16 201 | #define REGS16_BASE 32 202 | #define REGS8_BASE 48 203 | #define REGS8_REX_BASE 64 204 | #define SREGS_BASE 68 205 | #define FPUREGS_BASE 75 206 | #define MMXREGS_BASE 83 207 | #define SSEREGS_BASE 91 208 | #define AVXREGS_BASE 107 209 | #define CREGS_BASE 123 210 | #define DREGS_BASE 132 211 | 212 | #define OPERANDS_NO (4) 213 | 214 | typedef struct { 215 | /* Used by ops[n].type == O_IMM/O_IMM1&O_IMM2/O_PTR/O_PC. Its size is ops[n].size. */ 216 | _Value imm; 217 | /* Used by ops[n].type == O_SMEM/O_MEM/O_DISP. Its size is dispSize. */ 218 | uint64_t disp; 219 | /* Virtual address of first byte of instruction. */ 220 | _OffsetType addr; 221 | /* General flags of instruction, holds prefixes and more, if FLAG_NOT_DECODABLE, instruction is invalid. */ 222 | uint16_t flags; 223 | /* Unused prefixes mask, for each bit that is set that prefix is not used (LSB is byte [addr + 0]). */ 224 | uint16_t unusedPrefixesMask; 225 | /* Mask of registers that were used in the operands, only used for quick look up, in order to know *some* operand uses that register class. */ 226 | uint32_t usedRegistersMask; 227 | /* ID of opcode in the global opcode table. Use for mnemonic look up. */ 228 | uint16_t opcode; 229 | /* Up to four operands per instruction, ignored if ops[n].type == O_NONE. */ 230 | _Operand ops[OPERANDS_NO]; 231 | /* Number of valid ops entries. */ 232 | uint8_t opsNo; 233 | /* Size of the whole instruction in bytes. */ 234 | uint8_t size; 235 | /* Segment information of memory indirection, default segment, or overriden one, can be -1. Use SEGMENT macros. */ 236 | uint8_t segment; 237 | /* Used by ops[n].type == O_MEM. Base global register index (might be R_NONE), scale size (2/4/8), ignored for 0 or 1. */ 238 | uint8_t base, scale; 239 | uint8_t dispSize; 240 | /* Meta defines the instruction set class, and the flow control flags. Use META macros. */ 241 | uint16_t meta; 242 | /* The CPU flags that the instruction operates upon, set only with DF_FILL_EFLAGS enabled, otherwise 0. */ 243 | uint16_t modifiedFlagsMask, testedFlagsMask, undefinedFlagsMask; 244 | } _DInst; 245 | 246 | #ifndef DISTORM_LIGHT 247 | 248 | /* Static size of strings. Do not change this value. Keep Python wrapper in sync. */ 249 | #define MAX_TEXT_SIZE (48) 250 | typedef struct { 251 | unsigned int length; 252 | unsigned char p[MAX_TEXT_SIZE]; /* p is a null terminated string. */ 253 | } _WString; 254 | 255 | /* 256 | * Old decoded instruction structure in text format. 257 | * Used only for backward compatibility with diStorm64. 258 | * This structure holds all information the disassembler generates per instruction. 259 | */ 260 | typedef struct { 261 | _OffsetType offset; /* Start offset of the decoded instruction. */ 262 | unsigned int size; /* Size of decoded instruction in bytes. */ 263 | _WString mnemonic; /* Mnemonic of decoded instruction, prefixed if required by REP, LOCK etc. */ 264 | _WString operands; /* Operands of the decoded instruction, up to 3 operands, comma-seperated. */ 265 | _WString instructionHex; /* Hex dump - little endian, including prefixes. */ 266 | } _DecodedInst; 267 | 268 | #endif /* DISTORM_LIGHT */ 269 | 270 | /* Register masks for quick look up, each mask indicates one of a register-class that is being used in some operand. */ 271 | #define RM_AX 1 /* AL, AH, AX, EAX, RAX */ 272 | #define RM_CX 2 /* CL, CH, CX, ECX, RCX */ 273 | #define RM_DX 4 /* DL, DH, DX, EDX, RDX */ 274 | #define RM_BX 8 /* BL, BH, BX, EBX, RBX */ 275 | #define RM_SP 0x10 /* SPL, SP, ESP, RSP */ 276 | #define RM_BP 0x20 /* BPL, BP, EBP, RBP */ 277 | #define RM_SI 0x40 /* SIL, SI, ESI, RSI */ 278 | #define RM_DI 0x80 /* DIL, DI, EDI, RDI */ 279 | #define RM_FPU 0x100 /* ST(0) - ST(7) */ 280 | #define RM_MMX 0x200 /* MM0 - MM7 */ 281 | #define RM_SSE 0x400 /* XMM0 - XMM15 */ 282 | #define RM_AVX 0x800 /* YMM0 - YMM15 */ 283 | #define RM_CR 0x1000 /* CR0, CR2, CR3, CR4, CR8 */ 284 | #define RM_DR 0x2000 /* DR0, DR1, DR2, DR3, DR6, DR7 */ 285 | #define RM_R8 0x4000 /* R8B, R8W, R8D, R8 */ 286 | #define RM_R9 0x8000 /* R9B, R9W, R9D, R9 */ 287 | #define RM_R10 0x10000 /* R10B, R10W, R10D, R10 */ 288 | #define RM_R11 0x20000 /* R11B, R11W, R11D, R11 */ 289 | #define RM_R12 0x40000 /* R12B, R12W, R12D, R12 */ 290 | #define RM_R13 0x80000 /* R13B, R13W, R13D, R13 */ 291 | #define RM_R14 0x100000 /* R14B, R14W, R14D, R14 */ 292 | #define RM_R15 0x200000 /* R15B, R15W, R15D, R15 */ 293 | #define RM_SEG 0x400000 /* CS, SS, DS, ES, FS, GS */ 294 | 295 | /* RIP should be checked using the 'flags' field and FLAG_RIP_RELATIVE. 296 | * Segments should be checked using the segment macros. 297 | * For now R8 - R15 are not supported and non general purpose registers map into same RM. 298 | */ 299 | 300 | /* CPU flags that instructions modify, test or undefine (are EFLAGS compatible!). */ 301 | #define D_CF 1 /* Carry */ 302 | #define D_PF 4 /* Parity */ 303 | #define D_AF 0x10 /* Auxiliary */ 304 | #define D_ZF 0x40 /* Zero */ 305 | #define D_SF 0x80 /* Sign */ 306 | #define D_IF 0x200 /* Interrupt */ 307 | #define D_DF 0x400 /* Direction */ 308 | #define D_OF 0x800 /* Overflow */ 309 | 310 | /* 311 | * Instructions Set classes: 312 | * if you want a better understanding of the available classes, look at disOps project, file: x86sets.py. 313 | */ 314 | /* Indicates the instruction belongs to the General Integer set. */ 315 | #define ISC_INTEGER 1 316 | /* Indicates the instruction belongs to the 387 FPU set. */ 317 | #define ISC_FPU 2 318 | /* Indicates the instruction belongs to the P6 set. */ 319 | #define ISC_P6 3 320 | /* Indicates the instruction belongs to the MMX set. */ 321 | #define ISC_MMX 4 322 | /* Indicates the instruction belongs to the SSE set. */ 323 | #define ISC_SSE 5 324 | /* Indicates the instruction belongs to the SSE2 set. */ 325 | #define ISC_SSE2 6 326 | /* Indicates the instruction belongs to the SSE3 set. */ 327 | #define ISC_SSE3 7 328 | /* Indicates the instruction belongs to the SSSE3 set. */ 329 | #define ISC_SSSE3 8 330 | /* Indicates the instruction belongs to the SSE4.1 set. */ 331 | #define ISC_SSE4_1 9 332 | /* Indicates the instruction belongs to the SSE4.2 set. */ 333 | #define ISC_SSE4_2 10 334 | /* Indicates the instruction belongs to the AMD's SSE4.A set. */ 335 | #define ISC_SSE4_A 11 336 | /* Indicates the instruction belongs to the 3DNow! set. */ 337 | #define ISC_3DNOW 12 338 | /* Indicates the instruction belongs to the 3DNow! Extensions set. */ 339 | #define ISC_3DNOWEXT 13 340 | /* Indicates the instruction belongs to the VMX (Intel) set. */ 341 | #define ISC_VMX 14 342 | /* Indicates the instruction belongs to the SVM (AMD) set. */ 343 | #define ISC_SVM 15 344 | /* Indicates the instruction belongs to the AVX (Intel) set. */ 345 | #define ISC_AVX 16 346 | /* Indicates the instruction belongs to the FMA (Intel) set. */ 347 | #define ISC_FMA 17 348 | /* Indicates the instruction belongs to the AES/AVX (Intel) set. */ 349 | #define ISC_AES 18 350 | /* Indicates the instruction belongs to the CLMUL (Intel) set. */ 351 | #define ISC_CLMUL 19 352 | 353 | /* Features for decompose: */ 354 | #define DF_NONE 0 355 | /* The decoder will limit addresses to a maximum of 16 bits. */ 356 | #define DF_MAXIMUM_ADDR16 1 357 | /* The decoder will limit addresses to a maximum of 32 bits. */ 358 | #define DF_MAXIMUM_ADDR32 2 359 | /* The decoder will return only flow control instructions (and filter the others internally). */ 360 | #define DF_RETURN_FC_ONLY 4 361 | /* The decoder will stop and return to the caller when the instruction 'CALL' (near and far) was decoded. */ 362 | #define DF_STOP_ON_CALL 8 363 | /* The decoder will stop and return to the caller when the instruction 'RET' (near and far) was decoded. */ 364 | #define DF_STOP_ON_RET 0x10 365 | /* The decoder will stop and return to the caller when the instruction system-call/ret was decoded. */ 366 | #define DF_STOP_ON_SYS 0x20 367 | /* The decoder will stop and return to the caller when any of the branch 'JMP', (near and far) instructions were decoded. */ 368 | #define DF_STOP_ON_UNC_BRANCH 0x40 369 | /* The decoder will stop and return to the caller when any of the conditional branch instruction were decoded. */ 370 | #define DF_STOP_ON_CND_BRANCH 0x80 371 | /* The decoder will stop and return to the caller when the instruction 'INT' (INT, INT1, INTO, INT 3) was decoded. */ 372 | #define DF_STOP_ON_INT 0x100 373 | /* The decoder will stop and return to the caller when any of the 'CMOVxx' instruction was decoded. */ 374 | #define DF_STOP_ON_CMOV 0x200 375 | /* The decoder will stop and return to the caller when it encounters the HLT instruction. */ 376 | #define DF_STOP_ON_HLT 0x400 377 | /* The decoder will stop and return to the caller when it encounters a privileged instruction. */ 378 | #define DF_STOP_ON_PRIVILEGED 0x800 379 | /* The decoder will stop and return to the caller when an instruction couldn't be decoded. */ 380 | #define DF_STOP_ON_UNDECODEABLE 0x1000 381 | /* The decoder will not synchronize to the next byte after the previosuly decoded instruction, instead it will start decoding at the next byte. */ 382 | #define DF_SINGLE_BYTE_STEP 0x2000 383 | /* The decoder will fill in the eflags fields for the decoded instruction. */ 384 | #define DF_FILL_EFLAGS 0x4000 385 | /* The decoder will use the addrMask in CodeInfo structure instead of DF_MAXIMUM_ADDR16/32. */ 386 | #define DF_USE_ADDR_MASK 0x8000 387 | 388 | /* The decoder will stop and return to the caller when any flow control instruction was decoded. */ 389 | #define DF_STOP_ON_FLOW_CONTROL (DF_STOP_ON_CALL | DF_STOP_ON_RET | DF_STOP_ON_SYS | DF_STOP_ON_UNC_BRANCH | DF_STOP_ON_CND_BRANCH | DF_STOP_ON_INT | DF_STOP_ON_CMOV | DF_STOP_ON_HLT) 390 | 391 | /* Indicates the instruction is not a flow-control instruction. */ 392 | #define FC_NONE 0 393 | /* Indicates the instruction is one of: CALL, CALL FAR. */ 394 | #define FC_CALL 1 395 | /* Indicates the instruction is one of: RET, IRET, RETF. */ 396 | #define FC_RET 2 397 | /* Indicates the instruction is one of: SYSCALL, SYSRET, SYSENTER, SYSEXIT. */ 398 | #define FC_SYS 3 399 | /* Indicates the instruction is one of: JMP, JMP FAR. */ 400 | #define FC_UNC_BRANCH 4 401 | /* 402 | * Indicates the instruction is one of: 403 | * JCXZ, JO, JNO, JB, JAE, JZ, JNZ, JBE, JA, JS, JNS, JP, JNP, JL, JGE, JLE, JG, LOOP, LOOPZ, LOOPNZ. 404 | */ 405 | #define FC_CND_BRANCH 5 406 | /* Indiciates the instruction is one of: INT, INT1, INT 3, INTO, UD2. */ 407 | #define FC_INT 6 408 | /* Indicates the instruction is one of: CMOVxx. */ 409 | #define FC_CMOV 7 410 | /* Indicates the instruction is HLT. */ 411 | #define FC_HLT 8 412 | 413 | /* Return code of the decoding function. */ 414 | typedef enum { DECRES_NONE, DECRES_SUCCESS, DECRES_MEMORYERR, DECRES_INPUTERR } _DecodeResult; 415 | 416 | /* Define the following interface functions only for outer projects. */ 417 | #if !(defined(DISTORM_STATIC) || defined(DISTORM_DYNAMIC)) 418 | 419 | /* distorm_decode 420 | * Input: 421 | * offset - Origin of the given code (virtual address that is), NOT an offset in code. 422 | * code - Pointer to the code buffer to be disassembled. 423 | * length - Amount of bytes that should be decoded from the code buffer. 424 | * dt - Decoding mode, 16 bits (Decode16Bits), 32 bits (Decode32Bits) or AMD64 (Decode64Bits). 425 | * result - Array of type _DecodeInst which will be used by this function in order to return the disassembled instructions. 426 | * maxInstructions - The maximum number of entries in the result array that you pass to this function, so it won't exceed its bound. 427 | * usedInstructionsCount - Number of the instruction that successfully were disassembled and written to the result array. 428 | * Output: usedInstructionsCount will hold the number of entries used in the result array 429 | * and the result array itself will be filled with the disassembled instructions. 430 | * Return: DECRES_SUCCESS on success (no more to disassemble), DECRES_INPUTERR on input error (null code buffer, invalid decoding mode, etc...), 431 | * DECRES_MEMORYERR when there are not enough entries to use in the result array, BUT YOU STILL have to check for usedInstructionsCount! 432 | * Side-Effects: Even if the return code is DECRES_MEMORYERR, there might STILL be data in the 433 | * array you passed, this function will try to use as much entries as possible! 434 | * Notes: 1)The minimal size of maxInstructions is 15. 435 | * 2)You will have to synchronize the offset,code and length by yourself if you pass code fragments and not a complete code block! 436 | */ 437 | 438 | /* distorm_decompose 439 | * See more documentation online at the GitHub project's wiki. 440 | * 441 | */ 442 | #ifdef SUPPORT_64BIT_OFFSET 443 | 444 | _DecodeResult distorm_decompose64(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount); 445 | #define distorm_decompose distorm_decompose64 446 | 447 | #ifndef DISTORM_LIGHT 448 | /* If distorm-light is defined, we won't export these text-formatting functionality. */ 449 | _DecodeResult distorm_decode64(_OffsetType codeOffset, unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount); 450 | void distorm_format64(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result); 451 | #define distorm_decode distorm_decode64 452 | #define distorm_format distorm_format64 453 | #endif /*DISTORM_LIGHT*/ 454 | 455 | #else /*SUPPORT_64BIT_OFFSET*/ 456 | 457 | _DecodeResult distorm_decompose32(_CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount); 458 | #define distorm_decompose distorm_decompose32 459 | 460 | #ifndef DISTORM_LIGHT 461 | /* If distorm-light is defined, we won't export these text-formatting functionality. */ 462 | _DecodeResult distorm_decode32(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount); 463 | void distorm_format32(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result); 464 | #define distorm_decode distorm_decode32 465 | #define distorm_format distorm_format32 466 | #endif /*DISTORM_LIGHT*/ 467 | 468 | #endif 469 | 470 | /* 471 | * distorm_version 472 | * Input: 473 | * none 474 | * 475 | * Output: unsigned int - version of compiled library. 476 | */ 477 | unsigned int distorm_version(void); 478 | 479 | #endif /* DISTORM_STATIC */ 480 | 481 | #ifdef __cplusplus 482 | } /* End Of Extern */ 483 | #endif 484 | 485 | #endif /* DISTORM_H */ 486 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/instructions.h: -------------------------------------------------------------------------------- 1 | /* 2 | instructions.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef INSTRUCTIONS_H 13 | #define INSTRUCTIONS_H 14 | 15 | #include "config.h" 16 | #include "prefix.h" 17 | 18 | 19 | /* 20 | * Operand type possibilities: 21 | * Note "_FULL" suffix indicates to decode the operand as 16 bits or 32 bits depends on DecodeType - 22 | * actually, it depends on the decoding mode, unless there's an operand/address size prefix. 23 | * For example, the code: 33 c0 could be decoded/executed as XOR AX, AX or XOR EAX, EAX. 24 | */ 25 | 26 | typedef enum OpType { 27 | /* No operand is set */ 28 | OT_NONE = 0, 29 | 30 | /* Read a byte(8 bits) immediate */ 31 | OT_IMM8, 32 | /* Force a read of a word(16 bits) immediate, used by ret only */ 33 | OT_IMM16, 34 | /* Read a word/dword immediate */ 35 | OT_IMM_FULL, 36 | /* Read a double-word(32 bits) immediate */ 37 | OT_IMM32, 38 | 39 | /* Read a signed extended byte(8 bits) immediate */ 40 | OT_SEIMM8, 41 | 42 | /* Use a 8bit register */ 43 | OT_REG8, 44 | /* Use a 16bit register */ 45 | OT_REG16, 46 | /* Use a 16/32/64bit register */ 47 | OT_REG_FULL, 48 | /* Use a 32bit register */ 49 | OT_REG32, 50 | /* 51 | * If used with REX the reg operand size becomes 64 bits, otherwise 32 bits. 52 | * VMX instructions are promoted automatically without a REX prefix. 53 | */ 54 | OT_REG32_64, 55 | 56 | /* Use AL */ 57 | OT_ACC8, 58 | /* Use AX (FSTSW) */ 59 | OT_ACC16, 60 | /* Use AX/EAX/RAX */ 61 | OT_ACC_FULL, 62 | /* Use AX/EAX, no REX is possible for RAX, used only with IN/OUT which don't support 64 bit registers */ 63 | OT_ACC_FULL_NOT64, 64 | 65 | /* Read a byte(8 bits) immediate and calculate it relatively to the current offset of the instruction being decoded */ 66 | OT_RELCB, 67 | /* Read a word/dword immediate and calculate it relatively to the current offset of the instruction being decoded */ 68 | OT_RELC_FULL, 69 | 70 | /* 71 | * Instruction-Block for one byte long instructions, used by INC/DEC/PUSH/POP/XCHG, 72 | * REG is extracted from the value of opcode 73 | * Use a 8bit register 74 | */ 75 | OT_IB_RB, 76 | /* Use a 16/32/64bit register */ 77 | OT_IB_R_FULL, 78 | 79 | /* Read an immediate as an absolute address, size is known by instruction, used by MOV (memory offset) only */ 80 | OT_MOFFS8, 81 | OT_MOFFS_FULL, 82 | /* Use [(r)SI] as INDIRECTION, for repeatable instructions */ 83 | OT_REGI_ESI, 84 | /* Use [(r)DI] as INDIRECTION, for repeatable instructions */ 85 | OT_REGI_EDI, 86 | /* Use [(r)BX + AL] as INDIRECTIOM, used by XLAT only */ 87 | OT_REGI_EBXAL, 88 | /* Use [(r)AX] as INDIRECTION, used by AMD's SVM instructions */ 89 | OT_REGI_EAX, 90 | /* Use DX, as for OUTS DX, BYTE [SI] */ 91 | OT_REGDX, 92 | /* Use ECX in INVLPGA instruction */ 93 | OT_REGECX, 94 | 95 | /* FPU registers: */ 96 | OT_FPU_SI, /* ST(i) */ 97 | OT_FPU_SSI, /* ST(0), ST(i) */ 98 | OT_FPU_SIS, /* ST(i), ST(0) */ 99 | 100 | /* SSE registers: */ 101 | OT_XMM, 102 | /* Extract the SSE register from the RM bits this time (used when the REG bits are used for opcode extension) */ 103 | OT_XMM_RM, 104 | /* Implied XMM0 register as operand, used in SSE4. */ 105 | OT_REGXMM0, 106 | /* Reg32/Reg 64 depends on prefix width only. */ 107 | OT_WREG32_64, 108 | 109 | /* XMM is encoded in VEX.VVVV. */ 110 | OT_VXMM, 111 | /* XMM is encoded in the high nibble of an immediate byte. */ 112 | OT_XMM_IMM, 113 | /* YMM/XMM is dependent on VEX.L. */ 114 | OT_YXMM, 115 | /* YMM/XMM (depends on prefix length) is encoded in the high nibble of an immediate byte. */ 116 | OT_YXMM_IMM, 117 | /* YMM is encoded in reg. */ 118 | OT_YMM, 119 | /* YMM is encoded in VEX.VVVV. */ 120 | OT_VYMM, 121 | /* YMM/XMM is dependent on VEX.L, and encoded in VEX.VVVV. */ 122 | OT_VYXMM, 123 | 124 | /* Use an immediate of 1, as for SHR R/M, 1 */ 125 | OT_CONST1, 126 | /* Use CL, as for SHR R/M, CL */ 127 | OT_REGCL, 128 | 129 | /* Use a control register */ 130 | OT_CREG, 131 | /* Use a debug register */ 132 | OT_DREG, 133 | /* Use a segment register */ 134 | OT_SREG, 135 | /* 136 | * SEG is encoded in the flags of the opcode itself! 137 | * This is used for specific "push SS" where SS is a segment where 138 | * each "push SS" has an absolutely different opcode byte. 139 | * We need this to detect whether an operand size prefix is used. 140 | */ 141 | OT_SEG, 142 | 143 | /* 144 | * Special immediates for instructions which have more than one immediate, 145 | * which is an exception from standard instruction format. 146 | * As to version v1.0: ENTER, INSERTQ, EXTRQ are the only problematic ones. 147 | */ 148 | /* 16 bits immediate using the first imm-slot */ 149 | OT_IMM16_1, 150 | /* 8 bits immediate using the first imm-slot */ 151 | OT_IMM8_1, 152 | /* 8 bits immediate using the second imm-slot */ 153 | OT_IMM8_2, 154 | 155 | /* Read one word (seg) and a word/dword/qword (depends on operand size), usually SEG:OFF, JMP 1234:1234 */ 156 | OT_PTR16_FULL, 157 | 158 | /* Used only by MOV CR/DR(n). Promoted with REX onlly. */ 159 | OT_FREG32_64_RM, 160 | 161 | /* MMX registers: */ 162 | OT_MM, 163 | /* Extract the MMX register from the RM bits this time (used when the REG bits are used for opcode extension) */ 164 | OT_MM_RM, 165 | 166 | 167 | /**** MEMORY only operands: ****/ 168 | 169 | /* Use general memory indirection, with varying sizes: */ 170 | OT_MEM, 171 | OT_MEM32, 172 | /* Memory dereference for MOVNTI, either 32 or 64 bits (with REX). */ 173 | OT_MEM32_64, 174 | OT_MEM64, 175 | /* Used for cmpxchg8b/16b. */ 176 | OT_MEM64_128, 177 | OT_MEM128, 178 | /* 179 | * Read one word (seg), and a word/dword/qword (depends on operand size) from memory. 180 | * JMP FAR [EBX] means EBX point to 16:32 ptr. 181 | */ 182 | OT_MEM16_FULL, 183 | /* Read one word (limit) and a dword/qword (limit) (depends on operand size), used by SGDT, SIDT, LGDT, LIDT. */ 184 | OT_MEM16_3264, 185 | /* Used when a memory indirection is required, but if the mod field is 11, this operand will be ignored. */ 186 | OT_MEM_OPT, 187 | 188 | /* Same as OT_RMXX but POINTS to 16 bits [cannot use GENERAL-PURPOSE REG!] */ 189 | OT_FPUM16, 190 | /* Same as OT_RMXX but POINTS to 32 bits (single precision) [cannot use GENERAL-PURPOSE REG!] */ 191 | OT_FPUM32, 192 | /* Same as OT_RMXX but POINTS to 64 bits (double precision) [cannot use GENERAL-PURPOSE REG!] */ 193 | OT_FPUM64, 194 | /* Same as OT_RMXX but POINTS to 80 bits (extended precision) [cannot use GENERAL-PURPOSE REG!] */ 195 | OT_FPUM80, 196 | 197 | /* Mem128/Mem256 is dependent on VEX.L. */ 198 | OT_LMEM128_256, 199 | 200 | 201 | /**** MEMORY & REGISTER only operands: ****/ 202 | 203 | /* Use or read (indirection) a 8bit register or immediate byte */ 204 | OT_RM8, 205 | /* Some instructions force 16 bits (mov sreg, rm16) */ 206 | OT_RM16, 207 | /* ModR/M for 32 bits. */ 208 | OT_RM32, 209 | /* 210 | * Special operand type for MOV reg16/32/64/mem16, segReg 8C /r. and SMSW. 211 | * It supports all decoding modes, but if used as a memory indirection it's a 16 bit ModR/M indirection. 212 | */ 213 | OT_RFULL_M16, 214 | /* Use or read a 16/32/64bit register or immediate word/dword/qword */ 215 | OT_RM_FULL, 216 | 217 | /* RM32/RM64 depends on prefix width only. */ 218 | OT_WRM32_64, 219 | /* 220 | * Special type for SSE4, ModR/M might be a 32 bits or 64 bits (with REX) register or 221 | * a 8 bits memory indirection operand. 222 | */ 223 | OT_R32_64_M8, 224 | /* 225 | * Special type for SSE4, ModR/M might be a 32 bits or 64 bits (with REX) register or 226 | * a 16 bits memory indirection operand. 227 | */ 228 | OT_R32_64_M16, 229 | 230 | /* 231 | * 32 or 64 bits (with REX) operand size indirection memory operand. 232 | * Some instructions are promoted automatically without a REX prefix. 233 | */ 234 | OT_RM32_64, 235 | /* 16 or 32 bits RM. This is used only with MOVZXD instruction in 64bits. */ 236 | OT_RM16_32, 237 | 238 | /* 239 | * Special operand type for SSE4 where the ModR/M might 240 | * be a 32 bits register or 8 bits memory indirection operand. 241 | */ 242 | OT_R32_M8, 243 | /* 244 | * Special ModR/M for PINSRW, which need a 16 bits memory operand or 32 bits register. 245 | * In 16 bits decoding mode R32 becomes R16, operand size cannot affect this. 246 | */ 247 | OT_R32_M16, 248 | /* Reg32/Reg64 (prefix width) or Mem8. */ 249 | OT_REG32_64_M8, 250 | /* Reg32/Reg64 (prefix width) or Mem16. */ 251 | OT_REG32_64_M16, 252 | 253 | /* ModR/M points to 32 bits MMX variable */ 254 | OT_MM32, 255 | /* ModR/M points to 32 bits MMX variable */ 256 | OT_MM64, 257 | 258 | /* ModR/M points to 16 bits SSE variable */ 259 | OT_XMM16, 260 | /* ModR/M points to 32 bits SSE variable */ 261 | OT_XMM32, 262 | /* ModR/M points to 64 bits SSE variable */ 263 | OT_XMM64, 264 | /* ModR/M points to 128 bits SSE variable */ 265 | OT_XMM128, 266 | 267 | /* AVX operands: */ 268 | /* XMM or Mem32/Mem64 depends on perfix width only. */ 269 | OT_WXMM32_64, 270 | /* YMM or Mem256. */ 271 | OT_YMM256, 272 | /* YMM/XMM or Mem64/Mem256 is dependent on VEX.L. */ 273 | OT_YXMM64_256, 274 | /* YMM/XMM or Mem128/Mem256 is dependent on VEX.L. */ 275 | OT_YXMM128_256, 276 | /* XMM or Mem64/Mem256 is dependent on VEX.L. */ 277 | OT_LXMM64_128 278 | } _OpType; 279 | 280 | /* Flags for instruction: */ 281 | 282 | /* Empty flags indicator: */ 283 | #define INST_FLAGS_NONE (0) 284 | /* The instruction we are going to decode requires ModR/M encoding. */ 285 | #define INST_MODRM_REQUIRED (1) 286 | /* Special treatment for instructions which are in the divided-category but still needs the whole byte for ModR/M... */ 287 | #define INST_NOT_DIVIDED (1 << 1) 288 | /* 289 | * Used explicitly in repeatable instructions, 290 | * which needs a suffix letter in their mnemonic to specify operation-size (depend on operands). 291 | */ 292 | #define INST_16BITS (1 << 2) 293 | /* If the opcode is supported by 80286 and upper models (16/32 bits). */ 294 | #define INST_32BITS (1 << 3) 295 | /* 296 | * Prefix flags (6 types: lock/rep, seg override, addr-size, oper-size, REX, VEX) 297 | * There are several specific instructions that can follow LOCK prefix, 298 | * note that they must be using a memory operand form, otherwise they generate an exception. 299 | */ 300 | #define INST_PRE_LOCK (1 << 4) 301 | /* REPNZ prefix for string instructions only - means an instruction can follow it. */ 302 | #define INST_PRE_REPNZ (1 << 5) 303 | /* REP prefix for string instructions only - means an instruction can follow it. */ 304 | #define INST_PRE_REP (1 << 6) 305 | /* CS override prefix. */ 306 | #define INST_PRE_CS (1 << 7) 307 | /* SS override prefix. */ 308 | #define INST_PRE_SS (1 << 8) 309 | /* DS override prefix. */ 310 | #define INST_PRE_DS (1 << 9) 311 | /* ES override prefix. */ 312 | #define INST_PRE_ES (1 << 10) 313 | /* FS override prefix. Funky Segment :) */ 314 | #define INST_PRE_FS (1 << 11) 315 | /* GS override prefix. Groovy Segment, of course not, duh ! */ 316 | #define INST_PRE_GS (1 << 12) 317 | /* Switch operand size from 32 to 16 and vice versa. */ 318 | #define INST_PRE_OP_SIZE (1 << 13) 319 | /* Switch address size from 32 to 16 and vice versa. */ 320 | #define INST_PRE_ADDR_SIZE (1 << 14) 321 | /* Native instructions which needs suffix letter to indicate their operation-size (and don't depend on operands). */ 322 | #define INST_NATIVE (1 << 15) 323 | /* Use extended mnemonic, means it's an _InstInfoEx structure, which contains another mnemonic for 32 bits specifically. */ 324 | #define INST_USE_EXMNEMONIC (1 << 16) 325 | /* Use third operand, means it's an _InstInfoEx structure, which contains another operand for special instructions. */ 326 | #define INST_USE_OP3 (1 << 17) 327 | /* Use fourth operand, means it's an _InstInfoEx structure, which contains another operand for special instructions. */ 328 | #define INST_USE_OP4 (1 << 18) 329 | /* The instruction's mnemonic depends on the mod value of the ModR/M byte (mod=11, mod!=11). */ 330 | #define INST_MNEMONIC_MODRM_BASED (1 << 19) 331 | /* The instruction uses a ModR/M byte which the MOD must be 11 (for registers operands only). */ 332 | #define INST_MODRR_REQUIRED (1 << 20) 333 | /* The way of 3DNow! instructions are built, we have to handle their locating specially. Suffix imm8 tells which instruction it is. */ 334 | #define INST_3DNOW_FETCH (1 << 21) 335 | /* The instruction needs two suffixes, one for the comparison type (imm8) and the second for its operation size indication (second mnemonic). */ 336 | #define INST_PSEUDO_OPCODE (1 << 22) 337 | /* Invalid instruction at 64 bits decoding mode. */ 338 | #define INST_INVALID_64BITS (1 << 23) 339 | /* Specific instruction can be promoted to 64 bits (without REX, it is promoted automatically). */ 340 | #define INST_64BITS (1 << 24) 341 | /* Indicates the instruction must be REX prefixed in order to use 64 bits operands. */ 342 | #define INST_PRE_REX (1 << 25) 343 | /* Third mnemonic is set. */ 344 | #define INST_USE_EXMNEMONIC2 (1 << 26) 345 | /* Instruction is only valid in 64 bits decoding mode. */ 346 | #define INST_64BITS_FETCH (1 << 27) 347 | /* Forces that the ModRM-REG/Opcode field will be 0. (For EXTRQ). */ 348 | #define INST_FORCE_REG0 (1 << 28) 349 | /* Indicates that instruction is encoded with a VEX prefix. */ 350 | #define INST_PRE_VEX (1 << 29) 351 | /* Indicates that the instruction is encoded with a ModRM byte (REG field specifically). */ 352 | #define INST_MODRM_INCLUDED (1 << 30) 353 | /* Indicates that the first (/destination) operand of the instruction is writable. */ 354 | #define INST_DST_WR (1 << 31) 355 | 356 | #define INST_PRE_REPS (INST_PRE_REPNZ | INST_PRE_REP) 357 | #define INST_PRE_LOKREP_MASK (INST_PRE_LOCK | INST_PRE_REPNZ | INST_PRE_REP) 358 | #define INST_PRE_SEGOVRD_MASK32 (INST_PRE_CS | INST_PRE_SS | INST_PRE_DS | INST_PRE_ES) 359 | #define INST_PRE_SEGOVRD_MASK64 (INST_PRE_FS | INST_PRE_GS) 360 | #define INST_PRE_SEGOVRD_MASK (INST_PRE_SEGOVRD_MASK32 | INST_PRE_SEGOVRD_MASK64) 361 | 362 | /* Extended flags for VEX: */ 363 | /* Indicates that the instruction might have VEX.L encoded. */ 364 | #define INST_VEX_L (1) 365 | /* Indicates that the instruction might have VEX.W encoded. */ 366 | #define INST_VEX_W (1 << 1) 367 | /* Indicates that the mnemonic of the instruction is based on the VEX.W bit. */ 368 | #define INST_MNEMONIC_VEXW_BASED (1 << 2) 369 | /* Indicates that the mnemonic of the instruction is based on the VEX.L bit. */ 370 | #define INST_MNEMONIC_VEXL_BASED (1 << 3) 371 | /* Forces the instruction to be encoded with VEX.L, otherwise it's undefined. */ 372 | #define INST_FORCE_VEXL (1 << 4) 373 | /* 374 | * Indicates that the instruction is based on the MOD field of the ModRM byte. 375 | * (MOD==11: got the right instruction, else skip +4 in prefixed table for the correct instruction). 376 | */ 377 | #define INST_MODRR_BASED (1 << 5) 378 | /* Indicates that the instruction doesn't use the VVVV field of the VEX prefix, if it does then it's undecodable. */ 379 | #define INST_VEX_V_UNUSED (1 << 6) 380 | 381 | /* Indication that the instruction is privileged (Ring 0), this should be checked on the opcodeId field. */ 382 | #define META_INST_PRIVILEGED ((uint16_t)0x8000) 383 | 384 | /* 385 | * Indicates which operand is being decoded. 386 | * Destination (1st), Source (2nd), op3 (3rd), op4 (4th). 387 | * Used to set the operands' fields in the _DInst structure! 388 | */ 389 | typedef enum {ONT_NONE = -1, ONT_1 = 0, ONT_2 = 1, ONT_3 = 2, ONT_4 = 3} _OperandNumberType; 390 | 391 | /* CPU Flags that instructions modify, test or undefine, in compacted form (CF,PF,AF,ZF,SF are 1:1 map to EFLAGS). */ 392 | #define D_COMPACT_CF 1 /* Carry */ 393 | #define D_COMPACT_PF 4 /* Parity */ 394 | #define D_COMPACT_AF 0x10 /* Auxiliary */ 395 | #define D_COMPACT_ZF 0x40 /* Zero */ 396 | #define D_COMPACT_SF 0x80 /* Sign */ 397 | /* The following flags have to be translated to EFLAGS. */ 398 | #define D_COMPACT_IF 2 /* Interrupt */ 399 | #define D_COMPACT_DF 8 /* Direction */ 400 | #define D_COMPACT_OF 0x20 /* Overflow */ 401 | 402 | /* The mask of flags that are already compatible with EFLAGS. */ 403 | #define D_COMPACT_SAME_FLAGS (D_COMPACT_CF | D_COMPACT_PF | D_COMPACT_AF | D_COMPACT_ZF | D_COMPACT_SF) 404 | 405 | /* 406 | * In order to save more space for storing the DB statically, 407 | * I came up with another level of shared info. 408 | * Because I saw that most of the information that instructions use repeats itself. 409 | * 410 | * Info about the instruction, source/dest types, meta and flags. 411 | * _InstInfo points to a table of _InstSharedInfo. 412 | */ 413 | typedef struct { 414 | uint8_t flagsIndex; /* An index into FlagsTables */ 415 | uint8_t s, d; /* OpType. */ 416 | /* 417 | * The following are CPU flag masks that the instruction changes. 418 | * The flags are compacted so 8 bits representation is enough. 419 | * They will be expanded in runtime to be compatible to EFLAGS. 420 | */ 421 | uint8_t modifiedFlagsMask; 422 | uint8_t testedFlagsMask; 423 | uint8_t undefinedFlagsMask; 424 | uint16_t meta; /* High byte = Instruction set class | Low byte = flow control flags. */ 425 | } _InstSharedInfo; 426 | 427 | /* 428 | * This structure is used for the instructions DB and NOT for the disassembled result code! 429 | * This is the BASE structure, there are extensions to this structure below. 430 | */ 431 | typedef struct { 432 | uint16_t sharedIndex; /* An index into the SharedInfoTable. */ 433 | uint16_t opcodeId; /* The opcodeId is really a byte-offset into the mnemonics table. MSB is a privileged indication. */ 434 | } _InstInfo; 435 | 436 | /* 437 | * There are merely few instructions which need a second mnemonic for 32 bits. 438 | * Or a third for 64 bits. Therefore sometimes the second mnemonic is empty but not the third. 439 | * In all decoding modes the first mnemonic is the default. 440 | * A flag will indicate it uses another mnemonic. 441 | * 442 | * There are a couple of (SSE4) instructions in the whole DB which need both op3 and 3rd mnemonic for 64bits, 443 | * therefore, I decided to make the extended structure contain all extra info in the same structure. 444 | * There are a few instructions (SHLD/SHRD/IMUL and SSE too) which use third operand (or a fourth). 445 | * A flag will indicate it uses a third/fourth operand. 446 | */ 447 | typedef struct { 448 | /* Base structure (doesn't get accessed directly from code). */ 449 | _InstInfo BASE; 450 | 451 | /* Extended starts here. */ 452 | uint8_t flagsEx; /* 8 bits are enough, in the future we might make it a bigger integer. */ 453 | uint8_t op3, op4; /* OpType. */ 454 | uint16_t opcodeId2, opcodeId3; 455 | } _InstInfoEx; 456 | 457 | /* Trie data structure node type: */ 458 | typedef enum { 459 | INT_NOTEXISTS = 0, /* Not exists. */ 460 | INT_INFO = 1, /* It's an instruction info. */ 461 | INT_INFOEX, 462 | INT_INFO_TREAT, /* Extra intervention is required by inst_lookup. */ 463 | INT_LIST_GROUP, 464 | INT_LIST_FULL, 465 | INT_LIST_DIVIDED, 466 | INT_LIST_PREFIXED 467 | } _InstNodeType; 468 | 469 | /* Used to check instType < INT_INFOS, means we got an inst-info. Cause it has to be only one of them. */ 470 | #define INT_INFOS (INT_LIST_GROUP) 471 | 472 | /* Instruction node is treated as { int index:13; int type:3; } */ 473 | typedef uint16_t _InstNode; 474 | 475 | _InstInfo* inst_lookup(_CodeInfo* ci, _PrefixState* ps, int* isPrefixed); 476 | _InstInfo* inst_lookup_3dnow(_CodeInfo* ci); 477 | 478 | #endif /* INSTRUCTIONS_H */ 479 | 480 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/insts.h: -------------------------------------------------------------------------------- 1 | /* 2 | insts.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef INSTS_H 13 | #define INSTS_H 14 | 15 | #include "instructions.h" 16 | 17 | 18 | /* Flags Table */ 19 | extern _iflags FlagsTable[]; 20 | 21 | /* Root Trie DB */ 22 | extern _InstSharedInfo InstSharedInfoTable[]; 23 | extern _InstInfo InstInfos[]; 24 | extern _InstInfoEx InstInfosEx[]; 25 | extern _InstNode InstructionsTree[]; 26 | 27 | /* 3DNow! Trie DB */ 28 | extern _InstNode Table_0F_0F; 29 | /* AVX related: */ 30 | extern _InstNode Table_0F, Table_0F_38, Table_0F_3A; 31 | 32 | /* 33 | * The inst_lookup will return on of these two instructions according to the specified decoding mode. 34 | * ARPL or MOVSXD on 64 bits is one byte instruction at index 0x63. 35 | */ 36 | extern _InstInfo II_MOVSXD; 37 | 38 | /* 39 | * The NOP instruction can be prefixed by REX in 64bits, therefore we have to decide in runtime whether it's an XCHG or NOP instruction. 40 | * If 0x90 is prefixed by a usable REX it will become XCHG, otherwise it will become a NOP. 41 | * Also note that if it's prefixed by 0xf3, it becomes a Pause. 42 | */ 43 | extern _InstInfo II_NOP; 44 | extern _InstInfo II_PAUSE; 45 | 46 | /* 47 | * RDRAND and VMPTRLD share same 2.3 bytes opcode, and then alternates on the MOD bits, 48 | * RDRAND is OT_FULL_REG while VMPTRLD is OT_MEM, and there's no such mixed type. 49 | * So a hack into the inst_lookup was added for this decision, the DB isn't flexible enough. :( 50 | */ 51 | extern _InstInfo II_RDRAND; 52 | 53 | /* 54 | * Used for letting the extract operand know the type of operands without knowing the 55 | * instruction itself yet, because of the way those instructions work. 56 | * See function instructions.c!inst_lookup_3dnow. 57 | */ 58 | extern _InstInfo II_3DNOW; 59 | 60 | /* Helper tables for pseudo compare mnemonics. */ 61 | extern uint16_t CmpMnemonicOffsets[8]; /* SSE */ 62 | extern uint16_t VCmpMnemonicOffsets[32]; /* AVX */ 63 | 64 | #endif /* INSTS_H */ 65 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/mnemonics.h: -------------------------------------------------------------------------------- 1 | /* 2 | mnemonics.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef MNEMONICS_H 13 | #define MNEMONICS_H 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #ifndef DISTORM_LIGHT 20 | 21 | typedef struct WMnemonic { 22 | unsigned char length; 23 | unsigned char p[1]; /* p is a null terminated string, which contains 'length' characters. */ 24 | } _WMnemonic; 25 | 26 | typedef struct WRegister { 27 | unsigned int length; 28 | unsigned char p[6]; /* p is a null terminated string. */ 29 | } _WRegister; 30 | 31 | extern const unsigned char _MNEMONICS[]; 32 | extern const _WRegister _REGISTERS[]; 33 | 34 | #endif /* DISTORM_LIGHT */ 35 | 36 | #ifdef __cplusplus 37 | } /* End Of Extern */ 38 | #endif 39 | 40 | #define GET_REGISTER_NAME(r) (unsigned char*)_REGISTERS[(r)].p 41 | #define GET_MNEMONIC_NAME(m) ((_WMnemonic*)&_MNEMONICS[(m)])->p 42 | 43 | typedef enum { 44 | I_UNDEFINED = 0, I_AAA = 66, I_AAD = 388, I_AAM = 383, I_AAS = 76, I_ADC = 31, I_ADD = 11, I_ADDPD = 3143, 45 | I_ADDPS = 3136, I_ADDSD = 3157, I_ADDSS = 3150, I_ADDSUBPD = 6427, I_ADDSUBPS = 6437, 46 | I_AESDEC = 9242, I_AESDECLAST = 9259, I_AESENC = 9200, I_AESENCLAST = 9217, 47 | I_AESIMC = 9183, I_AESKEYGENASSIST = 9828, I_AND = 41, I_ANDNPD = 3054, I_ANDNPS = 3046, 48 | I_ANDPD = 3023, I_ANDPS = 3016, I_ARPL = 111, I_BLENDPD = 9405, I_BLENDPS = 9386, 49 | I_BLENDVPD = 7652, I_BLENDVPS = 7642, I_BOUND = 104, I_BSF = 4379, I_BSR = 4391, 50 | I_BSWAP = 959, I_BT = 871, I_BTC = 933, I_BTR = 911, I_BTS = 886, I_CALL = 455, 51 | I_CALL_FAR = 260, I_CBW = 228, I_CDQ = 250, I_CDQE = 239, I_CLAC = 1786, I_CLC = 491, 52 | I_CLD = 511, I_CLFLUSH = 4362, I_CLGI = 1866, I_CLI = 501, I_CLTS = 540, I_CMC = 486, 53 | I_CMOVA = 693, I_CMOVAE = 662, I_CMOVB = 655, I_CMOVBE = 685, I_CMOVG = 753, 54 | I_CMOVGE = 737, I_CMOVL = 730, I_CMOVLE = 745, I_CMOVNO = 647, I_CMOVNP = 722, 55 | I_CMOVNS = 707, I_CMOVNZ = 677, I_CMOVO = 640, I_CMOVP = 715, I_CMOVS = 700, 56 | I_CMOVZ = 670, I_CMP = 71, I_CMPEQPD = 4482, I_CMPEQPS = 4403, I_CMPEQSD = 4640, 57 | I_CMPEQSS = 4561, I_CMPLEPD = 4500, I_CMPLEPS = 4421, I_CMPLESD = 4658, I_CMPLESS = 4579, 58 | I_CMPLTPD = 4491, I_CMPLTPS = 4412, I_CMPLTSD = 4649, I_CMPLTSS = 4570, I_CMPNEQPD = 4521, 59 | I_CMPNEQPS = 4442, I_CMPNEQSD = 4679, I_CMPNEQSS = 4600, I_CMPNLEPD = 4541, 60 | I_CMPNLEPS = 4462, I_CMPNLESD = 4699, I_CMPNLESS = 4620, I_CMPNLTPD = 4531, 61 | I_CMPNLTPS = 4452, I_CMPNLTSD = 4689, I_CMPNLTSS = 4610, I_CMPORDPD = 4551, 62 | I_CMPORDPS = 4472, I_CMPORDSD = 4709, I_CMPORDSS = 4630, I_CMPS = 301, I_CMPUNORDPD = 4509, 63 | I_CMPUNORDPS = 4430, I_CMPUNORDSD = 4667, I_CMPUNORDSS = 4588, I_CMPXCHG = 897, 64 | I_CMPXCHG16B = 6406, I_CMPXCHG8B = 6395, I_COMISD = 2812, I_COMISS = 2804, 65 | I_CPUID = 864, I_CQO = 255, I_CRC32 = 9291, I_CVTDQ2PD = 6820, I_CVTDQ2PS = 3340, 66 | I_CVTPD2DQ = 6830, I_CVTPD2PI = 2714, I_CVTPD2PS = 3266, I_CVTPH2PS = 4194, 67 | I_CVTPI2PD = 2528, I_CVTPI2PS = 2518, I_CVTPS2DQ = 3350, I_CVTPS2PD = 3256, 68 | I_CVTPS2PH = 4204, I_CVTPS2PI = 2704, I_CVTSD2SI = 2734, I_CVTSD2SS = 3286, 69 | I_CVTSI2SD = 2548, I_CVTSI2SS = 2538, I_CVTSS2SD = 3276, I_CVTSS2SI = 2724, 70 | I_CVTTPD2DQ = 6809, I_CVTTPD2PI = 2647, I_CVTTPS2DQ = 3360, I_CVTTPS2PI = 2636, 71 | I_CVTTSD2SI = 2669, I_CVTTSS2SI = 2658, I_CWD = 245, I_CWDE = 233, I_DAA = 46, 72 | I_DAS = 56, I_DEC = 86, I_DIV = 1645, I_DIVPD = 3532, I_DIVPS = 3525, I_DIVSD = 3546, 73 | I_DIVSS = 3539, I_DPPD = 9648, I_DPPS = 9635, I_EMMS = 4133, I_ENTER = 340, 74 | I_EXTRACTPS = 9513, I_EXTRQ = 4169, I_F2XM1 = 1191, I_FABS = 1122, I_FADD = 1022, 75 | I_FADDP = 1548, I_FBLD = 1600, I_FBSTP = 1606, I_FCHS = 1116, I_FCLEX = 7322, 76 | I_FCMOVB = 1375, I_FCMOVBE = 1391, I_FCMOVE = 1383, I_FCMOVNB = 1444, I_FCMOVNBE = 1462, 77 | I_FCMOVNE = 1453, I_FCMOVNU = 1472, I_FCMOVU = 1400, I_FCOM = 1034, I_FCOMI = 1511, 78 | I_FCOMIP = 1622, I_FCOMP = 1040, I_FCOMPP = 1562, I_FCOS = 1310, I_FDECSTP = 1237, 79 | I_FDIV = 1060, I_FDIVP = 1593, I_FDIVR = 1066, I_FDIVRP = 1585, I_FEDISI = 1487, 80 | I_FEMMS = 573, I_FENI = 1481, I_FFREE = 1526, I_FIADD = 1316, I_FICOM = 1330, 81 | I_FICOMP = 1337, I_FIDIV = 1360, I_FIDIVR = 1367, I_FILD = 1417, I_FIMUL = 1323, 82 | I_FINCSTP = 1246, I_FINIT = 7337, I_FIST = 1431, I_FISTP = 1437, I_FISTTP = 1423, 83 | I_FISUB = 1345, I_FISUBR = 1352, I_FLD = 1073, I_FLD1 = 1140, I_FLDCW = 1097, 84 | I_FLDENV = 1089, I_FLDL2E = 1154, I_FLDL2T = 1146, I_FLDLG2 = 1169, I_FLDLN2 = 1177, 85 | I_FLDPI = 1162, I_FLDZ = 1185, I_FMUL = 1028, I_FMULP = 1555, I_FNCLEX = 7314, 86 | I_FNINIT = 7329, I_FNOP = 1110, I_FNSAVE = 7344, I_FNSTCW = 7299, I_FNSTENV = 7282, 87 | I_FNSTSW = 7359, I_FPATAN = 1212, I_FPREM = 1255, I_FPREM1 = 1229, I_FPTAN = 1205, 88 | I_FRNDINT = 1287, I_FRSTOR = 1518, I_FSAVE = 7352, I_FSCALE = 1296, I_FSETPM = 1495, 89 | I_FSIN = 1304, I_FSINCOS = 1278, I_FSQRT = 1271, I_FST = 1078, I_FSTCW = 7307, 90 | I_FSTENV = 7291, I_FSTP = 1083, I_FSTSW = 7367, I_FSUB = 1047, I_FSUBP = 1578, 91 | I_FSUBR = 1053, I_FSUBRP = 1570, I_FTST = 1128, I_FUCOM = 1533, I_FUCOMI = 1503, 92 | I_FUCOMIP = 1613, I_FUCOMP = 1540, I_FUCOMPP = 1408, I_FXAM = 1134, I_FXCH = 1104, 93 | I_FXRSTOR = 9925, I_FXRSTOR64 = 9934, I_FXSAVE = 9897, I_FXSAVE64 = 9905, 94 | I_FXTRACT = 1220, I_FYL2X = 1198, I_FYL2XP1 = 1262, I_GETSEC = 632, I_HADDPD = 4214, 95 | I_HADDPS = 4222, I_HLT = 481, I_HSUBPD = 4248, I_HSUBPS = 4256, I_IDIV = 1650, 96 | I_IMUL = 117, I_IN = 446, I_INC = 81, I_INS = 123, I_INSERTPS = 9580, I_INSERTQ = 4176, 97 | I_INT = 366, I_INT1 = 475, I_INT3 = 360, I_INTO = 371, I_INVD = 554, I_INVEPT = 8317, 98 | I_INVLPG = 1726, I_INVLPGA = 1880, I_INVPCID = 8334, I_INVVPID = 8325, I_IRET = 377, 99 | I_JA = 166, I_JAE = 147, I_JB = 143, I_JBE = 161, I_JCXZ = 426, I_JECXZ = 432, 100 | I_JG = 202, I_JGE = 192, I_JL = 188, I_JLE = 197, I_JMP = 461, I_JMP_FAR = 466, 101 | I_JNO = 138, I_JNP = 183, I_JNS = 174, I_JNZ = 156, I_JO = 134, I_JP = 179, 102 | I_JRCXZ = 439, I_JS = 170, I_JZ = 152, I_LAHF = 289, I_LAR = 521, I_LDDQU = 7027, 103 | I_LDMXCSR = 9955, I_LDS = 335, I_LEA = 223, I_LEAVE = 347, I_LES = 330, I_LFENCE = 4298, 104 | I_LFS = 916, I_LGDT = 1702, I_LGS = 921, I_LIDT = 1708, I_LLDT = 1667, I_LMSW = 1720, 105 | I_LODS = 313, I_LOOP = 420, I_LOOPNZ = 405, I_LOOPZ = 413, I_LSL = 526, I_LSS = 906, 106 | I_LTR = 1673, I_LZCNT = 4396, I_MASKMOVDQU = 7152, I_MASKMOVQ = 7142, I_MAXPD = 3592, 107 | I_MAXPS = 3585, I_MAXSD = 3606, I_MAXSS = 3599, I_MFENCE = 4324, I_MINPD = 3472, 108 | I_MINPS = 3465, I_MINSD = 3486, I_MINSS = 3479, I_MONITOR = 1770, I_MOV = 218, 109 | I_MOVAPD = 2492, I_MOVAPS = 2484, I_MOVBE = 9284, I_MOVD = 3953, I_MOVDDUP = 2219, 110 | I_MOVDQ2Q = 6555, I_MOVDQA = 3979, I_MOVDQU = 3987, I_MOVHLPS = 2184, I_MOVHPD = 2378, 111 | I_MOVHPS = 2370, I_MOVLHPS = 2361, I_MOVLPD = 2201, I_MOVLPS = 2193, I_MOVMSKPD = 2848, 112 | I_MOVMSKPS = 2838, I_MOVNTDQ = 6882, I_MOVNTDQA = 7928, I_MOVNTI = 951, I_MOVNTPD = 2589, 113 | I_MOVNTPS = 2580, I_MOVNTQ = 6874, I_MOVNTSD = 2607, I_MOVNTSS = 2598, I_MOVQ = 3959, 114 | I_MOVQ2DQ = 6546, I_MOVS = 295, I_MOVSD = 2143, I_MOVSHDUP = 2386, I_MOVSLDUP = 2209, 115 | I_MOVSS = 2136, I_MOVSX = 938, I_MOVSXD = 10038, I_MOVUPD = 2128, I_MOVUPS = 2120, 116 | I_MOVZX = 926, I_MPSADBW = 9661, I_MUL = 1640, I_MULPD = 3203, I_MULPS = 3196, 117 | I_MULSD = 3217, I_MULSS = 3210, I_MWAIT = 1779, I_NEG = 1635, I_NOP = 580, 118 | I_NOT = 1630, I_OR = 27, I_ORPD = 3086, I_ORPS = 3080, I_OUT = 450, I_OUTS = 128, 119 | I_PABSB = 7721, I_PABSD = 7751, I_PABSW = 7736, I_PACKSSDW = 3882, I_PACKSSWB = 3714, 120 | I_PACKUSDW = 7949, I_PACKUSWB = 3792, I_PADDB = 7237, I_PADDD = 7267, I_PADDQ = 6514, 121 | I_PADDSB = 6963, I_PADDSW = 6980, I_PADDUSB = 6653, I_PADDUSW = 6672, I_PADDW = 7252, 122 | I_PALIGNR = 9443, I_PAND = 6640, I_PANDN = 6698, I_PAUSE = 10046, I_PAVGB = 6713, 123 | I_PAVGUSB = 2111, I_PAVGW = 6758, I_PBLENDVB = 7632, I_PBLENDW = 9424, I_PCLMULQDQ = 9680, 124 | I_PCMPEQB = 4076, I_PCMPEQD = 4114, I_PCMPEQQ = 7909, I_PCMPEQW = 4095, I_PCMPESTRI = 9759, 125 | I_PCMPESTRM = 9736, I_PCMPGTB = 3735, I_PCMPGTD = 3773, I_PCMPGTQ = 8120, 126 | I_PCMPGTW = 3754, I_PCMPISTRI = 9805, I_PCMPISTRM = 9782, I_PEXTRB = 9462, 127 | I_PEXTRD = 9479, I_PEXTRQ = 9487, I_PEXTRW = 6344, I_PF2ID = 1947, I_PF2IW = 1940, 128 | I_PFACC = 2061, I_PFADD = 2010, I_PFCMPEQ = 2068, I_PFCMPGE = 1971, I_PFCMPGT = 2017, 129 | I_PFMAX = 2026, I_PFMIN = 1980, I_PFMUL = 2077, I_PFNACC = 1954, I_PFPNACC = 1962, 130 | I_PFRCP = 1987, I_PFRCPIT1 = 2033, I_PFRCPIT2 = 2084, I_PFRSQIT1 = 2043, I_PFRSQRT = 1994, 131 | I_PFSUB = 2003, I_PFSUBR = 2053, I_PHADDD = 7408, I_PHADDSW = 7425, I_PHADDW = 7391, 132 | I_PHMINPOSUW = 8292, I_PHSUBD = 7484, I_PHSUBSW = 7501, I_PHSUBW = 7467, I_PI2FD = 1933, 133 | I_PI2FW = 1926, I_PINSRB = 9563, I_PINSRD = 9601, I_PINSRQ = 9609, I_PINSRW = 6327, 134 | I_PMADDUBSW = 7444, I_PMADDWD = 7106, I_PMAXSB = 8207, I_PMAXSD = 8224, I_PMAXSW = 6997, 135 | I_PMAXUB = 6681, I_PMAXUD = 8258, I_PMAXUW = 8241, I_PMINSB = 8139, I_PMINSD = 8156, 136 | I_PMINSW = 6935, I_PMINUB = 6623, I_PMINUD = 8190, I_PMINUW = 8173, I_PMOVMSKB = 6564, 137 | I_PMOVSXBD = 7787, I_PMOVSXBQ = 7808, I_PMOVSXBW = 7766, I_PMOVSXDQ = 7871, 138 | I_PMOVSXWD = 7829, I_PMOVSXWQ = 7850, I_PMOVZXBD = 8015, I_PMOVZXBQ = 8036, 139 | I_PMOVZXBW = 7994, I_PMOVZXDQ = 8099, I_PMOVZXWD = 8057, I_PMOVZXWQ = 8078, 140 | I_PMULDQ = 7892, I_PMULHRSW = 7571, I_PMULHRW = 2094, I_PMULHUW = 6773, I_PMULHW = 6792, 141 | I_PMULLD = 8275, I_PMULLW = 6529, I_PMULUDQ = 7087, I_POP = 22, I_POPA = 98, 142 | I_POPCNT = 4371, I_POPF = 277, I_POR = 6952, I_PREFETCH = 1905, I_PREFETCHNTA = 2435, 143 | I_PREFETCHT0 = 2448, I_PREFETCHT1 = 2460, I_PREFETCHT2 = 2472, I_PREFETCHW = 1915, 144 | I_PSADBW = 7125, I_PSHUFB = 7374, I_PSHUFD = 4021, I_PSHUFHW = 4029, I_PSHUFLW = 4038, 145 | I_PSHUFW = 4013, I_PSIGNB = 7520, I_PSIGND = 7554, I_PSIGNW = 7537, I_PSLLD = 7057, 146 | I_PSLLDQ = 9880, I_PSLLQ = 7072, I_PSLLW = 7042, I_PSRAD = 6743, I_PSRAW = 6728, 147 | I_PSRLD = 6484, I_PSRLDQ = 9863, I_PSRLQ = 6499, I_PSRLW = 6469, I_PSUBB = 7177, 148 | I_PSUBD = 7207, I_PSUBQ = 7222, I_PSUBSB = 6901, I_PSUBSW = 6918, I_PSUBUSB = 6585, 149 | I_PSUBUSW = 6604, I_PSUBW = 7192, I_PSWAPD = 2103, I_PTEST = 7662, I_PUNPCKHBW = 3813, 150 | I_PUNPCKHDQ = 3859, I_PUNPCKHQDQ = 3928, I_PUNPCKHWD = 3836, I_PUNPCKLBW = 3645, 151 | I_PUNPCKLDQ = 3691, I_PUNPCKLQDQ = 3903, I_PUNPCKLWD = 3668, I_PUSH = 16, 152 | I_PUSHA = 91, I_PUSHF = 270, I_PXOR = 7014, I_RCL = 976, I_RCPPS = 2986, I_RCPSS = 2993, 153 | I_RCR = 981, I_RDFSBASE = 9915, I_RDGSBASE = 9945, I_RDMSR = 599, I_RDPMC = 606, 154 | I_RDRAND = 10059, I_RDTSC = 592, I_RDTSCP = 1897, I_RET = 325, I_RETF = 354, 155 | I_ROL = 966, I_ROR = 971, I_ROUNDPD = 9329, I_ROUNDPS = 9310, I_ROUNDSD = 9367, 156 | I_ROUNDSS = 9348, I_RSM = 881, I_RSQRTPS = 2948, I_RSQRTSS = 2957, I_SAHF = 283, 157 | I_SAL = 996, I_SALC = 393, I_SAR = 1001, I_SBB = 36, I_SCAS = 319, I_SETA = 806, 158 | I_SETAE = 779, I_SETB = 773, I_SETBE = 799, I_SETG = 858, I_SETGE = 844, I_SETL = 838, 159 | I_SETLE = 851, I_SETNO = 766, I_SETNP = 831, I_SETNS = 818, I_SETNZ = 792, 160 | I_SETO = 760, I_SETP = 825, I_SETS = 812, I_SETZ = 786, I_SFENCE = 4354, I_SGDT = 1690, 161 | I_SHL = 986, I_SHLD = 875, I_SHR = 991, I_SHRD = 891, I_SHUFPD = 6369, I_SHUFPS = 6361, 162 | I_SIDT = 1696, I_SKINIT = 1872, I_SLDT = 1656, I_SMSW = 1714, I_SQRTPD = 2888, 163 | I_SQRTPS = 2880, I_SQRTSD = 2904, I_SQRTSS = 2896, I_STAC = 1792, I_STC = 496, 164 | I_STD = 516, I_STGI = 1860, I_STI = 506, I_STMXCSR = 9984, I_STOS = 307, I_STR = 1662, 165 | I_SUB = 51, I_SUBPD = 3412, I_SUBPS = 3405, I_SUBSD = 3426, I_SUBSS = 3419, 166 | I_SWAPGS = 1889, I_SYSCALL = 531, I_SYSENTER = 613, I_SYSEXIT = 623, I_SYSRET = 546, 167 | I_TEST = 206, I_TZCNT = 4384, I_UCOMISD = 2775, I_UCOMISS = 2766, I_UD2 = 568, 168 | I_UNPCKHPD = 2329, I_UNPCKHPS = 2319, I_UNPCKLPD = 2287, I_UNPCKLPS = 2277, 169 | I_VADDPD = 3172, I_VADDPS = 3164, I_VADDSD = 3188, I_VADDSS = 3180, I_VADDSUBPD = 6447, 170 | I_VADDSUBPS = 6458, I_VAESDEC = 9250, I_VAESDECLAST = 9271, I_VAESENC = 9208, 171 | I_VAESENCLAST = 9229, I_VAESIMC = 9191, I_VAESKEYGENASSIST = 9845, I_VANDNPD = 3071, 172 | I_VANDNPS = 3062, I_VANDPD = 3038, I_VANDPS = 3030, I_VBLENDPD = 9414, I_VBLENDPS = 9395, 173 | I_VBLENDVPD = 9714, I_VBLENDVPS = 9703, I_VBROADCASTF128 = 7705, I_VBROADCASTSD = 7691, 174 | I_VBROADCASTSS = 7677, I_VCMPEQPD = 5121, I_VCMPEQPS = 4719, I_VCMPEQSD = 5925, 175 | I_VCMPEQSS = 5523, I_VCMPEQ_OSPD = 5302, I_VCMPEQ_OSPS = 4900, I_VCMPEQ_OSSD = 6106, 176 | I_VCMPEQ_OSSS = 5704, I_VCMPEQ_UQPD = 5208, I_VCMPEQ_UQPS = 4806, I_VCMPEQ_UQSD = 6012, 177 | I_VCMPEQ_UQSS = 5610, I_VCMPEQ_USPD = 5411, I_VCMPEQ_USPS = 5009, I_VCMPEQ_USSD = 6215, 178 | I_VCMPEQ_USSS = 5813, I_VCMPFALSEPD = 5243, I_VCMPFALSEPS = 4841, I_VCMPFALSESD = 6047, 179 | I_VCMPFALSESS = 5645, I_VCMPFALSE_OSPD = 5452, I_VCMPFALSE_OSPS = 5050, I_VCMPFALSE_OSSD = 6256, 180 | I_VCMPFALSE_OSSS = 5854, I_VCMPGEPD = 5270, I_VCMPGEPS = 4868, I_VCMPGESD = 6074, 181 | I_VCMPGESS = 5672, I_VCMPGE_OQPD = 5482, I_VCMPGE_OQPS = 5080, I_VCMPGE_OQSD = 6286, 182 | I_VCMPGE_OQSS = 5884, I_VCMPGTPD = 5280, I_VCMPGTPS = 4878, I_VCMPGTSD = 6084, 183 | I_VCMPGTSS = 5682, I_VCMPGT_OQPD = 5495, I_VCMPGT_OQPS = 5093, I_VCMPGT_OQSD = 6299, 184 | I_VCMPGT_OQSS = 5897, I_VCMPLEPD = 5141, I_VCMPLEPS = 4739, I_VCMPLESD = 5945, 185 | I_VCMPLESS = 5543, I_VCMPLE_OQPD = 5328, I_VCMPLE_OQPS = 4926, I_VCMPLE_OQSD = 6132, 186 | I_VCMPLE_OQSS = 5730, I_VCMPLTPD = 5131, I_VCMPLTPS = 4729, I_VCMPLTSD = 5935, 187 | I_VCMPLTSS = 5533, I_VCMPLT_OQPD = 5315, I_VCMPLT_OQPS = 4913, I_VCMPLT_OQSD = 6119, 188 | I_VCMPLT_OQSS = 5717, I_VCMPNEQPD = 5164, I_VCMPNEQPS = 4762, I_VCMPNEQSD = 5968, 189 | I_VCMPNEQSS = 5566, I_VCMPNEQ_OQPD = 5256, I_VCMPNEQ_OQPS = 4854, I_VCMPNEQ_OQSD = 6060, 190 | I_VCMPNEQ_OQSS = 5658, I_VCMPNEQ_OSPD = 5468, I_VCMPNEQ_OSPS = 5066, I_VCMPNEQ_OSSD = 6272, 191 | I_VCMPNEQ_OSSS = 5870, I_VCMPNEQ_USPD = 5356, I_VCMPNEQ_USPS = 4954, I_VCMPNEQ_USSD = 6160, 192 | I_VCMPNEQ_USSS = 5758, I_VCMPNGEPD = 5221, I_VCMPNGEPS = 4819, I_VCMPNGESD = 6025, 193 | I_VCMPNGESS = 5623, I_VCMPNGE_UQPD = 5424, I_VCMPNGE_UQPS = 5022, I_VCMPNGE_UQSD = 6228, 194 | I_VCMPNGE_UQSS = 5826, I_VCMPNGTPD = 5232, I_VCMPNGTPS = 4830, I_VCMPNGTSD = 6036, 195 | I_VCMPNGTSS = 5634, I_VCMPNGT_UQPD = 5438, I_VCMPNGT_UQPS = 5036, I_VCMPNGT_UQSD = 6242, 196 | I_VCMPNGT_UQSS = 5840, I_VCMPNLEPD = 5186, I_VCMPNLEPS = 4784, I_VCMPNLESD = 5990, 197 | I_VCMPNLESS = 5588, I_VCMPNLE_UQPD = 5384, I_VCMPNLE_UQPS = 4982, I_VCMPNLE_UQSD = 6188, 198 | I_VCMPNLE_UQSS = 5786, I_VCMPNLTPD = 5175, I_VCMPNLTPS = 4773, I_VCMPNLTSD = 5979, 199 | I_VCMPNLTSS = 5577, I_VCMPNLT_UQPD = 5370, I_VCMPNLT_UQPS = 4968, I_VCMPNLT_UQSD = 6174, 200 | I_VCMPNLT_UQSS = 5772, I_VCMPORDPD = 5197, I_VCMPORDPS = 4795, I_VCMPORDSD = 6001, 201 | I_VCMPORDSS = 5599, I_VCMPORD_SPD = 5398, I_VCMPORD_SPS = 4996, I_VCMPORD_SSD = 6202, 202 | I_VCMPORD_SSS = 5800, I_VCMPTRUEPD = 5290, I_VCMPTRUEPS = 4888, I_VCMPTRUESD = 6094, 203 | I_VCMPTRUESS = 5692, I_VCMPTRUE_USPD = 5508, I_VCMPTRUE_USPS = 5106, I_VCMPTRUE_USSD = 6312, 204 | I_VCMPTRUE_USSS = 5910, I_VCMPUNORDPD = 5151, I_VCMPUNORDPS = 4749, I_VCMPUNORDSD = 5955, 205 | I_VCMPUNORDSS = 5553, I_VCMPUNORD_SPD = 5341, I_VCMPUNORD_SPS = 4939, I_VCMPUNORD_SSD = 6145, 206 | I_VCMPUNORD_SSS = 5743, I_VCOMISD = 2829, I_VCOMISS = 2820, I_VCVTDQ2PD = 6852, 207 | I_VCVTDQ2PS = 3371, I_VCVTPD2DQ = 6863, I_VCVTPD2PS = 3307, I_VCVTPS2DQ = 3382, 208 | I_VCVTPS2PD = 3296, I_VCVTSD2SI = 2755, I_VCVTSD2SS = 3329, I_VCVTSI2SD = 2569, 209 | I_VCVTSI2SS = 2558, I_VCVTSS2SD = 3318, I_VCVTSS2SI = 2744, I_VCVTTPD2DQ = 6840, 210 | I_VCVTTPS2DQ = 3393, I_VCVTTSD2SI = 2692, I_VCVTTSS2SI = 2680, I_VDIVPD = 3561, 211 | I_VDIVPS = 3553, I_VDIVSD = 3577, I_VDIVSS = 3569, I_VDPPD = 9654, I_VDPPS = 9641, 212 | I_VERR = 1678, I_VERW = 1684, I_VEXTRACTF128 = 9549, I_VEXTRACTPS = 9524, 213 | I_VFMADD132PD = 8420, I_VFMADD132PS = 8407, I_VFMADD132SD = 8446, I_VFMADD132SS = 8433, 214 | I_VFMADD213PD = 8700, I_VFMADD213PS = 8687, I_VFMADD213SD = 8726, I_VFMADD213SS = 8713, 215 | I_VFMADD231PD = 8980, I_VFMADD231PS = 8967, I_VFMADD231SD = 9006, I_VFMADD231SS = 8993, 216 | I_VFMADDSUB132PD = 8359, I_VFMADDSUB132PS = 8343, I_VFMADDSUB213PD = 8639, 217 | I_VFMADDSUB213PS = 8623, I_VFMADDSUB231PD = 8919, I_VFMADDSUB231PS = 8903, 218 | I_VFMSUB132PD = 8472, I_VFMSUB132PS = 8459, I_VFMSUB132SD = 8498, I_VFMSUB132SS = 8485, 219 | I_VFMSUB213PD = 8752, I_VFMSUB213PS = 8739, I_VFMSUB213SD = 8778, I_VFMSUB213SS = 8765, 220 | I_VFMSUB231PD = 9032, I_VFMSUB231PS = 9019, I_VFMSUB231SD = 9058, I_VFMSUB231SS = 9045, 221 | I_VFMSUBADD132PD = 8391, I_VFMSUBADD132PS = 8375, I_VFMSUBADD213PD = 8671, 222 | I_VFMSUBADD213PS = 8655, I_VFMSUBADD231PD = 8951, I_VFMSUBADD231PS = 8935, 223 | I_VFNMADD132PD = 8525, I_VFNMADD132PS = 8511, I_VFNMADD132SD = 8553, I_VFNMADD132SS = 8539, 224 | I_VFNMADD213PD = 8805, I_VFNMADD213PS = 8791, I_VFNMADD213SD = 8833, I_VFNMADD213SS = 8819, 225 | I_VFNMADD231PD = 9085, I_VFNMADD231PS = 9071, I_VFNMADD231SD = 9113, I_VFNMADD231SS = 9099, 226 | I_VFNMSUB132PD = 8581, I_VFNMSUB132PS = 8567, I_VFNMSUB132SD = 8609, I_VFNMSUB132SS = 8595, 227 | I_VFNMSUB213PD = 8861, I_VFNMSUB213PS = 8847, I_VFNMSUB213SD = 8889, I_VFNMSUB213SS = 8875, 228 | I_VFNMSUB231PD = 9141, I_VFNMSUB231PS = 9127, I_VFNMSUB231SD = 9169, I_VFNMSUB231SS = 9155, 229 | I_VHADDPD = 4230, I_VHADDPS = 4239, I_VHSUBPD = 4264, I_VHSUBPS = 4273, I_VINSERTF128 = 9536, 230 | I_VINSERTPS = 9590, I_VLDDQU = 7034, I_VLDMXCSR = 9974, I_VMASKMOVDQU = 7164, 231 | I_VMASKMOVPD = 7982, I_VMASKMOVPS = 7970, I_VMAXPD = 3621, I_VMAXPS = 3613, 232 | I_VMAXSD = 3637, I_VMAXSS = 3629, I_VMCALL = 1734, I_VMCLEAR = 10022, I_VMFUNC = 1814, 233 | I_VMINPD = 3501, I_VMINPS = 3493, I_VMINSD = 3517, I_VMINSS = 3509, I_VMLAUNCH = 1742, 234 | I_VMLOAD = 1844, I_VMMCALL = 1835, I_VMOVAPD = 2509, I_VMOVAPS = 2500, I_VMOVD = 3965, 235 | I_VMOVDDUP = 2267, I_VMOVDQA = 3995, I_VMOVDQU = 4004, I_VMOVHLPS = 2228, 236 | I_VMOVHPD = 2415, I_VMOVHPS = 2406, I_VMOVLHPS = 2396, I_VMOVLPD = 2247, I_VMOVLPS = 2238, 237 | I_VMOVMSKPD = 2869, I_VMOVMSKPS = 2858, I_VMOVNTDQ = 6891, I_VMOVNTDQA = 7938, 238 | I_VMOVNTPD = 2626, I_VMOVNTPS = 2616, I_VMOVQ = 3972, I_VMOVSD = 2176, I_VMOVSHDUP = 2424, 239 | I_VMOVSLDUP = 2256, I_VMOVSS = 2168, I_VMOVUPD = 2159, I_VMOVUPS = 2150, I_VMPSADBW = 9670, 240 | I_VMPTRLD = 10013, I_VMPTRST = 6418, I_VMREAD = 4161, I_VMRESUME = 1752, I_VMRUN = 1828, 241 | I_VMSAVE = 1852, I_VMULPD = 3232, I_VMULPS = 3224, I_VMULSD = 3248, I_VMULSS = 3240, 242 | I_VMWRITE = 4185, I_VMXOFF = 1762, I_VMXON = 10031, I_VORPD = 3099, I_VORPS = 3092, 243 | I_VPABSB = 7728, I_VPABSD = 7758, I_VPABSW = 7743, I_VPACKSSDW = 3892, I_VPACKSSWB = 3724, 244 | I_VPACKUSDW = 7959, I_VPACKUSWB = 3802, I_VPADDB = 7244, I_VPADDD = 7274, 245 | I_VPADDQ = 6521, I_VPADDSB = 6971, I_VPADDSW = 6988, I_VPADDUSW = 6662, I_VPADDW = 7259, 246 | I_VPALIGNR = 9452, I_VPAND = 6646, I_VPANDN = 6705, I_VPAVGB = 6720, I_VPAVGW = 6765, 247 | I_VPBLENDVB = 9725, I_VPBLENDW = 9433, I_VPCLMULQDQ = 9691, I_VPCMPEQB = 4085, 248 | I_VPCMPEQD = 4123, I_VPCMPEQQ = 7918, I_VPCMPEQW = 4104, I_VPCMPESTRI = 9770, 249 | I_VPCMPESTRM = 9747, I_VPCMPGTB = 3744, I_VPCMPGTD = 3782, I_VPCMPGTQ = 8129, 250 | I_VPCMPGTW = 3763, I_VPCMPISTRI = 9816, I_VPCMPISTRM = 9793, I_VPERM2F128 = 9298, 251 | I_VPERMILPD = 7603, I_VPERMILPS = 7592, I_VPEXTRB = 9470, I_VPEXTRD = 9495, 252 | I_VPEXTRQ = 9504, I_VPEXTRW = 6352, I_VPHADDD = 7416, I_VPHADDSW = 7434, I_VPHADDW = 7399, 253 | I_VPHMINPOSUW = 8304, I_VPHSUBD = 7492, I_VPHSUBSW = 7510, I_VPHSUBW = 7475, 254 | I_VPINSRB = 9571, I_VPINSRD = 9617, I_VPINSRQ = 9626, I_VPINSRW = 6335, I_VPMADDUBSW = 7455, 255 | I_VPMADDWD = 7115, I_VPMAXSB = 8215, I_VPMAXSD = 8232, I_VPMAXSW = 7005, I_VPMAXUB = 6689, 256 | I_VPMAXUD = 8266, I_VPMAXUW = 8249, I_VPMINSB = 8147, I_VPMINSD = 8164, I_VPMINSW = 6943, 257 | I_VPMINUB = 6631, I_VPMINUD = 8198, I_VPMINUW = 8181, I_VPMOVMSKB = 6574, 258 | I_VPMOVSXBD = 7797, I_VPMOVSXBQ = 7818, I_VPMOVSXBW = 7776, I_VPMOVSXDQ = 7881, 259 | I_VPMOVSXWD = 7839, I_VPMOVSXWQ = 7860, I_VPMOVZXBD = 8025, I_VPMOVZXBQ = 8046, 260 | I_VPMOVZXBW = 8004, I_VPMOVZXDQ = 8109, I_VPMOVZXWD = 8067, I_VPMOVZXWQ = 8088, 261 | I_VPMULDQ = 7900, I_VPMULHRSW = 7581, I_VPMULHUW = 6782, I_VPMULHW = 6800, 262 | I_VPMULLD = 8283, I_VPMULLW = 6537, I_VPMULUDQ = 7096, I_VPOR = 6957, I_VPSADBW = 7133, 263 | I_VPSHUFB = 7382, I_VPSHUFD = 4047, I_VPSHUFHW = 4056, I_VPSHUFLW = 4066, 264 | I_VPSIGNB = 7528, I_VPSIGND = 7562, I_VPSIGNW = 7545, I_VPSLLD = 7064, I_VPSLLDQ = 9888, 265 | I_VPSLLQ = 7079, I_VPSLLW = 7049, I_VPSRAD = 6750, I_VPSRAW = 6735, I_VPSRLD = 6491, 266 | I_VPSRLDQ = 9871, I_VPSRLQ = 6506, I_VPSRLW = 6476, I_VPSUBB = 7184, I_VPSUBD = 7214, 267 | I_VPSUBQ = 7229, I_VPSUBSB = 6909, I_VPSUBSW = 6926, I_VPSUBUSB = 6594, I_VPSUBUSW = 6613, 268 | I_VPSUBW = 7199, I_VPTEST = 7669, I_VPUNPCKHBW = 3824, I_VPUNPCKHDQ = 3870, 269 | I_VPUNPCKHQDQ = 3940, I_VPUNPCKHWD = 3847, I_VPUNPCKLBW = 3656, I_VPUNPCKLDQ = 3702, 270 | I_VPUNPCKLQDQ = 3915, I_VPUNPCKLWD = 3679, I_VPXOR = 7020, I_VRCPPS = 3000, 271 | I_VRCPSS = 3008, I_VROUNDPD = 9338, I_VROUNDPS = 9319, I_VROUNDSD = 9376, 272 | I_VROUNDSS = 9357, I_VRSQRTPS = 2966, I_VRSQRTSS = 2976, I_VSHUFPD = 6386, 273 | I_VSHUFPS = 6377, I_VSQRTPD = 2921, I_VSQRTPS = 2912, I_VSQRTSD = 2939, I_VSQRTSS = 2930, 274 | I_VSTMXCSR = 10003, I_VSUBPD = 3441, I_VSUBPS = 3433, I_VSUBSD = 3457, I_VSUBSS = 3449, 275 | I_VTESTPD = 7623, I_VTESTPS = 7614, I_VUCOMISD = 2794, I_VUCOMISS = 2784, 276 | I_VUNPCKHPD = 2350, I_VUNPCKHPS = 2339, I_VUNPCKLPD = 2308, I_VUNPCKLPS = 2297, 277 | I_VXORPD = 3128, I_VXORPS = 3120, I_VZEROALL = 4151, I_VZEROUPPER = 4139, 278 | I_WAIT = 10053, I_WBINVD = 560, I_WRFSBASE = 9964, I_WRGSBASE = 9993, I_WRMSR = 585, 279 | I_XABORT = 1006, I_XADD = 945, I_XBEGIN = 1014, I_XCHG = 212, I_XEND = 1822, 280 | I_XGETBV = 1798, I_XLAT = 399, I_XOR = 61, I_XORPD = 3113, I_XORPS = 3106, 281 | I_XRSTOR = 4306, I_XRSTOR64 = 4314, I_XSAVE = 4282, I_XSAVE64 = 4289, I_XSAVEOPT = 4332, 282 | I_XSAVEOPT64 = 4342, I_XSETBV = 1806, I__3DNOW = 10067 283 | } _InstructionType; 284 | 285 | typedef enum { 286 | R_RAX, R_RCX, R_RDX, R_RBX, R_RSP, R_RBP, R_RSI, R_RDI, R_R8, R_R9, R_R10, R_R11, R_R12, R_R13, R_R14, R_R15, 287 | R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI, R_R8D, R_R9D, R_R10D, R_R11D, R_R12D, R_R13D, R_R14D, R_R15D, 288 | R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI, R_R8W, R_R9W, R_R10W, R_R11W, R_R12W, R_R13W, R_R14W, R_R15W, 289 | R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH, R_R8B, R_R9B, R_R10B, R_R11B, R_R12B, R_R13B, R_R14B, R_R15B, 290 | R_SPL, R_BPL, R_SIL, R_DIL, 291 | R_ES, R_CS, R_SS, R_DS, R_FS, R_GS, 292 | R_RIP, 293 | R_ST0, R_ST1, R_ST2, R_ST3, R_ST4, R_ST5, R_ST6, R_ST7, 294 | R_MM0, R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7, 295 | R_XMM0, R_XMM1, R_XMM2, R_XMM3, R_XMM4, R_XMM5, R_XMM6, R_XMM7, R_XMM8, R_XMM9, R_XMM10, R_XMM11, R_XMM12, R_XMM13, R_XMM14, R_XMM15, 296 | R_YMM0, R_YMM1, R_YMM2, R_YMM3, R_YMM4, R_YMM5, R_YMM6, R_YMM7, R_YMM8, R_YMM9, R_YMM10, R_YMM11, R_YMM12, R_YMM13, R_YMM14, R_YMM15, 297 | R_CR0, R_UNUSED0, R_CR2, R_CR3, R_CR4, R_UNUSED1, R_UNUSED2, R_UNUSED3, R_CR8, 298 | R_DR0, R_DR1, R_DR2, R_DR3, R_UNUSED4, R_UNUSED5, R_DR6, R_DR7 299 | } _RegisterType; 300 | 301 | #endif /* MNEMONICS_H */ 302 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/operands.h: -------------------------------------------------------------------------------- 1 | /* 2 | operands.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef OPERANDS_H 13 | #define OPERANDS_H 14 | 15 | #include "config.h" 16 | #include "decoder.h" 17 | #include "prefix.h" 18 | #include "instructions.h" 19 | 20 | int operands_extract(_CodeInfo* ci, _DInst* di, _InstInfo* ii, 21 | _iflags instFlags, _OpType type, 22 | unsigned int modrm, _PrefixState* ps, _DecodeType effOpSz, 23 | _DecodeType effAdrSz, _Operand* op); 24 | 25 | #endif /* OPERANDS_H */ 26 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/prefix.c: -------------------------------------------------------------------------------- 1 | /* 2 | prefix.c 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #include "prefix.h" 13 | 14 | #include "x86defs.h" 15 | #include "instructions.h" 16 | #include "mnemonics.h" 17 | 18 | 19 | /* 20 | * The main purpose of this module is to keep track of all kind of prefixes a single instruction may have. 21 | * The problem is that a single instruction may have up to six different prefix-types. 22 | * That's why I have to detect such cases and drop those excess prefixes. 23 | */ 24 | 25 | 26 | int PrefixTables[256 * 2] = { 27 | /* Decode 16/32 Bits */ 28 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* ES (0x26) CS (0x2e) */ 31 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, /* DS (0x3e) SS (0x36) */ 32 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* FS(0x64) GS(0x65) OP_SIZE(0x66) ADDR_SIZE(0x67) */ 35 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 | 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* VEX2b (0xc5) VEX3b (0xc4) */ 41 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43 | 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* LOCK (0xf0) REPNZ (0xf2) REP (0xf3) */ 44 | /* Decode64Bits */ 45 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 48 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 49 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* REX: 0x40 - 0x4f */ 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57 | 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 | 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 61 | }; 62 | 63 | /* Ignore all prefix. */ 64 | void prefixes_ignore_all(_PrefixState* ps) 65 | { 66 | int i; 67 | for (i = 0; i < PFXIDX_MAX; i++) 68 | prefixes_ignore(ps, i); 69 | } 70 | 71 | /* Calculates which prefixes weren't used and accordingly sets the bits in the unusedPrefixesMask. */ 72 | uint16_t prefixes_set_unused_mask(_PrefixState* ps) 73 | { 74 | /* 75 | * The decodedPrefixes represents the prefixes that were *read* from the binary stream for the instruction. 76 | * The usedPrefixes represents the prefixes that were actually used by the instruction in the *decode* phase. 77 | * Xoring between the two will result in a 'diff' which returns the prefixes that were read 78 | * from the stream *and* that were never used in the actual decoding. 79 | * 80 | * Only one prefix per type can be set in decodedPrefixes from the stream. 81 | * Therefore it's enough to check each type once and set the flag accordingly. 82 | * That's why we had to book-keep each prefix type and its position. 83 | * So now we know which bits we need to set exactly in the mask. 84 | */ 85 | _iflags unusedPrefixesDiff = ps->decodedPrefixes ^ ps->usedPrefixes; 86 | uint16_t unusedPrefixesMask = ps->unusedPrefixesMask; 87 | 88 | /* Examine unused prefixes by type: */ 89 | /* 90 | * About REX: it might be set in the diff although it was never in the stream itself. 91 | * This is because the vrex is shared between VEX and REX and some places flag it as REX usage, while 92 | * we were really decoding an AVX instruction. 93 | * It's not a big problem, because the prefixes_ignore func will ignore it anyway, 94 | * since it wasn't seen earlier. But it's important to know this. 95 | */ 96 | if (unusedPrefixesDiff) { 97 | if (unusedPrefixesDiff & INST_PRE_REX) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_REX]; 98 | if (unusedPrefixesDiff & INST_PRE_SEGOVRD_MASK) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_SEG]; 99 | if (unusedPrefixesDiff & INST_PRE_LOKREP_MASK) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_LOREP]; 100 | if (unusedPrefixesDiff & INST_PRE_OP_SIZE) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_OP_SIZE]; 101 | if (unusedPrefixesDiff & INST_PRE_ADDR_SIZE) unusedPrefixesMask |= ps->pfxIndexer[PFXIDX_ADRS]; 102 | /* If a VEX instruction was found, its prefix is considered as used, therefore no point for checking for it. */ 103 | } 104 | 105 | return unusedPrefixesMask; 106 | } 107 | 108 | /* 109 | * Mark a prefix as unused, and bookkeep where we last saw this same type, 110 | * because in the future we might want to disable it too. 111 | */ 112 | _INLINE_ void prefixes_track_unused(_PrefixState* ps, int index, _PrefixIndexer pi) 113 | { 114 | /* Mark the previously used prefix (if exists) in the unused mask. */ 115 | prefixes_ignore(ps, pi); 116 | /* Book-keep the current index for this type. */ 117 | ps->pfxIndexer[pi] = 1 << index; 118 | } 119 | 120 | /* 121 | * Read as many prefixes as possible, up to 15 bytes, and halt when we encounter non-prefix byte. 122 | * This algorithm tries to imitate a real processor, where the same prefix can appear a few times, etc. 123 | * The tiny complexity is that we want to know when a prefix was superfluous and mark any copy of it as unused. 124 | * Note that the last prefix of its type will be considered as used, and all the others (of same type) before it as unused. 125 | */ 126 | void prefixes_decode(_CodeInfo* ci, _PrefixState* ps) 127 | { 128 | const uint8_t* rexPos = NULL; 129 | const uint8_t* start = ci->code; 130 | uint8_t byte, vex; 131 | unsigned int index; 132 | /* 133 | * First thing to do, scan for prefixes, there are six types of prefixes. 134 | * There may be up to six prefixes before a single instruction, not the same type, no special order, 135 | * except REX/VEX must precede immediately the first opcode byte. 136 | * BTW - This is the reason why I didn't make the REP prefixes part of the instructions (STOS/SCAS/etc). 137 | * 138 | * Another thing, the instruction maximum size is 15 bytes, thus if we read more than 15 bytes, we will halt. 139 | * 140 | * We attach all prefixes to the next instruction, there might be two or more occurrences from the same prefix. 141 | * Also, since VEX can be allowed only once we will test it separately. 142 | */ 143 | for (index = 0; 144 | (ci->codeLen > 0) && (index < INST_MAXIMUM_SIZE); 145 | ci->code++, ci->codeLen--, index++) { 146 | /* 147 | NOTE: AMD treat lock/rep as two different groups... But I am based on Intel. 148 | 149 | - Lock and Repeat: 150 | - 0xF0 � LOCK 151 | - 0xF2 � REPNE/REPNZ 152 | - 0xF3 - REP/REPE/REPZ 153 | - Segment Override: 154 | - 0x2E - CS 155 | - 0x36 - SS 156 | - 0x3E - DS 157 | - 0x26 - ES 158 | - 0x64 - FS 159 | - 0x65 - GS 160 | - Operand-Size Override: 0x66, switching default size. 161 | - Address-Size Override: 0x67, switching default size. 162 | 163 | 64 Bits: 164 | - REX: 0x40 - 0x4f, extends register access. 165 | - 2 Bytes VEX: 0xc4 166 | - 3 Bytes VEX: 0xc5 167 | 32 Bits: 168 | - 2 Bytes VEX: 0xc4 11xx-xxxx 169 | - 3 Bytes VEX: 0xc5 11xx-xxxx 170 | */ 171 | 172 | /* Examine what type of prefix we got. */ 173 | byte = *ci->code; 174 | switch (byte) 175 | { 176 | case PREFIX_OP_SIZE: {/* Op Size type: */ 177 | ps->decodedPrefixes |= INST_PRE_OP_SIZE; 178 | prefixes_track_unused(ps, index, PFXIDX_OP_SIZE); 179 | } break; 180 | /* Look for both common arch prefixes. */ 181 | case PREFIX_LOCK: { 182 | /* LOCK and REPx type: */ 183 | ps->decodedPrefixes |= INST_PRE_LOCK; 184 | prefixes_track_unused(ps, index, PFXIDX_LOREP); 185 | } break; 186 | case PREFIX_REPNZ: { 187 | ps->decodedPrefixes |= INST_PRE_REPNZ; 188 | prefixes_track_unused(ps, index, PFXIDX_LOREP); 189 | } break; 190 | case PREFIX_REP: { 191 | ps->decodedPrefixes |= INST_PRE_REP; 192 | prefixes_track_unused(ps, index, PFXIDX_LOREP); 193 | } break; 194 | case PREFIX_CS: { 195 | /* Seg Overide type: */ 196 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK; 197 | ps->decodedPrefixes |= INST_PRE_CS; 198 | prefixes_track_unused(ps, index, PFXIDX_SEG); 199 | } break; 200 | case PREFIX_SS: { 201 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK; 202 | ps->decodedPrefixes |= INST_PRE_SS; 203 | prefixes_track_unused(ps, index, PFXIDX_SEG); 204 | } break; 205 | case PREFIX_DS: { 206 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK; 207 | ps->decodedPrefixes |= INST_PRE_DS; 208 | prefixes_track_unused(ps, index, PFXIDX_SEG); 209 | } break; 210 | case PREFIX_ES: { 211 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK; 212 | ps->decodedPrefixes |= INST_PRE_ES; 213 | prefixes_track_unused(ps, index, PFXIDX_SEG); 214 | } break; 215 | case PREFIX_FS: { 216 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK; 217 | ps->decodedPrefixes |= INST_PRE_FS; 218 | prefixes_track_unused(ps, index, PFXIDX_SEG); 219 | } break; 220 | case PREFIX_GS: { 221 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK; 222 | ps->decodedPrefixes |= INST_PRE_GS; 223 | prefixes_track_unused(ps, index, PFXIDX_SEG); 224 | } break; 225 | case PREFIX_ADDR_SIZE: { 226 | /* Addr Size type: */ 227 | ps->decodedPrefixes |= INST_PRE_ADDR_SIZE; 228 | prefixes_track_unused(ps, index, PFXIDX_ADRS); 229 | } break; 230 | default: 231 | if (ci->dt == Decode64Bits) { 232 | /* REX type, 64 bits decoding mode only: */ 233 | if ((byte & 0xf0) == 0x40) { 234 | ps->decodedPrefixes |= INST_PRE_REX; 235 | rexPos = ci->code; 236 | ps->vrex = byte & 0xf; /* Keep only BXRW. */ 237 | ps->prefixExtType = PET_REX; 238 | prefixes_track_unused(ps, index, PFXIDX_REX); 239 | continue; 240 | } 241 | } 242 | goto _Break2; 243 | } 244 | } 245 | _Break2: 246 | 247 | /* 2 Bytes VEX: */ 248 | if ((ci->codeLen >= 2) && 249 | (*ci->code == PREFIX_VEX2b) && 250 | ((ci->code - start) <= INST_MAXIMUM_SIZE - 2)) { 251 | /* 252 | * In 32 bits the second byte has to be in the special range of Mod=11. 253 | * Otherwise it might be a normal LDS instruction. 254 | */ 255 | if ((ci->dt == Decode64Bits) || (*(ci->code + 1) >= INST_DIVIDED_MODRM)) { 256 | ps->vexPos = ci->code + 1; 257 | ps->decodedPrefixes |= INST_PRE_VEX; 258 | ps->prefixExtType = PET_VEX2BYTES; 259 | 260 | /* 261 | * VEX 1 byte bits: 262 | * |7-6--3-2-10| 263 | * |R|vvvv|L|pp| 264 | * |-----------| 265 | */ 266 | 267 | /* -- Convert from VEX prefix to VREX flags -- */ 268 | vex = *ps->vexPos; 269 | if (!(vex & 0x80) && (ci->dt == Decode64Bits)) ps->vrex |= PREFIX_EX_R; /* Convert VEX.R. */ 270 | if (vex & 4) ps->vrex |= PREFIX_EX_L; /* Convert VEX.L. */ 271 | 272 | ci->code += 2; 273 | ci->codeLen -= 2; 274 | } 275 | } 276 | 277 | /* 3 Bytes VEX: */ 278 | if ((ci->codeLen >= 3) && 279 | (*ci->code == PREFIX_VEX3b) && 280 | ((ci->code - start) <= INST_MAXIMUM_SIZE - 3) && 281 | (!(ps->decodedPrefixes & INST_PRE_VEX))) { 282 | /* 283 | * In 32 bits the second byte has to be in the special range of Mod=11. 284 | * Otherwise it might be a normal LES instruction. 285 | * And we don't care now about the 3rd byte. 286 | */ 287 | if ((ci->dt == Decode64Bits) || (*(ci->code + 1) >= INST_DIVIDED_MODRM)) { 288 | ps->vexPos = ci->code + 1; 289 | ps->decodedPrefixes |= INST_PRE_VEX; 290 | ps->prefixExtType = PET_VEX3BYTES; 291 | 292 | /* 293 | * VEX first and second bytes: 294 | * |7-6-5-4----0| |7-6--3-2-10| 295 | * |R|X|B|m-mmmm| |W|vvvv|L|pp| 296 | * |------------| |-----------| 297 | */ 298 | 299 | /* -- Convert from VEX prefix to VREX flags -- */ 300 | vex = *ps->vexPos; 301 | ps->vrex |= ((~vex >> 5) & 0x7); /* Shift and invert VEX.R/X/B to their place */ 302 | vex = *(ps->vexPos + 1); 303 | if (vex & 4) ps->vrex |= PREFIX_EX_L; /* Convert VEX.L. */ 304 | if (vex & 0x80) ps->vrex |= PREFIX_EX_W; /* Convert VEX.W. */ 305 | 306 | /* Clear some flags if the mode isn't 64 bits. */ 307 | if (ci->dt != Decode64Bits) ps->vrex &= ~(PREFIX_EX_B | PREFIX_EX_X | PREFIX_EX_R | PREFIX_EX_W); 308 | 309 | ci->code += 3; 310 | ci->codeLen -= 3; 311 | } 312 | } 313 | 314 | if (ci->dt == Decode64Bits) { 315 | if (ps->decodedPrefixes & INST_PRE_REX) { 316 | /* REX prefix must precede first byte of instruction. */ 317 | if (rexPos != (ci->code - 1)) { 318 | ps->decodedPrefixes &= ~INST_PRE_REX; 319 | if (ps->prefixExtType == PET_REX) ps->prefixExtType = PET_NONE; /* It might be a VEX by now, keep it that way. */ 320 | prefixes_ignore(ps, PFXIDX_REX); 321 | } 322 | /* 323 | * We will disable operand size prefix, 324 | * if it exists only after decoding the instruction, since it might be a mandatory prefix. 325 | * This will be done after calling inst_lookup in decode_inst. 326 | */ 327 | } 328 | /* In 64 bits, segment overrides of CS, DS, ES and SS are ignored. So don't take'em into account. */ 329 | if (ps->decodedPrefixes & INST_PRE_SEGOVRD_MASK32) { 330 | ps->decodedPrefixes &= ~INST_PRE_SEGOVRD_MASK32; 331 | prefixes_ignore(ps, PFXIDX_SEG); 332 | } 333 | } 334 | 335 | /* Store number of prefixes scanned. */ 336 | ps->count = (uint8_t)(ci->code - start); 337 | } 338 | 339 | /* 340 | * For every memory-indirection operand we want to set a used segment. 341 | * If the segment is being overrided with a prefix, we will need to check if it's a default. 342 | * Defaults don't use their prefix, e.g "mov [rsp]" can ignore a given SS: prefix, 343 | * but still set the used segment as SS. 344 | * This function is called only with SS and DS as defaults. 345 | * If there's a segment prefix used, it will override the default one. 346 | * And If the prefix is a default seg in 64 bits, it will be ignored. 347 | */ 348 | void prefixes_use_segment(_iflags defaultSeg, _PrefixState* ps, _DecodeType dt, _DInst* di) 349 | { 350 | /* Extract given segment prefix from the decoded prefixes. */ 351 | _iflags flags; 352 | 353 | if (dt == Decode64Bits) { 354 | if (ps->decodedPrefixes & INST_PRE_SEGOVRD_MASK64) { /* Either GS or FS. */ 355 | di->segment = ps->decodedPrefixes & INST_PRE_GS ? R_GS : R_FS; 356 | } 357 | 358 | return; 359 | } 360 | 361 | flags = ps->decodedPrefixes & INST_PRE_SEGOVRD_MASK; 362 | 363 | /* Use the given prefix only if it's not the default. */ 364 | if (flags && (flags != defaultSeg)) { 365 | ps->usedPrefixes |= flags; 366 | 367 | switch (flags >> 7) /* INST_PRE_CS is 1 << 7. And the rest of the prefixes follow as bit fields. */ 368 | { 369 | case 1: di->segment = R_CS; break; 370 | case 2: di->segment = R_SS; break; 371 | case 4: di->segment = R_DS; break; 372 | case 8: di->segment = R_ES; break; 373 | case 0x10: di->segment = R_FS; break; 374 | case 0x20: di->segment = R_GS; break; 375 | } 376 | } 377 | else { 378 | if (defaultSeg == INST_PRE_SS) di->segment = SEGMENT_DEFAULT | R_SS; 379 | else di->segment = SEGMENT_DEFAULT | R_DS; 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/prefix.h: -------------------------------------------------------------------------------- 1 | /* 2 | prefix.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef PREFIX_H 13 | #define PREFIX_H 14 | 15 | #include "config.h" 16 | #include "decoder.h" 17 | 18 | 19 | /* Specifies the type of the extension prefix, such as: REX, 2 bytes VEX, 3 bytes VEX. */ 20 | typedef enum {PET_NONE = 0, PET_REX, PET_VEX2BYTES, PET_VEX3BYTES} _PrefixExtType; 21 | 22 | /* Specifies an index into a table of prefixes by their type. */ 23 | typedef enum {PFXIDX_NONE = -1, PFXIDX_REX, PFXIDX_LOREP, PFXIDX_SEG, PFXIDX_OP_SIZE, PFXIDX_ADRS, PFXIDX_MAX} _PrefixIndexer; 24 | 25 | /* 26 | * This holds the prefixes state for the current instruction we decode. 27 | * decodedPrefixes includes all specific prefixes that the instruction got. 28 | * start is a pointer to the first prefix to take into account. 29 | * last is a pointer to the last byte we scanned. 30 | * Other pointers are used to keep track of prefixes positions and help us know if they appeared already and where. 31 | */ 32 | typedef struct { 33 | _iflags decodedPrefixes, usedPrefixes; 34 | /* Number of prefixes scanned for current instruction, including VEX! */ 35 | unsigned int count; 36 | uint16_t unusedPrefixesMask; 37 | /* Holds the offset to the prefix byte by its type. */ 38 | uint16_t pfxIndexer[PFXIDX_MAX]; 39 | _PrefixExtType prefixExtType; 40 | /* Indicates whether the operand size prefix (0x66) was used as a mandatory prefix. */ 41 | int isOpSizeMandatory; 42 | /* If VEX prefix is used, store the VEX.vvvv field. */ 43 | unsigned int vexV; 44 | /* The fields B/X/R/W/L of REX and VEX are stored together in this byte. */ 45 | unsigned int vrex; 46 | const uint8_t* vexPos; 47 | } _PrefixState; 48 | 49 | /* 50 | * Intel supports 6 types of prefixes, whereas AMD supports 5 types (lock is seperated from rep/nz). 51 | * REX is the fifth prefix type, this time I'm based on AMD64. 52 | * VEX is the 6th, though it can't be repeated. 53 | */ 54 | #define MAX_PREFIXES (5) 55 | 56 | extern int PrefixTables[256 * 2]; 57 | 58 | _INLINE_ int prefixes_is_valid(unsigned char ch, _DecodeType dt) 59 | { 60 | /* The predicate selects (branchlessly) second half table for 64 bits otherwise selects first half. */ 61 | return PrefixTables[ch + ((dt >> 1) << 8)]; 62 | } 63 | 64 | /* Ignore a specific prefix type. */ 65 | _INLINE_ void prefixes_ignore(_PrefixState* ps, _PrefixIndexer pi) 66 | { 67 | /* 68 | * If that type of prefix appeared already, set the bit of that *former* prefix. 69 | * Anyway, set the new index of that prefix type to the current index, so next time we know its position. 70 | */ 71 | ps->unusedPrefixesMask |= ps->pfxIndexer[pi]; 72 | } 73 | 74 | void prefixes_ignore_all(_PrefixState* ps); 75 | uint16_t prefixes_set_unused_mask(_PrefixState* ps); 76 | void prefixes_decode(_CodeInfo* ci, _PrefixState* ps); 77 | void prefixes_use_segment(_iflags defaultSeg, _PrefixState* ps, _DecodeType dt, _DInst* di); 78 | 79 | #endif /* PREFIX_H */ 80 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/textdefs.c: -------------------------------------------------------------------------------- 1 | /* 2 | textdefs.c 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #include "textdefs.h" 13 | 14 | #ifndef DISTORM_LIGHT 15 | 16 | static uint8_t Nibble2ChrTable[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 17 | #define NIBBLE_TO_CHR Nibble2ChrTable[t] 18 | 19 | void str_hex(_WString* s, const uint8_t* buf, unsigned int len) 20 | { 21 | /* 256 * 2 : 2 chars per byte value. */ 22 | static char* TextBTable = 23 | "000102030405060708090a0b0c0d0e0f" \ 24 | "101112131415161718191a1b1c1d1e1f" \ 25 | "202122232425262728292a2b2c2d2e2f" \ 26 | "303132333435363738393a3b3c3d3e3f" \ 27 | "404142434445464748494a4b4c4d4e4f" \ 28 | "505152535455565758595a5b5c5d5e5f" \ 29 | "606162636465666768696a6b6c6d6e6f" \ 30 | "707172737475767778797a7b7c7d7e7f" \ 31 | "808182838485868788898a8b8c8d8e8f" \ 32 | "909192939495969798999a9b9c9d9e9f" \ 33 | "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf" \ 34 | "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" \ 35 | "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" \ 36 | "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" \ 37 | "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" \ 38 | "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; 39 | 40 | unsigned int i = 0; 41 | /* Length is at least 1, enter loop. */ 42 | s->length = len * 2; 43 | s->p[len * 2] = 0; 44 | do { 45 | RSHORT(&s->p[i]) = RSHORT(&TextBTable[(*buf) * 2]); 46 | buf++; 47 | i += 2; 48 | } while (i < len * 2); 49 | } 50 | 51 | #ifdef SUPPORT_64BIT_OFFSET 52 | 53 | void str_int_impl(unsigned char** s, uint64_t x) 54 | { 55 | int8_t* buf; 56 | int shift = 0; 57 | OFFSET_INTEGER t = x; 58 | 59 | buf = (int8_t*)*s; 60 | 61 | *buf++ = '0'; 62 | *buf++ = 'x'; 63 | 64 | if (x == 0) { 65 | *buf = '0'; 66 | *s += 3; 67 | return; 68 | } 69 | 70 | do { 71 | t >>= 4; 72 | shift += 4; 73 | } while (t); 74 | 75 | do { 76 | shift -= 4; 77 | t = (x >> shift) & 0xf; 78 | *buf++ = NIBBLE_TO_CHR; 79 | } while (shift > 0); 80 | 81 | *s = (unsigned char*)buf; 82 | } 83 | 84 | #else 85 | 86 | void str_int_impl(unsigned char** s, uint8_t src[8]) 87 | { 88 | int8_t* buf; 89 | int i = 0, shift = 0; 90 | uint32_t x = RULONG(&src[sizeof(int32_t)]); 91 | int t; 92 | 93 | buf = (int8_t*)*s; 94 | buf[0] = '0'; 95 | buf[1] = 'x'; 96 | buf += 2; 97 | 98 | for (shift = 28; shift != -4; shift -= 4) { 99 | t = (x >> shift) & 0xf; 100 | if (i | t) buf[i++] = NIBBLE_TO_CHR; 101 | } 102 | 103 | x = RULONG(src); 104 | for (shift = 28; shift != 0; shift -= 4) { 105 | t = (x >> shift) & 0xf; 106 | if (i | t) buf[i++] = NIBBLE_TO_CHR; 107 | } 108 | t = x & 0xf; 109 | buf[i++] = NIBBLE_TO_CHR; 110 | 111 | *s += (size_t)(i + 2); 112 | } 113 | 114 | #endif /* SUPPORT_64BIT_OFFSET */ 115 | 116 | #endif /* DISTORM_LIGHT */ 117 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/textdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | textdefs.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef TEXTDEFS_H 13 | #define TEXTDEFS_H 14 | 15 | #include "config.h" 16 | #include "wstring.h" 17 | 18 | #ifndef DISTORM_LIGHT 19 | 20 | #define PLUS_DISP_CHR '+' 21 | #define MINUS_DISP_CHR '-' 22 | #define OPEN_CHR '[' 23 | #define CLOSE_CHR ']' 24 | #define SP_CHR ' ' 25 | #define SEG_OFF_CHR ':' 26 | 27 | /* 28 | Naming Convention: 29 | 30 | * get - returns a pointer to a string. 31 | * str - concatenates to string. 32 | 33 | * hex - means the function is used for hex dump (number is padded to required size) - Little Endian output. 34 | * code - means the function is used for disassembled instruction - Big Endian output. 35 | * off - means the function is used for 64bit offset - Big Endian output. 36 | 37 | * h - '0x' in front of the string. 38 | 39 | * b - byte 40 | * dw - double word (can be used for word also) 41 | * qw - quad word 42 | 43 | * all numbers are in HEX. 44 | */ 45 | 46 | void str_hex(_WString* s, const uint8_t* buf, unsigned int len); 47 | 48 | #ifdef SUPPORT_64BIT_OFFSET 49 | #define str_int(s, x) str_int_impl((s), (x)) 50 | void str_int_impl(unsigned char** s, uint64_t x); 51 | #else 52 | #define str_int(s, x) str_int_impl((s), (uint8_t*)&(x)) 53 | void str_int_impl(unsigned char** s, uint8_t src[8]); 54 | #endif 55 | 56 | #endif /* DISTORM_LIGHT */ 57 | 58 | #endif /* TEXTDEFS_H */ 59 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/wstring.h: -------------------------------------------------------------------------------- 1 | /* 2 | wstring.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef WSTRING_H 13 | #define WSTRING_H 14 | 15 | #include "config.h" 16 | #include "mnemonics.h" 17 | 18 | #ifndef DISTORM_LIGHT 19 | 20 | _INLINE_ void strcat_WSR(unsigned char** str, const _WRegister* reg) 21 | { 22 | /* 23 | * Longest register name is YMM15 - 5 characters, 24 | * Copy 8 so compiler can do a QWORD move. 25 | * We copy nul termination and fix the length, so it's okay to copy more to the output buffer. 26 | * There's a sentinel register to make sure we don't read past the end of the registers table. 27 | */ 28 | memcpy((int8_t*)*str, (const int8_t*)reg->p, 8); 29 | *str += reg->length; 30 | } 31 | 32 | #define strfinalize_WS(s, end) do { *end = 0; s.length = (unsigned int)((size_t)end - (size_t)s.p); } while (0) 33 | #define chrcat_WS(s, ch) do { *s = ch; s += 1; } while (0) 34 | #define strcat_WS(s, buf, copylen, advancelen) do { memcpy((int8_t*)s, buf, copylen); s += advancelen; } while(0) 35 | 36 | #endif /* DISTORM_LIGHT */ 37 | 38 | #endif /* WSTRING_H */ 39 | -------------------------------------------------------------------------------- /bsd/arch/amd64/distorm/x86defs.h: -------------------------------------------------------------------------------- 1 | /* 2 | x86defs.h 3 | 4 | diStorm3 - Powerful disassembler for X86/AMD64 5 | http://ragestorm.net/distorm/ 6 | distorm at gmail dot com 7 | Copyright (C) 2003-2021 Gil Dabah 8 | This library is licensed under the BSD license. See the file COPYING. 9 | */ 10 | 11 | 12 | #ifndef X86DEFS_H 13 | #define X86DEFS_H 14 | 15 | 16 | #define SEG_REGS_MAX (6) 17 | #define CREGS_MAX (9) 18 | #define DREGS_MAX (8) 19 | 20 | /* Maximum instruction size, including prefixes */ 21 | #define INST_MAXIMUM_SIZE (15) 22 | 23 | /* Maximum range of imm8 (comparison type) of special SSE CMP instructions. */ 24 | #define INST_CMP_MAX_RANGE (8) 25 | 26 | /* Maximum range of imm8 (comparison type) of special AVX VCMP instructions. */ 27 | #define INST_VCMP_MAX_RANGE (32) 28 | 29 | /* Wait instruction byte code. */ 30 | #define INST_WAIT_INDEX (0x9b) 31 | 32 | /* Lea instruction byte code. */ 33 | #define INST_LEA_INDEX (0x8d) 34 | 35 | /* NOP/XCHG instruction byte code. */ 36 | #define INST_NOP_INDEX (0x90) 37 | 38 | /* ARPL/MOVSXD instruction byte code. */ 39 | #define INST_ARPL_INDEX (0x63) 40 | 41 | /* 42 | * Minimal MODR/M value of divided instructions. 43 | * It's 0xc0, two MSBs set, which indicates a general purpose register is used too. 44 | */ 45 | #define INST_DIVIDED_MODRM (0xc0) 46 | 47 | /* This is the escape byte value used for 3DNow! instructions. */ 48 | #define _3DNOW_ESCAPE_BYTE (0x0f) 49 | 50 | #define PREFIX_LOCK (0xf0) 51 | #define PREFIX_REPNZ (0xf2) 52 | #define PREFIX_REP (0xf3) 53 | #define PREFIX_CS (0x2e) 54 | #define PREFIX_SS (0x36) 55 | #define PREFIX_DS (0x3e) 56 | #define PREFIX_ES (0x26) 57 | #define PREFIX_FS (0x64) 58 | #define PREFIX_GS (0x65) 59 | #define PREFIX_OP_SIZE (0x66) 60 | #define PREFIX_ADDR_SIZE (0x67) 61 | #define PREFIX_VEX2b (0xc5) 62 | #define PREFIX_VEX3b (0xc4) 63 | 64 | /* REX prefix value range, 64 bits mode decoding only. */ 65 | #define PREFIX_REX_LOW (0x40) 66 | #define PREFIX_REX_HI (0x4f) 67 | /* In order to use the extended GPR's we have to add 8 to the Modr/M info values. */ 68 | #define EX_GPR_BASE (8) 69 | 70 | /* Mask for REX and VEX features: */ 71 | /* Base */ 72 | #define PREFIX_EX_B (1) 73 | /* Index */ 74 | #define PREFIX_EX_X (2) 75 | /* Register */ 76 | #define PREFIX_EX_R (4) 77 | /* Operand Width */ 78 | #define PREFIX_EX_W (8) 79 | /* Vector Lengh */ 80 | #define PREFIX_EX_L (0x10) 81 | 82 | #endif /* X86DEFS_H */ 83 | -------------------------------------------------------------------------------- /bsd/arch/amd64/hijack_amd64.c: -------------------------------------------------------------------------------- 1 | #include "hijack_amd64.h" 2 | #include 3 | #include "distorm/distorm.h" 4 | #include "include/common_data.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | push %rax 12 | movabs $addr, %rax 13 | jmp *%rax 14 | pop %rax 15 | */ 16 | const char long_jmp_code[14]="\x50\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0\x58"; 17 | 18 | void fill_long_jmp(void *fill_dest, void *hijack_to_func) 19 | { 20 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 21 | memcpy((char *)fill_dest + 3, &hijack_to_func, sizeof(void *)); 22 | } 23 | 24 | static _DecodedInst decodedInstructions[MAX_INSTRUCTIONS]; 25 | 26 | static int disass_target(void *target) 27 | { 28 | unsigned int decodedInstructionsCount = 0, ret = 0, i; 29 | _DecodeResult res; 30 | 31 | res = distorm_decode(0, (unsigned char *)target, 32 | HIJACK_SIZE, Decode64Bits, 33 | decodedInstructions, MAX_INSTRUCTIONS, 34 | &decodedInstructionsCount); 35 | 36 | if (res == DECRES_INPUTERR) { 37 | printf("Disassemble %p failed!\n", target); 38 | return -1; 39 | } 40 | 41 | for (i = 0; i < decodedInstructionsCount; i++) { 42 | ret += decodedInstructions[i].size; 43 | if (ret >= LONG_JMP_CODE_LEN) 44 | break; 45 | } 46 | if (ret >= LONG_JMP_CODE_LEN) 47 | return ret; 48 | else 49 | return -1; 50 | } 51 | 52 | /* \x90: nop */ 53 | int fill_nop_for_target(void *fill_dest, void *target) 54 | { 55 | int actual_len = disass_target(target); 56 | if (actual_len < 0) 57 | return actual_len; 58 | memset((char *)fill_dest + LONG_JMP_CODE_LEN, '\x90', actual_len - LONG_JMP_CODE_LEN); 59 | return 0; 60 | } 61 | 62 | int fill_nop_for_code_space(void *fill_dest, void *target) 63 | { 64 | int actual_len = disass_target(target); 65 | if (actual_len < 0) 66 | return actual_len; 67 | memset((char *)fill_dest + actual_len, '\x90', HIJACK_SIZE - actual_len); 68 | return 0; 69 | } 70 | 71 | /* skip the check */ 72 | bool check_target_can_hijack(void *target) 73 | { 74 | return true; 75 | } 76 | 77 | int hook_write_range(void *target, void *source, int size) 78 | { 79 | bool old_wp; 80 | char *dest = (char *)target; 81 | char *src = (char *)source; 82 | 83 | old_wp = disable_wp(); 84 | while (size-- > 0) { 85 | *dest++ = *src++; 86 | } 87 | restore_wp(old_wp); 88 | return 0; 89 | } -------------------------------------------------------------------------------- /bsd/arch/amd64/hijack_amd64.h: -------------------------------------------------------------------------------- 1 | ../../../linux/src/arch/x86_64/hijack_x86_64.h -------------------------------------------------------------------------------- /bsd/arch/arm64/hijack_arm64.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "hijack_arm64.h" 5 | #include "include/common_data.h" 6 | 7 | /* 8 | stp x1, x0, [sp, #-0x20]! 9 | ldr x0, 8 10 | ret x0 11 | .addr(low) 12 | .addr(high) 13 | ldp x1, x0, [sp], #0x20 14 | */ 15 | const char long_jmp_code[24]="\xe1\x03\xbe\xa9\x40\x00\x00\x58\x00\x00\x5f\xd6\x00\x00\x00\x00\x00\x00\x00\x00\xe1\x03\xc2\xa8"; 16 | 17 | inline void fill_long_jmp(void *fill_dest, void *hijack_to_func) 18 | { 19 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 20 | memcpy((char *)fill_dest + 3 * INSTRUCTION_SIZE, &hijack_to_func, sizeof(void *)); 21 | } 22 | 23 | /* 24 | * Refer to https://github.com/CAS-Atlantic/AArch64-Encoding 25 | */ 26 | 27 | static bool check_instruction_can_hijack(uint32_t instruction); 28 | static bool check_instruction_can_hijack(uint32_t instruction) 29 | { 30 | bool ret = true; 31 | 32 | //todo: we want to fix these instructions 33 | switch(instruction & 0x9f000000u) { 34 | case 0x10000000u: //adr 35 | case 0x90000000u: //adrp 36 | ret = false; 37 | goto out; 38 | } 39 | switch(instruction & 0xfc000000u) { 40 | case 0x14000000u: //b 41 | case 0x94000000u: //bl 42 | ret = false; 43 | goto out; 44 | } 45 | switch(instruction & 0xff000000u) { 46 | case 0x54000000u: //b.c 47 | ret = false; 48 | goto out; 49 | } 50 | switch(instruction & 0x7e000000u) { 51 | case 0x34000000u: //cbz cbnz 52 | case 0x36000000u: //tbz tbnz 53 | ret = false; 54 | goto out; 55 | } 56 | switch(instruction & 0xbf000000u) { 57 | case 0x18000000u: //ldr 58 | ret = false; 59 | goto out; 60 | } 61 | switch(instruction & 0x3f000000u) { 62 | case 0x1c000000u: //ldrv 63 | ret = false; 64 | goto out; 65 | } 66 | switch(instruction & 0xff000000u) { 67 | case 0x98000000u: //ldrsw 68 | ret = false; 69 | goto out; 70 | } 71 | 72 | out: 73 | if (!ret) { 74 | printf("instruction %x cannot be hijacked!\n", instruction); 75 | } 76 | return ret; 77 | } 78 | 79 | bool check_target_can_hijack(void *target) 80 | { 81 | int offset = 0; 82 | for (; offset < HOOK_TARGET_OFFSET + HIJACK_SIZE; offset += INSTRUCTION_SIZE) { 83 | if (!check_instruction_can_hijack(*(uint32_t *)((char *)target + offset))) 84 | return false; 85 | } 86 | return true; 87 | } 88 | 89 | int hook_write_range(void *target, void *source, int size) 90 | { 91 | int i; 92 | char *dst, *data; 93 | vm_offset_t addr = (vm_offset_t)target; 94 | 95 | if (!arm64_get_writable_addr(addr, &addr)) { 96 | return 1; 97 | } else { 98 | dst = (char *)addr; 99 | data = (char *)source; 100 | for (i = 0; i < size; i++) 101 | *dst++ = *data++; 102 | dsb(ish); 103 | cpu_icache_sync_range(addr, (vm_size_t)size); 104 | } 105 | return 0; 106 | } -------------------------------------------------------------------------------- /bsd/arch/arm64/hijack_arm64.h: -------------------------------------------------------------------------------- 1 | ../../../linux/src/arch/arm64/hijack_arm64.h -------------------------------------------------------------------------------- /bsd/framework/dev_interface.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "include/common_data.h" 15 | 16 | static d_open_t hook_targets_open; 17 | static d_close_t hook_targets_close; 18 | static d_read_t hook_targets_read; 19 | static d_write_t hook_targets_write; 20 | 21 | MALLOC_DEFINE(M_KSYM_NAME, "ksym name buf", "ksym name buf"); 22 | 23 | static struct cdevsw c_hook_targets_cdevsw = { 24 | .d_version = D_VERSION, 25 | .d_open = hook_targets_open, 26 | .d_close = hook_targets_close, 27 | .d_read = hook_targets_read, 28 | .d_write = hook_targets_write, 29 | .d_name = "hook_targets", 30 | }; 31 | 32 | static struct cdev *c_hook_targets = NULL; 33 | 34 | static void 35 | free_priv(void *arg) 36 | { 37 | char *buf = arg; 38 | free(buf, M_KSYM_NAME); 39 | } 40 | 41 | static int 42 | hook_targets_open(struct cdev *dev, int flags, int devtype, struct thread *td) 43 | { 44 | char *buf = malloc(KSYM_NAME_LEN, M_KSYM_NAME, M_ZERO | M_WAITOK); 45 | if (!buf) 46 | return ENOMEM; 47 | devfs_set_cdevpriv(buf, free_priv); 48 | return 0; 49 | } 50 | 51 | static int 52 | hook_targets_close(struct cdev *dev, int flags, int devtype, struct thread *td) 53 | { 54 | return 0; 55 | } 56 | 57 | static int 58 | hook_targets_read(struct cdev *dev, struct uio *uio, int ioflag) 59 | { 60 | char *buf = NULL; 61 | int err = devfs_get_cdevpriv((void **)&buf); 62 | if (err) 63 | return err; 64 | return show_all_hook_targets(buf, uio); 65 | } 66 | 67 | static char * 68 | skip_spaces(char *str) 69 | { 70 | while (isspace(*str)) 71 | ++str; 72 | return (char *)str; 73 | } 74 | 75 | static char * 76 | strim(char *s) 77 | { 78 | size_t size; 79 | char *end; 80 | 81 | size = strlen(s); 82 | if (!size) 83 | return s; 84 | 85 | end = s + size - 1; 86 | while (end >= s && isspace(*end)) 87 | end--; 88 | *(end + 1) = '\0'; 89 | 90 | return skip_spaces(s); 91 | } 92 | 93 | static int 94 | hook_targets_write(struct cdev *dev, struct uio *uio, int ioflag) 95 | { 96 | char *buf = NULL; 97 | char *string_start, *sep, *val_start; 98 | long val; 99 | void *target; 100 | int ret; 101 | 102 | int err = devfs_get_cdevpriv((void **)&buf); 103 | if (err) 104 | return err; 105 | memset(buf, 0, KSYM_NAME_LEN); 106 | err = uiomove(buf, KSYM_NAME_LEN, uio); 107 | if (err) 108 | return err; 109 | 110 | string_start = strim(buf); 111 | if (!(sep = strchr(string_start, ' ')) || 112 | sep - buf > KSYM_NAME_LEN) { 113 | return EFAULT; 114 | } 115 | *sep++ = '\0'; 116 | val_start = strim(sep); 117 | val = strtol(val_start, NULL, 10); 118 | 119 | if (!(target = find_func(string_start))) { 120 | return EFAULT; 121 | } 122 | 123 | switch (val) { 124 | case 0: 125 | ret = hijack_target_disable(target, false); 126 | break; 127 | case 1: 128 | ret = hijack_target_enable(target); 129 | break; 130 | default: 131 | return EFAULT; 132 | } 133 | 134 | return ret ? EFAULT : 0; 135 | } 136 | 137 | int 138 | init_dev_interface(void) 139 | { 140 | int err; 141 | err = make_dev_p(MAKEDEV_WAITOK, &c_hook_targets, 142 | &c_hook_targets_cdevsw, 0, UID_ROOT, 143 | GID_WHEEL, 0600, "hook_targets"); 144 | if (err) 145 | return err; 146 | return 0; 147 | } 148 | 149 | void 150 | remove_dev_interface(void) 151 | { 152 | destroy_dev(c_hook_targets); 153 | } -------------------------------------------------------------------------------- /bsd/framework/hijack_operation.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | LIST_HEAD(sym_hook_list, sym_hook); 12 | static struct sym_hook_list sym_hook_list; 13 | static struct rwlock sym_hook_list_lock; 14 | 15 | static inline int 16 | fill_hook_template_code_space(void *hook_template_code_space, 17 | void *target_code, void *return_addr) 18 | { 19 | unsigned char tmp_code[HIJACK_SIZE * 2] = {0}; 20 | memcpy(tmp_code, target_code, HIJACK_SIZE); 21 | if (fill_nop_for_code_space(tmp_code, target_code)) { 22 | return -1; 23 | } 24 | fill_long_jmp((char *)tmp_code + HIJACK_SIZE, return_addr); 25 | return hook_write_range(hook_template_code_space, tmp_code, sizeof(tmp_code)); 26 | } 27 | 28 | struct do_hijack_struct { 29 | void *dest; 30 | void *source; 31 | }; 32 | 33 | MALLOC_DEFINE(M_HOOK, "hookstruct", "hookstruct"); 34 | 35 | static int do_hijack_target(void *data) 36 | { 37 | void *dest = ((struct do_hijack_struct *)data)->dest; 38 | void *source = ((struct do_hijack_struct *)data)->source; 39 | 40 | return hook_write_range(dest, source, HIJACK_SIZE); 41 | } 42 | 43 | int show_all_hook_targets(char *buf, struct uio *uio) 44 | { 45 | struct sym_hook *sa = NULL; 46 | long offset = 0; 47 | int res = 0; 48 | 49 | if (uio->uio_offset > 0) 50 | return 0; 51 | 52 | rw_rlock(&sym_hook_list_lock); 53 | LIST_FOREACH(sa, &sym_hook_list, node) { 54 | memset(buf, 0, KSYM_NAME_LEN); 55 | res = linker_ddb_search_symbol_name((caddr_t)sa->target, 56 | buf, KSYM_NAME_LEN, &offset); 57 | if (res) 58 | continue; 59 | offset = strlen(buf); 60 | offset = offset < (KSYM_NAME_LEN - 3) ? offset : (KSYM_NAME_LEN - 3); 61 | snprintf(buf + offset, KSYM_NAME_LEN - offset, 62 | " %d\n", sa->enabled); 63 | uiomove(buf, strlen(buf), uio); 64 | } 65 | rw_runlock(&sym_hook_list_lock); 66 | return 0; 67 | } 68 | 69 | int hijack_target_prepare(void *target, void *hook_dest, void *hook_template_code_space) 70 | { 71 | struct sym_hook *sa = NULL; 72 | int ret = 0; 73 | 74 | /*first, target function should longer than HIJACK_SIZE*/ 75 | if (!check_function_length_enough(target)) { 76 | printf("%p short than hijack_size %d, cannot hijack...\n", 77 | target, HIJACK_SIZE); 78 | ret = -1; 79 | goto out; 80 | } 81 | 82 | /*second, target cannot repeat*/ 83 | rw_rlock(&sym_hook_list_lock); 84 | LIST_FOREACH(sa, &sym_hook_list, node) { 85 | if (target == sa->target) { 86 | rw_runlock(&sym_hook_list_lock); 87 | printf("%p has been prepared, skip...\n", target); 88 | ret = -1; 89 | goto out; 90 | } 91 | } 92 | rw_runlock(&sym_hook_list_lock); 93 | 94 | /*check passed, now to allocation*/ 95 | sa = malloc(sizeof(*sa), M_HOOK, M_ZERO | M_WAITOK); 96 | if (!sa) { 97 | printf("No enough memory to hijack %p\n", target); 98 | ret = -1; 99 | goto out; 100 | } 101 | 102 | sa->target = target; 103 | memcpy(sa->target_code, target, HIJACK_SIZE); 104 | sa->hook_dest = hook_dest; 105 | sa->hook_template_code_space = hook_template_code_space; 106 | sa->template_return_addr = (char *)target 107 | #ifdef _arm64_ 108 | + HIJACK_SIZE - 1 * INSTRUCTION_SIZE; 109 | #endif 110 | 111 | #ifdef _amd64_ 112 | + LONG_JMP_CODE_LEN - 1; 113 | #endif 114 | sa->enabled = false; 115 | 116 | rw_wlock(&sym_hook_list_lock); 117 | LIST_INSERT_HEAD(&sym_hook_list, sa, node); 118 | rw_wunlock(&sym_hook_list_lock); 119 | 120 | out: 121 | return ret; 122 | } 123 | 124 | int hijack_target_enable(void *target) 125 | { 126 | struct sym_hook *sa; 127 | int ret = -1; 128 | unsigned char source_code[HIJACK_SIZE] = {0}; 129 | struct do_hijack_struct do_hijack_struct = { 130 | .dest = target, 131 | .source = source_code, 132 | }; 133 | 134 | rw_wlock(&sym_hook_list_lock); 135 | LIST_FOREACH(sa, &sym_hook_list, node) { 136 | if (sa->target == target) { 137 | if (sa->enabled == false) { 138 | if (sa->hook_template_code_space && 139 | fill_hook_template_code_space( 140 | sa->hook_template_code_space, 141 | sa->target_code, 142 | sa->template_return_addr)) { 143 | goto out; 144 | } 145 | memcpy(source_code, sa->target_code, HIJACK_SIZE); 146 | fill_long_jmp(source_code, sa->hook_dest); 147 | if ((ret = fill_nop_for_target(source_code, sa->target))) 148 | goto out; 149 | if (!(ret = do_hijack_target(&do_hijack_struct))) { 150 | sa->enabled = true; 151 | } 152 | } else { 153 | printf("%p has been hijacked, skip...\n", sa->target); 154 | ret = 0; 155 | } 156 | goto out; 157 | } 158 | } 159 | printf("%p not been prepared, skip...\n", target); 160 | out: 161 | rw_wunlock(&sym_hook_list_lock); 162 | 163 | return ret; 164 | } 165 | 166 | int hijack_target_disable(void *target, bool need_remove) 167 | { 168 | struct sym_hook *sa, *tmp; 169 | int ret = -1; 170 | struct do_hijack_struct do_hijack_struct = { 171 | .dest = target 172 | }; 173 | 174 | rw_wlock(&sym_hook_list_lock); 175 | LIST_FOREACH_SAFE(sa, &sym_hook_list, node, tmp) { 176 | if (sa->target == target) { 177 | if (sa->enabled == true) { 178 | do_hijack_struct.source = sa->target_code; 179 | if (!(ret = do_hijack_target(&do_hijack_struct))) 180 | sa->enabled = false; 181 | } else { 182 | printf("%p has been disabled\n", sa->target); 183 | ret = 0; 184 | } 185 | 186 | if (need_remove && !ret) { 187 | printf("remove hijack target %p\n", target); 188 | LIST_REMOVE(sa, node); 189 | free(sa, M_HOOK); 190 | } 191 | goto out; 192 | } 193 | } 194 | printf("%p not been prepared, skip...\n", target); 195 | out: 196 | rw_wunlock(&sym_hook_list_lock); 197 | 198 | return ret; 199 | } 200 | 201 | void hijack_target_disable_all(bool need_remove) 202 | { 203 | struct sym_hook *sa, *tmp; 204 | bool retry; 205 | struct do_hijack_struct do_hijack_struct; 206 | 207 | do { 208 | retry = false; 209 | rw_wlock(&sym_hook_list_lock); 210 | LIST_FOREACH_SAFE(sa, &sym_hook_list, node, tmp) { 211 | if (sa->enabled == true) { 212 | do_hijack_struct.dest = sa->target; 213 | do_hijack_struct.source = sa->target_code; 214 | if (do_hijack_target(&do_hijack_struct)) { 215 | retry = true; 216 | continue; 217 | } 218 | sa->enabled = false; 219 | } 220 | if (need_remove) { 221 | LIST_REMOVE(sa, node); 222 | free(sa, M_HOOK); 223 | } 224 | } 225 | rw_wunlock(&sym_hook_list_lock); 226 | } while(retry && (DELAY(1000000), true)); 227 | 228 | printf("all hijacked target disabled%s\n", need_remove ?" and removed":""); 229 | return; 230 | } 231 | 232 | /************************************************************************************/ 233 | 234 | int init_hijack_operation(void) 235 | { 236 | LIST_INIT(&sym_hook_list); 237 | rw_init(&sym_hook_list_lock, "hook list lock"); 238 | return 0; 239 | } -------------------------------------------------------------------------------- /bsd/framework/include/common_data.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_DATA_H_ 2 | #define _COMMON_DATA_H_ 3 | 4 | #ifdef _amd64_ 5 | #include "hijack_amd64.h" 6 | #endif 7 | #ifdef _arm64_ 8 | #include "hijack_arm64.h" 9 | #endif 10 | #include 11 | #include 12 | #include 13 | 14 | #define DEFAULT_HASH_BUCKET_BITS 17 15 | #define KSYM_NAME_LEN 64 16 | 17 | struct sym_hook { 18 | void *target; 19 | void *hook_dest; 20 | void *template_return_addr; 21 | void *hook_template_code_space; 22 | bool enabled; 23 | LIST_ENTRY(sym_hook) node; 24 | unsigned char target_code[HIJACK_SIZE]; 25 | }; 26 | 27 | char *find_func(const char *name); 28 | bool check_function_length_enough(void *target); 29 | bool check_target_can_hijack(void *target); 30 | int hook_write_range(void *target, void *source, int size); 31 | void fill_long_jmp(void *fill_dest, void *hijack_to_func); 32 | int init_dev_interface(void); 33 | void remove_dev_interface(void); 34 | 35 | bool hook_sys_openat_init(void); 36 | void hook_sys_openat_exit(void); 37 | bool hook__fdrop_init(void); 38 | void hook__fdrop_exit(void); 39 | 40 | int hijack_target_prepare(void *target, void *hook_dest, void *hook_template_code_space); 41 | int hijack_target_enable(void *target); 42 | int hijack_target_disable(void *target, bool need_remove); 43 | void hijack_target_disable_all(bool need_remove); 44 | int show_all_hook_targets(char *buf, struct uio *uio); 45 | int init_hijack_operation(void); 46 | 47 | #define SHOW_KSYM_CACHE 1 48 | #define CLEAN_ALL_KSYM_CACHE (1 << 1) 49 | #endif -------------------------------------------------------------------------------- /bsd/framework/module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "include/common_data.h" 7 | 8 | static int init(void) 9 | { 10 | int ret = 0; 11 | 12 | printf("hookFrame loading start!\n"); 13 | if ((ret = init_hijack_operation())) { 14 | goto out; 15 | } 16 | if ((ret = init_dev_interface())) { 17 | goto out; 18 | } 19 | if ((ret = hook_sys_openat_init())) { 20 | goto out; 21 | } 22 | if ((ret = hook__fdrop_init())) { 23 | goto out; 24 | } 25 | printf("hookFrame loaded!\n"); 26 | out: 27 | return ret; 28 | } 29 | 30 | static void exit(void) 31 | { 32 | hook_sys_openat_exit(); 33 | hook__fdrop_exit(); 34 | remove_dev_interface(); 35 | printf("hookFrame unloaded!\n"); 36 | } 37 | 38 | static int 39 | module_handler(struct module *m, int what, void *arg) 40 | { 41 | switch (what) { 42 | case MOD_LOAD: 43 | if (init()) { 44 | printf("hookFrame load error!\n"); 45 | exit(); 46 | return EFAULT; 47 | } 48 | return 0; 49 | case MOD_UNLOAD: 50 | exit(); 51 | return 0; 52 | default: 53 | return EOPNOTSUPP; 54 | } 55 | } 56 | 57 | static moduledata_t hookFrame_data = { 58 | "hookFrame", 59 | module_handler, 60 | NULL 61 | }; 62 | 63 | DECLARE_MODULE(hookFrame, hookFrame_data, SI_SUB_KLD, SI_ORDER_ANY); 64 | -------------------------------------------------------------------------------- /bsd/framework/symbol_resolve.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "include/common_data.h" 9 | 10 | struct sym_elem { 11 | const char *name; 12 | caddr_t val; 13 | }; 14 | 15 | static int search_symbol_name(linker_file_t lf, void *arg) 16 | { 17 | struct sym_elem *se = (struct sym_elem *)arg; 18 | 19 | se->val = linker_file_lookup_symbol(lf, se->name, 0); 20 | return se->val > 0; 21 | } 22 | 23 | char *find_func(const char *name) 24 | { 25 | int ret; 26 | struct sym_elem se = { 27 | .val = 0, 28 | .name = name, 29 | }; 30 | 31 | ret = linker_file_foreach(search_symbol_name, &se); 32 | 33 | if (!ret) { 34 | printf("Symbol %s not found!\n", name); 35 | } 36 | return (char *)se.val; 37 | } 38 | 39 | bool check_function_length_enough(void *target) 40 | { 41 | char namebuf_orig[64] = {0}; 42 | char namebuf_aft[64] = {0}; 43 | long offset = 0; 44 | int ret = 0; 45 | 46 | ret = linker_ddb_search_symbol_name((caddr_t)target, 47 | namebuf_orig, 64, &offset); 48 | if (ret) 49 | goto fail; 50 | ret = linker_ddb_search_symbol_name((caddr_t)target + HIJACK_SIZE, 51 | namebuf_aft, 64, &offset); 52 | if (ret) 53 | goto fail; 54 | if (strcmp(namebuf_orig, namebuf_aft)) 55 | goto fail; 56 | return true; 57 | fail: 58 | return false; 59 | } -------------------------------------------------------------------------------- /bsd/readme_bsd.md: -------------------------------------------------------------------------------- 1 | ## Usage ## 2 | 3 | ``` 4 | $ make # to build hookFrame.ko 5 | $ kldload ./hookFrame.ko 6 | $ kldunload hookFrame.ko 7 | $ echo "sys_openat 0" > /dev/hook_targets #Disable sys_openat's hook 8 | $ echo "sys_openat 1" > /dev/hook_targets #Enable sys_openat's hook 9 | ``` 10 | 11 | #### Dev ##### 12 | 13 | Unlike linux, only one hookFrame.ko will be generated, which contains both 14 | inline hook framework and customized hook targets. 15 | 16 | #### Runtime ##### 17 | 18 | "/dev/hook_targets" interface acts the same as "/proc/hook_targets" in linux, 19 | by which users can enable/disable hook functions by cmd echo. After ko file 20 | loaded successfully, there will be similar outputs in console as presented in 21 | the demo. 22 | 23 | ## Limits ## 24 | 25 | [Distorm](https://github.com/gdabah/distorm) is integrated for x86_64 support, the credit goes to the original authors. 26 | 27 | ## Usecase ## 28 | 29 | Hack FreeBSD kernel at your own risk. 30 | -------------------------------------------------------------------------------- /bsd/sample/hook_fdrop.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | HOOK_FUNC_TEMPLATE(_fdrop); 9 | int hook__fdrop(struct file *fp, struct thread *td); 10 | int hook__fdrop(struct file *fp, struct thread *td) 11 | { 12 | char *fullpath = NULL; 13 | char *freepath = NULL; 14 | int error = 0; 15 | char *origin__fdrop = GET_CODESPACE_ADDERSS(_fdrop); 16 | 17 | error = vn_fullpath_global(fp->f_vnode, &fullpath, &freepath); 18 | if (error) 19 | goto out; 20 | printf("Reading %s\n", fullpath); 21 | 22 | if (freepath != NULL) 23 | free(freepath, M_TEMP); 24 | out: 25 | return ((int (*)(struct file *, struct thread *)) 26 | origin__fdrop)(fp, td); 27 | } 28 | 29 | void *_fdrop_fn = NULL; 30 | 31 | bool hook__fdrop_init(void) 32 | { 33 | _fdrop_fn = find_func("_fdrop"); 34 | if (!_fdrop_fn) 35 | goto out; 36 | 37 | if (hijack_target_prepare(_fdrop_fn, GET_TEMPLATE_ADDERSS(_fdrop), 38 | GET_CODESPACE_ADDERSS(_fdrop))) { 39 | printf("_fdrop prepare error!\n"); 40 | goto out; 41 | } 42 | if (hijack_target_enable(_fdrop_fn)) { 43 | printf("_fdrop enable error!\n"); 44 | goto out; 45 | } 46 | return 0; 47 | out: 48 | hijack_target_disable_all(true); 49 | return 1; 50 | } 51 | 52 | void hook__fdrop_exit(void) 53 | { 54 | hijack_target_disable(_fdrop_fn, true); 55 | } -------------------------------------------------------------------------------- /bsd/sample/replace_sys_open.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include 3 | #include 4 | #include 5 | 6 | HOOK_FUNC_TEMPLATE(sys_openat); 7 | int hook_sys_openat(struct thread *td, struct openat_args *uap); 8 | int hook_sys_openat(struct thread *td, struct openat_args *uap) 9 | { 10 | printf("In replaced sys_openat\n"); 11 | return (kern_openat(td, uap->fd, uap->path, UIO_USERSPACE, uap->flag, 12 | uap->mode)); 13 | } 14 | 15 | void *sys_openat_fn = NULL; 16 | 17 | bool hook_sys_openat_init(void) 18 | { 19 | sys_openat_fn = find_func("sys_openat"); 20 | if (!sys_openat_fn) 21 | goto out; 22 | 23 | if (hijack_target_prepare(sys_openat_fn, GET_TEMPLATE_ADDERSS(sys_openat), NULL)) { 24 | printf("sys_openat prepare error!\n"); 25 | goto out; 26 | } 27 | if (hijack_target_enable(sys_openat_fn)) { 28 | printf("sys_openat enable error!\n"); 29 | goto out; 30 | } 31 | return 0; 32 | out: 33 | hijack_target_disable_all(true); 34 | return 1; 35 | } 36 | 37 | void hook_sys_openat_exit(void) 38 | { 39 | hijack_target_disable(sys_openat_fn, true); 40 | } 41 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WeiJiLab/kernel-inline-hook-framework/500c4f7f016e271c3c54a4f52df8a9cc117b002c/demo.gif -------------------------------------------------------------------------------- /linux/sample/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += hookFrameTest.o 2 | 3 | hookFrameTest-y += module.o 4 | hookFrameTest-y += hook_vfs_read.o 5 | hookFrameTest-y += hook_fuse_open.o 6 | hookFrameTest-y += replace_vfs_open.o 7 | 8 | PWD := $(shell pwd) 9 | KBUILD_EXTRA_SYMBOLS = $(PWD)/../src/Module.symvers 10 | 11 | default: 12 | @echo "make TARGET KDIR=/path/to/kernel CROSS_COMPILE= vermagic=" 13 | @echo 14 | @echo "Supported targets:" 15 | @echo "arm64 Linux, ARM" 16 | @echo "arm32 Linux, ARM" 17 | @echo "x86_64 Linux, X86_64" 18 | @echo "x86 Linux, X86" 19 | @echo "powerpc Linux, PPC64LE" 20 | 21 | arm64: 22 | ifndef KDIR 23 | @echo "Must provide KDIR!" 24 | @exit 1 25 | endif 26 | ifndef vermagic 27 | $(call compile,arm64,-D_ARCH_ARM64_) 28 | else 29 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 30 | $(call compile,arm64,-D_ARCH_ARM64_) 31 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrameTest 32 | endif 33 | 34 | arm: 35 | ifndef KDIR 36 | @echo "Must provide KDIR!" 37 | @exit 1 38 | endif 39 | ifndef vermagic 40 | $(call compile,arm,-D_ARCH_ARM_) 41 | else 42 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 43 | $(call compile,arm,-D_ARCH_ARM_) 44 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrameTest 45 | endif 46 | 47 | x86_64: 48 | ifndef KDIR 49 | @echo "Must provide KDIR!" 50 | @exit 1 51 | endif 52 | ifndef vermagic 53 | $(call compile,x86_64,-D_ARCH_X86_64_) 54 | else 55 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 56 | $(call compile,x86_64,-D_ARCH_X86_64_) 57 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrameTest 58 | endif 59 | 60 | x86: 61 | ifndef KDIR 62 | @echo "Must provide KDIR!" 63 | @exit 1 64 | endif 65 | ifndef vermagic 66 | $(call compile,x86,-D_ARCH_X86_) 67 | else 68 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 69 | $(call compile,x86,-D_ARCH_X86_) 70 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrameTest 71 | endif 72 | 73 | powerpc: 74 | ifndef KDIR 75 | @echo "Must provide KDIR!" 76 | @exit 1 77 | endif 78 | ifndef vermagic 79 | $(call compile,powerpc,-D_ARCH_POWERPC_) 80 | else 81 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 82 | $(call compile,powerpc,-D_ARCH_POWERPC_) 83 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrame 84 | endif 85 | 86 | compile = $(MAKE) ARCH=$(1) CROSS_COMPILE=$(CROSS_COMPILE) KBUILD_MODPOST_WARN=1 KBUILD_EXTRA_SYMBOLS=$(KBUILD_EXTRA_SYMBOLS) EXTRA_CFLAGS="$(2) -I$(PWD)/include -fno-pic" -C $(KDIR) M=$(PWD) modules 87 | 88 | clean: 89 | find ./ -regextype posix-extended -regex ".*\.(ko|o|mod.c|order|symvers|d|cmd|mod)" | xargs rm -f 90 | -------------------------------------------------------------------------------- /linux/sample/aftvermagic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RELATE_UTSRELEASE="include/generated/utsrelease.h" 4 | UTSRELEASE=$1/$RELATE_UTSRELEASE 5 | 6 | if [ ! -e $UTSRELEASE ]; then 7 | echo "error! $UTSRELEASE not exist" 8 | exit 1 9 | fi 10 | 11 | if [ ! -e $3.ko ]; then 12 | echo "$3.ko not found!" 13 | exit 1 14 | fi 15 | 16 | esp_str=`echo "${2}"|sed 's/ /\\\\x20/g'` 17 | bbe -b "/vermagic=/:/\x00/" -e "r 0 vermagic=$esp_str\0" $3.ko > $3.ko.bak 18 | mv $3.ko.bak $3.ko 19 | mv $UTSRELEASE.bak $UTSRELEASE 20 | echo "modified $3 vermagic to:$2" -------------------------------------------------------------------------------- /linux/sample/hook_fuse_open.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include "hook_framework.h" 3 | #include 4 | #include 5 | 6 | HOOK_FUNC_TEMPLATE(fuse_open); 7 | int hook_fuse_open(struct inode *inode, struct file *file) 8 | { 9 | char *origin_fuse_open; 10 | 11 | printk(KERN_ALERT"in hooked fuse_open\n"); 12 | origin_fuse_open = GET_CODESPACE_ADDERSS(fuse_open); 13 | return ((int (*)(struct inode *, struct file *))origin_fuse_open)(inode, file); 14 | } 15 | 16 | static void *fuse_open_fn = NULL; 17 | 18 | int hook_fuse_open_init(void) 19 | { 20 | int ret = -EFAULT; 21 | 22 | fuse_open_fn = (void *)find_func("fuse_open"); 23 | if (!fuse_open_fn) 24 | goto out; 25 | 26 | #ifndef _ARCH_POWERPC_ 27 | /* 28 | * Same as hook_vfs_read(), please refer to it for code explaination. 29 | */ 30 | if (hijack_target_prepare(fuse_open_fn, GET_TEMPLATE_ADDERSS(fuse_open), GET_CODESPACE_ADDERSS(fuse_open))) { 31 | printk(KERN_ALERT"fuse_open prepare error!\n"); 32 | goto out; 33 | } 34 | if (hijack_target_enable(fuse_open_fn)) { 35 | printk(KERN_ALERT"fuse_open enable error!\n"); 36 | goto out; 37 | } 38 | #endif 39 | return 0; 40 | 41 | out: 42 | hijack_target_disable(fuse_open_fn, true); 43 | return ret; 44 | } 45 | 46 | void hook_fuse_open_exit(void) 47 | { 48 | hijack_target_disable(fuse_open_fn, true); 49 | } -------------------------------------------------------------------------------- /linux/sample/hook_vfs_read.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include "hook_framework.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | ssize_t hook_vfs_read(struct file *, char __user *, size_t, loff_t *); 10 | 11 | /* Must pass the origin_function_name to HOOK_FUNC_TEMPLATE() */ 12 | HOOK_FUNC_TEMPLATE(vfs_read); 13 | 14 | /* The hook function name must be "hook_ + origin_function_name" */ 15 | ssize_t hook_vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) 16 | { 17 | char *path_buffer = NULL; 18 | char *result = NULL; 19 | 20 | /* 21 | * To resume the original function, get the original function address 22 | * by GET_CODESPACE_ADDERSS(), which must pass the origin_function_name 23 | * to it. 24 | */ 25 | char *origin_vfs_read = GET_CODESPACE_ADDERSS(vfs_read); 26 | 27 | path_buffer = kmalloc(512, GFP_KERNEL); 28 | if (!path_buffer) 29 | goto out; 30 | 31 | result = d_path(&file->f_path, path_buffer, 512); 32 | if (!IS_ERR(result)) { 33 | if (!strnstr(result, "/dev/kmsg", 512 - (result - path_buffer)) && 34 | !strnstr(result, "[timerfd]", 512 - (result - path_buffer)) && 35 | !strnstr(result, "/proc/kmsg", 512 - (result - path_buffer)) && 36 | !strnstr(result, "/run/log", 512 - (result - path_buffer)) && 37 | !strnstr(result, "/var/log", 512 - (result - path_buffer))) 38 | printk(KERN_ALERT"reading %s\n", result); 39 | } 40 | kfree(path_buffer); 41 | out: 42 | return ((ssize_t (*)(struct file *file, char __user *buf, size_t count, loff_t *pos))origin_vfs_read)(file, buf, count, pos); 43 | } 44 | 45 | static void *vfs_read_fn = NULL; 46 | 47 | int hook_vfs_read_init(void) 48 | { 49 | int ret = -EFAULT; 50 | 51 | vfs_read_fn = (void *)find_func("vfs_read"); 52 | if (!vfs_read_fn) 53 | goto out; 54 | 55 | /* 56 | * template address is the trampoline where kernel function been hijacked to, 57 | * codespace address is the original kernel function which been hijacked and repositioned to resume. 58 | * If you want to replace the whole function, then leave the 3rd parameter of "hijack_target_prepare" 59 | * to NULL. 60 | * If you only want to insert your hook before or after a certain function, then leave it to be 61 | * "GET_CODESPACE_ADDERSS(xx_func)" 62 | */ 63 | 64 | /* 65 | For powerpc, function resume is not supported, currently only function 66 | replacement is supported. 67 | */ 68 | #ifndef _ARCH_POWERPC_ 69 | if (hijack_target_prepare(vfs_read_fn, GET_TEMPLATE_ADDERSS(vfs_read), GET_CODESPACE_ADDERSS(vfs_read))) { 70 | printk(KERN_ALERT"vfs_read prepare error!\n"); 71 | goto out; 72 | } 73 | if (hijack_target_enable(vfs_read_fn)) { 74 | printk(KERN_ALERT"vfs_read enable error!\n"); 75 | goto out; 76 | } 77 | #endif 78 | return 0; 79 | 80 | out: 81 | hijack_target_disable(vfs_read_fn, true); 82 | return ret; 83 | } 84 | 85 | void hook_vfs_read_exit(void) 86 | { 87 | hijack_target_disable(vfs_read_fn, true); 88 | } 89 | -------------------------------------------------------------------------------- /linux/sample/include/common_data.h: -------------------------------------------------------------------------------- 1 | ../../src/include/common_data.h -------------------------------------------------------------------------------- /linux/sample/include/hijack_arm.h: -------------------------------------------------------------------------------- 1 | ../../src/arch/arm/hijack_arm.h -------------------------------------------------------------------------------- /linux/sample/include/hijack_arm64.h: -------------------------------------------------------------------------------- 1 | ../../src/arch/arm64/hijack_arm64.h -------------------------------------------------------------------------------- /linux/sample/include/hijack_powerpc.h: -------------------------------------------------------------------------------- 1 | ../../src/arch/powerpc/hijack_powerpc.h -------------------------------------------------------------------------------- /linux/sample/include/hijack_x86.h: -------------------------------------------------------------------------------- 1 | ../../src/arch/x86/hijack_x86.h -------------------------------------------------------------------------------- /linux/sample/include/hijack_x86_64.h: -------------------------------------------------------------------------------- 1 | ../../src/arch/x86_64/hijack_x86_64.h -------------------------------------------------------------------------------- /linux/sample/include/hook_framework.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOOK_FRAMEWORK_H_ 2 | #define _HOOK_FRAMEWORK_H_ 3 | 4 | #include 5 | 6 | extern int hijack_target_prepare(void *target, void *hook_dest, void *hook_template_code_space); 7 | extern int hijack_target_enable(void *target); 8 | extern int hijack_target_disable(void *target, bool need_remove); 9 | extern void hijack_target_disable_all(bool need_remove); 10 | extern void *find_func(const char *name); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /linux/sample/module.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | MODULE_AUTHOR("Liu Tao "); 5 | MODULE_LICENSE("GPL"); 6 | 7 | extern int hook_fuse_open_init(void); 8 | extern int hook_vfs_open_init(void); 9 | extern int hook_vfs_read_init(void); 10 | extern void hook_fuse_open_exit(void); 11 | extern void hook_vfs_open_exit(void); 12 | extern void hook_vfs_read_exit(void); 13 | 14 | static int __init test_hookframe_init(void) 15 | { 16 | int ret = -EFAULT; 17 | 18 | if (hook_fuse_open_init()) 19 | goto out; 20 | if (hook_vfs_open_init()) 21 | goto out; 22 | if (hook_vfs_read_init()) 23 | goto out; 24 | return 0; 25 | 26 | out: 27 | hook_fuse_open_exit(); 28 | hook_vfs_open_exit(); 29 | hook_vfs_read_exit(); 30 | return ret; 31 | } 32 | 33 | static void __exit test_hookframe_exit(void) 34 | { 35 | hook_fuse_open_exit(); 36 | hook_vfs_open_exit(); 37 | hook_vfs_read_exit(); 38 | printk(KERN_ALERT"unload hook framework test!\n"); 39 | } 40 | 41 | module_init(test_hookframe_init); 42 | module_exit(test_hookframe_exit); -------------------------------------------------------------------------------- /linux/sample/prevermagic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RELATE_UTSRELEASE="include/generated/utsrelease.h" 4 | UTSRELEASE=$1/$RELATE_UTSRELEASE 5 | 6 | if [ ! -e $UTSRELEASE ]; then 7 | echo "error! $UTSRELEASE not exist" 8 | exit 1 9 | fi 10 | 11 | str_len=${#2} 12 | padding="" 13 | 14 | for (( i=0; i<=$str_len; i++ )) 15 | do 16 | padding="X"$padding 17 | done 18 | 19 | line=`wc -l $UTSRELEASE | awk -F ' ' '{print $1}'` 20 | 21 | cp $UTSRELEASE $UTSRELEASE.bak 22 | cat $UTSRELEASE.bak | awk -v pad=$padding -v line=$line -F '"' \ 23 | '{if(NR==line){printf("%s \"%s%s\"", $1, pad, $2)}else{print $0}}' > $UTSRELEASE 24 | -------------------------------------------------------------------------------- /linux/sample/replace_vfs_open.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include "hook_framework.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern int do_dentry_open(struct file *f, 10 | int (*open)(struct inode *, struct file *)); 11 | 12 | HOOK_FUNC_TEMPLATE(vfs_open); 13 | int hook_vfs_open(const struct path *path, struct file *file) 14 | { 15 | int ret; 16 | 17 | printk(KERN_ALERT"in replaced vfs_open\n"); 18 | file->f_path = *path; 19 | ret = do_dentry_open(file, NULL); 20 | if (!ret) { 21 | /* 22 | * Once we return a file with FMODE_OPENED, __fput() will call 23 | * fsnotify_close(), so we need fsnotify_open() here for 24 | * symmetry. 25 | */ 26 | fsnotify_open(file); 27 | } 28 | return ret; 29 | } 30 | 31 | static void *vfs_open_fn = NULL; 32 | 33 | int hook_vfs_open_init(void) 34 | { 35 | int ret = -EFAULT; 36 | 37 | vfs_open_fn = (void *)find_func("vfs_open"); 38 | if (!vfs_open_fn) 39 | goto out; 40 | 41 | /* 42 | * We will relace the original vfs_open with hook_vfs_open, so there is no 43 | * need to resume to the original vfs_open, therefore leave the 3rd 44 | * arguement to be NULL. 45 | */ 46 | if (hijack_target_prepare(vfs_open_fn, GET_TEMPLATE_ADDERSS(vfs_open), NULL)) { 47 | printk(KERN_ALERT"vfs_open prepare error!\n"); 48 | goto out; 49 | } 50 | if (hijack_target_enable(vfs_open_fn)) { 51 | printk(KERN_ALERT"vfs_open enable error!\n"); 52 | goto out; 53 | } 54 | return 0; 55 | out: 56 | hijack_target_disable(vfs_open_fn, true); 57 | return ret; 58 | } 59 | 60 | void hook_vfs_open_exit(void) 61 | { 62 | hijack_target_disable(vfs_open_fn, true); 63 | } -------------------------------------------------------------------------------- /linux/src/Makefile: -------------------------------------------------------------------------------- 1 | obj-m += hookFrame.o 2 | 3 | hookFrame-y += framework/module.o 4 | hookFrame-y += framework/hijack_operation.o 5 | hookFrame-y += framework/stack_safety_check.o 6 | 7 | ifeq ($(HAS_NO_SIMPLIFY_SYMBOLS),1) 8 | hookFrame-y += framework/symbol_resolver_bak.o 9 | else 10 | hookFrame-y += framework/symbol_resolver.o 11 | endif 12 | 13 | hookFrame-y += framework/write_map_page.o 14 | hookFrame-y += framework/proc_interface.o 15 | hookFrame-y += arch/$(ARCH)/hijack_$(ARCH).o 16 | ifneq ($(findstring $(ARCH),"x86_64 x86"),) 17 | hookFrame-y += arch/$(ARCH)/common.o 18 | endif 19 | 20 | PWD := $(shell pwd) 21 | default: 22 | @echo "make TARGET KDIR=/path/to/kernel CROSS_COMPILE= vermagic=" 23 | @echo 24 | @echo "Supported targets:" 25 | @echo "arm64 Linux, ARM" 26 | @echo "arm Linux, ARM" 27 | @echo "x86_64 Linux, X86_64" 28 | @echo "x86 Linux, X86" 29 | @echo "powerpc Linux, PPC64LE" 30 | 31 | arm64: 32 | ifndef KDIR 33 | @echo "Must provide KDIR!" 34 | @exit 1 35 | endif 36 | ifndef vermagic 37 | $(call compile,arm64,-D_ARCH_ARM64_) 38 | else 39 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 40 | $(call compile,arm64,-D_ARCH_ARM64_) 41 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrame 42 | endif 43 | 44 | arm: 45 | ifndef KDIR 46 | @echo "Must provide KDIR!" 47 | @exit 1 48 | endif 49 | ifndef vermagic 50 | $(call compile,arm,-D_ARCH_ARM_) 51 | else 52 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 53 | $(call compile,arm,-D_ARCH_ARM_) 54 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrame 55 | endif 56 | 57 | x86_64: 58 | ifndef KDIR 59 | @echo "Must provide KDIR!" 60 | @exit 1 61 | endif 62 | ifndef vermagic 63 | $(call compile,x86_64,-D_ARCH_X86_64_) 64 | else 65 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 66 | $(call compile,x86_64,-D_ARCH_X86_64_) 67 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrame 68 | endif 69 | 70 | x86: 71 | ifndef KDIR 72 | @echo "Must provide KDIR!" 73 | @exit 1 74 | endif 75 | ifndef vermagic 76 | $(call compile,x86,-D_ARCH_X86_) 77 | else 78 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 79 | $(call compile,x86,-D_ARCH_X86_) 80 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrame 81 | endif 82 | 83 | powerpc: 84 | ifndef KDIR 85 | @echo "Must provide KDIR!" 86 | @exit 1 87 | endif 88 | ifndef vermagic 89 | $(call compile,powerpc,-D_ARCH_POWERPC_) 90 | else 91 | @bash prevermagic.sh $(KDIR) "$(vermagic)" 92 | $(call compile,powerpc,-D_ARCH_POWERPC_) 93 | @bash aftvermagic.sh $(KDIR) "$(vermagic)" hookFrame 94 | endif 95 | 96 | define compile 97 | $(MAKE) ARCH=$(1) CROSS_COMPILE=$(CROSS_COMPILE) EXTRA_CFLAGS="$(2) -I$(PWD) -I$(PWD)/arch/$(1) -fno-pic -fno-stack-protector" -C $(KDIR) M=$(PWD) modules 98 | endef 99 | 100 | clean: 101 | find ./ -regextype posix-extended -regex ".*\.(ko|o|mod.c|order|symvers|d|cmd|mod)" | xargs rm -f 102 | -------------------------------------------------------------------------------- /linux/src/aftvermagic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RELATE_UTSRELEASE="include/generated/utsrelease.h" 4 | UTSRELEASE=$1/$RELATE_UTSRELEASE 5 | 6 | if [ ! -e $UTSRELEASE ]; then 7 | echo "error! $UTSRELEASE not exist" 8 | exit 1 9 | fi 10 | 11 | if [ ! -e $3.ko ]; then 12 | echo "$3.ko not found!" 13 | exit 1 14 | fi 15 | 16 | esp_str=`echo "${2}"|sed 's/ /\\\\x20/g'` 17 | bbe -b "/vermagic=/:/\x00/" -e "r 0 vermagic=$esp_str\0" $3.ko > $3.ko.bak 18 | mv $3.ko.bak $3.ko 19 | mv $UTSRELEASE.bak $UTSRELEASE 20 | echo "modified $3 vermagic to:$2" -------------------------------------------------------------------------------- /linux/src/arch/arm/hijack_arm.c: -------------------------------------------------------------------------------- 1 | #include "hijack_arm.h" 2 | #include 3 | 4 | //There MUST be 4 5 | /* 6 | ldr pc, [pc, #-0x4] 7 | .addr 8 | */ 9 | const char long_jmp_code[4]="\x04\xf0\x1f\xe5"; 10 | 11 | inline void fill_long_jmp(void *fill_dest, void *hijack_to_func) 12 | { 13 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 14 | memcpy(fill_dest + sizeof(long_jmp_code), &hijack_to_func, sizeof(void *)); 15 | } 16 | 17 | /* 18 | * Refer to http://engold.ui.ac.ir/~nikmehr/Appendix_B2.pdf 19 | */ 20 | bool check_instruction_can_hijack(uint32_t instruction) 21 | { 22 | bool ret = true; 23 | 24 | //todo: we want to fix these instructions 25 | switch (instruction & 0xfe000000u) { 26 | case 0xfa000000u: // blx 27 | ret = false; 28 | goto out; 29 | } 30 | 31 | switch (instruction & 0x0f000000u) { 32 | case 0x0a000000u: // b 33 | case 0x0b000000u: // bl 34 | ret = false; 35 | goto out; 36 | } 37 | 38 | switch (instruction & 0xff000ffu) { 39 | case 0x0120001fu: // bx 40 | ret = false; 41 | goto out; 42 | } 43 | 44 | switch (instruction & 0x0f00f010u) { 45 | case 0x0000f000u: // and eor sub rsb add adc sbs rsc to PC 46 | ret = false; 47 | goto out; 48 | } 49 | 50 | switch (instruction & 0x0f00f090u) { 51 | case 0x0000f010u: // and eor sub rsb add adc sbs rsc to PC 52 | ret = false; 53 | goto out; 54 | } 55 | 56 | switch (instruction & 0x0fe0f000u) { 57 | case 0x01a0f000u: // mov to PC 58 | ret = false; 59 | goto out; 60 | } 61 | 62 | switch (instruction & 0x0e5ff000u) { 63 | case 0x041ff000u: // ldr to PC 64 | ret = false; 65 | goto out; 66 | } 67 | 68 | switch (instruction & 0x0ffff000u) { 69 | case 0x028ff000u: // adr to PC 70 | case 0x024ff000u: 71 | ret = false; 72 | goto out; 73 | } 74 | 75 | out: 76 | if (!ret) { 77 | printk(KERN_ALERT"instruction %x cannot be hijacked!\n", instruction); 78 | } 79 | return ret; 80 | } 81 | 82 | bool check_target_can_hijack(void *target) 83 | { 84 | int offset = 0; 85 | for (; offset < HOOK_TARGET_OFFSET + HIJACK_SIZE; offset += INSTRUCTION_SIZE) { 86 | if (!check_instruction_can_hijack(*(uint32_t *)(target + offset))) 87 | return false; 88 | } 89 | return true; 90 | } 91 | 92 | void (*__patch_text_real_ptr)(void *, unsigned int, bool) = NULL; 93 | void *find_func(const char *name); 94 | 95 | int hook_write_range(void *target, void *source, int size) 96 | { 97 | int i; 98 | for (i = 0; i < size; i = i + INSTRUCTION_SIZE) { 99 | __patch_text_real_ptr(target + i, *(unsigned int *)(source + i), true); 100 | } 101 | 102 | return 0; 103 | } 104 | 105 | int init_arch(void) 106 | { 107 | __patch_text_real_ptr = (void *)find_func("__patch_text_real"); 108 | return !__patch_text_real_ptr; 109 | } -------------------------------------------------------------------------------- /linux/src/arch/arm/hijack_arm.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOOK_ARM_H_ 2 | #define _HOOK_ARM_H_ 3 | 4 | #define HOOK_FUNC_TEMPLATE(s) \ 5 | extern void hook_##s##_template(void); \ 6 | asm ( \ 7 | ".globl hook_"#s"_template\n\t" \ 8 | "hook_"#s"_template:\n\t" \ 9 | "b hook_"#s"\n\t" \ 10 | \ 11 | ".globl "#s"_code_space\n\t" \ 12 | #s"_code_space:\n\t" \ 13 | ".word 0\n\t" \ 14 | ".word 0\n\t" \ 15 | \ 16 | ".word 0\n\t" \ 17 | ".word 0\n\t" \ 18 | ); 19 | 20 | #define GET_TEMPLATE_ADDERSS(s) \ 21 | ({ \ 22 | void *template; \ 23 | __asm__ volatile ("ldr %0, =hook_"#s"_template\n\t":"=r"(template)); \ 24 | template; \ 25 | }) 26 | 27 | #define GET_CODESPACE_ADDERSS(s) \ 28 | ({ \ 29 | void *codespace; \ 30 | __asm__ volatile ("ldr %0, ="#s"_code_space\n\t":"=r"(codespace)); \ 31 | codespace; \ 32 | }) 33 | 34 | #define INSTRUCTION_SIZE 4 35 | #define HIJACK_INST_NUM 2 36 | #define HIJACK_SIZE (INSTRUCTION_SIZE * HIJACK_INST_NUM) 37 | #define fill_nop_for_target(x, y) (0) 38 | #define fill_nop_for_code_space(x, y) (0) 39 | #define HOOK_TARGET_OFFSET (0) 40 | #define CODE_SPACE_OFFSET (0) 41 | int init_arch(void); 42 | #endif -------------------------------------------------------------------------------- /linux/src/arch/arm64/hijack_arm64.c: -------------------------------------------------------------------------------- 1 | #include "hijack_arm64.h" 2 | #include 3 | 4 | /* 5 | stp x1, x0, [sp, #-0x20]! 6 | ldr x0, 8 7 | ret x0 8 | .addr(low) 9 | .addr(high) 10 | ldp x1, x0, [sp], #0x20 11 | */ 12 | const char long_jmp_code[24]="\xe1\x03\xbe\xa9\x40\x00\x00\x58\x00\x00\x5f\xd6\x00\x00\x00\x00\x00\x00\x00\x00\xe1\x03\xc2\xa8"; 13 | 14 | inline void fill_long_jmp(void *fill_dest, void *hijack_to_func) 15 | { 16 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 17 | memcpy(fill_dest + 3 * INSTRUCTION_SIZE, &hijack_to_func, sizeof(void *)); 18 | } 19 | 20 | /* 21 | * Refer to https://github.com/CAS-Atlantic/AArch64-Encoding 22 | */ 23 | 24 | bool check_instruction_can_hijack(uint32_t instruction) 25 | { 26 | bool ret = true; 27 | 28 | //todo: we want to fix these instructions 29 | switch(instruction & 0x9f000000u) { 30 | case 0x10000000u: //adr 31 | case 0x90000000u: //adrp 32 | ret = false; 33 | goto out; 34 | } 35 | switch(instruction & 0xfc000000u) { 36 | case 0x14000000u: //b 37 | case 0x94000000u: //bl 38 | ret = false; 39 | goto out; 40 | } 41 | switch(instruction & 0xff000000u) { 42 | case 0x54000000u: //b.c 43 | ret = false; 44 | goto out; 45 | } 46 | switch(instruction & 0x7e000000u) { 47 | case 0x34000000u: //cbz cbnz 48 | case 0x36000000u: //tbz tbnz 49 | ret = false; 50 | goto out; 51 | } 52 | switch(instruction & 0xbf000000u) { 53 | case 0x18000000u: //ldr 54 | ret = false; 55 | goto out; 56 | } 57 | switch(instruction & 0x3f000000u) { 58 | case 0x1c000000u: //ldrv 59 | ret = false; 60 | goto out; 61 | } 62 | switch(instruction & 0xff000000u) { 63 | case 0x98000000u: //ldrsw 64 | ret = false; 65 | goto out; 66 | } 67 | 68 | out: 69 | if (!ret) { 70 | printk(KERN_ALERT"instruction %x cannot be hijacked!\n", instruction); 71 | } 72 | return ret; 73 | } 74 | 75 | bool check_target_can_hijack(void *target) 76 | { 77 | int offset = 0; 78 | for (; offset < HOOK_TARGET_OFFSET + HIJACK_SIZE; offset += INSTRUCTION_SIZE) { 79 | if (!check_instruction_can_hijack(*(uint32_t *)(target + offset))) 80 | return false; 81 | } 82 | return true; 83 | } 84 | 85 | int (*aarch64_insn_write_ptr)(void *, u32) = NULL; 86 | void *find_func(const char *name); 87 | void (*flush_icache_range_ptr)(unsigned long, unsigned long) = NULL; 88 | 89 | int hook_write_range(void *target, void *source, int size) 90 | { 91 | int ret = 0, i; 92 | 93 | for (i = 0; i < size; i = i + INSTRUCTION_SIZE) { 94 | ret = aarch64_insn_write_ptr(target + i, *(u32 *)(source + i)); 95 | if (ret) { 96 | goto out; 97 | } 98 | } 99 | flush_icache_range_ptr((unsigned long)target, (unsigned long)target + size); 100 | 101 | out: 102 | return ret; 103 | } 104 | 105 | int init_arch(void) 106 | { 107 | aarch64_insn_write_ptr = (void *)find_func("aarch64_insn_write"); 108 | flush_icache_range_ptr = (void *)find_func("caches_clean_inval_pou"); 109 | if (!flush_icache_range_ptr) { 110 | flush_icache_range_ptr = (void *)find_func("__flush_icache_range"); 111 | } 112 | return !(aarch64_insn_write_ptr && flush_icache_range_ptr); 113 | } -------------------------------------------------------------------------------- /linux/src/arch/arm64/hijack_arm64.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOOK_ARM64_H_ 2 | #define _HOOK_ARM64_H_ 3 | 4 | #define HOOK_FUNC_TEMPLATE(s) \ 5 | extern void hook_##s##_template(void); \ 6 | asm ( \ 7 | ".globl hook_"#s"_template\n\t" \ 8 | "hook_"#s"_template:\n\t" \ 9 | "ldp x1, x0, [sp], #0x20\n\t" \ 10 | "b hook_"#s"\n\t" \ 11 | \ 12 | ".globl "#s"_code_space\n\t" \ 13 | #s"_code_space:\n\t" \ 14 | ".word 0\n\t" \ 15 | ".word 0\n\t" \ 16 | ".word 0\n\t" \ 17 | ".word 0\n\t" \ 18 | ".word 0\n\t" \ 19 | ".word 0\n\t" \ 20 | \ 21 | ".word 0\n\t" \ 22 | ".word 0\n\t" \ 23 | ".word 0\n\t" \ 24 | ".word 0\n\t" \ 25 | ".word 0\n\t" \ 26 | ".word 0\n\t" \ 27 | ); 28 | 29 | #define GET_TEMPLATE_ADDERSS(s) \ 30 | ({ \ 31 | void *template; \ 32 | __asm__ volatile ("ldr %0, =hook_"#s"_template\n\t":"=r"(template)); \ 33 | template; \ 34 | }) 35 | 36 | #define GET_CODESPACE_ADDERSS(s) \ 37 | ({ \ 38 | void *codespace; \ 39 | __asm__ volatile ("ldr %0, ="#s"_code_space\n\t":"=r"(codespace)); \ 40 | codespace; \ 41 | }) 42 | 43 | #define INSTRUCTION_SIZE 4 44 | #define HIJACK_INST_NUM 6 45 | #define HIJACK_SIZE (INSTRUCTION_SIZE * HIJACK_INST_NUM) 46 | #define fill_nop_for_target(x, y) (0) 47 | #define fill_nop_for_code_space(x, y) (0) 48 | #define HOOK_TARGET_OFFSET (0) 49 | #define CODE_SPACE_OFFSET (0) 50 | int init_arch(void); 51 | #endif -------------------------------------------------------------------------------- /linux/src/arch/powerpc/hijack_powerpc.c: -------------------------------------------------------------------------------- 1 | #include "hijack_powerpc.h" 2 | #include 3 | #include 4 | 5 | /* 6 | Usually the first 3 instructions are doing: 1) save r2, 2) save return addr to 7 | r0. So we need to save them as kernel env. 8 | 9 | orig_inst 0 \ 10 | orig_inst 1 | => HOOK_TARGET_OFFSET = inst_size * 3 11 | orig_inst 2 / 12 | 13 | bcl 20, 31, .+4 14 | mflr 12 15 | ld 12, 16(12) 16 | mtctr 12 17 | bctr 12 18 | .addr(low) 19 | .addr(high) 20 | */ 21 | 22 | const char long_jmp_code[28]= 23 | "\x05\x00\x9f\x42\xa6\x02\x88\x7d\x10\x00\x8c\xe9\xa6\x03\x89\x7d\x20\x04\x80\x4e\x00\x00\x00\x00\x00\x00\x00\x00"; 24 | 25 | inline void fill_long_jmp(void *fill_dest, void *hijack_to_func) 26 | { 27 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 28 | memcpy(fill_dest + 5 * INSTRUCTION_SIZE, &hijack_to_func, sizeof(void *)); 29 | } 30 | 31 | bool check_instruction_can_hijack(uint32_t instruction) 32 | { 33 | bool ret = true; 34 | return ret; 35 | } 36 | 37 | bool check_target_can_hijack(void *target) 38 | { 39 | int offset = 0; 40 | for (; offset < HOOK_TARGET_OFFSET + HIJACK_SIZE; offset += INSTRUCTION_SIZE) { 41 | if (!check_instruction_can_hijack(*(uint32_t *)(target + offset))) 42 | return false; 43 | } 44 | return true; 45 | } 46 | 47 | int (*patch_instruction_ptr)(u32 *, ppc_inst_t) = NULL; 48 | void *find_func(const char *name); 49 | 50 | int hook_write_range(void *target, void *source, int size) 51 | { 52 | int ret = 0, i; 53 | ppc_inst_t inst; 54 | 55 | for (i = 0; i < size; i = i + INSTRUCTION_SIZE) { 56 | *(u32 *)&inst = *(u32 *)(source + i); 57 | ret = patch_instruction_ptr(target + i, inst); 58 | if (ret) { 59 | goto out; 60 | } 61 | } 62 | 63 | out: 64 | return ret; 65 | } 66 | 67 | int init_arch(void) 68 | { 69 | patch_instruction_ptr = (void *)find_func("patch_instruction"); 70 | return !patch_instruction_ptr; 71 | } -------------------------------------------------------------------------------- /linux/src/arch/powerpc/hijack_powerpc.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOOK_POWERPC_H_ 2 | #define _HOOK_POWERPC_H_ 3 | 4 | /* 5 | The following complex jump trampoline will be explained one by one: 6 | part 1: local data section 7 | part 2: save kernel env(r2), return addr(r0), hook_"#s"_template addr(r12) to 8 | stack, then switch to hook_"#s"_template env 9 | part 3: save the stack r2 to data section _r2 10 | part 4: save the stack r0 to data section _r0 11 | part 5: make part 6 to be the return address of real hook_func, then jump to 12 | hook_func 13 | part 6: after return from hook_func, then switch to hook_"#s"_template env, 14 | then restore r2, r0 from data section _r2, _r0, then return back to 15 | kernel. 16 | 17 | above is enough for replace a kernel function use. 18 | ------------------------------------------------------------------------------ 19 | below is used for kernel function resume. 20 | 21 | part 7: switch env to hook_##s##_template, and load r2 from data section _r2, 22 | that is switch to kernel env. 23 | part 8: the part of kernel function, been copied here. 24 | part 9: long jump back to kernel function, to resume the rest of the kernel 25 | function. 26 | */ 27 | 28 | #define HOOK_FUNC_TEMPLATE(s) \ 29 | extern void hook_##s##_template(void); \ 30 | asm ( \ 31 | ".section \".data\"\n\t" \ 32 | "."#s"_r0:\n\t" \ 33 | ".quad 0\n\t" \ 34 | "."#s"_r2:\n\t" \ 35 | ".quad 0\n\t" \ 36 | \ 37 | ".section \".text\"\n\t" \ 38 | ".quad .TOC.-hook_"#s"_template\n\t" \ 39 | ".globl hook_"#s"_template\n\t" \ 40 | "hook_"#s"_template:\n\t" \ 41 | "stdu 12, -16(1)\n\t" \ 42 | "stdu 0, -16(1)\n\t" \ 43 | "stdu 2, -16(1)\n\t" \ 44 | "ld 2, -8(12)\n\t" \ 45 | "add 2, 2, 12\n\t" \ 46 | \ 47 | "addis 12, 2, ."#s"_r2@toc@ha\n\t" \ 48 | "addi 12, 12, ."#s"_r2@toc@l\n\t" \ 49 | "ld 0, 0(1)\n\t" \ 50 | "std 0, 0(12)\n\t" \ 51 | \ 52 | "addis 12, 2, ."#s"_r0@toc@ha\n\t" \ 53 | "addi 12, 12, ."#s"_r0@toc@l\n\t" \ 54 | "ld 0, 16(1)\n\t" \ 55 | "std 0, 0(12)\n\t" \ 56 | \ 57 | "ld 12, 32(1)\n\t" \ 58 | "addi 0, 12, 84\n\t" \ 59 | "mtlr 0\n\t" \ 60 | "addi 1, 1, 48\n\t" \ 61 | "addis 12, 2, hook_"#s"@toc@ha\n\t" \ 62 | "addi 12, 12, hook_"#s"@toc@l\n\t" \ 63 | "mtctr 12\n\t" \ 64 | "bctr\n\t" \ 65 | \ 66 | "mflr 12\n\t" \ 67 | "addi 12, 12, -84\n\t" \ 68 | "ld 2, -8(12)\n\t" \ 69 | "add 2, 2, 12\n\t" \ 70 | "addis 12, 2, ."#s"_r0@toc@ha\n\t" \ 71 | "ld 0, ."#s"_r0@toc@l(12)\n\t" \ 72 | "mtlr 0\n\t" \ 73 | "addis 12, 2, ."#s"_r2@toc@ha\n\t" \ 74 | "ld 2, ."#s"_r2@toc@l(12)\n\t" \ 75 | "blr\n\t" \ 76 | \ 77 | ".quad .TOC.-"#s"_code_space\n\t" \ 78 | ".globl "#s"_code_space\n\t" \ 79 | #s"_code_space:\n\t" \ 80 | "ld 2, -8(12)\n\t" \ 81 | "add 2, 2, 12\n\t" \ 82 | "addis 12, 2, ."#s"_r2@toc@ha\n\t" \ 83 | "ld 2, ."#s"_r2@toc@l(12)\n\t" \ 84 | \ 85 | ".long 0\n\t" \ 86 | ".long 0\n\t" \ 87 | ".long 0\n\t" \ 88 | ".long 0\n\t" \ 89 | ".long 0\n\t" \ 90 | ".long 0\n\t" \ 91 | ".long 0\n\t" \ 92 | \ 93 | ".long 0\n\t" \ 94 | ".long 0\n\t" \ 95 | ".long 0\n\t" \ 96 | ".long 0\n\t" \ 97 | ".long 0\n\t" \ 98 | ".long 0\n\t" \ 99 | ".long 0\n\t" \ 100 | ); 101 | 102 | #define GET_TEMPLATE_ADDERSS(s) \ 103 | ({ \ 104 | void *template; \ 105 | __asm__ volatile ( \ 106 | "addis %0,2,hook_"#s"_template@toc@ha\n\t" \ 107 | "addi %0,%0,hook_"#s"_template@toc@l\n\t": \ 108 | "=r"(template) \ 109 | ); \ 110 | template; \ 111 | }) 112 | 113 | #define GET_CODESPACE_ADDERSS(s) \ 114 | ({ \ 115 | void *codespace; \ 116 | __asm__ volatile ( \ 117 | "addis %0,2,"#s"_code_space@toc@ha\n\t" \ 118 | "addi %0,%0,"#s"_code_space@toc@l\n\t": \ 119 | "=r"(codespace) \ 120 | ); \ 121 | codespace; \ 122 | }) 123 | 124 | #define INSTRUCTION_SIZE 4 125 | #define HIJACK_INST_NUM 7 126 | #define HIJACK_SIZE (INSTRUCTION_SIZE * HIJACK_INST_NUM) 127 | #define fill_nop_for_target(x, y) (0) 128 | #define fill_nop_for_code_space(x, y) (0) 129 | /* 130 | 3 instrucions are saved for saving r2 and r0, we fill long jump start 131 | from an offset. see hijack_powerpc.c 132 | */ 133 | #define HOOK_TARGET_OFFSET (INSTRUCTION_SIZE * 3) 134 | // The real code filling area is 4 instrucions offset of #s"_code_space 135 | #define CODE_SPACE_OFFSET (INSTRUCTION_SIZE * 4) 136 | int init_arch(void); 137 | #endif -------------------------------------------------------------------------------- /linux/src/arch/x86/common.c: -------------------------------------------------------------------------------- 1 | ../x86_64/common.c -------------------------------------------------------------------------------- /linux/src/arch/x86/hijack_x86.c: -------------------------------------------------------------------------------- 1 | #include "hijack_x86.h" 2 | #include 3 | 4 | /* 5 | push %eax 6 | mov $addr, %eax 7 | jmp *%eax 8 | pop %eax 9 | */ 10 | const char long_jmp_code[9]="\x50\xb8\x00\x00\x00\x00\xff\xe0\x58"; 11 | 12 | inline void fill_long_jmp(void *fill_dest, void *hijack_to_func) 13 | { 14 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 15 | memcpy(fill_dest + 2, &hijack_to_func, sizeof(void *)); 16 | } -------------------------------------------------------------------------------- /linux/src/arch/x86/hijack_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOOK_X86_H_ 2 | #define _HOOK_X86_H_ 3 | 4 | #define HOOK_FUNC_TEMPLATE(s) \ 5 | extern void hook_##s##_template(void); \ 6 | asm ( \ 7 | ".globl hook_"#s"_template\n\t" \ 8 | "hook_"#s"_template:\n\t" \ 9 | "pop %eax\n\t" \ 10 | "jmp hook_"#s"\n\t" \ 11 | \ 12 | ".globl "#s"_code_space\n\t" \ 13 | #s"_code_space:\n\t" \ 14 | ".long 0\n\t" \ 15 | ".long 0\n\t" \ 16 | ".long 0\n\t" \ 17 | ".long 0\n\t" \ 18 | \ 19 | ".long 0\n\t" \ 20 | ".long 0\n\t" \ 21 | ".long 0\n\t" \ 22 | ".long 0\n\t" \ 23 | ); 24 | 25 | #define GET_TEMPLATE_ADDERSS(s) \ 26 | ({ \ 27 | void *template; \ 28 | __asm__ volatile ("mov $hook_"#s"_template, %0\n\t":"=r"(template)); \ 29 | template; \ 30 | }) 31 | 32 | #define GET_CODESPACE_ADDERSS(s) \ 33 | ({ \ 34 | void *codespace; \ 35 | __asm__ volatile ("mov $"#s"_code_space, %0\n\t":"=r"(codespace)); \ 36 | codespace; \ 37 | }) 38 | 39 | #define HIJACK_SIZE 16 40 | #define LONG_JMP_CODE_LEN 9 41 | int fill_nop_for_target(void *, void *); 42 | int fill_nop_for_code_space(void *, void *); 43 | int init_arch(void); 44 | #define HOOK_TARGET_OFFSET (0) 45 | #define CODE_SPACE_OFFSET (0) 46 | #define MAX_INSTRUCTIONS 10 47 | #endif -------------------------------------------------------------------------------- /linux/src/arch/x86_64/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "include/common_data.h" 11 | 12 | int (*insn_decode_ptr)(struct insn *, const void *, int, enum insn_mode) = NULL; 13 | 14 | extern int (*core_kernel_text_ptr)(unsigned long); 15 | extern bool (*is_module_text_address_ptr)(unsigned long); 16 | 17 | int disass_target(void *target) 18 | { 19 | struct insn insn; 20 | int off = 0, ret; 21 | 22 | while (off < LONG_JMP_CODE_LEN) { 23 | ret = insn_decode_ptr(&insn, target + off, MAX_INSN_SIZE, INSN_MODE_KERN); 24 | if (ret) 25 | return ret; 26 | off += insn.length; 27 | } 28 | return off; 29 | } 30 | 31 | /* \x90: nop */ 32 | int fill_nop_for_target(void *fill_dest, void *target) 33 | { 34 | int actual_len = disass_target(target); 35 | if (actual_len < 0) 36 | return actual_len; 37 | if (actual_len > HIJACK_SIZE) { 38 | printk(KERN_ALERT"Maybe long(>=%d) instructions encountered before %llx\n", 39 | HIJACK_SIZE - LONG_JMP_CODE_LEN, (u64)(target + actual_len)); 40 | return -1; 41 | } 42 | memset(fill_dest + LONG_JMP_CODE_LEN, '\x90', actual_len - LONG_JMP_CODE_LEN); 43 | return 0; 44 | } 45 | 46 | int fill_nop_for_code_space(void *fill_dest, void *target) 47 | { 48 | int actual_len = disass_target(target); 49 | if (actual_len < 0) 50 | return actual_len; 51 | if (actual_len > HIJACK_SIZE) { 52 | printk(KERN_ALERT"Maybe long(>=%d) instructions encountered before %llx\n", 53 | HIJACK_SIZE - LONG_JMP_CODE_LEN, (u64)(target + actual_len)); 54 | return -1; 55 | } 56 | memset(fill_dest + actual_len, '\x90', HIJACK_SIZE - actual_len); 57 | return 0; 58 | } 59 | 60 | /* skip the check */ 61 | bool check_target_can_hijack(void *target) 62 | { 63 | return true; 64 | } 65 | 66 | /* 67 | * Since we are inserting jump instrcutions, if we insert in kernel area(to jump out of kernel), 68 | * we should use phys_to_page(__pa(target)), if we insert in kernel_module(to jump back to kernel), 69 | * we should use vmalloc_to_page(target) instead 70 | */ 71 | int remap_write_range(void *target, void *source, int size) 72 | { 73 | struct page *page = NULL; 74 | void *new_target = NULL; 75 | 76 | if ((((unsigned long)target + size) ^ (unsigned long)target) & PAGE_MASK) { 77 | printk(KERN_ALERT"Try to write word across page boundary %p\n", target); 78 | return -EFAULT; 79 | } 80 | 81 | if (core_kernel_text_ptr((unsigned long)target)) { 82 | page = virt_to_page(target); 83 | } else if (is_module_text_address_ptr((unsigned long)target)) { 84 | page = vmalloc_to_page(target); 85 | } else { 86 | printk(KERN_ALERT"Try to write to non kernel text address %p\n", target); 87 | return -EFAULT; 88 | } 89 | 90 | if (!page) { 91 | printk(KERN_ALERT"Cannot get page of address %p\n", target); 92 | return -EFAULT; 93 | } 94 | 95 | new_target = vm_map_ram(&page, 1, -1); 96 | if (!new_target) { 97 | printk(KERN_ALERT"Remap address %p failed\n", target); 98 | return -EFAULT; 99 | } else { 100 | memcpy(new_target + ((unsigned long)target & (~ PAGE_MASK)), source, size); 101 | vm_unmap_ram(new_target, 1); 102 | flush_icache_range((unsigned long)target, (unsigned long)target + size); 103 | return 0; 104 | } 105 | } 106 | 107 | int hook_write_range(void *target, void *source, int size) 108 | { 109 | long ret = remap_write_range(target, source, size); 110 | return (int)ret; 111 | } 112 | 113 | int init_arch(void) { 114 | insn_decode_ptr = (void *)find_func("insn_decode"); 115 | return !insn_decode_ptr; 116 | } -------------------------------------------------------------------------------- /linux/src/arch/x86_64/hijack_x86_64.c: -------------------------------------------------------------------------------- 1 | #include "hijack_x86_64.h" 2 | #include 3 | 4 | /* 5 | push %rax 6 | movabs $addr, %rax 7 | jmp *%rax 8 | pop %rax 9 | */ 10 | const char long_jmp_code[14]="\x50\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0\x58"; 11 | 12 | inline void fill_long_jmp(void *fill_dest, void *hijack_to_func) 13 | { 14 | memcpy(fill_dest, long_jmp_code, sizeof(long_jmp_code)); 15 | memcpy(fill_dest + 3, &hijack_to_func, sizeof(void *)); 16 | } -------------------------------------------------------------------------------- /linux/src/arch/x86_64/hijack_x86_64.h: -------------------------------------------------------------------------------- 1 | #ifndef _HOOK_X86_64_H_ 2 | #define _HOOK_X86_64_H_ 3 | 4 | #define HOOK_FUNC_TEMPLATE(s) \ 5 | extern void hook_##s##_template(void); \ 6 | asm ( \ 7 | ".globl hook_"#s"_template\n\t" \ 8 | "hook_"#s"_template:\n\t" \ 9 | "pop %rax\n\t" \ 10 | "jmp hook_"#s"\n\t" \ 11 | \ 12 | ".globl "#s"_code_space\n\t" \ 13 | #s"_code_space:\n\t" \ 14 | ".long 0\n\t" \ 15 | ".long 0\n\t" \ 16 | ".long 0\n\t" \ 17 | ".long 0\n\t" \ 18 | ".long 0\n\t" \ 19 | ".long 0\n\t" \ 20 | \ 21 | ".long 0\n\t" \ 22 | ".long 0\n\t" \ 23 | ".long 0\n\t" \ 24 | ".long 0\n\t" \ 25 | ".long 0\n\t" \ 26 | ".long 0\n\t" \ 27 | ); 28 | 29 | #define GET_TEMPLATE_ADDERSS(s) \ 30 | ({ \ 31 | void *template; \ 32 | __asm__ volatile ("mov $hook_"#s"_template, %0\n\t":"=r"(template)); \ 33 | template; \ 34 | }) 35 | 36 | #define GET_CODESPACE_ADDERSS(s) \ 37 | ({ \ 38 | void *codespace; \ 39 | __asm__ volatile ("mov $"#s"_code_space, %0\n\t":"=r"(codespace)); \ 40 | codespace; \ 41 | }) 42 | 43 | #define HIJACK_SIZE 24 44 | #define LONG_JMP_CODE_LEN 14 45 | int fill_nop_for_target(void *, void *); 46 | int fill_nop_for_code_space(void *, void *); 47 | int init_arch(void); 48 | #define HOOK_TARGET_OFFSET (0) 49 | #define CODE_SPACE_OFFSET (0) 50 | #define MAX_INSTRUCTIONS 20 51 | #endif -------------------------------------------------------------------------------- /linux/src/framework/hijack_operation.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "include/common_data.h" 10 | 11 | extern int hook_write_range(void *, void *, int, bool); 12 | extern int stack_activeness_safety_check(unsigned long); 13 | extern void fill_long_jmp(void *, void *); 14 | extern bool check_target_can_hijack(void *); 15 | extern void (*save_stack_trace_tsk_ptr)(struct task_struct *, 16 | struct stack_trace *); 17 | 18 | DEFINE_HASHTABLE(all_hijack_targets, DEFAULT_HASH_BUCKET_BITS); 19 | static DECLARE_RWSEM(hijack_targets_hashtable_lock); 20 | int (*kallsyms_lookup_size_offset_ptr)(unsigned long, 21 | unsigned long *, unsigned long *) = NULL; 22 | static char name_buf[KSYM_NAME_LEN]; 23 | 24 | inline int fill_hook_template_code_space(void *hook_template_code_space, 25 | void *target_code, void *return_addr) 26 | { 27 | unsigned char tmp_code[HIJACK_SIZE * 2] = {0}; 28 | memcpy(tmp_code, target_code, HIJACK_SIZE); 29 | if (fill_nop_for_code_space(tmp_code, target_code)) { 30 | return -1; 31 | } 32 | fill_long_jmp(tmp_code + HIJACK_SIZE, return_addr); 33 | return hook_write_range(hook_template_code_space, tmp_code, sizeof(tmp_code), false); 34 | } 35 | 36 | struct do_hijack_struct { 37 | void *dest; 38 | void *source; 39 | }; 40 | 41 | int do_hijack_target(void *data) 42 | { 43 | void *dest = ((struct do_hijack_struct *)data)->dest; 44 | void *source = ((struct do_hijack_struct *)data)->source; 45 | int ret = 0; 46 | 47 | /*if CONFIG_STACKTRACE not enabled, skip stack safety check*/ 48 | if (!save_stack_trace_tsk_ptr) { 49 | return hook_write_range(dest, source, HIJACK_SIZE, true); 50 | } 51 | 52 | if (!(ret = stack_activeness_safety_check((unsigned long)dest))) { //no problem 53 | ret = hook_write_range(dest, source, HIJACK_SIZE, true); 54 | } 55 | return ret; 56 | } 57 | 58 | bool check_function_length_enough(void *target) 59 | { 60 | unsigned long symbolsize, offset; 61 | unsigned long pos; 62 | pos = (*kallsyms_lookup_size_offset_ptr)((unsigned long)target, &symbolsize, &offset); 63 | if (pos && symbolsize >= HIJACK_SIZE + offset) { 64 | return true; 65 | } else { 66 | return false; 67 | } 68 | } 69 | 70 | int show_all_hook_targets(struct seq_file *p, void *v) 71 | { 72 | int bkt; 73 | struct sym_hook *sa = NULL; 74 | struct hlist_node *tmp; 75 | 76 | down_read(&hijack_targets_hashtable_lock); 77 | hash_for_each_safe(all_hijack_targets, bkt, tmp, sa, node) { 78 | memset(p->private, 0, KSYM_NAME_LEN); 79 | sprint_symbol_no_offset((char *)(p->private), (unsigned long)(sa->target)); 80 | seq_printf(p, "%s %d\n", (char *)(p->private), sa->enabled); 81 | } 82 | up_read(&hijack_targets_hashtable_lock); 83 | return 0; 84 | } 85 | 86 | int hijack_target_prepare (void *target, void *hook_dest, void *hook_template_code_space) 87 | { 88 | struct sym_hook *sa = NULL; 89 | uint32_t ptr_hash; 90 | int ret = 0; 91 | 92 | target += HOOK_TARGET_OFFSET; 93 | ptr_hash = jhash_pointer(target); 94 | 95 | /*first, target function should longer than HIJACK_SIZE*/ 96 | if (!check_function_length_enough(target)) { 97 | printk(KERN_ALERT"%p short than hijack_size %d, cannot hijack...\n", target, HIJACK_SIZE); 98 | ret = -1; 99 | goto out; 100 | } 101 | 102 | /*second, not contain unhookable instructions*/ 103 | if (hook_template_code_space && !check_target_can_hijack(target)) { 104 | hook_template_code_space += CODE_SPACE_OFFSET; 105 | printk(KERN_ALERT"%p contains instruction which cannot hijack...\n", target); 106 | ret = -1; 107 | goto out; 108 | } 109 | 110 | /*third, target cannot repeat*/ 111 | down_read(&hijack_targets_hashtable_lock); 112 | hash_for_each_possible(all_hijack_targets, sa, node, ptr_hash) { 113 | if (target == sa->target) { 114 | up_read(&hijack_targets_hashtable_lock); 115 | printk(KERN_ALERT"%p has been prepared, skip...\n", target); 116 | ret = -1; 117 | goto out; 118 | } 119 | } 120 | up_read(&hijack_targets_hashtable_lock); 121 | 122 | /*check passed, now to allocation*/ 123 | sa = kmalloc(sizeof(*sa), GFP_KERNEL); 124 | if (!sa) { 125 | printk(KERN_ALERT"No enough memory to hijack %p\n", target); 126 | ret = -1; 127 | goto out; 128 | } 129 | 130 | sa->target = target; 131 | memcpy(sa->target_code, target, HIJACK_SIZE); 132 | sa->hook_dest = hook_dest; 133 | sa->hook_template_code_space = hook_template_code_space; 134 | sa->template_return_addr = target 135 | #ifdef _ARCH_ARM64_ 136 | + HIJACK_SIZE - 1 * INSTRUCTION_SIZE; 137 | #endif 138 | 139 | #ifdef _ARCH_ARM_ 140 | + HIJACK_SIZE; 141 | #endif 142 | 143 | #if defined(_ARCH_X86_64_) || defined(_ARCH_X86_) 144 | + LONG_JMP_CODE_LEN - 1; 145 | #endif 146 | 147 | #ifdef _ARCH_POWERPC_ 148 | + HIJACK_SIZE; 149 | #endif 150 | sa->enabled = false; 151 | 152 | down_write(&hijack_targets_hashtable_lock); 153 | hash_add(all_hijack_targets, &sa->node, ptr_hash); 154 | up_write(&hijack_targets_hashtable_lock); 155 | 156 | out: 157 | return ret; 158 | } 159 | EXPORT_SYMBOL(hijack_target_prepare); 160 | 161 | int hijack_target_enable(void *target) 162 | { 163 | struct sym_hook *sa; 164 | struct hlist_node *tmp; 165 | uint32_t ptr_hash; 166 | int ret = -1; 167 | unsigned char source_code[HIJACK_SIZE] = {0}; 168 | struct do_hijack_struct do_hijack_struct; 169 | 170 | target += HOOK_TARGET_OFFSET; 171 | ptr_hash = jhash_pointer(target); 172 | do_hijack_struct = (struct do_hijack_struct ) { 173 | .dest = target, 174 | .source = source_code, 175 | }; 176 | 177 | down_write(&hijack_targets_hashtable_lock); 178 | hash_for_each_possible_safe(all_hijack_targets, sa, tmp, node, ptr_hash) { 179 | if (sa->target == target) { 180 | if (sa->enabled == false) { 181 | if (sa->hook_template_code_space && fill_hook_template_code_space( 182 | sa->hook_template_code_space, sa->target_code, sa->template_return_addr)) { 183 | goto out; 184 | } 185 | memcpy(source_code, sa->target_code, HIJACK_SIZE); 186 | fill_long_jmp(source_code, sa->hook_dest); 187 | if ((ret = fill_nop_for_target(source_code, sa->target))) 188 | goto out; 189 | if (!(ret = stop_machine(do_hijack_target, &do_hijack_struct, NULL))) { 190 | sa->enabled = true; 191 | } 192 | } else { 193 | printk(KERN_ALERT"%p has been hijacked, skip...\n", sa->target); 194 | ret = 0; 195 | } 196 | goto out; 197 | } 198 | } 199 | printk(KERN_ALERT"%p not been prepared, skip...\n", target); 200 | out: 201 | up_write(&hijack_targets_hashtable_lock); 202 | 203 | return ret; 204 | } 205 | EXPORT_SYMBOL(hijack_target_enable); 206 | 207 | int hijack_target_disable(void *target, bool need_remove) 208 | { 209 | struct sym_hook *sa; 210 | struct hlist_node *tmp; 211 | uint32_t ptr_hash; 212 | int ret = -1; 213 | struct do_hijack_struct do_hijack_struct; 214 | 215 | target += HOOK_TARGET_OFFSET; 216 | ptr_hash = jhash_pointer(target); 217 | do_hijack_struct = (struct do_hijack_struct) { 218 | .dest = target 219 | }; 220 | 221 | down_write(&hijack_targets_hashtable_lock); 222 | hash_for_each_possible_safe(all_hijack_targets, sa, tmp, node, ptr_hash) { 223 | if (sa->target == target) { 224 | sprint_symbol_no_offset(name_buf, (unsigned long)(sa->target)); 225 | if (sa->enabled == true) { 226 | do_hijack_struct.source = sa->target_code; 227 | if (!(ret = stop_machine(do_hijack_target, &do_hijack_struct, NULL))) 228 | sa->enabled = false; 229 | } else { 230 | printk(KERN_ALERT"%s has been disabled\n", name_buf); 231 | ret = 0; 232 | } 233 | 234 | if (need_remove && !ret) { 235 | printk(KERN_ALERT"remove hijack target %s\n", name_buf); 236 | hash_del(&sa->node); 237 | kfree(sa); 238 | } 239 | goto out; 240 | } 241 | } 242 | printk(KERN_ALERT"%p not been prepared, skip...\n", target); 243 | out: 244 | up_write(&hijack_targets_hashtable_lock); 245 | 246 | return ret; 247 | } 248 | EXPORT_SYMBOL(hijack_target_disable); 249 | 250 | void hijack_target_disable_all(bool need_remove) 251 | { 252 | struct sym_hook *sa; 253 | struct hlist_node *tmp; 254 | int bkt; 255 | bool retry; 256 | struct do_hijack_struct do_hijack_struct; 257 | 258 | do { 259 | retry = false; 260 | down_write(&hijack_targets_hashtable_lock); 261 | hash_for_each_safe(all_hijack_targets, bkt, tmp, sa, node) { 262 | if (sa->enabled == true) { 263 | do_hijack_struct.dest = sa->target; 264 | do_hijack_struct.source = sa->target_code; 265 | if (stop_machine(do_hijack_target, &do_hijack_struct, NULL)) { 266 | retry = true; 267 | continue; 268 | } 269 | sa->enabled = false; 270 | } 271 | if (need_remove) { 272 | hash_del(&sa->node); 273 | kfree(sa); 274 | } 275 | } 276 | up_write(&hijack_targets_hashtable_lock); 277 | } while(retry && (msleep(1000), true)); 278 | 279 | printk(KERN_ALERT"all hijacked target disabled%s\n", need_remove ?" and removed":""); 280 | return; 281 | } 282 | EXPORT_SYMBOL(hijack_target_disable_all); 283 | 284 | /************************************************************************************/ 285 | 286 | int init_hijack_operation(void) 287 | { 288 | kallsyms_lookup_size_offset_ptr = find_func("kallsyms_lookup_size_offset"); 289 | if (kallsyms_lookup_size_offset_ptr) { 290 | return 0; 291 | } else { 292 | return -14; 293 | } 294 | } -------------------------------------------------------------------------------- /linux/src/framework/module.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | MODULE_AUTHOR("Liu Tao "); 4 | MODULE_LICENSE("GPL"); 5 | 6 | extern int init_kallsyms_lookup_func(void); 7 | extern int init_simplify_symbols_hook(void); 8 | extern void init_stack_safety_check(void); 9 | extern int init_hijack_operation(void); 10 | extern int init_write_map_page(void); 11 | extern int init_proc_interface(void); 12 | extern void remove_proc_interface(void); 13 | extern void hijack_target_disable_all(bool); 14 | 15 | static int __init hook_framework_init(void) 16 | { 17 | int ret = 0; 18 | ret = init_kallsyms_lookup_func(); 19 | if (ret) { 20 | goto out; 21 | } 22 | ret = init_write_map_page(); 23 | if (ret) { 24 | goto out; 25 | } 26 | init_stack_safety_check(); 27 | ret = init_hijack_operation(); 28 | if (ret) { 29 | goto out; 30 | } 31 | ret = init_proc_interface(); 32 | if (ret) { 33 | goto out; 34 | } 35 | ret = init_simplify_symbols_hook(); 36 | if (ret) { 37 | goto clean_proc; 38 | } 39 | printk(KERN_ALERT"load hook framework success!\n"); 40 | return ret; 41 | 42 | clean_proc: 43 | remove_proc_interface(); 44 | out: 45 | printk(KERN_ALERT"load hook framework fail!\n"); 46 | return ret; 47 | } 48 | 49 | static void __exit hook_framework_exit(void) 50 | { 51 | printk(KERN_ALERT"unload hook framework!\n"); 52 | hijack_target_disable_all(true); 53 | remove_proc_interface(); 54 | } 55 | 56 | module_init(hook_framework_init); 57 | module_exit(hook_framework_exit); -------------------------------------------------------------------------------- /linux/src/framework/proc_interface.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "include/common_data.h" 13 | 14 | extern int hijack_target_enable(void *); 15 | extern int hijack_target_disable(void *, bool); 16 | 17 | static ssize_t hook_targets_write(struct file *file, const char __user *buf, size_t count, loff_t *offp) 18 | { 19 | char *string_start, *sep, *val_start; 20 | long val; 21 | void *target; 22 | int ret; 23 | char *buffer = ((struct seq_file *)file->private_data)->private; 24 | 25 | memset(buffer, 0, KSYM_NAME_LEN); 26 | if (copy_from_user(buffer, buf, 27 | count > KSYM_NAME_LEN ? KSYM_NAME_LEN : count)) { 28 | return -EFAULT; 29 | } 30 | string_start = strim(buffer); 31 | if (!(sep = strnchr(string_start, KSYM_NAME_LEN, ' '))) { 32 | return -EFAULT; 33 | } 34 | *sep++ = '\0'; 35 | val_start = strim(sep); 36 | if (kstrtol(val_start, 10, &val) < 0) { 37 | return -EFAULT; 38 | } 39 | 40 | if (!(target = find_func(string_start))) { 41 | return -EFAULT; 42 | } 43 | 44 | switch (val) { 45 | case 0: 46 | ret = hijack_target_disable(target, false); 47 | break; 48 | case 1: 49 | ret = hijack_target_enable(target); 50 | break; 51 | default: 52 | return -EFAULT; 53 | } 54 | 55 | return ret < 0 ? -EFAULT : count; 56 | } 57 | 58 | extern int show_all_hook_targets(struct seq_file *, void *); 59 | 60 | static int hook_targets_open(struct inode *inode, struct file *file) 61 | { 62 | void *buffer = kzalloc(KSYM_NAME_LEN, GFP_KERNEL); 63 | if (!buffer) { 64 | return -ENOMEM; 65 | } 66 | return single_open(file, show_all_hook_targets, buffer); 67 | } 68 | 69 | static int hook_targets_release(struct inode *inode, struct file *file) 70 | { 71 | struct seq_file *sqf= (struct seq_file *)file->private_data; 72 | kfree(sqf->private); 73 | sqf->private = NULL; 74 | return single_release(inode, file); 75 | } 76 | 77 | static struct proc_ops proc_ops = { 78 | .proc_open = hook_targets_open, 79 | .proc_read = seq_read, 80 | .proc_lseek = seq_lseek, 81 | .proc_release = hook_targets_release, 82 | .proc_write = hook_targets_write, 83 | }; 84 | 85 | int init_proc_interface(void) 86 | { 87 | if (!proc_create("hook_targets", 0600, NULL, &proc_ops)) 88 | return -1; 89 | return 0; 90 | } 91 | 92 | void remove_proc_interface(void) 93 | { 94 | remove_proc_entry("hook_targets", NULL); 95 | } 96 | -------------------------------------------------------------------------------- /linux/src/framework/stack_safety_check.c: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_STACKTRACE 2 | #define CONFIG_STACKTRACE 3 | #endif 4 | #ifdef CONFIG_ARCH_STACKWALK 5 | #undef CONFIG_ARCH_STACKWALK 6 | #endif 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "include/common_data.h" 12 | 13 | #define MAC_STACK_TRACE_DEPTH 64 14 | void (*save_stack_trace_tsk_ptr)(struct task_struct *, 15 | struct stack_trace *) = NULL; 16 | 17 | static unsigned long stack_entries[MAC_STACK_TRACE_DEPTH]; 18 | static struct stack_trace trace = { 19 | .max_entries = ARRAY_SIZE(stack_entries), 20 | .entries = &stack_entries[0], 21 | }; 22 | 23 | inline int check_address_in_stack(unsigned long addr, unsigned long stack_addr) 24 | { 25 | if (stack_addr >= addr && stack_addr < addr + HIJACK_SIZE) { 26 | return -16; //EBUSY 27 | } 28 | return 0; 29 | } 30 | 31 | /* 32 | * referenced from https://github.com/dynup/kpatch/blob/master/kmod/core/core.c 33 | */ 34 | int stack_activeness_safety_check(unsigned long addr) 35 | { 36 | struct task_struct *g, *t; 37 | int ret = 0; 38 | int i; 39 | for_each_process_thread(g, t) { 40 | trace.nr_entries = 0; 41 | (*save_stack_trace_tsk_ptr)(t, &trace); 42 | if (trace.nr_entries >= trace.max_entries) { 43 | ret = -16; //EBUSY 44 | printk(KERN_ALERT"More than %d max trace entries!\n", trace.max_entries); 45 | goto out; 46 | } 47 | 48 | for (i = 0; i < trace.nr_entries; i++) { 49 | if (trace.entries[i] == ULONG_MAX) 50 | break; 51 | ret = check_address_in_stack(addr, trace.entries[i]); 52 | if (ret) 53 | goto out; 54 | } 55 | } 56 | 57 | out: 58 | if (ret) { 59 | printk(KERN_ALERT"PID: %d Comm: %.20s\n", t->pid, t->comm); 60 | for (i = 0; i < trace.nr_entries; i++) { 61 | if (trace.entries[i] == ULONG_MAX) 62 | break; 63 | printk(KERN_ALERT" [<%pK>] %pB\n", (void *)trace.entries[i], (void *)trace.entries[i]); 64 | } 65 | } 66 | return ret; 67 | } 68 | 69 | void init_stack_safety_check(void) 70 | { 71 | save_stack_trace_tsk_ptr = find_func("save_stack_trace_tsk"); 72 | if (!save_stack_trace_tsk_ptr) { 73 | printk(KERN_ALERT"Your kernel should be \"CONFIG_STACKTRACE && !CONFIG_ARCH_STACKWALK\", skip stack safety check and use as your risk!!!\n"); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /linux/src/framework/symbol_resolver.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | struct load_info { 16 | const char *name; 17 | /* pointer to module in temporary copy, freed at end of load_module() */ 18 | struct module *mod; 19 | Elf_Ehdr *hdr; 20 | unsigned long len; 21 | Elf_Shdr *sechdrs; 22 | char *secstrings, *strtab; 23 | unsigned long symoffs, stroffs, init_typeoffs, core_typeoffs; 24 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0) 25 | #if LINUX_VERSION_CODE < KERNEL_VERSION(6,4,0) 26 | struct _ddebug_info dyndbg; 27 | #endif 28 | #else 29 | struct _ddebug *debug; 30 | unsigned int num_debug; 31 | #endif 32 | bool sig_ok; 33 | 34 | #ifdef CONFIG_KALLSYMS 35 | unsigned long mod_kallsyms_init_off; 36 | #endif 37 | 38 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) 39 | #ifdef CONFIG_MODULE_DECOMPRESS 40 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,4,0) 41 | #ifdef CONFIG_MODULE_STATS 42 | unsigned long compressed_len; 43 | #endif 44 | #endif 45 | struct page **pages; 46 | unsigned int max_pages; 47 | unsigned int used_pages; 48 | #endif 49 | #endif 50 | struct { 51 | unsigned int sym, str, mod, vers, info, pcpu; 52 | } index; 53 | }; 54 | 55 | 56 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,5,0) 57 | struct kernel_symbol { 58 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 59 | int value_offset; 60 | int name_offset; 61 | int namespace_offset; 62 | #else 63 | unsigned long value; 64 | const char *name; 65 | const char *namespace; 66 | #endif 67 | }; 68 | #endif 69 | 70 | /******************************************************************************/ 71 | 72 | static const struct kernel_symbol *(*resolve_symbol_ptr)(struct module *, 73 | const struct load_info *, 74 | const char *, 75 | char []) = NULL; 76 | static struct wait_queue_head *module_wq_ptr = NULL; 77 | static unsigned long (*kallsyms_lookup_name_ptr)(const char *) = NULL; 78 | extern int hijack_target_prepare(void *, void *, void *); 79 | extern int hijack_target_enable(void *); 80 | 81 | void *find_func(const char *name) 82 | { 83 | void *ret = NULL; 84 | ret = (void *)kallsyms_lookup_name_ptr(name); 85 | if (!ret) { 86 | printk(KERN_ALERT"Symbol %s not found!\n", name); 87 | } 88 | return ret; 89 | } 90 | EXPORT_SYMBOL(find_func); 91 | 92 | /******************************************************************************/ 93 | 94 | static inline void __percpu *mod_percpu(struct module *mod) 95 | { 96 | #ifdef CONFIG_SMP 97 | return mod->percpu; 98 | #else 99 | return NULL; 100 | #endif 101 | } 102 | 103 | static const struct kernel_symbol * 104 | resolve_symbol_wait(struct module *mod, 105 | const struct load_info *info, 106 | const char *name) 107 | { 108 | const struct kernel_symbol *ksym; 109 | char owner[MODULE_NAME_LEN]; 110 | 111 | if (wait_event_interruptible_timeout(*module_wq_ptr, 112 | !IS_ERR(ksym = resolve_symbol_ptr(mod, info, name, owner)) 113 | || PTR_ERR(ksym) != -EBUSY, 114 | 30 * HZ) <= 0) { 115 | pr_warn("%s: gave up waiting for init of module %s.\n", 116 | mod->name, owner); 117 | } 118 | return ksym; 119 | } 120 | 121 | static inline unsigned long kernel_symbol_value(const struct kernel_symbol *sym) 122 | { 123 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 124 | return (unsigned long)offset_to_ptr(&sym->value_offset); 125 | #else 126 | return sym->value; 127 | #endif 128 | } 129 | 130 | static bool ignore_undef_symbol(Elf_Half emachine, const char *name) 131 | { 132 | /* 133 | * On x86, PIC code and Clang non-PIC code may have call foo@PLT. GNU as 134 | * before 2.37 produces an unreferenced _GLOBAL_OFFSET_TABLE_ on x86-64. 135 | * i386 has a similar problem but may not deserve a fix. 136 | * 137 | * If we ever have to ignore many symbols, consider refactoring the code to 138 | * only warn if referenced by a relocation. 139 | */ 140 | if (emachine == EM_386 || emachine == EM_X86_64) 141 | return !strcmp(name, "_GLOBAL_OFFSET_TABLE_"); 142 | return false; 143 | } 144 | 145 | int hook_simplify_symbols(struct module *mod, const struct load_info *info) 146 | { 147 | Elf_Shdr *symsec = &info->sechdrs[info->index.sym]; 148 | Elf_Sym *sym = (void *)symsec->sh_addr; 149 | unsigned long secbase; 150 | unsigned int i; 151 | int ret = 0; 152 | const struct kernel_symbol *ksym; 153 | 154 | for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) { 155 | const char *name = info->strtab + sym[i].st_name; 156 | 157 | switch (sym[i].st_shndx) { 158 | case SHN_COMMON: 159 | /* Ignore common symbols */ 160 | if (!strncmp(name, "__gnu_lto", 9)) 161 | break; 162 | 163 | /* 164 | * We compiled with -fno-common. These are not 165 | * supposed to happen. 166 | */ 167 | pr_debug("Common symbol: %s\n", name); 168 | pr_warn("%s: please compile with -fno-common\n", 169 | mod->name); 170 | ret = -ENOEXEC; 171 | break; 172 | 173 | case SHN_ABS: 174 | /* Don't need to do anything */ 175 | pr_debug("Absolute symbol: 0x%08lx %s\n", 176 | (long)sym[i].st_value, name); 177 | break; 178 | 179 | case SHN_LIVEPATCH: 180 | /* Livepatch symbols are resolved by livepatch */ 181 | break; 182 | 183 | case SHN_UNDEF: 184 | ksym = resolve_symbol_wait(mod, info, name); 185 | /* Ok if resolved. */ 186 | if (ksym && !IS_ERR(ksym)) { 187 | sym[i].st_value = kernel_symbol_value(ksym); 188 | break; 189 | } 190 | 191 | /* Ok if weak or ignored. */ 192 | if (!ksym && 193 | (ELF_ST_BIND(sym[i].st_info) == STB_WEAK || 194 | ignore_undef_symbol(info->hdr->e_machine, name))) 195 | break; 196 | 197 | ret = PTR_ERR(ksym) ?: -ENOENT; 198 | 199 | if (ret) { 200 | sym[i].st_value = (Elf_Addr)find_func(name); 201 | if (sym[i].st_value) { 202 | ret = 0; 203 | break; 204 | } 205 | } 206 | 207 | pr_warn("%s: Unknown symbol %s (err %d)\n", 208 | mod->name, name, ret); 209 | break; 210 | 211 | default: 212 | /* Divert to percpu allocation if a percpu var. */ 213 | if (sym[i].st_shndx == info->index.pcpu) 214 | secbase = (unsigned long)mod_percpu(mod); 215 | else 216 | secbase = info->sechdrs[sym[i].st_shndx].sh_addr; 217 | sym[i].st_value += secbase; 218 | break; 219 | } 220 | } 221 | 222 | return ret; 223 | } 224 | HOOK_FUNC_TEMPLATE(simplify_symbols); 225 | 226 | /******************************************************************************/ 227 | 228 | int init_kallsyms_lookup_func(void) 229 | { 230 | int ret; 231 | 232 | // First, we get kallsyms_lookup_name() 233 | struct kprobe kp = { 234 | .symbol_name = "kallsyms_lookup_name" 235 | }; 236 | 237 | ret = register_kprobe(&kp); 238 | if (ret < 0) { 239 | printk(KERN_ALERT"register_kprobe failed!\n"); 240 | goto out; 241 | } 242 | kallsyms_lookup_name_ptr = (void *)(kp.addr) - HOOK_TARGET_OFFSET; 243 | unregister_kprobe(&kp); 244 | ret = 0; 245 | out: 246 | return ret; 247 | } 248 | 249 | int init_simplify_symbols_hook(void) 250 | { 251 | void *simplify_symbols_ptr; 252 | 253 | resolve_symbol_ptr = find_func("resolve_symbol"); 254 | simplify_symbols_ptr = find_func("simplify_symbols"); 255 | module_wq_ptr = find_func("module_wq"); 256 | 257 | if (!resolve_symbol_ptr || !simplify_symbols_ptr || 258 | !module_wq_ptr) 259 | goto out; 260 | 261 | if (hijack_target_prepare(simplify_symbols_ptr, 262 | GET_TEMPLATE_ADDERSS(simplify_symbols), 263 | NULL)) { 264 | printk(KERN_ALERT"simplify_symbols prepare error!\n"); 265 | goto out; 266 | } 267 | if (hijack_target_enable(simplify_symbols_ptr)) { 268 | printk(KERN_ALERT"simplify_symbols enable error!\n"); 269 | goto out; 270 | } 271 | 272 | return 0; 273 | out: 274 | return -EFAULT; 275 | } -------------------------------------------------------------------------------- /linux/src/framework/symbol_resolver_bak.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | enum mod_license { 12 | NOT_GPL_ONLY, 13 | GPL_ONLY, 14 | }; 15 | 16 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(6,5,0) 17 | struct kernel_symbol { 18 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 19 | int value_offset; 20 | int name_offset; 21 | int namespace_offset; 22 | #else 23 | unsigned long value; 24 | const char *name; 25 | const char *namespace; 26 | #endif 27 | }; 28 | #endif 29 | 30 | struct symsearch { 31 | const struct kernel_symbol *start, *stop; 32 | const s32 *crcs; 33 | enum mod_license license; 34 | }; 35 | 36 | struct find_symbol_arg { 37 | /* Input */ 38 | const char *name; 39 | bool gplok; 40 | bool warn; 41 | 42 | /* Output */ 43 | struct module *owner; 44 | const s32 *crc; 45 | const struct kernel_symbol *sym; 46 | enum mod_license license; 47 | }; 48 | 49 | /******************************************************************************/ 50 | 51 | static struct symsearch arr[2]; 52 | static struct list_head *modules_ptr = NULL; 53 | static struct mutex *module_mutex_ptr = NULL; 54 | static bool (*find_exported_symbol_in_section_ptr)(const struct symsearch *, 55 | struct module *, 56 | struct find_symbol_arg *) = NULL; 57 | static unsigned long (*kallsyms_lookup_name_ptr)(const char *) = NULL; 58 | 59 | static DEFINE_HASHTABLE(ksyms_cache_hashtable, DEFAULT_HASH_BUCKET_BITS); 60 | static rwlock_t ksyms_cache_hashtable_lock; 61 | extern int hijack_target_prepare(void *, void *, void *); 62 | extern int hijack_target_enable(void *); 63 | static bool resolve_kallsyms_symbol(struct find_symbol_arg *); 64 | 65 | /******************************************************************************/ 66 | 67 | static inline void module_assert_mutex_or_preempt(void) 68 | { 69 | #ifdef CONFIG_LOCKDEP 70 | if (unlikely(!debug_locks)) 71 | return; 72 | 73 | WARN_ON_ONCE(!rcu_read_lock_sched_held() && 74 | !lockdep_is_held(module_mutex_ptr)); 75 | #endif 76 | } 77 | 78 | bool hook_find_symbol(struct find_symbol_arg *fsa) 79 | { 80 | struct module *mod; 81 | unsigned int i; 82 | 83 | module_assert_mutex_or_preempt(); 84 | 85 | for (i = 0; i < ARRAY_SIZE(arr); i++) 86 | if (find_exported_symbol_in_section_ptr(&arr[i], NULL, fsa)) 87 | return true; 88 | 89 | list_for_each_entry_rcu(mod, modules_ptr, list, 90 | lockdep_is_held(module_mutex_ptr)) { 91 | struct symsearch arr[] = { 92 | { mod->syms, mod->syms + mod->num_syms, mod->crcs, 93 | NOT_GPL_ONLY }, 94 | { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, 95 | mod->gpl_crcs, 96 | GPL_ONLY }, 97 | }; 98 | 99 | if (mod->state == MODULE_STATE_UNFORMED) 100 | continue; 101 | 102 | for (i = 0; i < ARRAY_SIZE(arr); i++) 103 | if (find_exported_symbol_in_section_ptr(&arr[i], mod, fsa)) 104 | return true; 105 | } 106 | 107 | if (resolve_kallsyms_symbol(fsa)) 108 | return true; 109 | 110 | pr_debug("Failed to find symbol %s\n", fsa->name); 111 | return false; 112 | } 113 | HOOK_FUNC_TEMPLATE(find_symbol); 114 | 115 | /******************************************************************************/ 116 | 117 | static void operate_ksyms_cache(uint32_t status) 118 | { 119 | int bkt; 120 | struct hlist_node *tmp; 121 | struct ksym_cache *ca; 122 | 123 | if (status & SHOW_KSYM_CACHE) { 124 | read_lock(&ksyms_cache_hashtable_lock); 125 | hash_for_each_safe(ksyms_cache_hashtable, bkt, tmp, ca, node) { 126 | printk(KERN_ALERT"ksyms_cache: %s, %p\n", ca->ksym_name, ca->ksym_addr); 127 | } 128 | read_unlock(&ksyms_cache_hashtable_lock); 129 | } 130 | 131 | if (status & CLEAN_ALL_KSYM_CACHE) { 132 | write_lock(&ksyms_cache_hashtable_lock); 133 | hash_for_each_safe(ksyms_cache_hashtable, bkt, tmp, ca, node) { 134 | hash_del(&ca->node); 135 | kfree(ca); 136 | } 137 | write_unlock(&ksyms_cache_hashtable_lock); 138 | } 139 | } 140 | 141 | static bool resolve_kallsyms_symbol(struct find_symbol_arg *fsa) 142 | { 143 | struct kernel_symbol *sym = NULL; 144 | void *sym_addr = NULL; 145 | struct ksym_cache *ca = NULL; 146 | uint32_t name_hash = jhash_string(fsa->name); 147 | 148 | //first, we lookup the cached hashtable 149 | read_lock(&ksyms_cache_hashtable_lock); 150 | hash_for_each_possible(ksyms_cache_hashtable, ca, node, name_hash) { 151 | if (!strncmp(fsa->name, ca->ksym_name, sizeof(ca->ksym_name))) { 152 | sym = (struct kernel_symbol *)ca; 153 | read_unlock(&ksyms_cache_hashtable_lock); 154 | goto success; 155 | } 156 | } 157 | read_unlock(&ksyms_cache_hashtable_lock); 158 | 159 | //second, we lookup the kallsyms 160 | sym_addr = (void *)kallsyms_lookup_name_ptr(fsa->name); 161 | if (!sym_addr) 162 | return false; 163 | 164 | ca = (struct ksym_cache *)kzalloc(sizeof(struct ksym_cache), GFP_KERNEL); 165 | if (!ca) { 166 | printk(KERN_ALERT"No memory cache allocated for %s\n", fsa->name); 167 | return false; 168 | } 169 | 170 | ca->ksym_addr = sym_addr; 171 | strncpy(ca->ksym_name, fsa->name, sizeof(ca->ksym_name)); 172 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 173 | ca->value_offset = (int)((unsigned long)sym_addr - (unsigned long)&ca->value_offset); 174 | ca->name_offset = (int)((unsigned long)ca->ksym_name - (unsigned long)&ca->name_offset); 175 | ca->namespace_offset = 0; 176 | #else 177 | ca->value = (unsigned long)sym_addr; 178 | ca->name = ca->ksym_name; 179 | ca->namespace = NULL; 180 | #endif 181 | 182 | //third, we insert the new cache into hashtable 183 | write_lock(&ksyms_cache_hashtable_lock); 184 | hash_add(ksyms_cache_hashtable, &ca->node, name_hash); 185 | write_unlock(&ksyms_cache_hashtable_lock); 186 | sym = (struct kernel_symbol *)ca; 187 | 188 | operate_ksyms_cache(SHOW_KSYM_CACHE); 189 | 190 | success: 191 | fsa->owner = NULL; 192 | fsa->crc = NULL; 193 | fsa->sym = sym; 194 | fsa->license = 0; 195 | return true; 196 | } 197 | 198 | void remove_symbol_resolver_cache(void) 199 | { 200 | operate_ksyms_cache(CLEAN_ALL_KSYM_CACHE); 201 | } 202 | 203 | void *find_func(const char *name) 204 | { 205 | void *ret = NULL; 206 | ret = (void *)kallsyms_lookup_name_ptr(name); 207 | if (!ret) { 208 | printk(KERN_ALERT"Symbol %s not found!\n", name); 209 | } 210 | return ret; 211 | } 212 | EXPORT_SYMBOL(find_func); 213 | 214 | int init_kallsyms_lookup_func(void) 215 | { 216 | int ret; 217 | 218 | // First, we get kallsyms_lookup_name() 219 | struct kprobe kp = { 220 | .symbol_name = "kallsyms_lookup_name" 221 | }; 222 | 223 | ret = register_kprobe(&kp); 224 | if (ret < 0) { 225 | printk(KERN_ALERT"register_kprobe failed!\n"); 226 | goto out; 227 | } 228 | kallsyms_lookup_name_ptr = (void *)(kp.addr) - HOOK_TARGET_OFFSET; 229 | unregister_kprobe(&kp); 230 | ret = 0; 231 | out: 232 | return ret; 233 | } 234 | 235 | int init_simplify_symbols_hook(void) 236 | { 237 | void *find_symbol_ptr; 238 | 239 | struct symsearch *__start___ksymtab_ptr = find_func("__start___ksymtab"); 240 | struct symsearch *__stop___ksymtab_ptr = find_func("__stop___ksymtab"); 241 | struct symsearch *__start___kcrctab_ptr = find_func("__start___kcrctab"); 242 | struct symsearch *__start___ksymtab_gpl_ptr = find_func("__start___ksymtab_gpl"); 243 | struct symsearch *__stop___ksymtab_gpl_ptr = find_func("__stop___ksymtab_gpl"); 244 | struct symsearch *__start___kcrctab_gpl_ptr = find_func("__start___kcrctab_gpl"); 245 | 246 | rwlock_init(&ksyms_cache_hashtable_lock); 247 | modules_ptr = find_func("modules"); 248 | module_mutex_ptr = find_func("module_mutex"); 249 | find_exported_symbol_in_section_ptr = find_func("find_exported_symbol_in_section"); 250 | 251 | if (!__start___ksymtab_ptr || !__stop___ksymtab_ptr || 252 | !__start___kcrctab_ptr || !__start___ksymtab_gpl_ptr || 253 | !__stop___ksymtab_gpl_ptr || !__start___kcrctab_gpl_ptr || 254 | !modules_ptr || !module_mutex_ptr || 255 | !find_exported_symbol_in_section_ptr) 256 | goto out; 257 | 258 | arr[0] = (struct symsearch){ (struct kernel_symbol *)__start___ksymtab_ptr, 259 | (struct kernel_symbol *)__stop___ksymtab_ptr, 260 | (s32 *)__start___kcrctab_ptr, NOT_GPL_ONLY }; 261 | arr[1] = (struct symsearch){ (struct kernel_symbol *)__start___ksymtab_gpl_ptr, 262 | (struct kernel_symbol *)__stop___ksymtab_gpl_ptr, 263 | (s32 *)__start___kcrctab_gpl_ptr, GPL_ONLY }; 264 | 265 | find_symbol_ptr = find_func("find_symbol"); 266 | 267 | if (!find_symbol_ptr) 268 | goto out; 269 | 270 | if (hijack_target_prepare(find_symbol_ptr, 271 | GET_TEMPLATE_ADDERSS(find_symbol), 272 | NULL)) { 273 | printk(KERN_ALERT"find_symbol prepare error!\n"); 274 | goto out; 275 | } 276 | if (hijack_target_enable(find_symbol_ptr)) { 277 | printk(KERN_ALERT"find_symbol enable error!\n"); 278 | goto out; 279 | } 280 | 281 | return 0; 282 | out: 283 | return -EFAULT; 284 | } 285 | -------------------------------------------------------------------------------- /linux/src/framework/write_map_page.c: -------------------------------------------------------------------------------- 1 | #include "include/common_data.h" 2 | 3 | void *_stext_ptr = NULL, *_etext_ptr = NULL, 4 | *_sinittext_ptr = NULL, *_einittext_ptr = NULL; 5 | 6 | int (*core_kernel_text_ptr)(unsigned long) = NULL; 7 | bool (*is_module_text_address_ptr)(unsigned long) = NULL; 8 | 9 | int init_kernel_text(unsigned long addr) 10 | { 11 | if (addr >= (unsigned long)_sinittext_ptr && 12 | addr < (unsigned long)_einittext_ptr) 13 | return 1; 14 | return 0; 15 | } 16 | 17 | int init_write_map_page(void) 18 | { 19 | int ret = -1; 20 | 21 | _stext_ptr = (void *)find_func("_stext"); 22 | _etext_ptr = (void *)find_func("_etext"); 23 | _sinittext_ptr = (void *)find_func("_sinittext"); 24 | _einittext_ptr = (void *)find_func("_einittext"); 25 | core_kernel_text_ptr = (void *)find_func("core_kernel_text"); 26 | is_module_text_address_ptr = (void *)find_func("is_module_text_address"); 27 | 28 | if (!(_stext_ptr && _etext_ptr && _sinittext_ptr && _einittext_ptr && 29 | core_kernel_text_ptr && is_module_text_address_ptr)) { 30 | goto out; 31 | } 32 | if (init_arch()) 33 | goto out; 34 | ret = 0; 35 | out: 36 | return ret; 37 | } -------------------------------------------------------------------------------- /linux/src/include/common_data.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_DATA_H_ 2 | #define _COMMON_DATA_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef _ARCH_ARM64_ 10 | #include "hijack_arm64.h" 11 | #include 12 | #endif 13 | 14 | #ifdef _ARCH_ARM_ 15 | #include "hijack_arm.h" 16 | #include 17 | #endif 18 | 19 | #ifdef _ARCH_X86_64_ 20 | #include "hijack_x86_64.h" 21 | #include 22 | #endif 23 | 24 | #ifdef _ARCH_X86_ 25 | #include "hijack_x86.h" 26 | #include 27 | #endif 28 | 29 | #ifdef _ARCH_POWERPC_ 30 | #include "hijack_powerpc.h" 31 | #include 32 | #endif 33 | 34 | #define DEFAULT_HASH_BUCKET_BITS 17 35 | 36 | #define jhash_pointer(pointer) jhash((&pointer), sizeof(pointer), 0x95279527) 37 | #define jhash_string(str) jhash((str), strlen(str), 0x12345678) 38 | 39 | struct ksym_cache { 40 | //Warning!!! don't put any thing here, we want to hack kernel_symbol, so that 41 | //struct kernel_symbol *sym_addr = (struct kernel_symbol *)ksym_cache_addr; 42 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS 43 | int value_offset; 44 | int name_offset; 45 | int namespace_offset; 46 | #else 47 | unsigned long value; 48 | const char *name; 49 | const char *namespace; 50 | #endif 51 | struct hlist_node node; 52 | void *ksym_addr; 53 | char ksym_name[KSYM_NAME_LEN]; 54 | }; 55 | 56 | struct sym_hook { 57 | void *target; 58 | void *hook_dest; 59 | void *template_return_addr; 60 | void *hook_template_code_space; 61 | bool enabled; 62 | struct hlist_node node; 63 | unsigned char target_code[HIJACK_SIZE]; 64 | }; 65 | 66 | void *find_func(const char *name); 67 | 68 | #define SHOW_KSYM_CACHE 1 69 | #define CLEAN_ALL_KSYM_CACHE (1 << 1) 70 | #endif -------------------------------------------------------------------------------- /linux/src/prevermagic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RELATE_UTSRELEASE="include/generated/utsrelease.h" 4 | UTSRELEASE=$1/$RELATE_UTSRELEASE 5 | 6 | if [ ! -e $UTSRELEASE ]; then 7 | echo "error! $UTSRELEASE not exist" 8 | exit 1 9 | fi 10 | 11 | str_len=${#2} 12 | padding="" 13 | 14 | for (( i=0; i<=$str_len; i++ )) 15 | do 16 | padding="X"$padding 17 | done 18 | 19 | line=`wc -l $UTSRELEASE | awk -F ' ' '{print $1}'` 20 | 21 | cp $UTSRELEASE $UTSRELEASE.bak 22 | cat $UTSRELEASE.bak | awk -v pad=$padding -v line=$line -F '"' \ 23 | '{if(NR==line){printf("%s \"%s%s\"", $1, pad, $2)}else{print $0}}' > $UTSRELEASE 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Overview # 2 | 3 | ## News 4 | 5 | 1) FreeBSD on x86_64/arm64 support 6 | 7 | ## Introduction ## 8 | 9 | Usually we want to hack a kernel function, 10 | 11 | 1) to insert customized code before or after a certain kernel function been called, or 12 | 13 | 2) to totally replace a function with new one. 14 | 15 | How can we manage that? Well it's time to bring inline hook technique to kernel space. By replacing the first few instructions of a specific function to conditionless jump, and store the original instructions to a trampoline function, we can customizing the functions calling, and do whatever we want do in the hook function. Isn't is exciting? 16 | 17 | ## Usage ## 18 | 19 | #### Dev ##### 20 | 21 | There will be 2 kernel modules: 22 | 23 | 1) linux/src/: The hook framework itself. In normal cases, you needn't modify its code, unless you are trying to fix bug, because we want to keep it as simple and independent to any customization. After compile, you will get hookFrame.ko. 24 | 25 | 2) linux/sample/: The customized hook/replacement functions. Write your code here, and you can take hook_vfs_read.c, replace_vfs_open.c as reference when writing your own function. Also in module.c, you can get a general view of how to register your function to hook framework. After compile, hookFrameTest.ko will be generated. 26 | 27 | Sometimes you will find the vermagic of hookFrame.ko and hookFrameTest.ko different from your target kernel. You can pass the target kernel's vermagic string to make: 28 | 29 | ``` 30 | # For example: 31 | $ sudo apt-get install bbe # install bbe to modify vermagic string within .ko 32 | $ make arm64 KDIR=/opt/linux-4.14.98 CROSS_COMPILE=aarch64-linux-android- vermagic="4.14.98 SMP preempt mod_unload modversions aarch64" 33 | ``` 34 | 35 | #### Runtime ##### 36 | Insert hookFrame.ko first, then insert hookFrameTest.ko. If success, you can see list of currently reading files, and strings as "in replaced vfs_open", which indicating the original kernel vfs_open and vfs_read has been hooked. 37 | 38 | you can rmmod hookFrameTest.ko, to restore the original state. Also you can find a file: /proc/hook_targets. When cat the file, you can view the currently hooked functions list, and it's status(0 disabled, 1 enabled). You can also call the following command to change hook targets status: 39 | 40 | ``` 41 | $ echo "vfs_read 0" > /proc/hook_targets # disable vfs_read hooking 42 | $ echo "vfs_read 1" > /proc/hook_targets # enable vfs_read hooking 43 | ``` 44 | 45 | ## Usecase ## 46 | This hook framework can help kernel developers to modify a specific function on 47 | live(a simplified livepatch ^_^), so we can insert our customized code to it as a 48 | quick experiment. This is extremely useful when we don't want to spend a few hours 49 | of new kernel source compiling. 50 | 51 | E.g, a quick way to change: 52 | 53 | ``` 54 | int target_function(const struct path *path, struct file *file) 55 | { 56 | file->f_path = *path; 57 | return dependent_func_1(file, dependent_func_2(path->dentry), NULL); 58 | } 59 | ``` 60 | 61 | into: 62 | 63 | ``` 64 | int target_function(const struct path *path, struct file *file) 65 | { 66 | printk(KERN_ALERT"%lx %lx", (unsigned long)path, (unsigned long)file); 67 | file->f_path = *path; 68 | return dependent_func_1(file, dependent_func_2(path->dentry), NULL); 69 | } 70 | ``` 71 | 72 | However using the hook framework is not as easy, it can be frustrating to identify 73 | and copy a lot of function dependencies. E.g, in order to make new target_function 74 | work in the hook framework, it may look like this, assuming dependent_func_1 and 75 | dependent_func_2 are not exported by EXPORT_SYMBOL() and friends, and can be found 76 | in "/proc/kallsyms": 77 | 78 | ``` 79 | struct inode *(*dependent_func_2_ptr) 80 | (const struct dentry *upper) = find_func("dependent_func_2"); 81 | 82 | int (*dependent_func_1_ptr)( 83 | struct file *f, 84 | struct inode *inode, 85 | int (*open)(struct inode *, struct file *)) = find_func("dependent_func_1"); 86 | 87 | HOOK_FUNC_TEMPLATE(target_function); 88 | int hook_target_function(const struct path *path, struct file *file) 89 | { 90 | printk(KERN_ALERT"%lx %lx", (unsigned long)path, (unsigned long)file); 91 | file->f_path = *path; 92 | return dependent_func_1_ptr(file, dependent_func_2_ptr(path->dentry), NULL); 93 | } 94 | ``` 95 | 96 | In order to make hook_target_function work, all dependent functions need to be 97 | changed and imported. If target_function have more dependent funcions, the recursive 98 | work can be tough and boring. To make the work easier, we now can use it this way, 99 | target_function is left unchanged, and less dependent functions will be copied into: 100 | 101 | ``` 102 | extern struct inode *dependent_func_2(const struct dentry *upper); 103 | 104 | extern int dependent_func_1( 105 | struct file *f, 106 | struct inode *inode, 107 | int (*open)(struct inode *, struct file *)); 108 | 109 | HOOK_FUNC_TEMPLATE(target_function); 110 | int hook_target_function(const struct path *path, struct file *file) 111 | { 112 | printk(KERN_ALERT"%lx %lx", (unsigned long)path, (unsigned long)file); 113 | file->f_path = *path; 114 | return dependent_func_1(file, dependent_func_2(path->dentry), NULL); 115 | } 116 | ``` 117 | 118 | That's because the symbol resolve function is hacked(see src/framework/ 119 | symbol_resolver.c). Previously only the EXPORT_SYMBOL symbols can be resolved in 120 | kernel modules, now all kallsyms symbols can be resolved. You can use kallsyms 121 | symbols just like EXPORT_SYMBOL symbols in hookFrameTest ko. 122 | 123 | ## Limits ## 124 | I have tested the code in fedora38(arm64 and x86_64). Since there is no redhat 125 | option in 32bit, so 32bit is not tested. In addition, please check if there is 126 | "simplify_symbols" in /proc/kallsyms. If yes, then the code can be built and 127 | run directly. If no, please pass HAS_NO_SIMPLIFY_SYMBOLS=1 to make when built: 128 | 129 | ``` 130 | make HAS_NO_SIMPLIFY_SYMBOLS=1 ... 131 | ``` 132 | 133 | Currently it support arm32, arm64, x86 and x86_64. 134 | 135 | In addition, in order to make hook framework work properly, target kernel's configuration CONFIG_KALLSYMS and CONFIG_KPROBES is a must. 136 | 137 | ## Bugs ## 138 | Please report any bugs to me: liutgnu@gmail.com, also any contributions are welcomed. Happy hacking!!! 139 | 140 | ## Demo ## 141 | ![demo](demo.gif) 142 | 143 | ## Coffee ## 144 | 145 | A cup of coffee can make me code faster. 146 | 147 | 148 | 149 | 150 | 151 | 152 |

Coffee me on PayPal

153 | --------------------------------------------------------------------------------