├── README.md ├── bins ├── EasyAntiCheat.sys └── README.md └── hierarchy-eac ├── context.asm ├── eac.cpp ├── eac.hpp ├── hde64.cpp ├── hde64.hpp ├── hierarchy-eac.inf ├── hierarchy-eac.vcxproj ├── hierarchy-eac.vcxproj.filters ├── hierarchy-eac.vcxproj.user ├── main.cpp ├── stdafx.hpp ├── table64.hpp ├── utils.cpp ├── utils.hpp ├── vm.cpp └── vm.hpp /README.md: -------------------------------------------------------------------------------- 1 | # hierarchy-eac 2 | Bypassing EasyAntiCheat.sys self-integrity by abusing call hierarchy 3 | 4 | # Writeup 5 | Full write up can be found [here](https://bright.engineer/posts/easyanticheat-integrity/) 6 | -------------------------------------------------------------------------------- /bins/EasyAntiCheat.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sinclairq/hierarchy-eac/bbdd77f223d9b20123a781a0009be0f86bd09eda/bins/EasyAntiCheat.sys -------------------------------------------------------------------------------- /bins/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /hierarchy-eac/context.asm: -------------------------------------------------------------------------------- 1 | .code 2 | 3 | extern is_reloc:proc 4 | vm_is_reloc PROC 5 | 6 | push rax 7 | push rcx 8 | push rbx 9 | push rdx 10 | push rsi 11 | push rdi 12 | push r8 13 | push r9 14 | push r10 15 | push r11 16 | push r12 17 | push r13 18 | push r14 19 | push r15 20 | 21 | mov rcx, rsp 22 | pushfq 23 | 24 | sub rsp, 20h 25 | call is_reloc 26 | add rsp, 20h 27 | 28 | popfq 29 | 30 | pop r15 31 | pop r14 32 | pop r13 33 | pop r12 34 | pop r11 35 | pop r10 36 | pop r9 37 | pop r8 38 | pop rdi 39 | pop rsi 40 | pop rdx 41 | pop rbx 42 | pop rcx 43 | pop rax 44 | 45 | ret 46 | 47 | vm_is_reloc ENDP 48 | END 49 | -------------------------------------------------------------------------------- /hierarchy-eac/eac.cpp: -------------------------------------------------------------------------------- 1 | #include "eac.hpp" 2 | 3 | uint8_t *eac_instance_t::get_image_base() 4 | { 5 | return static_cast( image_base ); 6 | } 7 | 8 | uint32_t eac_instance_t::get_img_size() 9 | { 10 | return image_size; 11 | } 12 | 13 | uint8_t *eac_instance_t::get_raw_image() 14 | { 15 | return static_cast( image_copy ); 16 | } 17 | 18 | bool eac_instance_t::mem_in_bounds( uint8_t *address ) 19 | { 20 | if ( address >= get_image_base() && address <= &get_image_base()[get_img_size()] ) 21 | return true; 22 | 23 | return false; 24 | } 25 | 26 | bool eac_instance_t::mem_in_scn( uint8_t *address, uint32_t scn_type ) 27 | { 28 | const auto rva = address - static_cast( image_base ); 29 | const auto scn_headers = IMAGE_FIRST_SECTION( nt_headers ); 30 | 31 | for ( auto i = 0U; i < nt_headers->FileHeader.NumberOfSections; ++i ) 32 | { 33 | const auto *c_section = &scn_headers[i]; 34 | if ( !( c_section->Characteristics & scn_type ) ) 35 | continue; 36 | 37 | if ( rva >= c_section->VirtualAddress && 38 | rva <= static_cast( c_section->VirtualAddress ) + c_section->Misc.VirtualSize ) 39 | return true; 40 | } 41 | 42 | return false; 43 | } 44 | 45 | PIMAGE_NT_HEADERS eac_instance_t::get_nt_headers() 46 | { 47 | return this->nt_headers; 48 | } 49 | 50 | void eac_instance_t::init( void *base, uint32_t size ) 51 | { 52 | image_base = base; 53 | image_size = size; 54 | 55 | if ( !image_base || !image_size ) 56 | return; 57 | 58 | image_copy = ExAllocatePool( NonPagedPoolNx, image_size ); 59 | if ( !image_copy ) 60 | return; 61 | 62 | memcpy( image_copy, image_base, image_size ); 63 | nt_headers = utils::get_nt_headers( reinterpret_cast( image_base ) ); 64 | } 65 | -------------------------------------------------------------------------------- /hierarchy-eac/eac.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.hpp" 3 | 4 | class eac_instance_t 5 | { 6 | private: 7 | void *image_base = 0; 8 | void *image_copy = 0; 9 | 10 | uint32_t image_size = 0; 11 | 12 | PIMAGE_NT_HEADERS nt_headers = 0; 13 | 14 | public: 15 | uint8_t *get_image_base(); 16 | uint8_t *get_raw_image(); 17 | uint32_t get_img_size(); 18 | 19 | PIMAGE_NT_HEADERS get_nt_headers(); 20 | 21 | bool mem_in_bounds( uint8_t *address ); 22 | bool mem_in_scn( uint8_t *address, uint32_t scn_type ); 23 | 24 | void init( void *base, uint32_t size ); 25 | }; 26 | -------------------------------------------------------------------------------- /hierarchy-eac/hde64.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #include "hde64.hpp" 9 | #include "table64.hpp" 10 | #include 11 | 12 | unsigned int hde64_disasm( const void *code, hde64s *hs ) 13 | { 14 | uint8_t x, c, *p = ( uint8_t * )code, cflags, opcode, pref = 0; 15 | uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0; 16 | uint8_t op64 = 0; 17 | 18 | memset( hs, 0, sizeof( hde64s ) ); 19 | 20 | for ( x = 16; x; x-- ) 21 | switch ( c = *p++ ) 22 | { 23 | case 0xf3: 24 | hs->p_rep = c; 25 | pref |= PRE_F3; 26 | break; 27 | case 0xf2: 28 | hs->p_rep = c; 29 | pref |= PRE_F2; 30 | break; 31 | case 0xf0: 32 | hs->p_lock = c; 33 | pref |= PRE_LOCK; 34 | break; 35 | case 0x26: 36 | case 0x2e: 37 | case 0x36: 38 | case 0x3e: 39 | case 0x64: 40 | case 0x65: 41 | hs->p_seg = c; 42 | pref |= PRE_SEG; 43 | break; 44 | case 0x66: 45 | hs->p_66 = c; 46 | pref |= PRE_66; 47 | break; 48 | case 0x67: 49 | hs->p_67 = c; 50 | pref |= PRE_67; 51 | break; 52 | default: 53 | goto pref_done; 54 | } 55 | pref_done: 56 | 57 | hs->flags = ( uint32_t )pref << 23; 58 | 59 | if ( !pref ) 60 | pref |= PRE_NONE; 61 | 62 | if ( ( c & 0xf0 ) == 0x40 ) 63 | { 64 | hs->flags |= F_PREFIX_REX; 65 | if ( ( hs->rex_w = ( c & 0xf ) >> 3 ) && ( *p & 0xf8 ) == 0xb8 ) 66 | op64++; 67 | hs->rex_r = ( c & 7 ) >> 2; 68 | hs->rex_x = ( c & 3 ) >> 1; 69 | hs->rex_b = c & 1; 70 | if ( ( ( c = *p++ ) & 0xf0 ) == 0x40 ) 71 | { 72 | opcode = c; 73 | goto error_opcode; 74 | } 75 | } 76 | 77 | if ( ( hs->opcode = c ) == 0x0f ) 78 | { 79 | hs->opcode2 = c = *p++; 80 | ht += DELTA_OPCODES; 81 | } 82 | else if ( c >= 0xa0 && c <= 0xa3 ) 83 | { 84 | op64++; 85 | if ( pref & PRE_67 ) 86 | pref |= PRE_66; 87 | else 88 | pref &= ~PRE_66; 89 | } 90 | 91 | opcode = c; 92 | cflags = ht[ ht[ opcode / 4 ] + ( opcode % 4 ) ]; 93 | 94 | if ( cflags == C_ERROR ) 95 | { 96 | error_opcode: 97 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 98 | cflags = 0; 99 | if ( ( opcode & -3 ) == 0x24 ) 100 | cflags++; 101 | } 102 | 103 | x = 0; 104 | if ( cflags & C_GROUP ) 105 | { 106 | uint16_t t; 107 | t = *( uint16_t * )( ht + ( cflags & 0x7f ) ); 108 | cflags = ( uint8_t )t; 109 | x = ( uint8_t )( t >> 8 ); 110 | } 111 | 112 | if ( hs->opcode2 ) 113 | { 114 | ht = hde64_table + DELTA_PREFIXES; 115 | if ( ht[ ht[ opcode / 4 ] + ( opcode % 4 ) ] & pref ) 116 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 117 | } 118 | 119 | if ( cflags & C_MODRM ) 120 | { 121 | hs->flags |= F_MODRM; 122 | hs->modrm = c = *p++; 123 | hs->modrm_mod = m_mod = c >> 6; 124 | hs->modrm_rm = m_rm = c & 7; 125 | hs->modrm_reg = m_reg = ( c & 0x3f ) >> 3; 126 | 127 | if ( x && ( ( x << m_reg ) & 0x80 ) ) 128 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 129 | 130 | if ( !hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf ) 131 | { 132 | uint8_t t = opcode - 0xd9; 133 | if ( m_mod == 3 ) 134 | { 135 | ht = hde64_table + DELTA_FPU_MODRM + t * 8; 136 | t = ht[ m_reg ] << m_rm; 137 | } 138 | else 139 | { 140 | ht = hde64_table + DELTA_FPU_REG; 141 | t = ht[ t ] << m_reg; 142 | } 143 | if ( t & 0x80 ) 144 | hs->flags |= F_ERROR | F_ERROR_OPCODE; 145 | } 146 | 147 | if ( pref & PRE_LOCK ) 148 | { 149 | if ( m_mod == 3 ) 150 | { 151 | hs->flags |= F_ERROR | F_ERROR_LOCK; 152 | } 153 | else 154 | { 155 | uint8_t *table_end, op = opcode; 156 | if ( hs->opcode2 ) 157 | { 158 | ht = hde64_table + DELTA_OP2_LOCK_OK; 159 | table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; 160 | } 161 | else 162 | { 163 | ht = hde64_table + DELTA_OP_LOCK_OK; 164 | table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; 165 | op &= -2; 166 | } 167 | for ( ; ht != table_end; ht++ ) 168 | if ( *ht++ == op ) 169 | { 170 | if ( !( ( *ht << m_reg ) & 0x80 ) ) 171 | goto no_lock_error; 172 | else 173 | break; 174 | } 175 | hs->flags |= F_ERROR | F_ERROR_LOCK; 176 | no_lock_error:; 177 | } 178 | } 179 | 180 | if ( hs->opcode2 ) 181 | { 182 | switch ( opcode ) 183 | { 184 | case 0x20: 185 | case 0x22: 186 | m_mod = 3; 187 | if ( m_reg > 4 || m_reg == 1 ) 188 | goto error_operand; 189 | else 190 | goto no_error_operand; 191 | case 0x21: 192 | case 0x23: 193 | m_mod = 3; 194 | if ( m_reg == 4 || m_reg == 5 ) 195 | goto error_operand; 196 | else 197 | goto no_error_operand; 198 | } 199 | } 200 | else 201 | { 202 | switch ( opcode ) 203 | { 204 | case 0x8c: 205 | if ( m_reg > 5 ) 206 | goto error_operand; 207 | else 208 | goto no_error_operand; 209 | case 0x8e: 210 | if ( m_reg == 1 || m_reg > 5 ) 211 | goto error_operand; 212 | else 213 | goto no_error_operand; 214 | } 215 | } 216 | 217 | if ( m_mod == 3 ) 218 | { 219 | uint8_t *table_end; 220 | if ( hs->opcode2 ) 221 | { 222 | ht = hde64_table + DELTA_OP2_ONLY_MEM; 223 | table_end = ht + sizeof( hde64_table ) - DELTA_OP2_ONLY_MEM; 224 | } 225 | else 226 | { 227 | ht = hde64_table + DELTA_OP_ONLY_MEM; 228 | table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; 229 | } 230 | for ( ; ht != table_end; ht += 2 ) 231 | if ( *ht++ == opcode ) 232 | { 233 | if ( *ht++ & pref && !( ( *ht << m_reg ) & 0x80 ) ) 234 | goto error_operand; 235 | else 236 | break; 237 | } 238 | goto no_error_operand; 239 | } 240 | else if ( hs->opcode2 ) 241 | { 242 | switch ( opcode ) 243 | { 244 | case 0x50: 245 | case 0xd7: 246 | case 0xf7: 247 | if ( pref & ( PRE_NONE | PRE_66 ) ) 248 | goto error_operand; 249 | break; 250 | case 0xd6: 251 | if ( pref & ( PRE_F2 | PRE_F3 ) ) 252 | goto error_operand; 253 | break; 254 | case 0xc5: 255 | goto error_operand; 256 | } 257 | goto no_error_operand; 258 | } 259 | else 260 | goto no_error_operand; 261 | 262 | error_operand: 263 | hs->flags |= F_ERROR | F_ERROR_OPERAND; 264 | no_error_operand: 265 | 266 | c = *p++; 267 | if ( m_reg <= 1 ) 268 | { 269 | if ( opcode == 0xf6 ) 270 | cflags |= C_IMM8; 271 | else if ( opcode == 0xf7 ) 272 | cflags |= C_IMM_P66; 273 | } 274 | 275 | switch ( m_mod ) 276 | { 277 | case 0: 278 | if ( pref & PRE_67 ) 279 | { 280 | if ( m_rm == 6 ) 281 | disp_size = 2; 282 | } 283 | else if ( m_rm == 5 ) 284 | disp_size = 4; 285 | break; 286 | case 1: 287 | disp_size = 1; 288 | break; 289 | case 2: 290 | disp_size = 2; 291 | if ( !( pref & PRE_67 ) ) 292 | disp_size <<= 1; 293 | } 294 | 295 | if ( m_mod != 3 && m_rm == 4 ) 296 | { 297 | hs->flags |= F_SIB; 298 | p++; 299 | hs->sib = c; 300 | hs->sib_scale = c >> 6; 301 | hs->sib_index = ( c & 0x3f ) >> 3; 302 | if ( ( hs->sib_base = c & 7 ) == 5 && !( m_mod & 1 ) ) 303 | disp_size = 4; 304 | } 305 | 306 | p--; 307 | switch ( disp_size ) 308 | { 309 | case 1: 310 | hs->flags |= F_DISP8; 311 | hs->disp.disp8 = *p; 312 | break; 313 | case 2: 314 | hs->flags |= F_DISP16; 315 | hs->disp.disp16 = *( uint16_t * )p; 316 | break; 317 | case 4: 318 | hs->flags |= F_DISP32; 319 | hs->disp.disp32 = *( uint32_t * )p; 320 | } 321 | p += disp_size; 322 | } 323 | else if ( pref & PRE_LOCK ) 324 | hs->flags |= F_ERROR | F_ERROR_LOCK; 325 | 326 | if ( cflags & C_IMM_P66 ) 327 | { 328 | if ( cflags & C_REL32 ) 329 | { 330 | if ( pref & PRE_66 ) 331 | { 332 | hs->flags |= F_IMM16 | F_RELATIVE; 333 | hs->imm.imm16 = *( uint16_t * )p; 334 | p += 2; 335 | goto disasm_done; 336 | } 337 | goto rel32_ok; 338 | } 339 | if ( op64 ) 340 | { 341 | hs->flags |= F_IMM64; 342 | hs->imm.imm64 = *( uint64_t * )p; 343 | p += 8; 344 | } 345 | else if ( !( pref & PRE_66 ) ) 346 | { 347 | hs->flags |= F_IMM32; 348 | hs->imm.imm32 = *( uint32_t * )p; 349 | p += 4; 350 | } 351 | else 352 | goto imm16_ok; 353 | } 354 | 355 | if ( cflags & C_IMM16 ) 356 | { 357 | imm16_ok: 358 | hs->flags |= F_IMM16; 359 | hs->imm.imm16 = *( uint16_t * )p; 360 | p += 2; 361 | } 362 | if ( cflags & C_IMM8 ) 363 | { 364 | hs->flags |= F_IMM8; 365 | hs->imm.imm8 = *p++; 366 | } 367 | 368 | if ( cflags & C_REL32 ) 369 | { 370 | rel32_ok: 371 | hs->flags |= F_IMM32 | F_RELATIVE; 372 | hs->imm.imm32 = *( uint32_t * )p; 373 | p += 4; 374 | } 375 | else if ( cflags & C_REL8 ) 376 | { 377 | hs->flags |= F_IMM8 | F_RELATIVE; 378 | hs->imm.imm8 = *p++; 379 | } 380 | 381 | disasm_done: 382 | 383 | if ( ( hs->len = ( uint8_t )( p - ( uint8_t * )code ) ) > 15 ) 384 | { 385 | hs->flags |= F_ERROR | F_ERROR_LENGTH; 386 | hs->len = 15; 387 | } 388 | 389 | return ( unsigned int )hs->len; 390 | } 391 | -------------------------------------------------------------------------------- /hierarchy-eac/hde64.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | * hde64.h: C/C++ header file 7 | * 8 | */ 9 | 10 | #ifndef _HDE64_H_ 11 | #define _HDE64_H_ 12 | 13 | #pragma once 14 | #include "stdafx.hpp" 15 | 16 | #define F_MODRM 0x00000001 17 | #define F_SIB 0x00000002 18 | #define F_IMM8 0x00000004 19 | #define F_IMM16 0x00000008 20 | #define F_IMM32 0x00000010 21 | #define F_IMM64 0x00000020 22 | #define F_DISP8 0x00000040 23 | #define F_DISP16 0x00000080 24 | #define F_DISP32 0x00000100 25 | #define F_RELATIVE 0x00000200 26 | #define F_ERROR 0x00001000 27 | #define F_ERROR_OPCODE 0x00002000 28 | #define F_ERROR_LENGTH 0x00004000 29 | #define F_ERROR_LOCK 0x00008000 30 | #define F_ERROR_OPERAND 0x00010000 31 | #define F_PREFIX_REPNZ 0x01000000 32 | #define F_PREFIX_REPX 0x02000000 33 | #define F_PREFIX_REP 0x03000000 34 | #define F_PREFIX_66 0x04000000 35 | #define F_PREFIX_67 0x08000000 36 | #define F_PREFIX_LOCK 0x10000000 37 | #define F_PREFIX_SEG 0x20000000 38 | #define F_PREFIX_REX 0x40000000 39 | #define F_PREFIX_ANY 0x7f000000 40 | 41 | #define PREFIX_SEGMENT_CS 0x2e 42 | #define PREFIX_SEGMENT_SS 0x36 43 | #define PREFIX_SEGMENT_DS 0x3e 44 | #define PREFIX_SEGMENT_ES 0x26 45 | #define PREFIX_SEGMENT_FS 0x64 46 | #define PREFIX_SEGMENT_GS 0x65 47 | #define PREFIX_LOCK 0xf0 48 | #define PREFIX_REPNZ 0xf2 49 | #define PREFIX_REPX 0xf3 50 | #define PREFIX_OPERAND_SIZE 0x66 51 | #define PREFIX_ADDRESS_SIZE 0x67 52 | 53 | #pragma pack( push, 1 ) 54 | 55 | typedef struct 56 | { 57 | uint8_t len; 58 | uint8_t p_rep; 59 | uint8_t p_lock; 60 | uint8_t p_seg; 61 | uint8_t p_66; 62 | uint8_t p_67; 63 | uint8_t rex; 64 | uint8_t rex_w; 65 | uint8_t rex_r; 66 | uint8_t rex_x; 67 | uint8_t rex_b; 68 | uint8_t opcode; 69 | uint8_t opcode2; 70 | uint8_t modrm; 71 | uint8_t modrm_mod; 72 | uint8_t modrm_reg; 73 | uint8_t modrm_rm; 74 | uint8_t sib; 75 | uint8_t sib_scale; 76 | uint8_t sib_index; 77 | uint8_t sib_base; 78 | union 79 | { 80 | uint8_t imm8; 81 | uint16_t imm16; 82 | uint32_t imm32; 83 | uint64_t imm64; 84 | } imm; 85 | 86 | union 87 | { 88 | uint8_t disp8; 89 | uint16_t disp16; 90 | uint32_t disp32; 91 | } disp; 92 | 93 | uint32_t flags; 94 | } hde64s; 95 | 96 | #pragma pack( pop ) 97 | 98 | #ifdef __cplusplus 99 | extern "C" 100 | { 101 | #endif 102 | 103 | unsigned int hde64_disasm( const void *code, hde64s *hs ); 104 | 105 | #ifdef __cplusplus 106 | } 107 | 108 | #endif 109 | #endif 110 | -------------------------------------------------------------------------------- /hierarchy-eac/hierarchy-eac.inf: -------------------------------------------------------------------------------- 1 | ; 2 | ; hierarchy-eac.inf 3 | ; 4 | 5 | [Version] 6 | Signature="$WINDOWS NT$" 7 | Class=Sample ; TODO: edit Class 8 | ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} ; TODO: edit ClassGuid 9 | Provider=%ManufacturerName% 10 | CatalogFile=hierarchy-eac.cat 11 | DriverVer= ; TODO: set DriverVer in stampinf property pages 12 | PnpLockDown=1 13 | 14 | [DestinationDirs] 15 | DefaultDestDir = 12 16 | hierarchy-eac_Device_CoInstaller_CopyFiles = 11 17 | 18 | ; ================= Class section ===================== 19 | 20 | [ClassInstall32] 21 | Addreg=SampleClassReg 22 | 23 | [SampleClassReg] 24 | HKR,,,0,%ClassName% 25 | HKR,,Icon,,-5 26 | 27 | [SourceDisksNames] 28 | 1 = %DiskName%,,,"" 29 | 30 | [SourceDisksFiles] 31 | hierarchy-eac.sys = 1,, 32 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames 33 | 34 | ;***************************************** 35 | ; Install Section 36 | ;***************************************** 37 | 38 | [Manufacturer] 39 | %ManufacturerName%=Standard,NT$ARCH$ 40 | 41 | [Standard.NT$ARCH$] 42 | %hierarchy-eac.DeviceDesc%=hierarchy-eac_Device, Root\hierarchy-eac ; TODO: edit hw-id 43 | 44 | [hierarchy-eac_Device.NT] 45 | CopyFiles=Drivers_Dir 46 | 47 | [Drivers_Dir] 48 | hierarchy-eac.sys 49 | 50 | ;-------------- Service installation 51 | [hierarchy-eac_Device.NT.Services] 52 | AddService = hierarchy-eac,%SPSVCINST_ASSOCSERVICE%, hierarchy-eac_Service_Inst 53 | 54 | ; -------------- hierarchy-eac driver install sections 55 | [hierarchy-eac_Service_Inst] 56 | DisplayName = %hierarchy-eac.SVCDESC% 57 | ServiceType = 1 ; SERVICE_KERNEL_DRIVER 58 | StartType = 3 ; SERVICE_DEMAND_START 59 | ErrorControl = 1 ; SERVICE_ERROR_NORMAL 60 | ServiceBinary = %12%\hierarchy-eac.sys 61 | 62 | ; 63 | ;--- hierarchy-eac_Device Coinstaller installation ------ 64 | ; 65 | 66 | [hierarchy-eac_Device.NT.CoInstallers] 67 | AddReg=hierarchy-eac_Device_CoInstaller_AddReg 68 | CopyFiles=hierarchy-eac_Device_CoInstaller_CopyFiles 69 | 70 | [hierarchy-eac_Device_CoInstaller_AddReg] 71 | HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" 72 | 73 | [hierarchy-eac_Device_CoInstaller_CopyFiles] 74 | WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll 75 | 76 | [hierarchy-eac_Device.NT.Wdf] 77 | KmdfService = hierarchy-eac, hierarchy-eac_wdfsect 78 | [hierarchy-eac_wdfsect] 79 | KmdfLibraryVersion = $KMDFVERSION$ 80 | 81 | [Strings] 82 | SPSVCINST_ASSOCSERVICE= 0x00000002 83 | ManufacturerName="" ;TODO: Replace with your manufacturer name 84 | ClassName="Samples" ; TODO: edit ClassName 85 | DiskName = "hierarchy-eac Installation Disk" 86 | hierarchy-eac.DeviceDesc = "hierarchy-eac Device" 87 | hierarchy-eac.SVCDESC = "hierarchy-eac Service" 88 | -------------------------------------------------------------------------------- /hierarchy-eac/hierarchy-eac.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | Debug 22 | ARM 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Debug 30 | ARM64 31 | 32 | 33 | Release 34 | ARM64 35 | 36 | 37 | 38 | {E22E36FB-2598-45B9-A3AC-1B51EE8FD1B8} 39 | {1bc93793-694f-48fe-9372-81e2b05556fd} 40 | v4.5 41 | 12.0 42 | Debug 43 | Win32 44 | hierarchy_eac 45 | 46 | 47 | 48 | Windows10 49 | true 50 | WindowsKernelModeDriver10.0 51 | Driver 52 | KMDF 53 | Universal 54 | 55 | 56 | Windows10 57 | false 58 | WindowsKernelModeDriver10.0 59 | Driver 60 | KMDF 61 | Universal 62 | 63 | 64 | Windows10 65 | true 66 | WindowsKernelModeDriver10.0 67 | Driver 68 | KMDF 69 | Universal 70 | 71 | 72 | Windows10 73 | false 74 | WindowsKernelModeDriver10.0 75 | Driver 76 | KMDF 77 | Universal 78 | false 79 | 80 | 81 | Windows10 82 | true 83 | WindowsKernelModeDriver10.0 84 | Driver 85 | KMDF 86 | Universal 87 | 88 | 89 | Windows10 90 | false 91 | WindowsKernelModeDriver10.0 92 | Driver 93 | KMDF 94 | Universal 95 | 96 | 97 | Windows10 98 | true 99 | WindowsKernelModeDriver10.0 100 | Driver 101 | KMDF 102 | Universal 103 | 104 | 105 | Windows10 106 | false 107 | WindowsKernelModeDriver10.0 108 | Driver 109 | KMDF 110 | Universal 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | DbgengKernelDebugger 123 | 124 | 125 | DbgengKernelDebugger 126 | 127 | 128 | DbgengKernelDebugger 129 | 130 | 131 | DbgengKernelDebugger 132 | false 133 | 134 | 135 | DbgengKernelDebugger 136 | 137 | 138 | DbgengKernelDebugger 139 | 140 | 141 | DbgengKernelDebugger 142 | 143 | 144 | DbgengKernelDebugger 145 | 146 | 147 | 148 | TurnOffAllWarnings 149 | 150 | 151 | 152 | 153 | false 154 | true 155 | false 156 | false 157 | 158 | 159 | driver_entry 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /hierarchy-eac/hierarchy-eac.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | Resource Files 32 | 33 | 34 | Resource Files 35 | 36 | 37 | Resource Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | 64 | 65 | Resource Files 66 | 67 | 68 | -------------------------------------------------------------------------------- /hierarchy-eac/hierarchy-eac.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Off 5 | 6 | -------------------------------------------------------------------------------- /hierarchy-eac/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.hpp" 2 | 3 | eac_instance_t *g_eac_instance = nullptr; 4 | 5 | long driver_entry( PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path ) 6 | { 7 | if ( !driver_object || !registry_path ) 8 | { 9 | // 10 | // Driver is not meant to be manual mapped, add support for PsSetLoadImageNotify first... 11 | // 12 | 13 | return STATUS_UNSUCCESSFUL; 14 | } 15 | 16 | g_eac_instance = decltype( g_eac_instance )( ExAllocatePool( NonPagedPoolNx, sizeof( *g_eac_instance ) ) ); 17 | driver_object->DriverUnload = []( PDRIVER_OBJECT object ) { PsRemoveLoadImageNotifyRoutine( vm::image_callback ); }; 18 | 19 | return PsSetLoadImageNotifyRoutine( vm::image_callback ); 20 | } 21 | -------------------------------------------------------------------------------- /hierarchy-eac/stdafx.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using uint8_t = unsigned char; 4 | using uint16_t = unsigned short; 5 | using uint32_t = unsigned int; 6 | using uint64_t = unsigned long long; 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | class eac_instance_t; 13 | extern eac_instance_t *g_eac_instance; 14 | 15 | // 16 | // EAC_SHA1_CREATE_HASH -> E8 ? ? ? ? 48 8D 55 3F 17 | // EAC_IS_RELOC -> 48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 54 41 55 41 56 41 57 48 63 05 18 | // 19 | 20 | #define EAC_SHA1_CREATE_HASH(base) static_cast(base)+0xF054 21 | #define EAC_IS_RELOC(base) static_cast(base)+ 0x33F8 22 | #define CURRENT_THREAD_ID PsGetCurrentThreadId() 23 | 24 | #include "hde64.hpp" 25 | #include "utils.hpp" 26 | #include "eac.hpp" 27 | #include "vm.hpp" -------------------------------------------------------------------------------- /hierarchy-eac/table64.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Hacker Disassembler Engine 64 C 3 | * Copyright (c) 2008-2009, Vyacheslav Patkov. 4 | * All rights reserved. 5 | * 6 | */ 7 | 8 | #define C_NONE 0x00 9 | #define C_MODRM 0x01 10 | #define C_IMM8 0x02 11 | #define C_IMM16 0x04 12 | #define C_IMM_P66 0x10 13 | #define C_REL8 0x20 14 | #define C_REL32 0x40 15 | #define C_GROUP 0x80 16 | #define C_ERROR 0xff 17 | 18 | #define PRE_ANY 0x00 19 | #define PRE_NONE 0x01 20 | #define PRE_F2 0x02 21 | #define PRE_F3 0x04 22 | #define PRE_66 0x08 23 | #define PRE_67 0x10 24 | #define PRE_LOCK 0x20 25 | #define PRE_SEG 0x40 26 | #define PRE_ALL 0xff 27 | 28 | #define DELTA_OPCODES 0x4a 29 | #define DELTA_FPU_REG 0xfd 30 | #define DELTA_FPU_MODRM 0x104 31 | #define DELTA_PREFIXES 0x13c 32 | #define DELTA_OP_LOCK_OK 0x1ae 33 | #define DELTA_OP2_LOCK_OK 0x1c6 34 | #define DELTA_OP_ONLY_MEM 0x1d8 35 | #define DELTA_OP2_ONLY_MEM 0x1e7 36 | 37 | unsigned char hde64_table[] = { 38 | 0xa5, 0xaa, 0xa5, 0xb8, 0xa5, 0xaa, 0xa5, 0xaa, 0xa5, 0xb8, 0xa5, 0xb8, 0xa5, 0xb8, 0xa5, 0xb8, 0xc0, 0xc0, 0xc0, 39 | 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xac, 0xc0, 0xcc, 0xc0, 0xa1, 0xa1, 0xa1, 0xa1, 0xb1, 0xa5, 0xa5, 0xa6, 0xc0, 0xc0, 40 | 0xd7, 0xda, 0xe0, 0xc0, 0xe4, 0xc0, 0xea, 0xea, 0xe0, 0xe0, 0x98, 0xc8, 0xee, 0xf1, 0xa5, 0xd3, 0xa5, 0xa5, 0xa1, 41 | 0xea, 0x9e, 0xc0, 0xc0, 0xc2, 0xc0, 0xe6, 0x03, 0x7f, 0x11, 0x7f, 0x01, 0x7f, 0x01, 0x3f, 0x01, 0x01, 0xab, 0x8b, 42 | 0x90, 0x64, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x92, 0x5b, 0x5b, 0x76, 0x90, 0x92, 0x92, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 43 | 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x6a, 0x73, 0x90, 0x5b, 0x52, 0x52, 0x52, 0x52, 0x5b, 0x5b, 0x5b, 0x5b, 44 | 0x77, 0x7c, 0x77, 0x85, 0x5b, 0x5b, 0x70, 0x5b, 0x7a, 0xaf, 0x76, 0x76, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 45 | 0x5b, 0x5b, 0x5b, 0x5b, 0x86, 0x01, 0x03, 0x01, 0x04, 0x03, 0xd5, 0x03, 0xd5, 0x03, 0xcc, 0x01, 0xbc, 0x03, 0xf0, 46 | 0x03, 0x03, 0x04, 0x00, 0x50, 0x50, 0x50, 0x50, 0xff, 0x20, 0x20, 0x20, 0x20, 0x01, 0x01, 0x01, 0x01, 0xc4, 0x02, 47 | 0x10, 0xff, 0xff, 0xff, 0x01, 0x00, 0x03, 0x11, 0xff, 0x03, 0xc4, 0xc6, 0xc8, 0x02, 0x10, 0x00, 0xff, 0xcc, 0x01, 48 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x01, 0xff, 0xff, 0xc0, 0xc2, 0x10, 0x11, 0x02, 0x03, 0x01, 49 | 0x01, 0x01, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x10, 0x10, 0x10, 0x10, 50 | 0x02, 0x10, 0x00, 0x00, 0xc6, 0xc8, 0x02, 0x02, 0x02, 0x02, 0x06, 0x00, 0x04, 0x00, 0x02, 0xff, 0x00, 0xc0, 0xc2, 51 | 0x01, 0x01, 0x03, 0x03, 0x03, 0xca, 0x40, 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x33, 0x01, 52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xff, 0x00, 53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xbf, 54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x40, 0x40, 0x40, 0x40, 0x41, 0x49, 0x40, 55 | 0x40, 0x40, 0x40, 0x4c, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x44, 0x53, 0x40, 0x40, 0x40, 56 | 0x44, 0x57, 0x43, 0x5c, 0x40, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 57 | 0x40, 0x64, 0x66, 0x6e, 0x6b, 0x40, 0x40, 0x6a, 0x46, 0x40, 0x40, 0x44, 0x46, 0x40, 0x40, 0x5b, 0x44, 0x40, 0x40, 58 | 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x01, 0x06, 0x06, 0x02, 0x06, 0x06, 0x00, 0x06, 0x00, 0x0a, 0x0a, 59 | 0x00, 0x00, 0x00, 0x02, 0x07, 0x07, 0x06, 0x02, 0x0d, 0x06, 0x06, 0x06, 0x0e, 0x05, 0x05, 0x02, 0x02, 0x00, 0x00, 60 | 0x04, 0x04, 0x04, 0x04, 0x05, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x18, 61 | 0x00, 0x20, 0x00, 0x28, 0x00, 0x30, 0x00, 0x80, 0x01, 0x82, 0x01, 0x86, 0x00, 0xf6, 0xcf, 0xfe, 0x3f, 0xab, 0x00, 62 | 0xb0, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xba, 0xf8, 0xbb, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc7, 0xbf, 0x62, 0xff, 0x00, 63 | 0x8d, 0xff, 0x00, 0xc4, 0xff, 0x00, 0xc5, 0xff, 0x00, 0xff, 0xff, 0xeb, 0x01, 0xff, 0x0e, 0x12, 0x08, 0x00, 0x13, 64 | 0x09, 0x00, 0x16, 0x08, 0x00, 0x17, 0x09, 0x00, 0x2b, 0x09, 0x00, 0xae, 0xff, 0x07, 0xb2, 0xff, 0x00, 0xb4, 0xff, 65 | 0x00, 0xb5, 0xff, 0x00, 0xc3, 0x01, 0x00, 0xc7, 0xff, 0xbf, 0xe7, 0x08, 0x00, 0xf0, 0x02, 0x00 }; 66 | -------------------------------------------------------------------------------- /hierarchy-eac/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.hpp" 2 | 3 | namespace utils 4 | { 5 | PIMAGE_NT_HEADERS const get_nt_headers( const uint64_t image_base ) 6 | { 7 | if ( !image_base ) 8 | return nullptr; 9 | 10 | const PIMAGE_DOS_HEADER dos_header = reinterpret_cast< PIMAGE_DOS_HEADER >( image_base ); 11 | if ( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) 12 | return nullptr; 13 | 14 | const PIMAGE_NT_HEADERS nt_headers = reinterpret_cast< PIMAGE_NT_HEADERS >( image_base + dos_header->e_lfanew ); 15 | if ( nt_headers->Signature != IMAGE_NT_SIGNATURE ) 16 | return nullptr; 17 | 18 | return nt_headers; 19 | } 20 | 21 | bool memcpy_safe( void *dest, void *src, uint32_t len ) 22 | { 23 | // 24 | // Too lazy to handle 0x1000+ writes, because they require a for loop 25 | // and we don't even need them here 26 | // physical pages are not guaranteed to be contiguous... 27 | // 28 | 29 | if ( len > PAGE_SIZE ) 30 | return false; 31 | 32 | if ( !dest || !src ) 33 | return false; 34 | 35 | if ( !MmIsAddressValid( dest ) || !MmIsAddressValid( src ) ) 36 | return false; 37 | 38 | auto dst = static_cast< uint8_t * >( dest ); 39 | auto source = static_cast< uint8_t * >( src ); 40 | if ( &dst[ len ] > &static_cast< uint8_t * >( PAGE_ALIGN( dst ) )[ PAGE_SIZE ] ) 41 | { 42 | // 43 | // We cannot write into a single buffer due to page boundary issues... 44 | // 45 | 46 | while ( len ) 47 | { 48 | 49 | const auto phys_addr = MmGetPhysicalAddress( dst ); 50 | if ( !phys_addr.QuadPart ) 51 | return false; 52 | 53 | const auto next_page = &static_cast< uint8_t * >( PAGE_ALIGN( dst ) )[ PAGE_SIZE ]; 54 | const auto map_len = min( len, next_page - dst ); 55 | const auto map_dest = MmMapIoSpace( phys_addr, map_len, MmNonCached ); 56 | if ( !map_dest ) 57 | return false; 58 | 59 | memcpy( map_dest, source, map_len ); 60 | MmUnmapIoSpace( map_dest, map_len ); 61 | 62 | len -= map_len; 63 | dst += map_len; 64 | source += map_len; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | const auto phys_addr = MmGetPhysicalAddress( dest ); 71 | if ( !phys_addr.QuadPart ) 72 | return false; 73 | 74 | const auto dest_map = MmMapIoSpace( phys_addr, len, MmNonCached ); 75 | if ( !dest_map ) 76 | return false; 77 | 78 | memcpy( dest_map, src, len ); 79 | MmUnmapIoSpace( dest_map, len ); 80 | 81 | return true; 82 | } 83 | 84 | bool create_hook( uint8_t *address, void *target, void **p_original ) 85 | { 86 | if ( !address || !target ) 87 | return false; 88 | 89 | hde64s block; 90 | uint8_t instr_len = 0; 91 | while ( 14 > instr_len ) 92 | instr_len += hde64_disasm( &address[ instr_len ], &block ); 93 | 94 | uint8_t rel64_jmp[] = { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 95 | 96 | const auto p_trampoline = 97 | static_cast< uint8_t * >( ExAllocatePool( NonPagedPool, sizeof( rel64_jmp ) + instr_len ) ); 98 | 99 | if ( !p_trampoline ) 100 | return false; 101 | 102 | auto return_to = &address[ instr_len ]; 103 | 104 | // 105 | // TODO: Support RIP-relative instructions when copying original instructions.... 106 | // 107 | 108 | memcpy( p_trampoline, &address[ 0 ], instr_len ); 109 | memcpy( &p_trampoline[ instr_len ], rel64_jmp, sizeof( rel64_jmp ) ); 110 | memcpy( &p_trampoline[ instr_len + 6 ], &return_to, sizeof( void * ) ); 111 | 112 | if ( p_original ) 113 | *p_original = p_trampoline; 114 | 115 | memcpy( &rel64_jmp[ 6 ], &target, sizeof( void * ) ); 116 | utils::memcpy_safe( address, rel64_jmp, sizeof( rel64_jmp ) ); 117 | 118 | return true; 119 | } 120 | 121 | void kprint( const char *msg, ... ) 122 | { 123 | va_list args; 124 | va_start( args, msg ); 125 | 126 | vDbgPrintExWithPrefix( "", DPFLTR_IHVVIDEO_ID, 0, msg, args ); 127 | } 128 | 129 | } // namespace utils 130 | -------------------------------------------------------------------------------- /hierarchy-eac/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.hpp" 3 | 4 | namespace utils 5 | { 6 | PIMAGE_NT_HEADERS const get_nt_headers( const uint64_t image_base ); 7 | bool memcpy_safe( void *dest, void *src, uint32_t len ); 8 | bool create_hook( uint8_t *address, void *target, void **p_original ); 9 | void kprint( const char *msg, ... ); 10 | } 11 | -------------------------------------------------------------------------------- /hierarchy-eac/vm.cpp: -------------------------------------------------------------------------------- 1 | #include "vm.hpp" 2 | 3 | namespace vm 4 | { 5 | void *g_sha1_update = nullptr; 6 | void *g_is_reloc = nullptr; 7 | 8 | void is_reloc( context_t *context ) 9 | { 10 | 11 | const auto address = reinterpret_cast< uint8_t * >( context->rcx ); 12 | const auto read_addr = context->rcx; 13 | 14 | if ( g_eac_instance->mem_in_bounds( address ) && g_eac_instance->mem_in_scn( address, IMAGE_SCN_MEM_EXECUTE ) ) 15 | { 16 | const auto rebased = reinterpret_cast< uint64_t >( address - g_eac_instance->get_image_base() + 17 | g_eac_instance->get_raw_image() ); 18 | 19 | // 20 | // To 'spoof' all driver reads, we use IoGetStackLimits to 21 | // get the start-end address of the stack then proceed to 22 | // iterate through the entire stack looking for instances of the target 23 | // address then modifying it to our 'cleaned' address 24 | // 25 | // Moreover, spoofing registers are necessary to make sure the address 26 | // is no longer reachable from the current registers 27 | // 28 | 29 | uint64_t stack_low = 0, stack_high = 0; 30 | IoGetStackLimits( &stack_low, &stack_high ); 31 | 32 | while ( stack_low < stack_high ) 33 | { 34 | const auto current_offset = reinterpret_cast< uint64_t * >( stack_low ); 35 | if ( *current_offset == read_addr ) 36 | *current_offset = rebased; 37 | 38 | stack_low += sizeof( uint64_t ); 39 | } 40 | 41 | const auto ctx_array = reinterpret_cast< uint64_t * >( context ); 42 | for ( auto i = 0UL; i < sizeof( *context ); i++ ) 43 | { 44 | if ( ctx_array[ i ] == read_addr ) 45 | ctx_array[ i ] = rebased; 46 | } 47 | 48 | const auto rva = read_addr - reinterpret_cast< uint64_t >( g_eac_instance->get_image_base() ); 49 | if ( rva == reinterpret_cast< uint64_t >( PAGE_ALIGN( rva ) ) ) 50 | { 51 | // 52 | // Only log if EAC is reading the start of a page to prevent excess logging.... 53 | // 54 | 55 | utils::kprint( "is_reloc(tid: %i) reading -> EasyAntiCheat.sys+0x%x\n", CURRENT_THREAD_ID, rva ); 56 | } 57 | } 58 | 59 | // 60 | // this isn't a traditional hook; we must call the original and update the result register 61 | // with the return value, otherwise we can expect undefined behavior... 62 | // 63 | 64 | context->rax = reinterpret_cast< bool ( * )( uint64_t ) >( g_is_reloc )( read_addr ); 65 | } 66 | 67 | void *sha1_create_hash( void *sha1_ctx, uint8_t *address, uint64_t len ) 68 | { 69 | 70 | if ( g_eac_instance->mem_in_bounds( address ) ) 71 | { 72 | if ( g_eac_instance->mem_in_scn( address, IMAGE_SCN_MEM_EXECUTE ) ) 73 | { 74 | { 75 | utils::kprint( "Spoofing SHA1 read from(tid: %i) rva => 0x%x, len => 0x%04x!\n", CURRENT_THREAD_ID, 76 | address - g_eac_instance->get_image_base(), len ); 77 | 78 | address = ( address - g_eac_instance->get_image_base() ) + g_eac_instance->get_raw_image(); 79 | } 80 | } 81 | } 82 | 83 | return reinterpret_cast< decltype( &sha1_create_hash ) >( g_sha1_update )( sha1_ctx, address, len ); 84 | } 85 | 86 | void image_callback( PUNICODE_STRING image_name, HANDLE proc_id, PIMAGE_INFO image_info ) 87 | { 88 | if ( image_name && image_name->Buffer && image_name->Length ) 89 | { 90 | if ( !wcsstr( image_name->Buffer, L"EasyAntiCheat.sys" ) ) 91 | return; 92 | 93 | utils::kprint( "EasyAntiCheat.sys loaded at base => 0x%p, size => 0x%x\n", image_info->ImageBase, 94 | image_info->ImageSize ); 95 | 96 | // 97 | // Initialize the copy of EasyAntiCheat.sys used for spoofing reads.... 98 | // 99 | 100 | g_eac_instance->init( image_info->ImageBase, image_info->ImageSize ); 101 | utils::kprint( "EasyAntiCheat.sys copy loaded at base => 0x%p\n", g_eac_instance->get_raw_image() ); 102 | 103 | utils::create_hook( EAC_SHA1_CREATE_HASH( image_info->ImageBase ), &sha1_create_hash, &g_sha1_update ); 104 | utils::create_hook( EAC_IS_RELOC( image_info->ImageBase ), &vm_is_reloc, &g_is_reloc ); 105 | } 106 | } 107 | } // namespace vm 108 | -------------------------------------------------------------------------------- /hierarchy-eac/vm.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.hpp" 3 | 4 | struct context_t 5 | { 6 | uint64_t r15; 7 | uint64_t r14; 8 | uint64_t r13; 9 | uint64_t r12; 10 | uint64_t r11; 11 | uint64_t r10; 12 | uint64_t r9; 13 | uint64_t r8; 14 | uint64_t rdi; 15 | uint64_t rsi; 16 | uint64_t rdx; 17 | uint64_t rbx; 18 | uint64_t rcx; 19 | uint64_t rax; 20 | }; 21 | 22 | namespace vm 23 | { 24 | extern void *g_is_reloc; 25 | extern "C" void vm_is_reloc(); 26 | extern "C" void is_reloc( context_t *context ); 27 | 28 | void image_callback( PUNICODE_STRING image_name, HANDLE proc_id, PIMAGE_INFO image_info ); 29 | } // namespace vm 30 | --------------------------------------------------------------------------------