简介一份面向开发者的系统时间保护组件用于防止系统时间被恶意篡改保障依赖时间戳的软件逻辑如授权验证、日志记录、定时任务稳定运行。资源包含完整工程与可调用库涵盖时间检查模块、权限控制机制、事件记录及异常处理等核心功能并提供跨平台兼容与可配置策略适合需要强化系统时序安全的C开发人员。压缩包共32个文件主要包括SysTimeCtrl.dll、SysTimeCtrl.sys等动态库与内核驱动以及对应的.h头文件、.cpp源码、测试工程VCTest和使用说明txt文档整体仅755KB结构紧凑便于快速集成。已有1050人学习下载包内附带的Demo示例和reg.bat注册脚本可帮助开发者快速上手在自有应用中建立一道可靠的系统时间防护层。1. 禁止修改系统时间程序先想清楚你要拦的是什么在线考试系统、计费软件、日志审计服务都有一个共同的“被玩坏了”的经历某个用户把系统时间一改题库额外开放了半小时或者日志里出现了一堆时间戳错乱的数据。禁止修改系统时间程序干的就是这件事——拦截系统时间修改的入口要么把修改动作拒掉要么在修改发生后马上改回来。这个标题看着简单“禁止”两个字落地却要分层拦用户手动改、拦软件内部调用、拦管理员权限下的操作每一层用的技术完全不一样。这篇文章面向的读者是真正要接这个需求的人要么是做考试/防作弊系统的要么是做定时授权的桌面软件的要么是被日志与计费问题逼着去补这个功能的。我会按选型、Hook实现、踩坑、系统级兜底、验证方法这条线往后讲。2. 为什么拦不住三条修改路径与应用层选型2.1 Windows 里改时间远远不止“任务栏右键”一个入口会直接改系统时间的 API 有三个级别很多初做“禁止修改系统时间程序”的人只拦了其中最表层的一个。用户最熟悉的是任务栏右下角打开“日期和时间”设置走到控制面板图形界面改时间这在底层调用的是 Win32 APISetLocalTime。但如果用户写一个小程序一行SetSystemTime也能改这两个 API 走的是不同的权限路径。更隐蔽的是第三类SetSystemTimeAdjustment它不改绝对时间点而是把系统时钟速率往快或往慢调几分钟后系统时间就偏离了真实时间很多防修改程序根本没意识到这个入口存在。还有一个不能忽略的路径——cmd下直接用time 14:30:00命令它内部也是通过SetLocalTime完成的所以从 API 层拦截能覆盖命令行方式。但反过来date命令呢它走的是SetSystemTime如果程序只 Hook 了SetLocalTime这条路线就漏掉了。这里我先把三条路径列出后面选型要从这张表出发。修改入口调用 API权限要求说明控制面板/任务栏设置SetLocalTime普通管理员即可用户最常走的路径date/time 命令SetSystemTime / SetLocalTime需要管理员权限考试系统里最常见的攻击入口时间同步服务(W32Time)SetSystemTimeAdjustmentSYSTEM 权限会缓慢地间接改时间第三方校时软件混合调用以上全部管理员最容易被误杀的一类2.2 应用层 Hook、WMI 事件订阅、组策略限权怎么选“禁止修改系统时间程序”的常见做法有三种选型取决于一个核心问题你是想“拦下拒绝”还是想“发现后改回来”还是想“从权限上让用户根本上没资格改”。第一种应用层 Hook。在进程内改写SetLocalTime等 API 的内存跳转让所有调用先进到自己的过滤函数里判断是合法修改比如自家程序同步服务器时间还是非法修改非法就拒绝。优势是控制粒度细可以按进程名放行劣势是只对加载了 Hook DLL 的进程生效系统服务如 W32Time有自己的代码路径不会经过应用层 Hook。第二种WMI 事件订阅。Windows 的 WMI 会在Win32_LocalTime或Win32_SystemTime变化时触发__InstanceModificationEvent程序订阅事件后一旦时间发生变化就立刻把时间改回去。优势是无侵入不干扰进程劣势是有一个“被修改成功再改回来”的时间窗哪怕只有几百毫秒对并发校验严格的计费系统还是可能出问题。第三种组策略限权。在“安全设置 → 本地策略 → 用户权限分配”里把“更改系统时间”权限从用户和 Users 组里拿走只保留 SYSTEM 和 Administrators。优势是彻底任何非管理员都改不了劣势是对已经是管理员账户的程序防不住因为管理员可以自己把权限加回去。我做这类需求时默认框架是“组策略限权 应用层 Hook 拦截 WMI 兜底改回”三层叠加。只做任何一层都会被打穿三层各管一段才能覆盖“用户手动改、软件 API 改、管理员故意改”三条路。下面先给一个最小可用的 WMI 监控脚本让你在改代码前先感受一下这个方案的机制。2.3 先看一个最小可用的 WMI 监控脚本被改后自动改回PowerShell 里可以注册一个永久 WMI 事件当系统时间变更时触发脚本把时间同步回来# 注册 WMI 永久事件监听 Win32_LocalTime 的实例变化 $query SELECT * FROM __InstanceModificationEvent WITHIN 1 WHERE TargetInstance ISA Win32_LocalTime # 注册一个定时器事件每3秒执行一次后面的动作 Register-CimIndicationEvent -Namespace root/cimv2 -Query $query -SourceIdentifier TimeChanged # 当事件触发时用 w32tm 强制与时间服务器重新同步 Register-EngineEvent -SourceIdentifier TimeChanged -Action { w32tm /resync /nowait }这段脚本的逻辑是WMI 每 1 秒扫描一次系统时间对象只要发现Win32_LocalTime的实例与上次不同就认为时间被修改触发 Action 里写好的同步命令把时间拉回到 NTP 服务器。WITHIN 1这里的参数单位是秒数值越小扫描越频繁发现时间被改的延迟越低但 CPU 占用会略高。正常场景 1 到 3 秒都可以考试系统建议 1 秒普通计费软件 3 秒足够。这个脚本作为“兜底”够用但它不是真正的“禁止”因为时间已经被改成功过一次。如果用户改了时间后立刻断网w32tm /resync没有服务器可同步系统时间就会停在被修改的位置。所以把它当最后一道保险不能当主力主力还是要靠第 3 章的 Hook 方案把修改行为直接挡回去。3. 做真正的“禁止修改系统时间程序”Hook SetLocalTime 的 VC6.0 工程思路3.1 拦截 SetLocalTime 和 SetSystemTimeinline Hook 写法与全局注入在 VC6.0 年代一个被广泛采用的方案是 IAT Hook导入地址表 Hook它修改进程内kernel32.dll的导入表把SetLocalTime的地址替换成自己函数的地址。IAT Hook 实现简单老编译器编译也没问题但有个致命弱点只对调用了kernel32.dll导出函数的进程生效如果开发工具或攻击脚本直接自己调ntdll.dll层的NtSetSystemTimeIAT Hook 就瞎了。所以现在做禁止修改系统时间程序一般直接用 inline Hook——改目标函数头部的机器码插入一条jmp跳到我们的过滤函数处理完再跳回去。inline Hook 的最小核心代码是“改写函数开头 5 个字节 保存原字节 恢复执行”// 一个精简的 inline hook 框架VC6.0 可直接编译 #include windows.h // 保存原函数开头的原始字节 BYTE g_oldBytes[5]; // 记录是否已安装 hook BOOL g_hooked FALSE; // 自定义的“假 SetLocalTime”签名必须与真函数完全一致 BOOL WINAPI FakeSetLocalTime(const SYSTEMTIME* lpSystemTime) { // 在这里做业务判断是放行还是拒绝 // 为了演示直接拒绝一切修改 OutputDebugString(拦截到 SetLocalTime 调用); return FALSE; // 返回 FALSE 表示调用失败时间不会被改 } // 安装 hook改掉 SetLocalTime 开头 5 字节跳转到 FakeSetLocalTime void InstallHook() { HMODULE hKernel32 GetModuleHandleA(kernel32.dll); // GetProcAddress 拿到 API 在内存中的真实地址 PROC pFunc GetProcAddress(hKernel32, SetLocalTime); if (pFunc NULL) return; // 保存原始字节后面卸载 hook 时要用 DWORD dwOldProtect; VirtualProtect(pFunc, 5, PAGE_EXECUTE_READWRITE, dwOldProtect); memcpy(g_oldBytes, pFunc, 5); // 构造机器码E9 是 jmp 指令的 opcode后面跟相对偏移 BYTE jumpBytes[5] { 0xE9, 0, 0, 0, 0 }; // 计算跳转偏移目标地址 - 当前地址 - 指令长度(5) DWORD offset (DWORD)FakeSetLocalTime - (DWORD)pFunc - 5; memcpy(jumpBytes[1], offset, 4); memcpy(pFunc, jumpBytes, 5); VirtualProtect(pFunc, 5, dwOldProtect, dwOldProtect); g_hooked TRUE; } // 卸载 hook把原始字节写回去 void UninstallHook() { if (!g_hooked) return; HMODULE hKernel32 GetModuleHandleA(kernel32.dll); PROC pFunc GetProcAddress(hKernel32, SetLocalTime); DWORD dwOldProtect; VirtualProtect(pFunc, 5, PAGE_EXECUTE_READWRITE, dwOldProtect); memcpy(pFunc, g_oldBytes, 5); VirtualProtect(pFunc, 5, dwOldProtect, dwOldProtect); g_hooked FALSE; }机器码里0xE9后面跟的是相对偏移计算方式是“目标地址减去当前指令地址再减 5”这个 5 是jmp指令本身的长度。偏移算错会导致程序跳到错误地址直接崩溃这是 inline Hook 最常见的翻车点。VirtualProtect改内存页属性也是必须的SetLocalTime所在的内存页在 kernel32 里默认是只读的不改属性直接用memcpy写会访问违规。上面这段代码只做了SetLocalTime的 Hook实际工程还要同样处理SetSystemTime和SetSystemTimeAdjustment。一个取巧的办法是直接从kernel32.dll的导出表枚举函数名把函数名匹配到目标 API 后统一安装 hook。VC6.0 里可以手动解析 PE 导出表也可以用GetProcAddress 硬编码函数名的笨办法我一般在正式项目里把三个 API 分成三个 hook代码量稍大但排查问题方便。3.2 进程注入让 Hook 覆盖所有进程的两种路线单独一个进程里 Hook 自己的SetLocalTime没意义你需要让 hook DLL 注入到所有用户态进程里才能拦截所有软件调用的SetLocalTime。常见做法是写一个 DLLDLL 的DllMain里执行 InstallHook然后用SetWindowsHookEx(WH_GETMESSAGE)把这个 DLL 注入到所有有消息循环的 GUI 进程里。// dllmain.cpp —— 被注入到其他进程后自动安装 hook HHOOK g_hHook NULL; LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) { // 这个回调只是为了保持 DLL 被加载不需要做实际处理 return CallNextHookEx(g_hHook, nCode, wParam, lParam); } extern C __declspec(dllexport) void InstallGlobalHook() { // WH_GETMESSAGE 类型的全局钩子会让系统把本 DLL 注入到各 GUI 进程 g_hHook SetWindowsHookExA(WH_GETMESSAGE, GetMsgProc, GetModuleHandleA(MyHook.dll), 0); // 注入成功后DllMain 里会执行 InstallHook() } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) { if (reason DLL_PROCESS_ATTACH) { // 每个被注入的进程都在加载 DLL 时自动调用安装函数 InstallHook(); } return TRUE; }SetWindowsHookExA的最后一个线程 ID 传 0表示全局注入所有 GUI 进程。非 GUI 的纯命令行进程不会被注入所以还得配合一个“守护进程”每隔几秒扫描系统进程列表对还没有 hook 的进程执行CreateRemoteThread注入。这一步复杂度偏高很多小项目干脆放弃纯进程注入改用第 2 章说的 WMI 改回方案兜底。我自己的经验如果产品是考试客户端这种有主进程的软件只对自家主进程做 hook 就够了真正会在这类软件里被攻击的是考试客户端本身。如果做的是系统级防时间篡改工具那就必须全局注入加守护进程逃不掉。3.3 防止用户卸载你的“禁止修改时间”逻辑双进程守护上了 Hook 和 WMI 后下一个问题就是用户打开任务管理器结束掉守护进程Hook 卸载时间随便改。所以一个完整的禁止修改系统时间程序需要双进程互守护。方案是注册两个 Windows 服务服务 A 负责注入 Hook 和监控 WMI 事件服务 B 每隔几秒检测服务 A 是否还活着如果 A 被停止B 立刻把它拉起来。反过来 A 也检测 B。这里有一个 VC6.0 下很好用的技巧——用服务的方式让程序以 SYSTEM 权限运行。用户权限下启动的进程可以被用户结束而 SYSTEM 权限的服务在任务管理器里结束会失败提示“拒绝访问”。注册服务用OpenSCManagerA和CreateServiceA代码量不大但要注意服务回调函数里别调用可能阻塞的 UI 操作。按这个思路搭完架子你的程序已经能挡住绝大多数“考试时用命令行改时间”和“手动打开设置改时间”的行为。但真正的坑还没有完全踩完下一章讲哪几种情况会让这个方案看起来“失效了”。4. 五个真实踩坑为什么你的“禁止修改”会被打穿4.1 现象明明 Hook 了 SetLocalTime时间还是变了不少初做者只 Hook 了SetLocalTime然后测试时用time命令改时间发现照样改成功。原因time命令在本机用的其实是SetSystemTime不是SetLocalTimeHook 方向错了。解决把SetSystemTime也加上。更隐蔽的是SetSystemTimeAdjustment它不改时间点只改时钟频率时间在一两分钟内慢慢偏离必须一并 Hook。在三个函数里SetSystemTimeAdjustment的签名最特殊BOOL WINAPI FakeSetSystemTimeAdjustment(DWORD dwTimeAdjustment, BOOL bEnabled) { // 禁止一切时间调整 return FALSE; }4.2 现象WMI 事件订阅后系统时间被改了但脚本没触发PowerShell 的Register-CimIndicationEvent在脚本进程退出后会丢失尤其是用cmd窗口跑脚本时窗口一关监听就没了。解决不用临时脚本而是把 WMI 订阅写成 MOF 文件用mofcomp编译进 WMI 仓库成为永久事件订阅系统重启后仍然生效。MOF 文件注册事件的写法相当于“系统级配置”不依赖脚本进程存活。4.3 现象杀毒软件把 Hook DLL 当恶意行为清除HookSetLocalTime在杀软眼里和键盘记录器的行为特征很像尤其 DllMain 里做memcpy改写内核函数头经常被当成病毒启发式告警。解决给 DLL 做数字签名同时在杀毒软件控制台里加白名单。如果产品要分发到客户环境更稳的做法是把应用层 Hook 降级为“辅助拦截”主拦截用第 5 章会讲的组策略限权Hook 只负责拦管理员级别的 API 调用降低杀软的敏感度。4.4 现象NTP 自动校时把自己的程序拦了系统默认开启自动同步时间W32Time 服务调用SetSystemTimeAdjustment校时被 Hook 拒绝后系统时间会越来越慢或越来越快最终和真实时间偏出去十几分钟。这是“禁止修改”做过头了。解决在 Hook 过滤函数里判断进程名放行svchost.exe -k LocalServiceNetworkRestricted或所有W32Time相关的调用。判断方式是用GetModuleFileNameExA拿当前进程路径然后匹配%SystemRoot%System32svchost.exe加参数限定或者更粗一点只放行带特定命令行参数的系统服务。4.5 现象管理员用户用“提升权限”后你的 Hook 全失效用户右键“以管理员身份运行 cmd”进程成了高权限但你的守护服务和 Hook DLL 在普通进程里拦截不了不同权限级别进程的 API 调用。这在 Windows 的 UAC 机制下是必然的。解决依赖系统级方案——组策略限权只能限制非管理员对管理员用户需要在 Windows 内核层做回调或者接受一个事实本机管理员总有办法改时间禁止修改系统时间程序能拦的是“大多数普通用户和应用程序”防不住有 SYSTEM 权限的恶意代码。我一般会在这个层面给产品加审计日志把每次时间修改的时间点、进程名、结果记录到事件事后追责比事前死防更实用。5. 从应用层到系统层组策略限权与更硬的兜底方案5.1 组策略限权让普通用户根本没有“改时间”的资格第 2 章提过组策略的权限位这里给出具体配置路径。Win7、Win10、Win11 都在同一位置gpedit.msc → 计算机配置 → Windows 设置 → 安全设置 → 本地策略 → 用户权限分配右侧找“更改系统时间”项。双击打开删除Users组只保留Administrators和SYSTEM。这是系统级权限不依赖你的程序跑不跑。如果做成程序自动配置脚本如下echo off rem 禁止 Users 组修改系统时间 secedit /export /cfg C:\temp\secpol.cfg /areas USER_RIGHTS rem 在导出的配置里SeSystemtimePrivilege 一行移除用户的 SID rem 具体操作用脚本把 SeSystemtimePrivilege 行重写后重新导入 secedit /configure /db C:\windows\security\database\secedit.sdb /cfg C:\temp\secpol_new.cfg /areas USER_RIGHT直接编辑secpol.cfg比较麻烦SID 解析容易出错。更稳妥的落地方式是让程序调用LsaAddAccountRights或直接执行wmic脚本修改。工程上的常见做法是内部工具检测到当前用户是普通权限直接弹窗提示“请让管理员运行一次配置程序”由管理员手动在组策略里删除 Users 组。自动化配置做得好就成了产品卖点做不好容易把自己的系统权限搞乱。脚本方式适合 IT 管理员批量下发不适合做成面向普通用户的软件。5.2 NTP 强同步兜底把时间拉回真实轨道的最后一道闸如果被改时间后修改行为没被拦住至少要让系统尽快回到真实时间。Windows 自带的 W32Time 服务可以被配置成强制同步w32tm /config /manualpeerlist:ntp.aliyun.com,0x1 ntp.tencent.com,0x1 /syncfromflags:manual /reliable:yes /update w32tm /resync /rediscover0x1表示使用特殊模式同步manualpeerlist配置多个 NTP 服务器避免单一服务器不可用时同步失败。这个方案的局限也很明显被改时间后、下一次同步成功前系统时间已经“错”了一会儿对于毫秒级校验的计费系统还是要靠第 3 章的 Hook 提前拦截。NTP 强同步通常作为 WMI 兜底的进阶替代或与 WMI 配合WMI 事件触发后不再盲目执行w32tm /resync它有时比被改的时间还慢而是定时器每 5 分钟强制同步一次保证偏离不会累积。5.3 移动端时间保护的思路差异鸿蒙的时间显示只是表层讨论移动端时热词里有个很典型的例子——鸿蒙系统微信聊天时间 12 小时制显示用户看到的是“上午/下午”格式这和“禁止修改系统时间程序”不直接相关但它说明移动端时间处理有一个更麻烦的现实系统时间不仅能被改还能被“格式化显示”绕过去。在 Windows 桌面环境里禁止修改时间靠 API Hook在鸿蒙或 Android 上普通应用根本没有SetSystemTime权限只有系统应用或 adb shell 下的 root 才能改。所以移动端防时间篡改的重点不是拦截 API而是“以服务器时间为准”——所有校时逻辑放在客户端向服务端请求标准时间本地时间只做展示。这套思路反过来对 Windows 桌面也有启发如果产品的时间敏感度非常高不要相信本地时间登录时从服务器拿时间戳作为基准之后所有业务判断都基于“服务器时间 本地时间偏移量”本地时间被改了也能在业务层发现偏移异常。这不是标题里的技术要求但它能让整个方案在对抗性场景里更可用。我经手的计费类项目最终都是“Hook 拦截随手改 服务器时间基准兜底”双管齐下才收尾。6. 验证这套程序有没有拦住自测脚本与最后一层确认做完上述所有工作不要急着交付。我有一套固定的自测流程先正常改时间确认拦截生效再按不同入口逐一打。echo off rem 自测脚本分别从命令行和 API 角度尝试改时间 echo 1. 测试 SetLocalTime 拦截 time 12:34:56 echo 结果%errorlevel% echo 2. 测试 SetSystemTime 拦截 date 2024/01/01 echo 结果%errorlevel% echo 3. 查看系统当前时间是否已被改回 time /t date /ttime 12:34:56和date 2024/01/01会触发你 Hook 的两个 API。如果程序拦截成功屏幕上时间显示不会变化%errorlevel%应该非 0。更严格的自测是写一段小 C 程序直接调用SetLocalTime确认返回 FALSE。我在交付时还会做一次断网自测——拔掉网线改时间观察 WMI 兜底在无法联网时会不会把时间误同步一定要在兜底逻辑里加判断只有当前系统时间与上次记录值偏差大于阈值时才强制同步否则可能把正常的时间调整也拉回去。自测通过后把三个 Hook 的日志输出打开观察一天内拦截记录有没有非预期进程频繁触发。这个数据能帮你判断是不是误拦截了系统自己的校时服务。做这个方向最大的教训是不要把时间保护做成“绝对禁止”要留出白名单放行机制否则你自己的运维调整时间也会被自己的程序拦下来。希望这个实操方案对你有用按这套思路做下来即使被绕过一层后面两层也能兜住。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
Qwen-Image-Lightning在Mac M系列Metal部署全指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 4:47:17
YOLOv5+PyQt5课堂专注度实时检测系统 简介:本资源是一套面向计算机视觉初学者与教育技术开发者的课堂专注度实时检测预警系统实现方案,基于YOLOv5目标检测模型与PyQt5构建跨平台桌面应用,解决在线教学场景中学习者注意力状态自动识别与异常预警的实际需求。压缩包共146个文件&… · 2026/9/26 4:47:17
ax调度实战:从浏览器并发约束到前端请求队列设计与性能优化 我最近在一个数据看板项目里被自己的代码逼到了墙角:页面一打开就要同时请求二十多个图表接口,浏览器直接卡成PPT,接口超时、下拉列表加载不出来,测试同学在群里连着艾特我三次。排查到最后,问题根本不是某一个接口慢&… · 2026/9/26 4:47:17
WebRTC信令服务架构设计与实战:从P2P到集群扩展 一次真实的视频通话或者直播连麦背后,媒体流是用户能感知到的部分,但真正把“双方怎么会面”“各自的网络能力怎么交换”“媒体参数怎么达成一致”这些问题解决掉的,是藏在背后的信令服务。WebRTC P2P架构里,信令服务往往是最不起… · 2026/9/26 5:26:06
高校电动车租赁系统:SpringBoot+Vue+MySQL全栈毕设实战 每年到了毕业设计季,总能看到大量同学在“电动车租赁系统”、“共享单车系统”、“校园二手交易平台”这类题目之间反复横跳。这题目看着平淡无奇,但真上手去做,从技术选型、数据库设计到联调部署,每一步都藏着不少门道。这篇博文… · 2026/9/26 5:26:06
Substrate区块链开发框架:从Runtime到Pallet的工程实践指南 1. 为什么我最终选了Substrate来开发区块链先说结论:如果你打算发行一条自己的链,而不是在别人的链上写合约,那么Substrate几乎是当下最务实的选择,没有之一。这个判断不是看文档看出来的,是我这一年多真正拿它从零搭了… · 2026/9/26 5:26:06
商务洽谈总记不住客户需求?我用这套方案,告别“会后失忆症” 做销售和商务的朋友应该都有过这种体验:一场客户面谈聊了两个小时,对方说了很多需求、顾虑、期望,当时觉得都记住了,可回到公司写跟进记录的时候,大脑却一片空白——客户到底强调了哪三点?那个预算范围是多… · 2026/9/26 5:26:00
SSE流式传输实战:从协议原理到生产环境避坑指南 1. 从一次线上事故说起:为什么流式传输值得单独拎出来讲去年帮一个团队排查线上问题,现象很典型:AI 对话页面在回答较长内容时,用户要盯着空白转圈十几秒,然后整段文字"啪"地一下全冒出来。产品经理觉得是模… · 2026/9/26 5:26:00
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46