Bit records

Eclipse EasyExplore 插件配置与Log4j冲突解决
本文介绍了如何调整Eclipse插件EasyExplore的设置以实现打开目录而非文件的功能,并分享了一个关于Log4j配置冲突导致程序错误的问题及解决方案。

用eclipse插件easyexplore的时候,打开 文件的时候,总是会打开对应的文件而不是相应的目录,今天搜了一下,发现只要改一个参数就可以了。 eclipse->window->preferences->easy explore 把参数explorer.exe{0}改为explorer.exe /select,{0} (参考了网上的资料,源地址http://blog.youkuaiyun.com/xzknet/article/details/4627713

 

 最近有一天,早上起来后,发现程序突然报错,log system找不到吧,大概是这个意思,仔细看信息是发现有两个 log4j的包,原来是在 pom.xml 中 <test></test>中引入的包有冲突。但是很奇怪,没有改任何代码,不知道为什么以前不报这个错,突然有一天就报了。

 

 

#include <ntifs.h> #include <ntddk.h> #include <intrin.h> #include "ptehook.h" #define CR0_WP (1 << 16) #define DRIVER_TAG 'HKOB' #define MAX_G_BIT_RECORDS 128 #define MAX_HOOK_COUNT 64 #define PAGE_ALIGN(va) ((PVOID)((ULONG_PTR)(va) & ~0xFFF)) #define PTE_NX_BIT (1ULL << 63) // 调试打印宏 #define LOG_ERROR(fmt, ...) \ DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[PTE_HOOK] ERROR: " fmt "\n", ##__VA_ARGS__) #define LOG_INFO(fmt, ...) \ DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[PTE_HOOK] INFO: " fmt "\n", ##__VA_ARGS__) #define LOG_TRACE(fmt, ...) \ DbgPrintEx(DPFLTR极IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "[PTE_HOOK] TRACE: " fmt "\n", ##__VA_ARGS__) // 修正的跳板指令结构 #pragma pack(push, 1) typedef struct _JMP_ABS { UINT8 opcode[6]; // FF 25 00 00 00 00 = jmp [rip+0] ULONG64 address; // 目标地址 (紧跟在指令后) } JMP_ABS, * PJMP_ABS; #pragma pack(pop) static_assert(sizeof(JMP_ABS) == 14, "JMP_ABS size must be 14 bytes"); // 声明PsGetProcessImageFileName extern "C" NTSYSAPI CHAR* NTAPI PsGetProcessImageFileName(PEPROCESS Process); // 页表结构定义 typedef struct _PAGE_TABLE { UINT64 LineAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 极; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PteAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdeAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 ignored_1 : 1; UINT64 page_size : 1; UINT64 ignored_2 : 4; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdpteAddress; UINT64* Pml4Address; BOOLEAN IsLargePage; BOOLEAN Is1GBPage; UINT64 OriginalPte; UINT64 OriginalPde; UINT64 OriginalPdpte; UINT64 OriginalPml4e; HANDLE ProcessId; } PAGE_TABLE, * PPAGE_TABLE; // G位信息记录结构体 typedef struct _G_BIT_INFO { void* AlignAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 large_page : 1; UINT64 global : 1; UINT64 ignored_2 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_3 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PdeAddress; union { struct { UINT64 present : 1; UINT64 write : 1; UINT64 user : 1; UINT64 write_through : 1; UINT64 cache_disable : 1; UINT64 accessed : 1; UINT64 dirty : 1; UINT64 pat : 1; UINT64 global : 1; UINT64 ignored_1 : 3; UINT64 page_frame_number : 36; UINT64 reserved_1 : 4; UINT64 ignored_2 : 7; UINT64 protection_key : 4; UINT64 execute_disable : 1; } flags; UINT64 value; }*PteAddress; BOOLEAN IsLargePage; } G_BIT_INFO, * PG_BIT_INFO; typedef struct _HOOK_INFO { void* OriginalAddress; void* HookAddress; UINT8 OriginalBytes[20]; UINT8 HookBytes[20]; UINT32 HookLength; BOOLEAN IsHooked; HANDLE ProcessId; UINT64 OriginalPteValue; UINT64 HookedPteValue; } HOOK_INFO; class PteHookManager { public: bool fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr); bool fn_remove_hook(HANDLE process_id, void* hook_addr); static PteHookManager* GetInstance(); HOOK_INFO* GetHookInfo() { return m_HookInfo; } char* GetTrampLinePool() { return m_TrampLinePool; } UINT32 GetHookCount() { return m_HookCount; } bool fn_resume_global_bits(void* align_addr); ~PteHookManager(); private: bool WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd); bool SetPageExecution(void* address, bool executable); void fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address); bool fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde); bool fn_isolation_pages(HANDLE process_id, void* ori_addr); bool fn_split_large_pages(void* in_pde, void* out_pde); NTSTATUS get_page_table(UINT64 cr3, PAGE_TABLE& table); void* fn_pa_to_va(UINT64 pa); UINT64 fn_va_to_pa(void* va); __forceinline KIRQL DisableWriteProtection(); __forceinline void EnableWriteProtection(KIRQL oldIrql); void FlushCacheAndTlb(void* address); G_BIT_INFO m_GbitRecords[MAX_G_BIT_RECORDS]; UINT32 m_GbitCount = 0; void* m_PteBase = 0; HOOK_INFO m_HookInfo[MAX_HOOK_COUNT] = { 0 }; UINT32 m_HookCount = 0; char* m_TrampLinePool = nullptr; UINT32 m_PoolUsed = 0; static PteHookManager* m_Instance; }; PteHookManager* PteHookManager::m_Instance = nullptr; // 实现部分 __forceinline KIRQL P极HookManager::DisableWriteProtection() { KIRQL oldIrql = KeRaiseIrqlToDpcLevel(); UINT64 cr0 = __readcr0(); __writecr0(cr0 & ~CR0_WP); // 清除CR0.WP位 _mm_mfence(); return oldIrql; } __forceinline void PteHookManager::EnableWriteProtection(KIRQL oldIrql) { _mm_mfence(); UINT64 cr0 = __readcr0(); __writecr0(cr0 | CR0_WP); // 设置CR0.WP位 KeLowerIrql(oldIrql); } void* PteHookManager::fn_pa_to_va(UINT64 pa) { PHYSICAL_ADDRESS physAddr; physAddr.QuadPart = pa; return MmGetVirtualForPhysical(physAddr); } UINT64 PteHookManager::fn_va_to_pa(void* va) { PHYSICAL_ADDRESS physAddr = MmGetPhysicalAddress(va); return physAddr.QuadPart; } NTSTATUS PteHookManager::get_page_table(UINT64 cr3_val, PAGE_TABLE& table) { UINT64 va = table.LineAddress; UINT64 pml4e_index = (va >> 39) & 0x1FF; UINT64 pdpte_index = (va >> 30) & 0x1FF; UINT64 pde_index = (va >> 21) & 0x1FF; UINT64 pte_index = (va >> 12) & 0x1FF; // PML4 UINT64 pml4_pa = cr3_val & ~0xFFF; UINT64* pml4_va = (UINT64*)fn_pa_to_va(pml4_pa); if (!pml4_va) return STATUS_INVALID_ADDRESS; table.Pml4Address = &pml4_va[pml4e_index]; table.OriginalPml4e = *table.Pml4Address; if (!(table.OriginalPml4e & 1)) return STATUS_ACCESS_VIOLATION; // PDPTE UINT64 pdpte_pa = table.OriginalPml4e & ~0xFFF; UINT64* pdpte_va = (UINT64*)fn_pa_to_va(pdpte_pa); if (!pdpte_va) return STATUS_INVALID_ADDRESS; table.PdpteAddress = (decltype(table.PdpteAddress))&pdpte_va[pdpte_index]; table.OriginalPdpte = table.PdpteAddress->value; table.Is1GBPage = (table.PdpteAddress->flags.page_size) ? TRUE : FALSE; if (!(table.OriginalPdpte & 1)) return STATUS_ACCESS_VIOLATION; if (table.Is1GBPage) return STATUS_SUCCESS; // PDE UINT64 pde_pa = table.OriginalPdpte & ~0xFFF; UINT64* pde_va = (UINT64*)fn_pa_to_va(pde_pa); if (!pde_va) return STATUS_INVALID_ADDRESS; table.PdeAddress = (decltype(table.PdeAddress))&pde_va[pde_index]; table.OriginalPde = table.PdeAddress->value; table.IsLargePage = (table.PdeAddress->flags.large_page) ? TRUE : FALSE; if (!(table.OriginalPde & 1)) return STATUS_ACCESS_VIOLATION; if (table.IsLargePage) return STATUS_SUCCESS; // PTE UINT64 pte_pa = table.OriginalPde & ~0xFFF; UINT64* pte_va = (UINT64*)fn_pa_to_va(pte_pa); if (!pte_va) return STATUS_INVALID_ADDRESS; table.PteAddress = (decltype(table.PteAddress))&pte_va[pte_index]; table.OriginalPte = table.PteAddress->value; if (!(table.OriginalPte & 1)) return STATUS_ACCESS_VIOLATION; LOG_TRACE("Page Table Info: VA=0x%p, PTE=0x%llX", (void*)table.LineAddress, table.OriginalPte); return STATUS_SUCCESS; } bool PteHookManager::fn_split_large_pages(void* in_pde_ptr, void* out_pde_ptr) { auto in_pde = (decltype(PAGE_TABLE::PdeAddress))in_pde_ptr; auto out_pde = (decltype(PAGE_TABLE::PdeAddress))out_pde_ptr; LOG_INFO("Splitting large page: Input PDE=0x%llx", in_pde->value); PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 }; HighAddr.QuadPart = MAXULONG64; auto pt = (decltype(PAGE_TABLE::PteAddress))MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); if (!pt) { LOG_ERROR("Failed to allocate contiguous memory for page splitting"); return false; } UINT64 start_pfn = in_pde->flags.page_frame_number; for (int i = 0; i < 512; i++) { pt[i].value = 0; pt[i].flags.present = 1; pt[i].flags.write = in_pde->flags.write; pt[i].flags.user = in_pde->flags.user; pt[i].flags.write_through = in_pde->flags.write_through; pt[i].flags.cache_disable = in_pde->flags.cache_disable; pt[i].flags.accessed = in_pde->flags.accessed; pt[i].flags.dirty = in_pde->flags.dirty; pt[i].flags.global = 0; pt[i].flags.page_frame_number = start_pfn + i; } out_pde->value = in_pde->value; out_pde->flags.large_page = 0; out_pde->flags.page_frame_number = fn_va_to_pa(pt) >> 12; LOG_INFO("Large page split complete: New PTE table at PA=0x%llx", fn_va_to_pa(pt)); return true; } bool PteHookManager::SetPageExecution(void* address, bool executable) { // 使用页表遍历函数修改NX位 PAGE_TABLE table = { 0 }; table.LineAddress = (UINT64)address; NTSTATUS status = get_page_table(__readcr3(), table); if (!NT_SUCCESS(status)) { LOG_ERROR("Failed to get page table for address 0x%p", address); return false; } KIRQL oldIrql = DisableWriteProtection(); UINT64 oldPte = table.PteAddress->value; UINT64 newPte = oldPte; // 设置或清除NX位 if (executable) { newPte &= ~PTE_NX_BIT; } else { newPte |= PTE_NX_BIT; } table.PteAddress->value = newPte; // 刷新TLB __invlpg(address); _mm_mfence(); EnableWriteProtection(oldIrql); LOG_TRACE("PTE modified for 0x%p: Old=0x%llX, New=0x%llX", address, oldPte, newPte); return true; } bool PteHookManager::fn_isolation_pagetable(UINT64 cr3_val, void* replace_align_addr, void* split_pde_ptr) { PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { 0 }; HighAddr.QuadPart = MAXULONG64; LOG_INFO("Isolating page table: CR3=0x%llx, Address=0x%p", cr3_val, replace_align_addr); auto Va4kb = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, Low极, MmNonCached); auto VaPdt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); auto VaPdpt = (UINT64*)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmNonCached); if (!VaPt || !Va4kb || !VaPdt || !VaPdpt) { if (VaPt) MmFreeContiguousMemory(VaPt); if (Va4kb) MmFreeContiguousMemory(Va4kb); if (VaPdt) MmFreeContiguousMemory(VaPdt); if (VaPdpt) MmFreeContiguousMemory(VaPd极); LOG_ERROR("Failed to allocate contiguous memory for isolation"); return false; } PAGE_TABLE Table = { 0 }; Table.LineAddress = (UINT64)replace_align_addr; NTSTATUS status = get_page_table(cr3_val, Table); if (!NT_SUCCESS(status)) { MmFreeContiguousMemory(VaPt); MmFreeContiguousMemory(Va4kb); MmFreeContiguousMemory(VaPdt); MmFreeContiguousMemory(VaPdpt); LOG_ERROR("get_page_table failed with status 0x%X", status); return false; } UINT64 pte_index = (Table.LineAddress >> 12) & 0x1FF; UINT64 pde_index = (Table.LineAddress >> 21) & 0x1FF; UINT64 pdpte_index = (Table.LineAddress >> 30) & 0x1FF; UINT64 pml4e_index = (Table.LineAddress >> 39) & 0x1FF; memcpy(Va4kb, replace_align_addr, PAGE_SIZE); if (Table.IsLargePage && split_pde_ptr) { auto split_pde = (decltype(PAGE_TABLE::PdeAddress))split_pde_ptr; memcpy(VaPt, (void*)(split_pde->flags.page_frame_number << 12), PAGE_SIZE); } else { memcpy(VaPt, (void*)(Table.PdeAddress->flags.page_frame_number << 12), PAGE_SIZE); } memcpy(VaPdt, (void*)(Table.PdpteAddress->flags.page_frame_number << 12), PAGE_SIZE); memcpy(VaPdpt, (void*)(Table.Pml4Address[pml4e_index] & ~0xFFF), PAGE_SIZE); auto new_pte = (decltype(PAGE_TABLE::PteAddress))VaPt; new_pte[pte_index].flags.page_frame_number = fn_va_to_pa(Va4kb) >> 12; auto new_pde = (decltype(PAGE_TABLE::PdeAddress))VaPdt; new_pde[pde_index].value = Table.OriginalPde; new_pde[pde_index].flags.large_page = 0; new_pde[pde_index].flags.page_frame_number = fn_va_to_pa(VaPt) >> 12; auto new_pdpte = (decltype(PAGE_TABLE::PdpteAddress))VaPdpt; new_pdpte[pdpte_index].flags.page_frame_number = fn_va_to_pa(VaPdt) >> 12; auto new_pml4 = (UINT64*)fn_pa_to_va(cr3_val & ~0xFFF); new_pml4[pml4e_index] = (new_pml4[pml4e_index] & 0xFFF) | (fn_va_to_pa(VaPdpt) & ~0xFFF); __invlpg(replace_align_addr); LOG_INFO("Page table isolation complete: New PFN=0x%llx", fn_va_to_pa(Va4kb) >> 12); return true; } bool PteHookManager::fn_isolation_pages(HANDLE process_id, void* ori_addr) { PEPROCESS Process; if (!NT_SUCCESS(PsLookupProcessByProcessId(process_id, &Process))) { LOG_ERROR("PsLookupProcessByProcessId failed"); return false; } LOG_INFO("Isolating pages: PID=%d, Address=0x%p", HandleToUlong(process_id), ori_addr); KAPC_STATE ApcState; KeStackAttachProcess(Process, &ApcState); void* AlignAddr = PAGE_ALIGN(ori_addr); PAGE_TABLE Table = { 0 }; Table.LineAddress = (UINT64)AlignAddr; UINT64 target_cr3 = *(UINT64*)((UCHAR*)Process + 0x28); if (!NT_SUCCESS(get_page_table(target_cr3, Table))) { KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); LOG_ERROR("get_page_table failed"); return false; } bool success = false; decltype(PAGE_TABLE::PdeAddress) split_pde = nullptr; if (Table.IsLargePage) { split_pde = (decltype(PAGE_TABLE::PdeAddress))ExAllocatePoolWithTag(NonPagedPool, sizeof(*split_pde), 'pdeS'); if (!split_pde || !fn_split_large_pages(Table.PdeAddress, split_pde)) { if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS'); KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); LOG_ERROR("Splitting large page failed"); return false; } if (Table.PdeAddress->flags.global) { Table.PdeAddress->flags.global = 0; fn_add_g_bit_info(AlignAddr, Table.PdeAddress, nullptr); LOG_INFO("Cleared G-bit for large page PDE: 0x%llx", Table.PdeAddress->value); } } else if (Table.PteAddress && Table.PteAddress->flags.global) { Table.PteAddress->flags.global = 0; fn_add_g_bit_info(AlignAddr, nullptr, Table.PteAddress); LOG_INFO("Cleared G-bit for PTE: 0x%llx", Table.PteAddress->value); } success = fn_isolation_pagetable(__readcr3(), AlignAddr, split_pde); if (split_pde) ExFreePoolWithTag(split_pde, 'pdeS'); KeUnstackDetachProcess(&ApcState); ObDereferenceObject(Process); if (success) { LOG_INFO("Page isolation successful"); } else { LOG_ERROR("Page isolation failed"); } return success; } bool PteHookManager::WriteTrampolineInstruction(void* trampoline, const JMP_ABS& jmpCmd) { // 确保8字节对齐 if (reinterpret_cast<ULONG_PTR>(trampoline) & 0x7) { LOG_ERROR("Trampoline address not aligned: 0x%p", trampoline); return false; } // 禁用写保护 KIRQL oldIrql = DisableWriteProtection(); // 直接写入内存 RtlCopyMemory(trampoline, &jmpCmd, sizeof(JMP_ABS)); // 刷新缓存 __invlpg(trampoline); _mm_mfence(); // 恢复写保护 EnableWriteProtection(oldIrql); LOG_TRACE("Trampoline instruction written at 0x%p", trampoline); return true; } void PteHookManager::fn_add_g_bit_info(void* align_addr, void* pde_address, void* pte_address) { if (m_GbitCount >= MAX_G_BIT_RECORDS) { LOG_ERROR("Max G-bit records reached"); return; } PG_BIT_INFO record = &m_GbitRecords[m_GbitCount++]; record->AlignAddress = align_addr; record->PdeAddress = (decltype(G_BIT_INFO::PdeAddress))pde_address; record->PteAddress = (decltype(G_BIT_INFO::PteAddress))pte_address; record->IsLargePage = (pde_address != nullptr); LOG_TRACE("Added G-bit record: Address=0x%p, PDE=0x%p, PTE=0x%p", align_addr, pde_address, pte_address); } bool PteHookManager::fn_resume_global_bits(void* align_addr) { KIRQL oldIrql = DisableWriteProtection(); bool found = false; LOG_INFO("Restoring G-bits for address: 0x%p", align_addr); for (UINT32 i = 0; i < m_GbitCount; i++) { PG_BIT_INFO record = &m_GbitRecords[i]; if (align_addr && record->AlignAddress != align_addr) continue; if (record->PteAddress) { record->PteAddress->flags.global = 1; __invlpg(record->AlignAddress); LOG_TRACE("Restored G-bit for PTE: 0x%p", record->AlignAddress); } if (record->PdeAddress) { record->PdeAddress->flags.global = 1; if (record->IsLargePage) { __invlpg(record->AlignAddress); } LOG_TRACE("Restored G-bit for PDE: 0x%p", record->AlignAddress); } found = true; if (align_addr) break; } EnableWriteProtection(oldIrql); if (found) { LOG_INFO("G-bits restoration complete"); } else { LOG_ERROR("No matching G-bit record found"); } return found; } bool PteHookManager::fn_pte_inline_hook_bp_pg(HANDLE process_id, _Inout_ void** ori_addr, void* hk_addr) { if (!ori_addr || !hk_addr || !*ori_addr) { LOG_ERROR("Invalid parameters: ori_addr=%p, hk_addr=%p", ori_addr, hk_addr); return false; } // 分配跳板池(如果尚未分配) if (!m_TrampLinePool) { PHYSICAL_ADDRESS LowAddr; LowAddr.QuadPart = 0x100000; PHYSICAL_ADDRESS HighAddr; HighAddr.QuadPart = ~0ull; m_TrampLinePool = (char*)MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE * 8, LowAddr, HighAddr, LowAddr, MmNonCached); if (!m_TrampLinePool) { LOG_ERROR("Failed to allocate trampoline pool"); return false; } // 设置跳板池可执行 if (!SetPageExecution(m_TrampLinePool, true)) { MmFreeContiguousMemory(m_TrampLinePool); m_TrampLinePool = nullptr; LOG_ERROR("Failed to set trampoline pool executable"); return false; } LOG_INFO("Trampoline pool allocated: Address=0x%p, Size=%d bytes", m_TrampLinePool, PAGE_SIZE * 8); } // 计算跳板位置(16字节对齐确保RIP相对寻址) void* trampoline = (void*)((ULONG_PTR)(m_TrampLinePool + m_PoolUsed + 15) & ~15); SIZE_T requiredSize = ((char*)trampoline - m_TrampLinePool) + sizeof(JMP_ABS); // 检查跳板池空间 if (requiredSize > PAGE_SIZE * 8) { LOG_ERROR("Trampoline pool out of space: Used=%d, Required=%d", m_PoolUsed, requiredSize); return false; } // 构造跳转指令 JMP_ABS jmpCmd; memcpy(jmpCmd.opcode, "\xFF\x25\x00\x00\x00\x00", 6); // jmp [rip+0] jmpCmd.address = reinterpret_cast<ULONG64>(hk_addr); LOG_INFO("Constructing jump instruction: Target=0x%p, Trampoline=0x%p", hk_addr, trampoline); // 写入跳板指令 if (!WriteTrampolineInstruction(trampoline, jmpCmd)) { return false; } // 设置目标函数不可执行(触发页错误) if (!SetPageExecution(*ori_addr, false)) { LOG_ERROR("Failed to set target function non-executable"); return false; } // 记录Hook信息 bool hookRecorded = false; for (UINT32 i = 0; i < MAX_HOOK_COUNT; i++) { if (!m_HookInfo[i].IsHooked) { m_HookInfo[i].OriginalAddress = *ori_addr; m_HookInfo[i].HookAddress = trampoline; m_HookInfo[i].ProcessId = process_id; m_HookInfo极i].IsHooked = TRUE; m_HookInfo[i].HookLength = sizeof(JMP_ABS); RtlCopyMemory(m_HookInfo[i].HookBytes, &jmpCmd, sizeof(jmpCmd)); // 保存原始PTE值 PAGE_TABLE table = { 0 }; table.LineAddress = (UINT64)*ori_addr; if (NT_SUCCESS(get_page_table(__readcr3(), table))) { m_HookInfo[i].OriginalPteValue = table.OriginalPte; } m_HookCount++; hookRecorded = true; LOG_INFO("Hook recorded #%d: Original=0x%p, Trampoline=0x%p", i, *ori_addr, trampoline); break; } } if (!hookRecorded) { LOG_ERROR("Exceeded max hook count (%d)", MAX_HOOK_COUNT); return false; } // 更新原始地址为跳板地址 *ori_addr = trampoline; m_PoolUsed = (UINT32)requiredSize; LOG_INFO("Hook installed successfully: Trampoline=0x%p -> Hook=0x%p", trampoline, hk_addr); return true; } bool PteHookManager::fn_remove_hook(HANDLE process_id, void* hook_addr) { LOG_INFO("Removing hook: HookAddr=0x%p", hook_addr); for (UINT32 i = 0; i < m_HookCount; i++) { if (m_HookInfo[i].HookAddress == hook_addr && m_HookInfo[i].IsHooked) { LOG_INFO("Found matching hook: OriginalAddr=0x%p", m_HookInfo[i].OriginalAddress); // 恢复目标函数执行权限 SetPageExecution(m_HookInfo[i].OriginalAddress, true); // 恢复原始PTE值 if (m_HookInfo[i].OriginalPteValue) { PAGE_TABLE table = { 0 }; table.LineAddress = (UINT64)m_HookInfo[i].OriginalAddress; if (NT_SUCCESS(get_page_table(__readcr3(), table))) { KIRQL oldIrql = KeRaiseIrqlToDpcLevel(); table.PteAddress->value = m_HookInfo[i].OriginalPteValue; __invlpg(m_HookInfo[i].OriginalAddress); KeLowerIrql(oldIrql); LOG_TRACE("Restored PTE for 0x%p: 0x%llX", m_HookInfo[i].OriginalAddress, m_HookInfo[i].OriginalPteValue); } } m_HookInfo[i].IsHooked = FALSE; LOG_INFO("Hook removed successfully"); return true; } } LOG_ERROR("No matching hook found"); return false; } PteHookManager::~PteHookManager() { if (m_TrampLinePool) { MmFreeContiguousMemory(m_TrampLinePool); m_TrampLinePool = nullptr; LOG_INFO("Trampoline pool freed"); } } PteHookManager* PteHookManager::GetInstance() { if (!m_Instance) { m_Instance = static_cast<PteHookManager*>( ExAllocatePoolWithTag(NonPagedPool, sizeof(PteHookManager), 'tpHk')); if (m_Instance) { RtlZeroMemory(m_Instance, sizeof(PteHookManager)); LOG_INFO("PTE Hook Manager instance created: 0x%p", m_Instance); } else { LOG_ERROR("Failed to create PTE Hook Manager instance"); } } return m_Instance; } // 全局PTE Hook管理器实例 PteHookManager* g_PteHookManager = nullptr; // 目标进程名称 const char target_process_name[] = "oxygen.exe"; // 辅助函数:检查是否为目标进程 BOOLEAN IsTargetProcess(CHAR* imageName) { CHAR currentName[16]; RtlZeroMemory(currentName, sizeof(currentName)); strncpy(currentName, imageName, sizeof(currentName) - 1); return (_stricmp(currentName, target_process_name) == 0); } // 函数类型定义 typedef NTSTATUS(*fn_ObReferenceObjectByHandleWithTag)( HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, ULONG Tag, PVOID* Object, POBJECT_HANDLE_INFORMATION HandleInformation ); fn_ObReferenceObjectByHandleWithTag g_OriginalObReferenceObjectByHandleWithTag = nullptr; // Hook 函数 NTSTATUS MyObReferenceObjectByHandleWithTag( HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, ULONG Tag, PVOID* Object, POBJECT_HANDLE_INFORMATION HandleInformation ) { PEPROCESS currentProcess = PsGetCurrentProcess(); CHAR* imageName = PsGetProcessImageFileName(currentProcess); LOG_INFO("Hook function called by process: %s", imageName); if (IsTargetProcess(imageName)) { LOG_INFO("Access denied for target process: %s", imageName); return STATUS_ACCESS_DENIED; } return g_OriginalObReferenceObjectByHandleWithTag( Handle, DesiredAccess, ObjectType, AccessMode, Tag, Object, HandleInformation ); } NTSTATUS InstallHook(HANDLE targetProcessId) { UNICODE_STRING funcName; RtlInitUnicodeString(&funcName, L"ObReferenceObjectByHandleWithTag"); g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)MmGetSystemRoutineAddress(&funcName); if (!g_OriginalObReferenceObjectByHandleWithTag) { LOG_ERROR("ObReferenceObjectByHandleWithTag not found"); return STATUS_NOT_FOUND; } LOG_INFO("Target function found: 0x%p", g_OriginalObReferenceObjectByHandleWithTag); void* targetFunc = (void*)g_OriginalObReferenceObjectByHandleWithTag; void* hookFunc = (void*)MyObReferenceObjectByHandleWithTag; if (!g_PteHookManager->fn_pte_inline_hook_bp_pg(targetProcessId, &targetFunc, hookFunc)) { LOG_ERROR("PTE Hook installation failed"); return STATUS_UNSUCCESSFUL; } g_OriginalObReferenceObjectByHandleWithTag = (fn_ObReferenceObjectByHandleWithTag)targetFunc; LOG_INFO("Hook installed successfully. Trampoline: 0x%p", targetFunc); return STATUS_SUCCESS; } // 移除 Hook VOID RemoveHook() { if (g_OriginalObReferenceObjectByHandleWithTag && g_PteHookManager) { g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), (void*)MyObReferenceObjectByHandleWithTag); } } // 工作线程上下文 typedef struct _HOOK_THREAD_CONTEXT { HANDLE TargetProcessId; } HOOK_THREAD_CONTEXT, * PHOOK_THREAD_CONTEXT; // 工作线程函数 VOID InstallHookWorker(PVOID Context) { PHOOK_THREAD_CONTEXT ctx = (PHOOK_THREAD_CONTEXT)Context; if (ctx) { LOG_INFO("Installing hook for PID: %d", HandleToUlong(ctx->TargetProcessId)); InstallHook(ctx->TargetProcessId); ExFreePoolWithTag(ctx, 'CtxH'); } PsTerminateSystemThread(STATUS_SUCCESS); } // 进程创建回调 - 修正后的签名 VOID ProcessNotifyCallback( _In_ PEPROCESS Process, _In_ HANDLE ProcessId, _In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo ) { if (CreateInfo != NULL) { // 进程创建 CHAR* imageName = PsGetProcessImageFileName(Process); if (IsTargetProcess(imageName)) { LOG_INFO("Target process created: %s (PID: %d)", imageName, HandleToUlong(ProcessId)); // 创建工作线程上下文 PHOOK_THREAD_CONTEXT ctx = (PHOOK_THREAD_CONTEXT)ExAllocatePoolWithTag(NonPagedPool, sizeof(HOOK_THREAD_CONTEXT), 'CtxH'); if (ctx) { ctx->TargetProcessId = ProcessId; HANDLE threadHandle; NTSTATUS status = PsCreateSystemThread( &threadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, InstallHookWorker, ctx ); if (NT_SUCCESS(status)) { ZwClose(threadHandle); LOG_INFO("Worker thread created for hook installation"); } else { ExFreePoolWithTag(ctx, 'CtxH'); LOG_ERROR("Failed to create worker thread: 0x%X", status); } } else { LOG_ERROR("Failed to allocate thread context"); } } } } // 驱动卸载函数 VOID DriverUnload(PDRIVER_OBJECT DriverObject) { UNREFERENCED_PARAMETER(DriverObject); LOG_INFO("Driver unloading..."); // 移除进程通知回调 PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallback, TRUE); // 移除Hook RemoveHook(); // 清理PTE Hook资源 if (g_PteHookManager) { LOG_INFO("Cleaning up PTE Hook Manager"); // 恢复所有被修改的G位 g_PteHookManager->fn_resume_global_bits(nullptr); // 移除所有活动的Hook HOOK_INFO* hookInfo = g_PteHookManager->GetHookInfo(); UINT32 hookCount = g_PteHookManager->GetHookCount(); for (UINT32 i = 0; i < hookCount; i++) { if (hookInfo[i].IsHooked) { g_PteHookManager->fn_remove_hook(PsGetCurrentProcessId(), hookInfo[i].HookAddress); } } // 释放管理器实例 ExFreePoolWithTag(g_PteHookManager, 'tpHk'); g_PteHookManager = nullptr; } LOG_INFO("Driver unloaded successfully"); } extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { UNREFERENCED_PARAMETER(RegistryPath); LOG_INFO("Driver loading..."); DriverObject->DriverUnload = DriverUnload; g_PteHookManager = PteHookManager::GetInstance(); if (!g_PteHookManager) { LOG_ERROR("Failed to initialize PteHookManager"); return STATUS_INSUFFICIENT_RESOURCES; } NTSTATUS status = PsSetCreateProcessNotifyRoutineEx(ProcessNotifyCallback, FALSE); if (!NT_SUCCESS(status)) { LOG_ERROR("Failed to register process callback: 0x%X", status); return status; } LOG_INFO("Driver loaded successfully"); return STATUS_SUCCESS; } 严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误(活动) E0020 未定义标识符 "极" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 51 错误(活动) E0276 后面有“::”的名称一定是类名或命名空间名 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 203 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 276 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 349 错误(活动) E0020 未定义标识符 "Low极" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 360 错误(活动) E0020 未定义标识符 "VaPd极" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 368 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 508 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 524 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 541 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 549 错误(活动) E0020 未定义标识符 "m_HookInfo极i" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636 错误(活动) E0065 应输入“;” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636 错误(活动) E0020 未定义标识符 "DPFLTR极IHVDRIVER_ID" obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 687 错误 C2065 “极”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 51 错误 C2653 “P极HookManager”: 不是类或命名空间名称 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 203 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 276 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 349 错误 C2065 “Low极”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 360 错误 C3536 “VaPt”: 初始化之前无法使用 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 364 错误 C2664 “void MmFreeContiguousMemory(PVOID)”: 无法将参数 1 从“int”转换为“PVOID” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 365 错误 C2065 “VaPd极”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 368 错误 C2664 “void MmFreeContiguousMemory(PVOID)”: 无法将参数 1 从“int”转换为“PVOID” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 377 错误 C2664 “void *memcpy(void *,const void *,size_t)”: 无法将参数 1 从“int”转换为“void *” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 394 错误 C2664 “void *memcpy(void *,const void *,size_t)”: 无法将参数 1 从“int”转换为“void *” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 397 错误 C2664 “UINT64 PteHookManager::fn_va_to_pa(void *)”: 无法将参数 1 从“int”转换为“void *” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 409 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 508 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 524 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 541 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 549 错误 C2065 “m_HookInfo极i”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636 错误 C2143 语法错误: 缺少“;”(在“]”的前面) obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636 错误 C2059 语法错误:“]” obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 636 错误 C2065 “DPFLTR极IHVDRIVER_ID”: 未声明的标识符 obpcallback C:\Users\17116\source\repos\obpcallback\obpcallback\源.cpp 687
06-26
这是我的button.hbutton.c文件 /** * @File: flexible_button.h * @Author: MurphyZhao * @Date: 2018-09-29 * * Copyright (c) 2018-2019 MurphyZhao <d2014zjt@163.com> * https://github.com/murphyzhao * All rights reserved. * License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Change logs: * Date Author Notes * 2018-09-29 MurphyZhao First add * 2019-08-02 MurphyZhao Migrate code to github.com/murphyzhao account * 2019-12-26 MurphyZhao Refactor code and implement multiple clicks * */ #ifndef __BUTTON_H__ #define __BUTTON_H__ #include "stdint.h" #include "key_app.h" #include "KEY.h" #define FLEX_BTN_SCAN_FREQ_HZ 50 // How often flex_button_scan () is called #define FLEX_MS_TO_SCAN_CNT(ms) (ms / (1000 / FLEX_BTN_SCAN_FREQ_HZ)) /* Multiple clicks interval, default 300ms */ #define MAX_MULTIPLE_CLICKS_INTERVAL (FLEX_MS_TO_SCAN_CNT(300)) /** * @brief 按钮事件枚举类型 * * 定义了各种按钮触发事件类型,包括: * - 按下(FLEX_BTN_PRESS_DOWN) * - 单击(FLEX_BTN_PRESS_CLICK) * - 双击(FLEX_BTN_PRESS_DOUBLE_CLICK) * - 重复点击(FLEX_BTN_PRESS_REPEAT_CLICK) * - 短按开始(FLEX_BTN_PRESS_SHORT_START) * - 短按抬起(FLEX_BTN_PRESS_SHORT_UP) * - 长按开始(FLEX_BTN_PRESS_LONG_START) * - 长按抬起(FLEX_BTN_PRESS_LONG_UP) * - 长按保持(FLEX_BTN_PRESS_LONG_HOLD) * - 长按保持后抬起(FLEX_BTN_PRESS_LONG_HOLD_UP) * - 最大值(FLEX_BTN_PRESS_MAX) * - 无事件(FLEX_BTN_PRESS_NONE) */ typedef enum { FLEX_BTN_PRESS_DOWN = 0, FLEX_BTN_PRESS_CLICK, FLEX_BTN_PRESS_DOUBLE_CLICK, FLEX_BTN_PRESS_REPEAT_CLICK, FLEX_BTN_PRESS_SHORT_START, FLEX_BTN_PRESS_SHORT_UP, FLEX_BTN_PRESS_LONG_START, FLEX_BTN_PRESS_LONG_UP, FLEX_BTN_PRESS_LONG_HOLD, FLEX_BTN_PRESS_LONG_HOLD_UP, FLEX_BTN_PRESS_MAX, FLEX_BTN_PRESS_NONE, } flex_button_event_t; /** * flex_button_t * * @brief Button data structure * Below are members that need to user init before scan. * * @member next * Internal use. * One-way linked list, pointing to the next button. * * @member usr_button_read * User function is used to read button vaule. * * @member cb * Button event callback function. * * @member scan_cnt * Internal use, user read-only. * Number of scans, counted when the button is pressed, plus one per scan cycle. * * @member click_cnt * Internal use, user read-only. * Number of button clicks * * @member max_multiple_clicks_interval * Multiple click interval. Default 'MAX_MULTIPLE_CLICKS_INTERVAL'. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member debounce_tick * Debounce. Not used yet. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member short_press_start_tick * Short press start time. Requires user configuration. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member long_press_start_tick * Long press start time. Requires user configuration. * Need to use FLEX_MS_TO_SCAN_CNT to convert milliseconds into scan cnts. * * @member long_hold_start_tick * Long hold press start time. Requires user configuration. * * @member id * Button id. Requires user configuration. * When multiple buttons use the same button callback function, * they are used to distinguish the buttons. * Each button id must be unique. * * @member pressed_logic_level * Requires user configuration. * The logic level of the button pressed, each bit represents a button. * * @member event * Internal use, users can call 'flex_button_event_read' to get current button event. * Used to record the current button event. * * @member status * Internal use, user unavailable. * Used to record the current state of buttons. * */ typedef struct flex_button { struct flex_button* next; uint8_t (*usr_button_read)(void *); flex_button_response_callback cb; uint16_t scan_cnt; uint16_t click_cnt; uint16_t max_multiple_clicks_interval; uint16_t debounce_tick; uint16_t short_press_start_tick; uint16_t long_press_start_tick; uint16_t long_hold_start_tick; uint8_t id; uint8_t pressed_logic_level : 1; uint8_t event : 4; uint8_t status : 3; } flex_button_t; #ifdef __cplusplus extern "C" { #endif int32_t flex_button_register(flex_button_t *button); flex_button_event_t flex_button_event_read(flex_button_t* button); uint8_t flex_button_scan(void); void user_button_init(void); #ifdef __cplusplus } #endif #endif /* __FLEXIBLE_BUTTON_H__ */ /** * @File: flexible_button.c * @Author: MurphyZhao * @Date: 2018-09-29 * * Copyright (c) 2018-2019 MurphyZhao <d2014zjt@163.com> * https://github.com/murphyzhao * All rights reserved. * License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Change logs: * Date Author Notes * 2018-09-29 MurphyZhao First add * 2019-08-02 MurphyZhao Migrate code to github.com/murphyzhao account * 2019-12-26 MurphyZhao Refactor code and implement multiple clicks * */ #include "button.h" #include "KEY.h" #include "string.h" #include "key_app.h" typedef enum { USER_BUTTON_UP = 0, // 对应 IoT Board 开发板的 PIN_KEY0 USER_BUTTON_LEFT, // 对应 IoT Board 开发板的 PIN_KEY1 USER_BUTTON_RIGHT, // 对应 IoT Board 开发板的 PIN_KEY2 USER_BUTTON_DOWN, USER_BUTTON_MID, // 对应 IoT Board 开发板的 PIN_WK_UP USER_BUTTON_MAX } user_button_t; static flex_button_t user_button[USER_BUTTON_MAX]; static uint8_t common_btn_read(void *arg) { uint8_t value = 0; flex_button_t *btn = (flex_button_t *)arg; switch (btn->id) { case USER_BUTTON_UP: value = key_scan().up; break; case USER_BUTTON_LEFT: value = key_scan().left; break; case USER_BUTTON_RIGHT: value =key_scan().right; break; case USER_BUTTON_DOWN: value = key_scan().down; break; case USER_BUTTON_MID: value = key_scan().mid; break; } return value; } // 配置项 说明 // id 按键编号 // usr_button_read 设置按键读值回调函数 // cb 设置按键事件回调函数 // pressed_logic_level 设置按键按下时的逻辑电平 // short_press_start_tick 短按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // long_press_start_tick 长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // long_hold_start_tick 超长按起始 tick,使用 FLEX_MS_TO_SCAN_CNT 宏转化为扫描次数 // 注意,short_press_start_tick、long_press_start_tick long_hold_start_tick 必须使用 FLEX_MS_TO_SCAN_CNT 将毫秒时间转化为扫描次数。 // user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); 表示按键按下开始计时,1500 ms 后按键依旧是按下状态的话,就断定为短按开始。 //--------------------------------------------------改到这里了----------------------------- void user_button_init(void) { int i; memset(&user_button[0], 0x0, sizeof(user_button)); user_button[USER_BUTTON_UP].cb = up_btn_evt_cb; user_button[USER_BUTTON_LEFT].cb = left_btn_evt_cb; user_button[USER_BUTTON_RIGHT].cb = right_btn_evt_cb; user_button[USER_BUTTON_DOWN].cb = down_btn_evt_cb; user_button[USER_BUTTON_MID].cb = mid_btn_evt_cb; for (i = 0; i < USER_BUTTON_MAX; i ++) { user_button[i].id = i; user_button[i].usr_button_read = common_btn_read; user_button[i].pressed_logic_level = 0; user_button[i].short_press_start_tick = FLEX_MS_TO_SCAN_CNT(1500); user_button[i].long_press_start_tick = FLEX_MS_TO_SCAN_CNT(3000); user_button[i].long_hold_start_tick = FLEX_MS_TO_SCAN_CNT(4500); flex_button_register(&user_button[i]); } } #ifndef NULL #define NULL 0 #endif #define EVENT_SET_AND_EXEC_CB(btn, evt) \ do \ { \ btn->event = evt; \ if(btn->cb) \ btn->cb((flex_button_t*)btn); \ } while(0) /** * BTN_IS_PRESSED * * 1: is pressed * 0: is not pressed */ #define BTN_IS_PRESSED(i) (g_btn_status_reg & (1 << i)) enum FLEX_BTN_STAGE { FLEX_BTN_STAGE_DEFAULT = 0, FLEX_BTN_STAGE_DOWN = 1, FLEX_BTN_STAGE_MULTIPLE_CLICK = 2 }; typedef uint32_t btn_type_t; static flex_button_t *btn_head = NULL; /** * g_logic_level * * The logic level of the button pressed, * Each bit represents a button. * * First registered button, the logic level of the button pressed is * at the low bit of g_logic_level. */ btn_type_t g_logic_level = (btn_type_t)0; /** * g_btn_status_reg * * The status register of all button, each bit records the pressing state of a button. * * First registered button, the pressing state of the button is * at the low bit of g_btn_status_reg. */ btn_type_t g_btn_status_reg = (btn_type_t)0; static uint8_t button_cnt = 0; /** * @brief Register a user button * * @param button: button structure instance * @return Number of keys that have been registered, or -1 when error */ int32_t flex_button_register(flex_button_t *button) { flex_button_t *curr = btn_head; if (!button || (button_cnt > sizeof(btn_type_t) * 8)) { return -1; } while (curr) { if(curr == button) { return -1; /* already exist. */ } curr = curr->next; } /** * First registered button is at the end of the 'linked list'. * btn_head points to the head of the 'linked list'. */ button->next = btn_head; button->status = FLEX_BTN_STAGE_DEFAULT; button->event = FLEX_BTN_PRESS_NONE; button->scan_cnt = 0; button->click_cnt = 0; button->max_multiple_clicks_interval = MAX_MULTIPLE_CLICKS_INTERVAL; btn_head = button; /** * First registered button, the logic level of the button pressed is * at the low bit of g_logic_level. */ g_logic_level |= (button->pressed_logic_level << button_cnt); button_cnt ++; return button_cnt; } /** * @brief Read all key values in one scan cycle * * @param void * @return none */ static void flex_button_read(void) { uint8_t i; flex_button_t* target; /* The button that was registered first, the button value is in the low position of raw_data */ btn_type_t raw_data = 0; for(target = btn_head, i = button_cnt - 1; (target != NULL) && (target->usr_button_read != NULL); target = target->next, i--) { raw_data = raw_data | ((target->usr_button_read)(target) << i); } g_btn_status_reg = (~raw_data) ^ g_logic_level; } /** * @brief Handle all key events in one scan cycle. * Must be used after 'flex_button_read' API * * @param void * @return Activated button count */ static uint8_t flex_button_process(void) { uint8_t i; uint8_t active_btn_cnt = 0; flex_button_t* target; for (target = btn_head, i = button_cnt - 1; target != NULL; target = target->next, i--) { if (target->status > FLEX_BTN_STAGE_DEFAULT) { target->scan_cnt ++; if (target->scan_cnt >= ((1 << (sizeof(target->scan_cnt) * 8)) - 1)) { target->scan_cnt = target->long_hold_start_tick; } } switch (target->status) { case FLEX_BTN_STAGE_DEFAULT: /* stage: default(button up) */ if (BTN_IS_PRESSED(i)) /* is pressed */ { target->scan_cnt = 0; target->click_cnt = 0; EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_DOWN); /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; } else { target->event = FLEX_BTN_PRESS_NONE; } break; case FLEX_BTN_STAGE_DOWN: /* stage: button down */ if (BTN_IS_PRESSED(i)) /* is pressed */ { if (target->click_cnt > 0) /* multiple click */ { if (target->scan_cnt > target->max_multiple_clicks_interval) { EVENT_SET_AND_EXEC_CB(target, target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ? target->click_cnt : FLEX_BTN_PRESS_REPEAT_CLICK); /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; target->scan_cnt = 0; target->click_cnt = 0; } } else if (target->scan_cnt >= target->long_hold_start_tick) { if (target->event != FLEX_BTN_PRESS_LONG_HOLD) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD); } } else if (target->scan_cnt >= target->long_press_start_tick) { if (target->event != FLEX_BTN_PRESS_LONG_START) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_START); } } else if (target->scan_cnt >= target->short_press_start_tick) { if (target->event != FLEX_BTN_PRESS_SHORT_START) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_START); } } } else /* button up */ { if (target->scan_cnt >= target->long_hold_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_HOLD_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else if (target->scan_cnt >= target->long_press_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_LONG_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else if (target->scan_cnt >= target->short_press_start_tick) { EVENT_SET_AND_EXEC_CB(target, FLEX_BTN_PRESS_SHORT_UP); target->status = FLEX_BTN_STAGE_DEFAULT; } else { /* swtich to multiple click stage */ target->status = FLEX_BTN_STAGE_MULTIPLE_CLICK; target->click_cnt ++; } } break; case FLEX_BTN_STAGE_MULTIPLE_CLICK: /* stage: multiple click */ if (BTN_IS_PRESSED(i)) /* is pressed */ { /* swtich to button down stage */ target->status = FLEX_BTN_STAGE_DOWN; target->scan_cnt = 0; } else { if (target->scan_cnt > target->max_multiple_clicks_interval) { EVENT_SET_AND_EXEC_CB(target, target->click_cnt < FLEX_BTN_PRESS_REPEAT_CLICK ? target->click_cnt : FLEX_BTN_PRESS_REPEAT_CLICK); /* swtich to default stage */ target->status = FLEX_BTN_STAGE_DEFAULT; } } break; } if (target->status > FLEX_BTN_STAGE_DEFAULT) { active_btn_cnt ++; } } return active_btn_cnt; } /** * flex_button_event_read * * @brief Get the button event of the specified button. * * @param button: button structure instance * @return button event */ flex_button_event_t flex_button_event_read(flex_button_t* button) { return (flex_button_event_t)(button->event); } /** * flex_button_scan * * @brief Start key scan. * Need to be called cyclically within the specified period. * Sample cycle: 5 - 20ms * * @param void * @return Activated button count */ uint8_t flex_button_scan(void) { flex_button_read(); return flex_button_process(); }
07-13
翻译成中文,仅做翻译: 18. Multicast DNS Message Format This section describes specific rules pertaining to the allowable values for the header fields of a Multicast DNS message, and other message format considerations. 18.1. ID (Query Identifier) Multicast DNS implementations SHOULD listen for unsolicited responses issued by hosts booting up (or waking up from sleep or otherwise joining the network). Since these unsolicited responses may contain a useful answer to a question for which the querier is currently awaiting an answer, Multicast DNS implementations SHOULD examine all received Multicast DNS response messages for useful answers, without regard to the contents of the ID field or the Question Section. In Multicast DNS, knowing which particular query message (if any) is responsible for eliciting a particular response message is less interesting than knowing whether the response message contains useful information. Multicast DNS implementations MAY cache data from any or all Multicast DNS response messages they receive, for possible future use, provided of course that normal TTL aging is performed on these cached resource records. In multicast query messages, the Query Identifier SHOULD be set to zero on transmission. In multicast responses, including unsolicited multicast responses, the Query Identifier MUST be set to zero on transmission, and MUST be ignored on reception. In legacy unicast response messages generated specifically in response to a particular (unicast or multicast) query, the Query Identifier MUST match the ID from the query message. 18.2. QR (Query/Response) Bit In query messages the QR bit MUST be zero. In response messages the QR bit MUST be one. 18.3. OPCODE In both multicast query and multicast response messages, the OPCODE MUST be zero on transmission (only standard queries are currently supported over multicast). Multicast DNS messages received with an OPCODE other than zero MUST be silently ignored. 18.4. AA (Authoritative Answer) Bit In query messages, the Authoritative Answer bit MUST be zero on transmission, and MUST be ignored on reception. In response messages for Multicast domains, the Authoritative Answer bit MUST be set to one (not setting this bit would imply there's some other place where "better" information may be found) and MUST be ignored on reception. 18.5. TC (Truncated) Bit In query messages, if the TC bit is set, it means that additional Known-Answer records may be following shortly. A responder SHOULD record this fact, and wait for those additional Known-Answer records, before deciding whether to respond. If the TC bit is clear, it means that the querying host has no additional Known Answers. In multicast response messages, the TC bit MUST be zero on transmission, and MUST be ignored on reception. In legacy unicast response messages, the TC bit has the same meaning as in conventional Unicast DNS: it means that the response was too large to fit in a single packet, so the querier SHOULD reissue its query using TCP in order to receive the larger response. 18.6. RD (Recursion Desired) Bit In both multicast query and multicast response messages, the Recursion Desired bit SHOULD be zero on transmission, and MUST be ignored on reception. 18.7. RA (Recursion Available) Bit In both multicast query and multicast response messages, the Recursion Available bit MUST be zero on transmission, and MUST be ignored on reception. 18.8. Z (Zero) Bit In both query and response messages, the Zero bit MUST be zero on transmission, and MUST be ignored on reception. 18.9. AD (Authentic Data) Bit In both multicast query and multicast response messages, the Authentic Data bit [RFC2535] MUST be zero on transmission, and MUST be ignored on reception. 18.10. CD (Checking Disabled) Bit In both multicast query and multicast response messages, the Checking Disabled bit [RFC2535] MUST be zero on transmission, and MUST be ignored on reception. 18.11. RCODE (Response Code) In both multicast query and multicast response messages, the Response Code MUST be zero on transmission. Multicast DNS messages received with non-zero Response Codes MUST be silently ignored. 18.12. Repurposing of Top Bit of qclass in Question Section In the Question Section of a Multicast DNS query, the top bit of the qclass field is used to indicate that unicast responses are preferred for this particular question. (See Section 5.4.) 18.13. Repurposing of Top Bit of rrclass in Resource Record Sections In the Resource Record Sections of a Multicast DNS response, the top bit of the rrclass field is used to indicate that the record is a member of a unique RRSet, and the entire RRSet has been sent together (in the same packet, or in consecutive packets if there are too many records to fit in a single packet). (See Section 10.2.) 18.14. Name Compression When generating Multicast DNS messages, implementations SHOULD use name compression wherever possible to compress the names of resource records, by replacing some or all of the resource record name with a compact two-byte reference to an appearance of that data somewhere earlier in the message [RFC1035]. This applies not only to Multicast DNS responses, but also to queries. When a query contains more than one question, successive questions in the same message often contain similar names, and consequently name compression SHOULD be used, to save bytes. In addition, queries may also contain Known Answers in the Answer Section, or probe tiebreaking data in the Authority Section, and these names SHOULD similarly be compressed for network efficiency. In addition to compressing the *names* of resource records, names that appear within the *rdata* of the following rrtypes SHOULD also be compressed in all Multicast DNS messages: NS, CNAME, PTR, DNAME, SOA, MX, AFSDB, RT, KX, RP, PX, SRV, NSEC Until future IETF Standards Action [RFC5226] specifying that names in the rdata of other types should be compressed, names that appear within the rdata of any type not listed above MUST NOT be compressed. Implementations receiving Multicast DNS messages MUST correctly decode compressed names appearing in the Question Section, and compressed names of resource records appearing in other sections. In addition, implementations MUST correctly decode compressed names appearing within the *rdata* of the rrtypes listed above. Where possible, implementations SHOULD also correctly decode compressed names appearing within the *rdata* of other rrtypes known to the implementers at the time of implementation, because such forward- thinking planning helps facilitate the deployment of future implementations that may have reason to compress those rrtypes. It is possible that no future IETF Standards Action [RFC5226] will be created that mandates or permits the compression of rdata in new types, but having implementations designed such that they are capable of decompressing all known types helps keep future options open. One specific difference between Unicast DNS and Multicast DNS is that Unicast DNS does not allow name compression for the target host in an SRV record, because Unicast DNS implementations before the first SRV specification in 1996 [RFC2052] may not decode these compressed records properly. Since all Multicast DNS implementations were created after 1996, all Multicast DNS implementations are REQUIRED to decode compressed SRV records correctly. In legacy unicast responses generated to answer legacy queries, name compression MUST NOT be performed on SRV records.
10-20
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值