LONG dsfQueryCiOptions( PULONG_PTR pKernelBase, PVOID MappedKernel ) { PBYTE CiInit = NULL; ULONG c; LONG rel = 0; ldasm_data ld; // // Validate input parameters. // if ( (pKernelBase == NULL) || (MappedKernel == NULL) ) { return 0; } CiInit = (PBYTE)GetProcAddress(MappedKernel, "CiInitialize"); c = 0; do { /* jmp CipInitialize */ if (CiInit[c] == 0xE9) { rel = *(PLONG)(CiInit + c + 1); break; } c += ldasm(CiInit + c, &ld, 1); } while (c < 256); CiInit = CiInit + c + 5 + rel; c = 0; do { if (*(PUSHORT)(CiInit + c) == 0x0d89) { rel = *(PLONG)(CiInit + c + 2); break; } c += ldasm(CiInit + c, &ld, 1); } while (c < 256); CiInit = CiInit + c + 6 + rel; *pKernelBase = *pKernelBase + CiInit - (PBYTE)MappedKernel; return rel; }
/// <summary> /// Copy original bytes using LDASM /// </summary> /// <param name="pFunc">Original function ptr</param> /// <param name="OriginalStore">Buffer to store bytes</param> /// <param name="pSize">Lenght of copied data</param> /// <returns>Status code</returns> NTSTATUS PHpCopyCode( IN PVOID pFunc, OUT PUCHAR OriginalStore, OUT PULONG pSize ) { // Store original bytes PUCHAR src = pFunc; PUCHAR old = OriginalStore; ULONG all_len = 0; ldasm_data ld = { 0 }; do { ULONG len = ldasm( src, &ld, TRUE ); // Determine code end if (ld.flags & F_INVALID || (len == 1 && (src[ld.opcd_offset] == 0xCC || src[ld.opcd_offset] == 0xC3)) || (len == 3 && src[ld.opcd_offset] == 0xC2) || len + all_len > 128) { break; } // move instruction memcpy( old, src, len ); // if instruction has relative offset, calculate new offset if (ld.flags & F_RELATIVE) { LONG diff = 0; const uintptr_t ofst = (ld.disp_offset != 0 ? ld.disp_offset : ld.imm_offset); const uintptr_t sz = ld.disp_size != 0 ? ld.disp_size : ld.imm_size; memcpy( &diff, src + ofst, sz ); // exit if jump is greater then 2GB if (_abs64( src + len + diff - old ) > INT_MAX) { break; } else { diff += (LONG)(src - old); memcpy( old + ofst, &diff, sz ); } } src += len; old += len; all_len += len; } while (all_len < sizeof( JUMP_THUNK )); // Failed to copy old code, use backup plan if (all_len < sizeof( JUMP_THUNK )) { return STATUS_UNSUCCESSFUL; } else { PHpInitJumpThunk( (PJUMP_THUNK)old, (ULONG64)src ); *pSize = all_len; } return STATUS_SUCCESS; }
NTSTATUS RemoteLocalHook::SetHook( ptr_t address, asmjit::Assembler& /*hook*/ ) { HookCtx ctx = { { 0 } }; HOOK_CTX_T( ctx_t, ctx ); UNREFERENCED_PARAMETER( ctx_t ); // Already hooked if (_hooks.count( address ) != 0) return STATUS_ADDRESS_ALREADY_EXISTS; auto memBlock = _process.memory().Allocate( 0x1000 ); if (!memBlock.valid()) return LastNtStatus(); auto status = _process.memory().Read( address, sizeof( ctx_t.original_code ), ctx_t.original_code ); if (!NT_SUCCESS( status )) return status; // Copy original uint8_t* codePtr = ctx_t.original_code; ptr_t old = 0; uint32_t all_len = 0; ldasm_data ld = { 0 }; do { uint32_t len = ldasm( codePtr, &ld, is_x64 ); // Determine code end if (ld.flags & F_INVALID || (len == 1 && (codePtr[ld.opcd_offset] == 0xCC || codePtr[ld.opcd_offset] == 0xC3)) || (len == 3 && codePtr[ld.opcd_offset] == 0xC2) || len + all_len > 128) { break; } // if instruction has relative offset, calculate new offset if (ld.flags & F_RELATIVE) { #ifdef USE64 // exit if jump is greater then 2GB if (_abs64( (uintptr_t)(codePtr + *((int*)(old + ld.opcd_size))) - (uintptr_t)old ) > INT_MAX) break; else *(uint32_t*)(old + ld.opcd_size) += (uint32_t)(codePtr - old); #else *(uintptr_t*)(codePtr + ld.opcd_size) += reinterpret_cast<uintptr_t>(codePtr) - static_cast<uintptr_t>(old); #endif } codePtr += len; old += len; all_len += len; } while (all_len < 5); #ifdef USE64 #else *codePtr = ctx_t.jmp_code[0] = 0xE9; *(int32_t*)(codePtr + 1) = memBlock.ptr<int32_t>() - static_cast<int32_t>(address)- 5; *(int32_t*)(ctx_t.jmp_code + 1) = memBlock.ptr<int32_t>() + FIELD_OFFSET( HookCtx32, original_code ) - static_cast<int32_t>(address) - 5; #endif ctx_t.codeSize = all_len; memset( ctx_t.original_code + ctx_t.codeSize, 0x00, sizeof( ctx_t.original_code ) - ctx_t.codeSize ); memBlock.Write( 0, ctx_t ); /*DWORD flOld = 0; _process.memory().Protect( address, all_len, PAGE_EXECUTE_READWRITE, &flOld ); _process.memory().Write( address, ctx_t.jmp_code ); _process.memory().Protect( address, all_len, flOld );*/ _hooks.emplace( std::make_pair( address, ctx ) ); memBlock.Release(); return STATUS_SUCCESS; }
/// <summary> /// Copy original function bytes /// </summary> /// <param name="Ptr">Origianl function address</param> void DetourBase::CopyOldCode( uint8_t* ptr ) { // Store original bytes uint8_t* src = ptr; uint8_t* thunk = _origThunk, *original = _origCode; uint32_t all_len = 0; ldasm_data ld = { 0 }; do { uint32_t len = ldasm( src, &ld, is_x64 ); // Determine code end if (ld.flags & F_INVALID || (len == 1 && (src[ld.opcd_offset] == 0xCC || src[ld.opcd_offset] == 0xC3)) || (len == 3 && src[ld.opcd_offset] == 0xC2) || len + all_len > 128) { break; } // move instruction memcpy( original, src, len ); memcpy( thunk, src, len ); // if instruction has relative offset, calculate new offset if (ld.flags & F_RELATIVE) { int32_t diff = 0; const uintptr_t ofst = (ld.disp_offset != 0 ? ld.disp_offset : ld.imm_offset); const uintptr_t sz = ld.disp_size != 0 ? ld.disp_size : ld.imm_size; memcpy( &diff, src + ofst, sz ); #ifdef USE64 // exit if jump is greater then 2GB if (_abs64( src + len + diff - thunk ) > INT_MAX) { break; } else { diff += static_cast<int32_t>(src - thunk); memcpy( thunk + ofst, &diff, sz ); } #else diff += src - thunk; memcpy( thunk + ofst, &diff, sz ); #endif } src += len; thunk += len; original += len; all_len += len; } while (all_len < _origSize); // Failed to copy old code, use backup plan if (all_len < _origSize) { _type = HookType::InternalInline; memcpy( _origCode, ptr, _origSize ); } else { SET_JUMP( thunk, src ); _callOriginal = _origThunk; } }