Windows平台调试器原理与编写04.硬件断点

https://www.bpsend.net/thread-269-1-2.html

每个线程最多只能四个硬件断点,每一个可以设3种类型 ,硬件断点是由 CPU 支持的

硬件断点是为了解决某些情况下软件断点用不了的情况(例如软件中带有自修改,下断点处的代码被软件自身执行过程中把值改了)

硬件断点有3种类型

  1. 执行断点,跟一般断点作用差不多
  2. 写入断点 (长度有 子 ,字节 ,双字 3种)
  3. 访问断点(可读可写)

硬件断点与调试寄存器

  • 硬件断点容易被检测。
  • 硬件断点通过8个32位寄存器(调试寄存器)实现;
  • 硬件断点最多可设置4个,属性执行内存均可,调试寄存器命名从DR0-DR7:
    • DR0-DR3:表示断点的设置地址 ;
    • DR4、DR5:与硬件断点的实现无关,可忽略;
    • DR6:又称状态调试寄存器,表示断点命中的状态(命中为1,未命中为0);各个位的含义如下:B0~B3,如果其中任何一个位置位,则表示是相应的Dr0~3断点引发的调试陷阱。当如果多个断点同时命中他只会把其中一个置1 ,其他的不会
      • BD置位表示是GD位置位情况下访问调试寄存器引发的陷阱。
      • BT位:TSS任务切换时,若设置了T标志位,会引起调试异常,并使得BT位置位。
      • BS置位表示是单步中断引发的断点。即EFLAGS的TF置位时引发的调试陷阱。
      • DR6寄存器的值, 建议在每次异常提交之前清除。
    • DR7:表示设置到哪个寄存器上,L=局部(可忽略位项:GD=保护标志,GE,LE,G=全局):
      • L0-L3=1表示对应值的DRx已启动,即L0=1表DR0启动,反之未启动,即L2=0表示DR2未启动。
      • LE和GE:为了兼容性,Intel建议使用精确断点时把LE和GE都设置为1。(使用精确断点标志,P6及之后的cpu不支持该标志)
      • 16-31位:每个2位,4位一组,描述设的断点类型(R/W)和长度(LEN),长度(LEN)对执行不起作用。
        • R/W0到R/W3:指定各个断点的触发条件。对应DR0到DR3中的地址以及DR6中的4个断点条件标志。
          • 00=只执行;
          • 01=写入数据断点;
          • 10=I/O端口断点(只用于pentium+,需设置CR4的DE位,DE是CR4的第3位 );
          • 11=读或写数据断点。
        • LEN0到LEN3:指定在调试地址寄存器DR0到DR3中指定的地址位置的大小。
        • 如果R/Wx位为0(执行断点),则LENx位也必须为0,否则会产生不确定的行为。
          • 可能取值:**00=1字节;01=2字节;10=保留;11=4字节**。
            • 设置内存断点时,内存地址应与指定取值对齐。

代码实现 获取和设置寄存器环境

;获取寄存器环境
GetContext proc uses esi dwTID:DWORD, pCtx:ptr CONTEXT
    LOCAL @hThread:HANDLE 
  
    invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID
    mov @hThread, eax
  
    mov esi, pCtx
    assume esi:ptr CONTEXT
  
    mov [esi].ContextFlags, CONTEXT_ALL
    invoke GetThreadContext, @hThread, esi   ;获取寄存器环境信息
  
    assume esi:nothing
  
    invoke CloseHandle, @hThread
    ret

GetContext endp

;设置寄存器环境
SetContext proc dwTID:DWORD, pCtx:ptr CONTEXT
    LOCAL @hThread:HANDLE 
  
    invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID
    mov @hThread, eax

    invoke SetThreadContext, @hThread, pCtx   ;设置寄存器环境信息

    invoke CloseHandle, @hThread
    ret

SetContext endp
硬件执行断点

硬件断点触发 单步800000004异常,所以需要在单步异常里面区分一下。

如果有多个硬件断点,在设置DR7的时候,需要保留原有的,然后在清空自己的位,然后在设置。

注意:系统断点不是主线程,不能设置硬件断点。当有新进程创建,将所有的硬件断点寄存器重新设置一遍。

硬件断点在抛出异常的时候,此时eip的指令没有执行。执行不过去。解决办法:断步配合。

因为这个断点是CPU管理的,当CPU发现此时的eip和硬件断点地址相同时,就不执行了。此时的eip当前指令还没有执行,此时g和p等都过不去,如何才能让他继续执行呢?

解决办法:断步配合。再抛出硬件断点异常的时候清除当前断点,执行完这条语句后,通过单步重新设置硬件断点。

硬件执行断点

;设置硬件执行断点
invoke GetContext, [esi].dwThreadId, addr @ctx   ;获取寄存器环境
mov @ctx.iDr0, 01001BD2h                         ;设置下硬件执行断点的地址和寄存器 
or @ctx.iDr7, 1                                  ; L0 置 1 ,表示 在 dr0 下了断点
and @ctx.iDr7, 0fff0ffffh                        ;R/W0和LEN0都是0  (dr7 的 16 - 19位)
invoke SetContext, [esi].dwThreadId, addr @ctx   ;设置寄存器环境



;处理硬件执行断点异常
;重设硬件断点
.if g_bIsResetHardBpStep == TRUE
    mov g_bIsResetHardBpStep, FALSE
    ;设置硬件执行断点
    invoke GetContext, [esi].dwThreadId, addr @ctx     ;获取寄存器环境
    or @ctx.iDr7, 1                                    ;L0置1,说明在 dr0 设置了硬件断点 (其他的前面已经设置过了,因此这里不需要在设置)
    invoke SetContext, [esi].dwThreadId, addr @ctx     ;设置寄存器环境
    mov eax, DBG_CONTINUE
    ret
 .endif

  ;处理硬件断点的单步
  invoke GetContext, [esi].dwThreadId, addr @ctx
  .if @ctx.iDr6 & 1 ; 执行断点的异常来了dr0 上的断点
       ;取消硬件断点
       invoke GetContext, [esi].dwThreadId, addr @ctx  ;获取寄存器环境   
       and @ctx.iDr7, 0fffffffeh                       ;L0 置 0 取消 dr0 上的断点
       invoke SetContext, [esi].dwThreadId, addr @ctx  ;设置寄存器环境  
     
       ;设置单步
       invoke SetTF, [esi].dwThreadId
       ;下个单步重设硬件断点
       mov g_bIsResetHardBpStep, TRUE
       ;等待命令
       invoke InputCmd, pDE  
 .endif
硬件访问断点

硬件访问断点不需要做断步配合

硬件访问断点原理:当cpu译码,执行的时候,才知道访问的地方是不是硬件访问断点,说以都会断到该条的下一行。

硬件访问断点

;设置硬件访问断点
invoke GetContext, [esi].dwThreadId, addr @ctx   ;获取寄存器环境   
mov @ctx.iDr1, 1005000h                          ;设置下硬件访问断点的地址和寄存器
or @ctx.iDr7, 100b                               ;L1 置 1 ,表示 在 dr1 下了断点
or @ctx.iDr7, 00f00000h                          ;R/W1和LEN1都是11b,访问,长度为四个字节 (dr7 的 20 - 23位)
mov @ctx.iDr6, 0                                 ;dr6清0
invoke SetContext, [esi].dwThreadId, addr @ctx   ;设置寄存器环境   


处理硬件访问异常
invoke GetContext, [esi].dwThreadId, addr @ctx
.if @ctx.iDr6 & 10b     ;访问断点的异常来了dr1 上的断点

    invoke crt_printf, offset g_szHardbpTip
  
    ;等待命令
    invoke InputCmd, pDE
.endif


完整代码
 

.586 .model flat,stdcall option casemap:none include windows.inc include user32.inc include kernel32.inc include msvcrt.inc include udis86.inc includelib user32.lib includelib kernel32.lib includelib msvcrt.lib includelib libudis86.lib .data g_szExe db "winmine.exe", 0 g_hExe dd 0 g_szEXCEPTION_DEBUG_EVENT db "EXCEPTION_DEBUG_EVENT", 0dh, 0ah, 0 g_szCREATE_THREAD_DEBUG_EVENT db "CREATE_THREAD_DEBUG_EVENT", 0dh, 0ah, 0 g_szCREATE_PROCESS_DEBUG_EVENT db "CREATE_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0 g_szEXIT_THREAD_DEBUG_EVENT db "EXIT_THREAD_DEBUG_EVENT", 0dh, 0ah, 0 g_szEXIT_PROCESS_DEBUG_EVENT db "EXIT_PROCESS_DEBUG_EVENT", 0dh, 0ah, 0 g_szLOAD_DLL_DEBUG_EVENT db "LOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0 g_szUNLOAD_DLL_DEBUG_EVENT db "UNLOAD_DLL_DEBUG_EVENT", 0dh, 0ah, 0 g_szOUTPUT_DEBUG_STRING_EVENT db "OUTPUT_DEBUG_STRING_EVENT", 0dh, 0ah, 0 g_szHardbpTip db "硬件访问断点", 0 g_szLoadDllFmt db "%08X %s", 0dh, 0ah, 0 g_szwLoadDllFmt dw '%', '0', '8', 'X', ' ', '%', 's', 0dh, 0ah, 0 g_szBpFmt db "CC异常 %08X", 0dh, 0ah, 0 g_szSsFmt db "单步异常 %08X", 0dh, 0ah, 0 g_szOutPutAsmFmt db "%08x %-20s %-20s", 0dh, 0ah, 0 g_szInputCmd db "选择命令:", 0dh, 0ah db "是:设置硬件执行断点", 0dh, 0ah db "否:设置硬件访问断点", 0dh, 0ah db "取消:直接运行", 0dh, 0ah,0 g_btOldCode db 0 g_dwBpAddr dd 010021a9h g_byteCC db 0CCh g_szOutPutAsm db 64 dup(0) g_ud_obj db 1000h dup(0) g_bIsCCStep dd FALSE g_bIsStepStep dd FALSE g_bIsResetHardBpStep dd FALSE .code IsCallMn proc uses esi edi pDE:ptr DEBUG_EVENT, pdwCodeLen:DWORD LOCAL @dwBytesOut:DWORD LOCAL @dwOff:DWORD LOCAL @pHex:LPSTR LOCAL @pAsm:LPSTR mov esi, pDE assume esi:ptr DEBUG_EVENT ;显示下一条即将执行的指令 invoke ReadProcessMemory, g_hExe, [esi].u.Exception.pExceptionRecord.ExceptionAddress, \ offset g_szOutPutAsm, 20, addr @dwBytesOut invoke ud_init, offset g_ud_obj invoke ud_set_input_buffer, offset g_ud_obj, offset g_szOutPutAsm, 20 invoke ud_set_mode, offset g_ud_obj, 32 invoke ud_set_syntax, offset g_ud_obj, offset ud_translate_intel invoke ud_set_pc, offset g_ud_obj, [esi].u.Exception.pExceptionRecord.ExceptionAddress invoke ud_disassemble, offset g_ud_obj invoke ud_insn_off, offset g_ud_obj mov @dwOff, eax invoke ud_insn_hex, offset g_ud_obj mov @pHex, eax invoke ud_insn_asm, offset g_ud_obj mov @pAsm, eax invoke ud_insn_len, offset g_ud_obj mov edi, pdwCodeLen mov [edi], eax invoke crt_printf, offset g_szOutPutAsmFmt, @dwOff, @pHex, @pAsm mov eax, @pAsm .if dword ptr [eax] == 'llac' mov eax, TRUE ret .endif mov eax, FALSE ret IsCallMn endp SetTF proc dwTID:DWORD LOCAL @hThread:HANDLE LOCAL @ctx:CONTEXT invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID mov @hThread, eax mov @ctx.ContextFlags, CONTEXT_FULL invoke GetThreadContext, @hThread, addr @ctx or @ctx.regFlag, 100h invoke SetThreadContext, @hThread, addr @ctx invoke CloseHandle, @hThread ret SetTF endp DecEIP proc dwTID:DWORD LOCAL @hThread:HANDLE LOCAL @ctx:CONTEXT invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID mov @hThread, eax mov @ctx.ContextFlags, CONTEXT_FULL invoke GetThreadContext, @hThread, addr @ctx dec @ctx.regEip invoke SetThreadContext, @hThread, addr @ctx invoke CloseHandle, @hThread ret DecEIP endp ;获取寄存器环境 GetContext proc uses esi dwTID:DWORD, pCtx:ptr CONTEXT LOCAL @hThread:HANDLE invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID mov @hThread, eax mov esi, pCtx assume esi:ptr CONTEXT mov [esi].ContextFlags, CONTEXT_ALL invoke GetThreadContext, @hThread, esi ;获取寄存器环境信息 assume esi:nothing invoke CloseHandle, @hThread ret GetContext endp ;设置寄存器环境 SetContext proc dwTID:DWORD, pCtx:ptr CONTEXT LOCAL @hThread:HANDLE invoke OpenThread, THREAD_ALL_ACCESS, FALSE, dwTID mov @hThread, eax invoke SetThreadContext, @hThread, pCtx ;设置寄存器环境信息 invoke CloseHandle, @hThread ret SetContext endp SetBp proc LOCAL @dwBytesOut:DWORD ;保存原来的指令, 在 01001BCF写入CC invoke ReadProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut invoke WriteProcessMemory, g_hExe, g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut ret SetBp endp InputCmd proc uses esi pDE:ptr DEBUG_EVENT LOCAL @bIsCall:BOOL LOCAL @dwCodeLen:DWORD LOCAL @ctx:CONTEXT mov esi, pDE assume esi:ptr DEBUG_EVENT invoke IsCallMn, pDE, addr @dwCodeLen mov @bIsCall, eax invoke MessageBox, NULL, offset g_szInputCmd, NULL, MB_YESNOCANCEL .if eax == IDYES ;设置硬件执行断点 invoke GetContext, [esi].dwThreadId, addr @ctx ;获取寄存器环境 mov @ctx.iDr0, 01001BD2h ;设置下硬件执行断点的地址和寄存器 or @ctx.iDr7, 1 ; L0 置 1 ,表示 在 dr0 下了断点 and @ctx.iDr7, 0fff0ffffh ;R/W0和LEN0都是0 (dr7 的 16 - 19位) invoke SetContext, [esi].dwThreadId, addr @ctx ;设置寄存器环境 .elseif eax == IDNO ;设置硬件访问断点 invoke GetContext, [esi].dwThreadId, addr @ctx ;获取寄存器环境 mov @ctx.iDr1, 1005000h ;设置下硬件访问断点的地址和寄存器 or @ctx.iDr7, 100b ;L1 置 1 ,表示 在 dr1 下了断点 or @ctx.iDr7, 00f00000h ;R/W1和LEN1都是11b,访问,长度为四个字节 (dr7 的 20 - 23位) mov @ctx.iDr6, 0 ;dr6清0 invoke SetContext, [esi].dwThreadId, addr @ctx ;设置寄存器环境 .else ;直接运行 .endif ret InputCmd endp OnException proc uses esi pDE:ptr DEBUG_EVENT LOCAL @dwBytesOut:DWORD LOCAL @ctx:CONTEXT mov esi, pDE assume esi:ptr DEBUG_EVENT .if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT ;判断是否是自己的CC mov eax, [esi].u.Exception.pExceptionRecord.ExceptionAddress .if eax != g_dwBpAddr ;不是自己的CC异常,不处理 mov eax, DBG_EXCEPTION_NOT_HANDLED ret .endif ;处理自己的CC异常 invoke crt_printf, offset g_szBpFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress ;恢复指令 invoke WriteProcessMemory, g_hExe, g_dwBpAddr, offset g_btOldCode, size g_btOldCode, addr @dwBytesOut ;设置单步 invoke SetTF, [esi].dwThreadId invoke DecEIP, [esi].dwThreadId ;单步中需要处理CC的单步 mov g_bIsCCStep, TRUE ;输入命令 invoke InputCmd, pDE mov eax, DBG_CONTINUE ret .endif ;单步来了 .if [esi].u.Exception.pExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP ;处理自己的单步 invoke crt_printf, offset g_szSsFmt, [esi].u.Exception.pExceptionRecord.ExceptionAddress invoke GetContext, [esi].dwThreadId, addr @ctx ;处理CC的单步 .if g_bIsCCStep == TRUE mov g_bIsCCStep, FALSE ;重设断点, 重新写入CC ;invoke WriteProcessMemory, g_hExe, g_dwBpAddr, offset g_byteCC, size g_byteCC, addr @dwBytesOut mov eax, DBG_CONTINUE ret .endif ;重设硬件断点 .if g_bIsResetHardBpStep == TRUE mov g_bIsResetHardBpStep, FALSE ;设置硬件执行断点 invoke GetContext, [esi].dwThreadId, addr @ctx ;获取寄存器环境 or @ctx.iDr7, 1 ;L0置1,说明在 dr0 设置了硬件断点 (其他的前面已经设置过了,因此这里不需要在设置) invoke SetContext, [esi].dwThreadId, addr @ctx ;设置寄存器环境 mov eax, DBG_CONTINUE ret .endif ;处理硬件断点的单步 invoke GetContext, [esi].dwThreadId, addr @ctx .if @ctx.iDr6 & 1 ;执行断点的异常来了dr0 上的断点 ;取消硬件断点 invoke GetContext, [esi].dwThreadId, addr @ctx ;获取寄存器环境 and @ctx.iDr7, 0fffffffeh ;L0 置 0 取消 dr0 上的断点 invoke SetContext, [esi].dwThreadId, addr @ctx ;设置寄存器环境 ;设置单步 invoke SetTF, [esi].dwThreadId ;下个单步重设硬件断点 mov g_bIsResetHardBpStep, TRUE ;等待命令 invoke InputCmd, pDE .elseif @ctx.iDr6 & 10b ;访问断点的异常来了dr1 上的断点 invoke crt_printf, offset g_szHardbpTip ;硬件访问断点 invoke InputCmd, pDE .endif mov eax, DBG_CONTINUE ret .endif assume esi:nothing mov eax, DBG_EXCEPTION_NOT_HANDLED ret OnException endp OnCreateProcess proc ;保存原来的指令, 在 01001BCF写入CC invoke SetBp ret OnCreateProcess endp main proc LOCAL @si:STARTUPINFO LOCAL @pi:PROCESS_INFORMATION LOCAL @de:DEBUG_EVENT LOCAL @dwStatus:DWORD invoke RtlZeroMemory, addr @si, size @si invoke RtlZeroMemory, addr @pi, size @pi invoke RtlZeroMemory, addr @de, size @de mov @dwStatus, DBG_CONTINUE ;建立调试会话 invoke CreateProcess, NULL, offset g_szExe, NULL, NULL, FALSE, \ DEBUG_ONLY_THIS_PROCESS,\ NULL, NULL,\ addr @si,\ addr @pi .if !eax ret .endif mov eax, @pi.hProcess mov g_hExe, eax ;循环接受调试事件 .while TRUE invoke WaitForDebugEvent, addr @de, INFINITE ;处理调试事件 .if @de.dwDebugEventCode == EXCEPTION_DEBUG_EVENT ;invoke crt_printf, offset g_szEXCEPTION_DEBUG_EVENT invoke OnException, addr @de mov @dwStatus, eax .elseif @de.dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT invoke crt_printf, offset g_szCREATE_THREAD_DEBUG_EVENT .elseif @de.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT ;invoke crt_printf, offset g_szCREATE_PROCESS_DEBUG_EVENT invoke OnCreateProcess .elseif @de.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT invoke crt_printf, offset g_szEXIT_THREAD_DEBUG_EVENT .elseif @de.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT invoke crt_printf, offset g_szEXIT_PROCESS_DEBUG_EVENT .elseif @de.dwDebugEventCode == LOAD_DLL_DEBUG_EVENT ;invoke OnLoadDll, addr @de .elseif @de.dwDebugEventCode == UNLOAD_DLL_DEBUG_EVENT invoke crt_printf, offset g_szUNLOAD_DLL_DEBUG_EVENT .elseif @de.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT invoke crt_printf, offset g_szOUTPUT_DEBUG_STRING_EVENT .endif ;提交事件处理结果 invoke ContinueDebugEvent, @de.dwProcessId, @de.dwThreadId, @dwStatus invoke RtlZeroMemory, addr @de, size @de .endw ret main endp start: invoke main end start

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/981324.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springboot425-基于SpringBoot的BUG管理系统(源码+数据库+纯前后端分离+部署讲解等)

💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm&#xf…

机器人“照镜子”:开启智能新时代

机器人也爱 “照镜子”? 在科技飞速发展的今天,机器人的身影越来越频繁地出现在我们的生活和工作中。它们承担着各种各样的任务,从工业生产线上的精密操作,到家庭中的清洁服务,再到危险环境下的救援工作。然而&#xf…

让 LabVIEW 程序更稳定

LabVIEW 开发的系统,尤其是工业级应用,往往需要长时间稳定运行,容不得崩溃、卡顿或数据丢失。然而,许多系统在实际运行中会遭遇内存泄漏、通信中断、界面卡顿等问题,导致生产中断甚至设备损坏。如何设计一个既稳定又易…

基于CURL命令封装的JAVA通用HTTP工具

文章目录 一、简要概述二、封装过程1. 引入依赖2. 定义脚本执行类 三、单元测试四、其他资源 一、简要概述 在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具。它支持文件的上传和下载,是综合传输工具&…

npm ERR! code 128 npm ERR! An unknown git error occurred

【问题描述】 【问题解决】 管理员运行cmd(右键window --> 选择终端管理员) 执行命令 git config --global url.“https://”.insteadOf ssh://git cd 到项目目录 重新执行npm install 个人原因,这里执行npm install --registryhttps:…

汽车视频智能包装创作解决方案,让旅途记忆一键升级为影视级大片

在智能汽车时代,行车记录已不再是简单的影像留存,而是承载情感与创意的载体。美摄科技依托20余年视音频领域技术积累,推出汽车视频智能包装创作解决方案,以AI驱动影像处理与艺术创作,重新定义车载视频体验,…

Qt中txt文件输出为PDF格式

main.cpp PdfReportGenerator pdfReportGenerator;// 加载中文字体if (QFontDatabase::addApplicationFont(":/new/prefix1/simsun.ttf") -1) {QMessageBox::warning(nullptr, "警告", "无法加载中文字体");}// 解析日志文件QVector<LogEntr…

nlp进阶

1 Rnn RNN(Recurrent Neural Network),中文称作循环神经网络,它一般以序列数据为输入,通过网络内部的结构段计有效捕捉序列之间的关系特征,一般也是以序列形式进行输出. 单层网络结构 在循环 rnn处理的过程 rnn类别 n - n n - 1 使用sigmoid 或者softmax处理 应用在分类中…

2024 JAVA面试题

第一章-Java基础篇 1、你是怎样理解OOP面向对象 面向对象是利于语言对现实事物进行抽象。面向对象具有以下特征&#xff1a; 继承****&#xff1a;****继承是从已有类得到继承信息创建新类的过程 封装&#xff1a;封装是把数据和操作数据的方法绑定起来&#xff0c;对数据的…

浅色系可视化大屏看起来确实很漂亮,但用到的地方确实很少

在数字化信息飞速发展的时代&#xff0c;可视化大屏作为信息展示的重要载体&#xff0c;广泛应用于各类场景。其中&#xff0c;浅色系可视化大屏以其独特的视觉风格&#xff0c;在众多展示方案中脱颖而出&#xff0c;给人以清新、舒适的视觉感受。然而&#xff0c;尽管浅色系可…

蓝桥杯备考:动态规划线性dp之下楼梯问题进阶版

老规矩&#xff0c;按照dp题的顺序 step1 定义状态表达 f[i]表示到第i个台阶的方案数 step2:推导状态方程 step3:初始化 初始化要保证 1.数组不越界 2.推导结果正确 如图这种情况就越界了&#xff0c;我们如果把1到k的值全初始化也不现实&#xff0c;会增加程序的时间复杂度…

LLM 大模型基础认知篇

目录 1、基本概述 2、大模型工作原理 3、关键知识点 &#xff08;1&#xff09;RAG 知识库 &#xff08;2&#xff09;蒸馏 &#xff08;3&#xff09;微调 &#xff08;4&#xff09;智能体 1、基本概述 大型语言模型&#xff08;Large Language Model, LLM&#xff09…

物业管理系统源码 物业小程序源码

物业管理系统源码 物业小程序源码 一、基础信息管理 1. 房产信息管理 记录楼栋、单元、房间的详细信息&#xff08;面积、户型、产权等&#xff09;。 管理业主/租户的档案&#xff0c;包括联系方式、合同信息等。 2. 公共资源管理 管理停车场、电梯、绿化带、公…

Delphi连接MySql数据库房

在看Delpih6数据库开发实例导航这本书时&#xff0c;里面的数据库管理系统用的InterBase&#xff0c;但是Delphi11中已经没有这个东西了&#xff0c;我就想到利用MS的access但是里面有很多的SQL语句不支持&#xff0c;比如设置字段的默认值等&#xff0c;后来我想到连接到MySQL…

[51 单片机] --串口编程

1&#xff0c;通讯方式基本概念 1&#xff0c;按照 --> 数据传送方式串行通讯&#xff1a;使用一条数据线&#xff0c;将数据一位一位地依次传输&#xff0c;每一位数据占据一个固定的时间长度&#xff0c;串行通信的特点&#xff1a;传输线少&#xff0c;长距离传送时成本…

基础算法——模拟

模拟&#xff0c;顾名思义&#xff0c;就是题⽬让你做什么你就做什么&#xff0c;考察的是将思路转化成代码的代码能⼒。 这类题⼀般较为简单&#xff0c;属于竞赛⾥⾯的签到题&#xff08;但是&#xff0c;万事⽆绝对&#xff0c;也有可能会出现让⼈⾮常难受的 模拟题&#xf…

SparkStreaming之04:调优

SparkStreaming调优 一 、要点 4.1 SparkStreaming运行原理 深入理解 4.2 调优策略 4.2.1 调整BlockReceiver的数量 案例演示&#xff1a; object MultiReceiverNetworkWordCount {def main(args: Array[String]) {val sparkConf new SparkConf().setAppName("Networ…

Jenkins 删除历史构建记录

中文:系统管理 > 脚本命令行: 英文:Manage Jenkins > Script Console def jobName "Wens-Web" //删除的项目名称 def maxNumber 105 // 保留的最小编号&#xff0c;意味着小于该编号的构建都将被删除 Jenkins.instance.getItemByFullName(jobName).build…

全国青少年航天创新大赛各项目对比分析

全国青少年航天创新大赛各项目对比分析 一、比赛场地对比 项目名称场地尺寸场地特点组别差异筑梦天宫虚拟三维场景动态布局&#xff0c;小学组3停泊处&#xff0c;初高中组6停泊处&#xff1b;涉及传送带、机械臂、传感器等虚拟设备。初中/高中组任务复杂度更高&#xff0c;运…

探秘 Linux 系统编程:进程地址空间的奇妙世界

亲爱的读者朋友们&#x1f603;&#xff0c;此文开启知识盛宴与思想碰撞&#x1f389;。 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 在 Linux 系统编程的领域里&#xff0c;进程地址空间可是个相当重要的…