【第46节】windows程序的其他反调试手段中篇
目录
引言
一、利用SetUnhandledExceptionFilter/Debugger Interrupts
二、Trap Flag 单步标志异常
三、利用SeDebugPrivilege 进程权限
四、利用DebugObject:NtQueryObject()
五、OllyDbg:Guard
六、Software Breakpoint Detection
引言
在程序反调试领域,存在多种检测调试器的手段。接下来将介绍其他反调试手段中篇,诸如SetUnhandledExceptionFilter/Debugger Interrupts、Trap Flag单步标志异常等一系列其他反调试方法,这些方法通过不同的原理来识别程序是否正被调试,为程序的安全防护提供多维度保障 ,给新手学习带来灵感。
一、利用SetUnhandledExceptionFilter/Debugger Interrupts
当在调试器中执行步过操作,遇到`INT3`和`INT1`指令时,由于调试器一般会对这些调试中断进行处理,因此默认情况下,预先设置的异常处理例程不会被触发调用。而`Debugger Interrupts`正是借助了这一特性。基于此,我们能够在异常处理例程内设置标志。当执行`INT`指令后,若这些标志并未被设置,那就表明当前进程正处于被调试状态。
此外,`kernel32!DebugBreak()`函数在内部实现上是通过调用`INT3`来完成的,部分壳程序也会运用这个API。需注意的是,在进行测试时,要在异常处理设置中取消勾选`INT3 breaks`和`Singal-step break`选项。 在整个流程中,获取安全地址至关重要,相关代码如下:
static DWORD lpOldHandler;
typedef LPTOP_LEVEL_EXCEPTION_FILTER(__stdcall *pSetUnhandledExceptionFilter)(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
pSetUnhandledExceptionFilter lpSetUnhandledExceptionFilter;LONG WINAPI TopUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) {__asm pushadAfxMessageBox("回调函数");lpSetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)lpOldHandler);ExceptionInfo->ContextRecord->Eip = NewEip; // 转移到安全位置__asm popadreturn EXCEPTION_CONTINUE_EXECUTION;
}void CDetectODDlg::OnSetUnhandledExceptionFilter() {bool isDebugged = 0;lpSetUnhandledExceptionFilter = (pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary("kernel32.dll"), "SetUnhandledExceptionFilter");lpOldHandler = (DWORD)lpSetUnhandledExceptionFilter(TopUnhandledExceptionFilter);__asm {// 获取这个安全地址call me // 方式一,需要NewEip加上一个偏移值me:pop NewEip // 方式一结束mov NewEip, offset safe // 方式二,更简单int 3 // 触发异常}AfxMessageBox("检测到OD");isDebugged = 1;__asm {safe:}if (1 == isDebugged) {AfxMessageBox("发现OD");}else {AfxMessageBox("没有OD");}
}
当程序因调试中断而停止执行时,我们可以在OllyDbg(简称OD)里,通过“视图->SEH链”的路径找到异常处理例程,并在该例程处设置断点。随后按下“Shift+F9”组合键,将中断或异常传递给异常处理例程,最终异常处理例程里设置的断点就会生效,此时便能对程序进行跟踪调试了。
还有一种方式,就是让调试中断自动传递到异常处理例程。在OllyDbg中,具体操作是依次点击“选项->调试选项->异常”,接着在“忽略下列异常”选项卡中,勾选“INT3中断”和“单步中断”这两个复选框,如此便可完成相关设置。
二、Trap Flag 单步标志异常
当`TF`的值设为1时,会触发单步异常。这种检测方法属于异常处理的范畴,但有其特殊性。对于未经过修改的OllyDbg(OD),不管按`F9`键还是`F8`键,都无法处理这个异常。而装有插件的OllyDbg,按`F9`键时能正常处理异常,按`F8`键时则不能正确处理。
关键代码示例:
void CDetectODDlg::OnTrapFlag() {try {__asm {pushfd // 触发单步异常or dword ptr [esp], 100h ; TP = 1popfd}AfxMessageBox(" 检测到OD");}catch (...) {AfxMessageBox(" 没有OD");}
}
三、利用SeDebugPrivilege 进程权限
正常情况下,进程并不具备`SeDebugPrivilege`权限。但在调试进程时,它会从调试器那里继承到该权限。我们可以通过打开`CSRSS.EXE`进程,间接地利用`SeDebugPrivilege`权限来判断进程是否正在被调试。需要留意的是,默认状态下,只有`Administrators`组成员才被赋予这一权限。
获取`CSRSS.EXE`进程的PID有两种方式,一是借助`ntdll!CsrGetProcessId()`这个API,二是通过枚举进程来实现。在实际的实例测试中,发现当`OD`加载后,首次检测无法得到正确结果,第二次检测却能正常判断,至于其中原因暂不明确 。
关键代码示例:
void CDetectODDlg::OnSeDebugPrivilege() {HANDLE hProcessSnap;HANDLE hProcess;PROCESSENTRY32 tp32; // 结构体CString str = "csrss.exe";hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);if (INVALID_HANDLE_VALUE != hProcessSnap) {Process32First(hProcessSnap, &tp32);do {if (0 == lstrcmpi(str, tp32.szExeFile)) {hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, NULL, tp32.th32ProcessID);if (NULL != hProcess) {AfxMessageBox("发现OD");}else {AfxMessageBox("没有OD");}CloseHandle(hProcess);}} while (Process32Next(hProcessSnap, &tp32));}CloseHandle(hProcessSnap);
}
四、利用DebugObject:NtQueryObject()
除了判断进程是否正被调试外,还有一些调试器检测手段是去检查系统中有没有正在运行的调试器。在逆向论坛上,大家讨论过一种有意思的办法,即查看`DebugObject`类型的内核对象数量。该方法可行的原因在于,每当一个应用程序进入调试状态,内核就会为这次调试对话创建一个`DebugObject`类型的对象。
要获取`DebugObject`的数量,可以利用`ntdll!NtQueryObject()`函数来检索所有对象类型的相关信息。`NtQueryObject`函数需要5个参数,若要查询所有对象类型,就得把`ObjectHandle`参数设为`NULL`,将`ObjectInformationClass`参数设为`ObjectAllTypeInformation(3)` 。
`NtQueryObject` 函数原型为:
NTSTATUS NTAPI NtQueryObject(IN HANDLE ObjectHandle,IN OBJECT_INFORMATION_CLASS ObjectInformationClass,OUT PVOID ObjectInformation,IN ULONG Length,OUT PULONG ResultLength
);
这个API会返回一个`OBJECT_ALL_INFORMATION`结构。在这个结构里,`NumberOfObjectsTypes`成员代表着所有对象类型在`ObjectTypeInformation`数组中的数量统计 。
typedef struct _OBJECT_ALL_INFORMATION {ULONG NumberOfObjectsTypes;OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
} OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;
检测例程将遍历拥有如下结构的 `ObjectTypeInformation` 数组:
typedef struct _OBJECT_TYPE_INFORMATION {UNICODE_STRING TypeName;ULONG TotalNumberOfHandles;ULONG TotalNumberOfObjects;//...more fields...
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
将`TypeName`成员的值与`UNICODE`字符串“DebugObject”进行比对,随后查看`TotalNumberOfObjects`或者`TotalNumberOfHandles`的值是不是不为0。 下面是相关的类型定义内容:
#ifndef STATUS_INFO_LENGTH_MISMATCH
#define STATUS_INFO_LENGTH_MISMATCH((UINT32)0xC0000004L)
#endiftypedef enum POOL_TYPE {NonPagedPool,PagedPool,NonPagedPoolMustSucceed,DontUseThisType,NonPagedPoolCacheAligned,PagedPoolCacheAligned,NonPagedPoolCacheAlignedMustS
} POOL_TYPE;typedef struct UNICODE_STRING {USHORT Length;USHORT MaximumLength;PWSTR Buffer;
} UNICODE_STRING;typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;typedef enum OBJECT_INFORMATION_CLASS {ObjectBasicInformation,ObjectNameInformation,ObjectTypeInformation,ObjectAllTypesInformation,ObjectDataInformation
} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;typedef struct OBJECT_TYPE_INFORMATION {UNICODE_STRING TypeName;ULONG TotalNumberOfHandles;ULONG TotalNumberOfObjects;WCHAR Unused1[8];ULONG HighWaterNumberOfHandles;ULONG HighWaterNumberOfObjects;WCHAR Unused2[8];ACCESS_MASK InvalidAttributes;GENERIC_MAPPING GenericMapping;ACCESS_MASK ValidAttributes;BOOLEAN SecurityRequired;BOOLEAN MaintainHandleCount;USHORT MaintainTypeList;POOL_TYPE PoolType;ULONG DefaultPagedPoolCharge;ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;typedef struct OBJECT_ALL_INFORMATION {ULONG NumberOfObjectsTypes;OBJECT_TYPE_INFORMATION ObjectTypeInformation[1];
} OBJECT_ALL_INFORMATION, *POBJECT_ALL_INFORMATION;typedef struct _OBJECT_ALL_TYPES_INFORMATION {ULONG NumberOfTypes;OBJECT_TYPE_INFORMATION TypeInformation[1];
} OBJECT_ALL_TYPES_INFORMATION, *POBJECT_ALL_TYPES_INFORMATION;typedef UINT32(__stdcall *ZwQueryObject_t)(IN HANDLE ObjectHandle,IN OBJECT_INFORMATION_CLASS ObjectInformationClass,OUT PVOID ObjectInformation,IN ULONG Length,OUT PULONG ResultLength
);
检测函数实现如下:
void CDetectODDlg::OnNTQueryObject() {//TODO:Add your control notification handler code here// 调试器必须正在调试才能检测到,仅打开OD是检测不到的HMODULE hNtDLL;DWORD dwSize;UINT i;UCHAR KeyType = 0;OBJECT_ALL_TYPES_INFORMATION *Types;OBJECT_TYPE_INFORMATION *t;ZwQueryObject_t ZwQueryObject;hNtDLL = GetModuleHandle("ntdll.dll");if (hNtDLL) {ZwQueryObject = (ZwQueryObject_t)GetProcAddress(hNtDLL, "ZwQueryObject");UINT32 iResult = ZwQueryObject(NULL, ObjectAllTypesInformation, NULL, NULL, &dwSize);if (iResult == STATUS_INFO_LENGTH_MISMATCH) {Types = (OBJECT_ALL_TYPES_INFORMATION*)VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_READWRITE);if (Types == NULL) return;if (iResult = ZwQueryObject(NULL, ObjectAllTypesInformation, Types, dwSize, &dwSize)) return;for (t = Types->TypeInformation, i = 0; i < Types->NumberOfTypes; i++) {if (!_wcsicmp(t->TypeName.Buffer, L"DebugObject")) {if (t->TotalNumberOfHandles > 0 || t->TotalNumberOfObjects > 0) {AfxMessageBox("发现OD");VirtualFree(Types, 0, MEM_RELEASE);return;break; //Found Anyways}}t = (OBJECT_TYPE_INFORMATION*)((char*)t->TypeName.Buffer + ((t->TypeName.MaximumLength + 3) & 3));}AfxMessageBox("没有OD!");VirtualFree(Types, 0, MEM_RELEASE);}}
}
五、OllyDbg:Guard
这个检查专门针对OllyDbg,因为它跟OllyDbg的内存访问/写入断点功能有关。
除了硬件断点和软件断点,OllyDbg能设置一种内存访问/写入断点,它靠页面保护来实现。说白了,页面保护就是让应用程序在访问某块内存时能收到通知。
页面保护通过`PAGE_GUARD`页面保护修改符来设置。要是访问的内存地址属于受保护页面,就会产生`STATUS_GUARD_PAGE_VIOLATION(0x80000001)`异常。但要是进程正被OllyDbg调试,而且受保护页面被访问,就不会抛出这个异常,而是把访问当成内存断点处理,一些壳程序就利用了这一特性。
举例说明:下面的示例代码会先分配一段内存,把要执行的代码存进去,接着开启页面的`PAGE_GUARD`属性。然后把标志符`EAX`初始化为0,通过执行内存里的代码触发`STATUS_GUARD_PAGE_VIOLATION`异常。要是代码在OllyDbg里调试,由于异常处理例程不会被调用,标志符`EAX`的值就不会变。
应对办法:因为页面保护会引发异常,逆向分析人员可以主动引发异常,让异常处理例程被调用。在这个例子里,逆向分析人员可以把`RETN`指令换成`INT3`指令,一旦执行`INT3`指令,按`Shift+F9`就能强制调试器执行异常处理代码。等异常处理例程调用后,`EAX`就会被设为正确值,接着`RETN`指令执行。
要是异常处理例程检查异常是不是真的`STATUS_GUARD_PAGE_VIOLATION`,逆向分析人员可以在异常处理例程里下断点,修改传入的`ExceptionRecord`参数,具体就是把`ExceptionCode`手动改成`STATUS_GUARD_PAGE_VIOLATION`就行。
关键示例代码:
//需要用到在UnhandledExceptionHandler 里定义的一些结构
//********************************************************
static bool isDebugged = 1;
LONG WINAPI TopUnhandledExceptionFilter2(struct _EXCEPTION_POINTERS *ExceptionInfo
) {__asm pushadAfxMessageBox(" 回调函数");lpSetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)lpOldHandler);ExceptionInfo->ContextRecord->Eip = NewEip;isDebugged = 0;__asm popadreturn EXCEPTION_CONTINUE_EXECUTION;
}void CDetectODDlg::OnGuardPages() {//TODO: Add your control notification handler code hereULONG dwOldType;DWORD dwPageSize;LPVOID lpvBase;SYSTEM_INFO sSysInfo;//获取内存的基地址 系统信息GetSystemInfo(&sSysInfo); //获取系统信息//系统内存页大小dwPageSize = sSysInfo.dwPageSize;lpSetUnhandledExceptionFilter = (pSetUnhandledExceptionFilter)GetProcAddress(LoadLibrary("kernel32.dll"), "SetUnhandledExceptionFilter");lpOldHandler = (DWORD)lpSetUnhandledExceptionFilter(TopUnhandledExceptionFilter2);//分配内存lpvBase = VirtualAlloc(NULL, dwPageSize, MEM_COMMIT, PAGE_READWRITE);if (lpvBase == NULL) {AfxMessageBox("内存分配失败");}__asm {mov NewEip, offset safe //方式二,更简单mov eax, lpvBasepush eaxmov byte ptr [eax], 0C3H //写一个 RETN 到保留内存,以便下面的调用}if (0 == ::VirtualProtect(lpvBase, dwPageSize, PAGE_EXECUTE_READ | PAGE_GUARD, &dwOldType)) {AfxMessageBox(" 执行失败");}__asm {pop ecxcall ecx //调用时压栈safe:pop ecx //堆栈平衡,弹出调用时的压栈}if (1 == isDebugged) {AfxMessageBox("发现OD");}else {AfxMessageBox("没有OD");}VirtualFree(lpvBase, dwPageSize, MEM_DECOMMIT);
}
六、Software Breakpoint Detection
软件断点的设置,是把目标地址的代码改成`0xCC`(也就是`INT3/Breakpoint Interrupt`) 。要识别软件断点,可以在受保护的代码段以及(或者)API函数里,对字节`0xCC`进行扫描。下面分别以普通断点和函数断点为例展开说明。
(1) 实例一 :普通断点
要注意,测试时需要在受保护的代码区域设置`INT3`断点。
关键示例代码:
BOOL DetectBreakpoints() {BOOL bFoundOD;bFoundOD = FALSE;__asm {jmp CodeEndCodeStart:mov eax, ecx ;被保护的程序段noppush eaxpush ecxpop ecxpop eaxCodeEnd:cld ;检测代码开始mov edi, offset CodeStartmov edx, offset CodeStartmov ecx, offset CodeEndsub ecx, edxmov al, 0CCHscasbrepnejnz ODNotFoundmov bFoundOD, 1ODNotFound:}return bFoundOD;
}void CDetectODDlg::OnDectectBreakpoints() {//TODO:Add your control notification handler code hereHANDLE hProcess;hProcess = ::GetCurrentProcess();CString str = "利用我定位";if (DetectBreakpoints()) {AfxMessageBox("发现OD");}else {AfxMessageBox("没有OD");}
}
(2) 实例二 :函数断点 bp
使用`GetProcAddress`函数来获取API的地址。
需要注意的是,在进行检测的时候,要设置断点(BP)在`MessageBoxA`函数上。
关键示例代码:
BOOL DetectFuncBreakpoints() {BOOL bFoundOD;bFoundOD = FALSE;DWORD dwAddr;dwAddr = (DWORD)::GetProcAddress(LoadLibrary("user32.dll"), "MessageBoxA");__asm {cld ;检测代码开始mov edi, dwAddr ;起始地址mov ecx, 100 ;100bytes :检测100个字节mov al, 0CCHrepnescasbjnz ODNotFoundmov bFoundOD, 1ODNotFound:}return bFoundOD;
}void CDetectODDlg::OnDectectFuncBreakpoints() {//TODO:Add your control notification handler code hereCString str = "利用我定位";if (DetectFuncBreakpoints()) {AfxMessageBox("发现OD");}else {AfxMessageBox("没有OD");}
}
相关文章:
【第46节】windows程序的其他反调试手段中篇
目录 引言 一、利用SetUnhandledExceptionFilter/Debugger Interrupts 二、Trap Flag 单步标志异常 三、利用SeDebugPrivilege 进程权限 四、利用DebugObject:NtQueryObject() 五、OllyDbg:Guard 六、Software Breakpoint Detection 引言 在程序反调试领域,存…...
【APM】How to enable Trace to Logs on Grafana?
系列文章目录 【APM】Observability Solution 【APM】Build an environment for Traces, Metrics and Logs of App by OpenTelemetry 【APM】NET Traces, Metrics and Logs to OLTP 【APM】How to enable Trace to Logs on Grafana? 前言 本文将介绍如何在Grafana上启用 …...
第十节:性能优化-如何排查组件不必要的重复渲染?
工具:React DevTools Profiler 方法:memo、shouldComponentUpdate深度对比 React 组件性能优化:排查与解决重复渲染问题指南 一、定位性能问题:React DevTools 高级用法 使用 React Developer Tools Profiler 精准定位问题组件&…...
Spring Boot 项目中发布流式接口支持实时数据向客户端推送
1、pom依赖添加 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>2、事例代码 package com.pojo.prj.controller;import com.pojo.common.core.utils.String…...
SpringBoot整合Thymeleaf变量渲染全解析:从基础到高阶实践
Thymeleaf作为SpringBoot官方推荐的模板引擎,其核心价值在于将动态数据无缝注入静态HTML模板。本文将从基础语法到复杂场景,深入剖析Thymeleaf对各种类型变量的渲染机制。 一、环境搭建与基础配置 依赖注入 在pom.xml中引入核心依赖:<dependency><groupId>org.s…...
【verilog】Verilog 工程规范编码模板
这一套【Verilog 工程规范编码模板】,适合写清晰、可维护、可综合的 RTL 代码,适用于 FPGA/ASIC 开发: 📘 Verilog 工程级编码规范模板 1️⃣ 模块结构规范 module my_module #(parameter WIDTH 8 // 模块参数 )(input wire c…...
satoken的奇奇怪怪的错误
发了 /user/getBrowseDetail和/user/getResponDetail,但为什么进入handle里面有三次?且第一次的handle类型是AbstractHandleMapping$PreFlightHttpRequestHandlerxxx,这一次进来的时候flag为false,StpUtils.checkLogin抛出了异常 第二次进来的…...
使用prometheus-operator部署prometheus服务,并对外提供访问
先决条件: 已经部署好k8s #这里我使用的版本是1.28.12 [rootprometheus-operator /zpf/prometheus/kube-prometheus/manifests]$kubectl version Client Version: v1.28.12 Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3 Server Version: v1.28.12安装git服务 #安…...
FPGA阵列
FPGA(现场可编程门阵列)阵列是由多个 FPGA 芯片组成的集合,通过特定的架构和互联方式协同工作,以实现强大的计算和处理能力。以下是关于 FPGA 阵列的详细介绍: 基本原理 FPGA 是一种可重构的集成电路,内部…...
Oracle补丁安装工具opatch更新报错处理
今日,在进行Oracle补丁升级更新opatch工具包后,执行opatch命令出现了如下报错: [oracles203116 ~]$ opatch version /u01/product/oracle/12.1.0/db_1/OPatch/opatch: line 839: [: too many arguments /u01/product/oracle/12.1.0/db_1/O…...
前端笔记-html+css测试2
HTML & CSS 能力测试卷 选择题(每题2分,共20分) 下列哪个HTML5标签用于定义文档的导航链接? A) <nav> B) <navigate> C) <navbar> D) <navigation> CSS中哪个属性用于设置元素的透明度?…...
Visual Studio C++ 常用配置变量表
前言 visual studio中常用配置变量表 帮助你快速查阅,复制粘贴嘎嘎方便! 附上美图!! 一、解决方案 & 项目路径 变量含义示例(典型用法)$(SolutionDir)解决方案文件所在目录(末尾带\)$(S…...
论文阅读VACE: All-in-One Video Creation and Editing
code:https://github.com/ali-vilab/VACE 核心 单个模型同时处理多种视频生成和视频编辑任务通过VCU(视频条件单元)进行实现 方法 视频任务 所有的视频相关任务可以分为4类 文本生视频 参考图片生视频 视频生视频 视频mask生视频 VCU …...
【Python Cookbook】迭代器与生成器(一)
迭代器与生成器(一) 1.手动遍历迭代器2.代理迭代3.使用生成器创建新的迭代模式4.实现迭代器协议 1.手动遍历迭代器 你想遍历一个可迭代对象中的所有元素,但是却不想使用 for 循环。 为了手动的遍历可迭代对象,使用 next() 函数并…...
Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑
视频讲解:Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑_哔哩哔哩_bilibili Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑 今天复现下Qwen2.5-VL玩玩 https://github.com/QwenLM/Qwen2.5-VL 创建conda环境,实测22.04&#x…...
LVGL填充函数
lvgl填充函数的位置: static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);lv_disp_flush_ready(disp_drv); }填充函数的具体内容…...
关于 传感器 的详细解析,涵盖定义、分类、工作原理、常见类型、应用领域、技术挑战及未来趋势,结合实例帮助理解其核心概念
以下是关于 传感器 的详细解析,涵盖定义、分类、工作原理、常见类型、应用领域、技术挑战及未来趋势,结合实例帮助理解其核心概念: 一、传感器的定义与核心功能 1. 定义 传感器(Sensor)是一种能够将物理量ÿ…...
回归,git 分支开发操作命令
核心分支说明 主分支(master/production)存放随时可部署到生产环境的稳定代码,仅接受通过测试的合并请求。 开发分支(develop)集成所有功能开发的稳定版本,日常开发的基础分支,从该分支创建特性…...
指形铣刀的结构
指形铣刀,作为机械加工领域中一种至关重要的切削工具,其主要结构类型多样且各具特色,深入学习这些类型对于提升加工效率与精度至关重要。 首先,我们来看看最基本的直柄指形铣刀。这种铣刀的设计简洁明了,其柄部为直线…...
【verilog】always @(*) 是Verilog 中写组合逻辑
always (*) 是 Verilog 中写组合逻辑(combinational logic) 的标准写法,下面讲解含义、作用、以及为什么这么写。 🌟 什么是 always (*)? always (*) begin// 组合逻辑 end它的意思是: “只要块中用到的任…...
【IC】STA计算
这张图很好,把STA的方法展示的很清楚! 时序分析在每个设计阶段都是必不可少的,以便在现代 IC 设计中实现时序收敛。除了准确性之外,全芯片分析的效率和可扩展性也尤为重要。因此,门级静态时序分析 (STA&am…...
Linux 常用命令总结
Linux 常用命令总结(全面版) Linux 命令行是系统管理和开发的核心工具,掌握常用命令可以极大提升效率。本文全面总结 Linux 常用命令,涵盖文件操作、进程管理、网络管理、系统监控、用户管理、软件安装等多个方面,适合…...
Muduo网络库实现 [十四] - HttpResponse模块
目录 设计思路 类的设计 模块的实现 公有接口 疑问点 设计思路 这个模块和HttpRequest一样,主要就是存储http响应的要素,但是其实真正需要设置存储的要素会比http请求少,首先,要存储http的版本号,我们最终使用的是…...
2025年CNG 汽车加气站操作工考试真题练习
CNG 汽车加气站操作工考试真题练习: 一、单选题 1、CNG 加气站的核心设备是( )。 A. 压缩机 B. 储气瓶组 C. 加气机 D. 脱水装置 答案:A 解析:压缩机是 CNG 加气站的核心设备,其作用是将天然气压缩…...
B端网站建设,怎样平衡功能与美观,满足企业多元需求?
在当今数字化时代,B端网站不仅是企业展示自身形象和产品的重要窗口,更是实现业务转化和客户关系维护的关键平台。然而,B端网站建设面临着功能需求复杂与美观设计之间的平衡问题。如何在满足企业多元需求的同时,打造一个既实用又美…...
PTA:模拟EXCEL排序
Excel可以对一组纪录按任意指定列排序。现请编写程序实现类似功能。 输入格式: 输入的第一行包含两个正整数 n (≤105) 和 c,其中 n 是纪录的条数,c 是指定排序的列号。之后有 n 行,每行包含一条学生纪录。每条学生纪录由学号(6…...
Edge浏览器安卓版流畅度与广告拦截功能评测【不卡还净】
安卓设备上使用浏览器的体验,很大程度取决于两个方面。一个是滑动和页面切换时的反应速度,另一个是广告干扰的多少。Edge浏览器的安卓版本在这两方面的表现比较稳定,适合日常使用和内容浏览。 先看流畅度。Edge在中端和高端机型上启动速度快&…...
Qt 核心库总结
Qt 核心库(QtCore) QtCore 是 Qt 框架的基础模块,提供非图形界面的核心功能,是所有 Qt 应用程序的基石。它包含事件循环、信号与槽、线程管理、文件操作、字符串处理等功能,适用于 GUI 和非 GUI 应用程序。本文将从入…...
四大wordpress模板站
WP汉主题 WP汉主题是一个专注于提供高质量WordPress中文主题的平台。它为中文用户提供了丰富的WordPress主题选择,包括但不限于企业网站模板、外贸建站模板等。WP汉主题致力于帮助用户轻松搭建专业的中文网站,无论是企业官网还是个人博客,都…...
Linux之 grep、find、ls、wc 命令
Linux之 grep、find、ls、wc 命令 “ 在 Linux 世界中,命令行是不可或缺的一部分,而掌握一些常用的命令可以帮助你更有效率地管理文件和系统。本文将为你介绍四個基礎而强大的 Linux 命令:grep、find、ls 和 wc,带你开启高效文件…...
SFC的含义
SFC 即 Single File Component,也就是单文件组件,在现代前端开发尤其是 Vue.js 框架中被广泛应用。下面将从概念、结构、优势、工作原理和应用场景几个方面详细介绍 SFC。 概念 单文件组件是一种将一个组件的模板(HTML)、逻辑&a…...
Qt 性能优化总结
Qt 性能优化总结 本文简单解析 Qt 应用程序的性能优化策略,涵盖 GUI 渲染、内存管理、信号与槽、QML 性能等核心领域,并通过具体示例展示优化效果。 1. Qt 性能优化简介 性能优化目标是减少资源消耗(如 CPU、内存、GPU)、提高响…...
亚马逊关键字搜索数据通过 Product Advertising API 来获取
亚马逊关键字搜索数据主要通过 Product Advertising API 来获取。 以下是使用该接口进行关键字搜索的一般步骤: (测试示例) 注册开发者账号:访问亚马逊开发者中心,完成三方供应商注册并同意相关开发者协议࿰…...
现代C++的范式演进与工程实践深度解析(本文序号不知道怎么整的,有点问题)
引言:C++的复兴时代 在经历了"已死语言"的质疑后,现代C++正迎来前所未有的复兴。据2024年TIOBE指数显示,C++以8.33%的占比稳居第三,较2020年上升2.1个百分点。这种复兴并非偶然——随着C++20标准的全面落地和C++23特性的逐步实现,这门已有40年历史的语言正在系…...
第二十五天 - Web安全防护 - WAF原理与实现 - 练习:请求过滤中间件
一、Celery核心机制解析 1.1 分布式架构四要素 # celery_config.py BROKER_URL redis://:passwordlocalhost:6379/0 # 消息中间件 RESULT_BACKEND redis://:passwordlocalhost:6379/1 # 结果存储 TASK_SERIALIZER json ACCEPT_CONTENT [json] TIMEZONE Asia/Shanghai核…...
springboot自定义starter(避坑教学)
在实际开发中,经常会定义一些公共组件,提供给各个项目团队使用。而在springboot的项目中,一般会将这些公共组件封装为springboot的starter。 1.命名规范 Spring官方Starter通常命名为 spring-boot-starter-{name} 如:spr…...
Python 实现日志备份守护进程
实训背景 假设你是一名运维工程师,需要为公司的监控系统开发一个简单的日志备份守护进程。该进程需满足以下需求: 后台运行:脱离终端,长期监控指定目录(如 /var/log/app/)中的日志文件。自动备份…...
详解JVM的底层原理
目录 1.JVM的内存区域划分 1)程序计数器(Program Counter Register) 2)元数据区(Metaspace) 3)虚拟机栈(Java Virtual Machine Stacks) 4)堆(…...
制表符是什么?与.txt文件的关系?
李升伟 整理 制表符(Tab)是一种控制字符(ASCII码为9,Unicode为\u0009),用于在文本中创建水平间距。它的作用类似于键盘上的 Tab 键,通常表现为光标跳转到下一个预设的“制表位”(一…...
【专题刷题】双指针(三):两数之和,三数之和,四数之和
📝前言说明: 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码;ÿ…...
Java八种常见的设计模式
一、单例模式 单例模式是(Singleton Pattern)Java中最常用的设计模式之一,它保证一个类仅有一个实例,并提供一个全局访问点。 实现单例模式的核心是将类的构造方法私有化,以防止外部直接通过构造函数创建实例。同时&am…...
用Prompt 技术【提示词】打造自己的大语言智能体
机器如何按照人类的指令执行任务的探索 机器需具备理解任务叙述的能力,以便能够按照人类的指令执行任务,为机器提供一些范例作为参考,使其能够理解该执行的任务类型。这样的学习方式称为“Instruction learning”,透过精心设计的…...
灵鉴 AI五大核心能力洞穿 “数据黑箱”云取证深度支持8大核心应用
本文关键词:灵鉴AI 、电子数据取证分析AI助手、云取证、DeepSeek大模型 1.灵鉴AI ,V1.0深度融合DeepSeek大模型技术,破解行业痛点,5大核心能力,让大模型真正“懂”电子数据分析。 2.LX-A216云取证系统,V2.…...
了解高速设计的信号完整性仿真
高速设计需要精确的信号传输,以确保最佳性能。信号完整性差会导致关键应用中的误码、数据损坏甚至系统故障等问题。介电常数、损耗角正切和插入损耗等因素会显著影响信号质量。通过使用信号完整性仿真,您可以及早发现并解决这些挑战。这种主动方法有助于…...
用 Deepseek 写的html油耗计算器
在油价高企的今天,了解自己爱车的真实油耗情况对每位车主来说都至关重要。本文将介绍一个简单实用的油耗计算方法,并提供一个可以直接使用的HTML油耗计算器。 为什么要计算油耗? 计算油耗不仅能帮助我们: 了解车辆的真实燃油经济…...
SAP系统青果糖无法报工
问题:班长说工单号4100000101青果糖工单 无法报工 原因排查:工单4100000101的工艺路线版本错误,选了版本1的,版本1是委外的工艺,本厂生产应该选版本2. 解决: 1:重读主数据,更改工单4100000101的工艺路线版本. 2:工单成品已交库,不能直接更改工…...
GPU 招投标全流程分析与总结
GPU 招投标全流程分析与总结 招投标流程概述 以下是通过代理商采购Nvidia H20-GPU 141G的招投标全流程分析: #mermaid-svg-hMPPfkCpGj8GKXfV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hMPPfkCpGj8GKXfV .er…...
Centos7.6安装JDK 1.8教程
前提:先把jdk1.8文件上传到usr/local目录下,文件名如:jdk-8u151-linux-x64.tar.gz 1. 解压 JDK 压缩包 假设 jdk-8u151-linux-x64.tar.gz 文件位于 /usr/local 目录下。 进入 /usr/local 目录: cd /usr/local 解压文件&#…...
Golang errors 包快速上手
文章目录 1.变量2.类型3.函数3.1 New3.2 Is简介函数签名核心功能示例代码使用场景注意事项小结 3.3 As简介函数签名核心功能示例代码使用场景注意事项小结 3.4 Unwrap简介函数签名核心功能使用示例使用场景注意事项小结 3.5 Join简介函数签名核心功能使用场景注意事项小结 4.小…...
新型多机器人协作运输系统,轻松应对复杂路面
受到鱼类、鸟类和蚂蚁等微小生物体协作操纵的启发,研究人员开发了多机器人协作运输系统(Multirobot Cooperative Transportation Systems,MRCTS)运输单个机器人无法处理的重型超大物体,可用于搜救行动、灾难响应、军事…...