void CvOneWayDescriptor::Allocate(int pose_count, CvSize size, int nChannels) { m_pose_count = pose_count; m_samples = new IplImage* [m_pose_count]; m_pca_coeffs = new CvMat* [m_pose_count]; m_patch_size = cvSize(size.width/2, size.height/2); if(!m_transforms) { m_affine_poses = new CvAffinePose[m_pose_count]; } int length = m_pca_dim_low;//roi.width*roi.height; for(int i = 0; i < m_pose_count; i++) { m_samples[i] = cvCreateImage(cvSize(size.width/2, size.height/2), IPL_DEPTH_32F, nChannels); m_pca_coeffs[i] = cvCreateMat(1, length, CV_32FC1); } m_input_patch = cvCreateImage(GetPatchSize(), IPL_DEPTH_8U, 1); m_train_patch = cvCreateImage(GetInputPatchSize(), IPL_DEPTH_8U, 1); }
void CvOneWayDescriptor::EstimatePosePCA(CvArr* patch, int& pose_idx, float& distance, CvMat* avg, CvMat* eigenvectors) const { if(avg == 0) { // do not use pca if (!CV_IS_MAT(patch)) { EstimatePose((IplImage*)patch, pose_idx, distance); } else { } return; } CvRect roi; if (!CV_IS_MAT(patch)) { roi = cvGetImageROI((IplImage*)patch); if(roi.width != GetPatchSize().width || roi.height != GetPatchSize().height) { cvResize(patch, m_input_patch); patch = m_input_patch; roi = cvGetImageROI((IplImage*)patch); } } CvMat* pca_coeffs = cvCreateMat(1, m_pca_dim_low, CV_32FC1); if (CV_IS_MAT(patch)) { cvCopy((CvMat*)patch, pca_coeffs); } else { IplImage* patch_32f = cvCreateImage(cvSize(roi.width, roi.height), IPL_DEPTH_32F, 1); float sum = cvSum(patch).val[0]; cvConvertScale(patch, patch_32f, 1.0f/sum); ProjectPCASample(patch_32f, avg, eigenvectors, pca_coeffs); cvReleaseImage(&patch_32f); } distance = 1e10; pose_idx = -1; for(int i = 0; i < m_pose_count; i++) { float dist = cvNorm(m_pca_coeffs[i], pca_coeffs); // float dist = 0; // float data1, data2; // //CvMat* pose_pca_coeffs = m_pca_coeffs[i]; // for (int x=0; x < pca_coeffs->width; x++) // for (int y =0 ; y < pca_coeffs->height; y++) // { // data1 = ((float*)(pca_coeffs->data.ptr + pca_coeffs->step*x))[y]; // data2 = ((float*)(m_pca_coeffs[i]->data.ptr + m_pca_coeffs[i]->step*x))[y]; // dist+=(data1-data2)*(data1-data2); // } ////#if 1 // for (int j = 0; j < m_pca_dim_low; j++) // { // dist += (pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j])*(pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j]); // } //#else // for (int j = 0; j <= m_pca_dim_low - 4; j += 4) // { // dist += (pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j])* // (pose_pca_coeffs->data.fl[j]- pca_coeffs->data.fl[j]); // dist += (pose_pca_coeffs->data.fl[j+1]- pca_coeffs->data.fl[j+1])* // (pose_pca_coeffs->data.fl[j+1]- pca_coeffs->data.fl[j+1]); // dist += (pose_pca_coeffs->data.fl[j+2]- pca_coeffs->data.fl[j+2])* // (pose_pca_coeffs->data.fl[j+2]- pca_coeffs->data.fl[j+2]); // dist += (pose_pca_coeffs->data.fl[j+3]- pca_coeffs->data.fl[j+3])* // (pose_pca_coeffs->data.fl[j+3]- pca_coeffs->data.fl[j+3]); // } //#endif if(dist < distance) { distance = dist; pose_idx = i; } } cvReleaseMat(&pca_coeffs); }
virtual void Apply() override { if (applied_) { return; } if (detached_) { HADESMEM_DETAIL_ASSERT(false); return; } // Reset the trampolines here because we don't do it in remove, otherwise // there's a potential race condition where we want to unhook and unload // safely, so we unhook the function, then try waiting on our ref count to // become zero, but we haven't actually called the trampoline yet, so we end // up jumping to the memory we just free'd! trampoline_ = nullptr; trampolines_.clear(); stub_gate_ = nullptr; SuspendedProcess const suspended_process{process_->GetId()}; std::uint32_t const kMaxInstructionLen = 15; std::uint32_t const kTrampSize = kMaxInstructionLen * 3; trampoline_ = std::make_unique<Allocator>(*process_, kTrampSize); auto tramp_cur = static_cast<std::uint8_t*>(trampoline_->GetBase()); auto const detour_raw = detour_.target<DetourFuncRawT>(); if (detour_raw || detour_) { HADESMEM_DETAIL_TRACE_FORMAT_A( "Target = %p, Detour = %p, Trampoline = %p.", target_, detour_raw, trampoline_->GetBase()); } else { HADESMEM_DETAIL_TRACE_FORMAT_A( "Target = %p, Detour = INVALID, Trampoline = %p.", target_, trampoline_->GetBase()); } auto const buffer = ReadVector<std::uint8_t>(*process_, target_, kTrampSize); ud_t ud_obj; ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, buffer.data(), buffer.size()); ud_set_syntax(&ud_obj, UD_SYN_INTEL); ud_set_pc(&ud_obj, reinterpret_cast<std::uint64_t>(target_)); #if defined(HADESMEM_DETAIL_ARCH_X64) ud_set_mode(&ud_obj, 64); #elif defined(HADESMEM_DETAIL_ARCH_X86) ud_set_mode(&ud_obj, 32); #else #error "[HadesMem] Unsupported architecture." #endif stub_gate_ = detail::AllocatePageNear(*process_, target_); std::size_t const patch_size = GetPatchSize(); std::uint32_t instr_size = 0; do { std::uint32_t const len = ud_disassemble(&ud_obj); if (len == 0) { HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{"Disassembly failed."}); } #if !defined(HADESMEM_NO_TRACE) char const* const asm_str = ud_insn_asm(&ud_obj); char const* const asm_bytes_str = ud_insn_hex(&ud_obj); HADESMEM_DETAIL_TRACE_FORMAT_A( "%s. [%s].", (asm_str ? asm_str : "Invalid."), (asm_bytes_str ? asm_bytes_str : "Invalid.")); #endif ud_operand_t const* const op = ud_insn_opr(&ud_obj, 0); bool is_jimm = op && op->type == UD_OP_JIMM; // Handle JMP QWORD PTR [RIP+Rel32]. Necessary for hook chain support. bool is_jmem = op && op->type == UD_OP_MEM && op->base == UD_R_RIP && op->index == UD_NONE && op->scale == 0 && op->size == 0x40; if ((ud_obj.mnemonic == UD_Ijmp || ud_obj.mnemonic == UD_Icall) && op && (is_jimm || is_jmem)) { std::uint16_t const size = is_jimm ? op->size : op->offset; HADESMEM_DETAIL_TRACE_FORMAT_A("Operand/offset size is %hu.", size); std::int64_t const insn_target = [&]() -> std::int64_t { switch (size) { case sizeof(std::int8_t) * CHAR_BIT: return op->lval.sbyte; case sizeof(std::int16_t) * CHAR_BIT: return op->lval.sword; case sizeof(std::int32_t) * CHAR_BIT: return op->lval.sdword; case sizeof(std::int64_t) * CHAR_BIT: return op->lval.sqword; default: HADESMEM_DETAIL_ASSERT(false); HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"Unknown instruction size."}); } }(); auto const resolve_rel = [](std::uint64_t base, std::int64_t target, std::uint32_t insn_len) { return reinterpret_cast<std::uint8_t*>( static_cast<std::uintptr_t>(base)) + target + insn_len; }; std::uint64_t const insn_base = ud_insn_off(&ud_obj); std::uint32_t const insn_len = ud_insn_len(&ud_obj); auto const resolved_target = resolve_rel(insn_base, insn_target, insn_len); void* const jump_target = is_jimm ? resolved_target : Read<void*>(*process_, resolved_target); HADESMEM_DETAIL_TRACE_FORMAT_A("Jump/call target = %p.", jump_target); if (ud_obj.mnemonic == UD_Ijmp) { HADESMEM_DETAIL_TRACE_A("Writing resolved jump."); tramp_cur += detail::WriteJump( *process_, tramp_cur, jump_target, true, &trampolines_); } else { HADESMEM_DETAIL_ASSERT(ud_obj.mnemonic == UD_Icall); HADESMEM_DETAIL_TRACE_A("Writing resolved call."); tramp_cur += detail::WriteCall(*process_, tramp_cur, jump_target, trampolines_); } } else { std::uint8_t const* const raw = ud_insn_ptr(&ud_obj); Write(*process_, tramp_cur, raw, raw + len); tramp_cur += len; } instr_size += len; } while (instr_size < patch_size); HADESMEM_DETAIL_TRACE_A("Writing jump back to original code."); tramp_cur += detail::WriteJump(*process_, tramp_cur, reinterpret_cast<std::uint8_t*>(target_) + instr_size, true, &trampolines_); FlushInstructionCache( *process_, trampoline_->GetBase(), trampoline_->GetSize()); detail::WriteStubGate<TargetFuncT>(*process_, stub_gate_->GetBase(), &*stub_, &GetOriginalArbitraryUserPtrPtr); orig_ = ReadVector<std::uint8_t>(*process_, target_, patch_size); detail::VerifyPatchThreads(process_->GetId(), target_, orig_.size()); WritePatch(); FlushInstructionCache(*process_, target_, instr_size); applied_ = true; }