首页/新闻资讯/正文详情

C++ D3D Hook 透视实现:虚表 Hook 与世界坐标转屏幕坐标详解

发布时间:2026/9/28 1:10:40 来源:云帆数科 栏目:资讯中心
C++ D3D Hook 透视实现:虚表 Hook 与世界坐标转屏幕坐标详解
简介这份资源是面向游戏逆向工程与图形编程学习者的C Direct3D Hook源码工程核心围绕D3D函数拦截与游戏透视效果的实现展开。作者snakezl3通过API Hook方式捕获CreateDevice、Present等关键渲染函数在自定义钩子中动态修改视图矩阵与投影矩阵从而在不改动游戏原始代码的前提下实现透视涉及VTable Hook、3D数学与图形管线等知识点适合具备一定C与D3D基础的中高级开发者研究。压缩包共71个文件约67.5MB以cpp与h源码文件为主体辅以vcxproj、sln等VS工程配置、obj、pdb、ilk等编译中间产物以及exe、dll、lib等可执行与库文件另有rc、ico等资源文件工程结构完整可直接编译调试。目前已有310人学习下载。通过研读源码读者可掌握D3D Hook的完整实现流程、透视矩阵的计算思路与Hook的挂载及卸载时机是理解游戏逆向与3D图形调试的实用参考使用时请遵循合法合规原则。1. 从 D3DHOOK.zip 说起C 里 D3D Hook 透视到底在做什么很多人第一次看到「D3DHOOK.zip_C D3DHOOK源码_D3D Hook透视」这类标题脑子里冒出来的画面是打开一个压缩包、编译一下、进游戏就能看到墙后的人。实际做过的人都知道事情没这么简单但也没玄学到完全摸不着边。它本质上是三件事叠在一起用 C 写一个 DLL把 Direct3D 的渲染流程接管一段再在每一帧画完场景之后把原本不该被看见的目标用另一种方式重新画一遍。所谓「透视」在 D3D Hook 这个语境里绝大多数实现走的是「读取实体坐标 → 世界坐标转屏幕坐标 → 在屏幕空间叠加绘制」这条路而不是去改游戏内存里的可见性标志。这套东西适合谁适合已经能写 C、懂一点 Windows 消息循环和 COM 接口、想搞清楚「游戏画面是怎么被第三方代码插进去的」这类问题的从业者。它不适合把 C 当第一门语言的人因为你会同时面对指针、虚表、调用约定、渲染管线四座山。但只要你写过结构体链表、用过回调函数剩下的就是耐心问题。下面我按「先立住原理、再动手复现、最后讲坑」的顺序把这条链路拆开讲清楚中间会给出可以直接抄的代码骨架和参数说明。2. D3D Hook 的三条主流路线与选型理由2.1 虚函数表 Hook为什么它是最常见的入口Direct3D 9 的设备对象IDirect3DDevice9是一个 COM 接口它的所有方法都通过虚函数表vtable暴露。所谓 vtable Hook就是拿到这个对象的虚表指针找到EndScene或Present对应的槽位把里面的函数地址替换成我们自己的函数地址。游戏每帧都会调用EndScene于是我们的代码每帧都会被顺带执行一次。这是最经典、资料最多、也最容易理解的一种方式。为什么选EndScene而不是Present因为EndScene在 D3D9 里是「场景绘制结束、准备提交」的时机此时后台缓冲已经画完我们在它之后叠加绘制内容会直接出现在这一帧里。Present也可以但它涉及交换链某些多交换链的游戏里Present会被调用多次容易重复绘制。常见做法是优先 HookEndScene如果游戏用的是 D3D11 或 D3D12那就要换成Present配合交换链的 vtable思路一样槽位不同。选型上还有两条路一条是直接改游戏内存里的函数头inline hook / detour另一条是注入后替换整个 DLL。前者对代码段有写保护需要改内存属性容易被反作弊盯上后者动静大但实现简单。vtable Hook 介于两者之间改的是虚表里的一个指针不改原始函数体相对干净。我一般会先试 vtable不行再考虑 detour。2.2 世界坐标转屏幕坐标透视的数学核心Hook 只是「拿到每帧的执行权」真正让透视成立的是坐标变换。游戏里每个角色、载具、物资都有一个世界坐标(x, y, z)而屏幕是二维的。要把世界坐标画到屏幕上需要经过「世界矩阵 → 视图矩阵 → 投影矩阵」三次变换最后做透视除法。D3D9 里这套矩阵通常可以通过GetTransform拿到或者从游戏自己的渲染状态里读。核心公式是先把世界坐标乘上视图投影矩阵得到一个四维齐次坐标再用w分量做除法得到归一化设备坐标NDC最后映射到屏幕像素。下面这段代码是常见的实现骨架参数含义我会逐行说明。// 世界坐标转屏幕坐标D3D9 常用实现 bool WorldToScreen(const D3DXVECTOR3 world, D3DXVECTOR3 screen, const D3DXMATRIX view, const D3DXMATRIX proj, float screenW, float screenH) { // 1. 世界坐标扩展成四维w 初始为 1 D3DXVECTOR4 pos(world.x, world.y, world.z, 1.0f); // 2. 先乘视图矩阵再乘投影矩阵得到裁剪空间坐标 D3DXMATRIX viewProj view * proj; D3DXVec4Transform(pos, pos, viewProj); // 3. w 小于等于 0 说明点在相机背后直接丢弃 if (pos.w 0.01f) return false; // 4. 透视除法得到 NDC范围 [-1, 1] float ndcX pos.x / pos.w; float ndcY pos.y / pos.w; // 5. 映射到屏幕像素Y 轴要翻转 screen.x (ndcX 1.0f) * 0.5f * screenW; screen.y (1.0f - ndcY) * 0.5f * screenH; screen.z pos.w; // 保留深度用于排序 return true; }逻辑说明第 2 步把视图和投影合并成一个矩阵再乘减少一次矩阵乘法第 3 步的w 0.01f是必须的否则相机背后的点会被错误地投影到屏幕上出现「鬼影」。第 5 步的 Y 轴翻转是因为 NDC 的 Y 向上而屏幕坐标 Y 向下。参数screenW、screenH一般取游戏窗口的客户区宽高不是显示器分辨率这一点后面避坑章节会展开。2.3 从坐标到方框绘制阶段的最小实现拿到屏幕坐标后透视的呈现方式有很多种画方框、画骨骼、画射线、画血条。最基础的是方框因为只需要两个点。常见做法是用目标的世界坐标加上一个高度偏移得到「头顶」和「脚底」两个世界点分别转屏幕坐标然后画矩形。下面是一个用 D3D9 画线框的简化函数。// 在 EndScene 之后绘制一个矩形框 void DrawBox(LPDIRECT3DDEVICE9 device, float x, float y, float w, float h, D3DCOLOR color) { // 顶点格式变换后的屏幕坐标 颜色 struct Vertex { float x, y, z, rhw; D3DCOLOR color; }; Vertex v[4] { { x, y, 0.0f, 1.0f, color }, { x w, y, 0.0f, 1.0f, color }, { x w, y h, 0.0f, 1.0f, color }, { x, y h, 0.0f, 1.0f, color }, }; // 关闭光照和剔除保证线框一定可见 device-SetRenderState(D3DRS_LIGHTING, FALSE); device-SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); device-SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); device-DrawPrimitiveUP(D3DPT_LINESTRIP, 3, v, sizeof(Vertex)); }逻辑说明D3DFVF_XYZRHW表示顶点已经是屏幕坐标不需要再经过变换管线rhw是齐次 w 的倒数固定填 1.0f。DrawPrimitiveUP用 LINESTRIP 画三条边最后一条边靠首尾闭合所以顶点数传 3。参数color用D3DCOLOR_ARGB构造比如D3DCOLOR_ARGB(255, 255, 0, 0)是纯红。注意每帧绘制前要保存并恢复渲染状态否则会把游戏自己的画面搞花这是血泪经验。3. 用 C 把 D3DHOOK 跑起来的最小工程3.1 工程配置DLL 类型、字符集与链接库新建工程时选「动态链接库DLL」不要选控制台。字符集建议用「多字节字符集」因为 D3D9 的很多老接口和示例代码是按多字节写的用 Unicode 会多出一堆LPCWSTR转换。链接库需要加d3d9.lib和d3dx9.lib前者提供设备接口后者提供矩阵和向量运算。如果你用的是 Visual Studio在「项目属性 → 链接器 → 输入 → 附加依赖项」里加上这两个即可。入口函数用DllMain在DLL_PROCESS_ATTACH时创建一条线程去初始化 Hook。不要在DllMain里直接做复杂操作因为加载锁的存在容易死锁。常见做法是CreateThread后立刻返回让 Hook 在独立线程里完成。// dllmain.cpp #include windows.h DWORD WINAPI InitThread(LPVOID param) { // 在这里做 Hook 初始化比如创建临时 D3D 设备拿虚表 // 具体实现见下一节 return 0; } BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved) { if (reason DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hModule); CreateThread(nullptr, 0, InitThread, nullptr, 0, nullptr); } return TRUE; }逻辑说明DisableThreadLibraryCalls关闭线程创建/销毁通知减少不必要的调用。CreateThread的第五个参数传 0 表示立即运行。参数hModule是当前 DLL 的句柄后面如果要做卸载或资源定位会用到。3.2 拿到 IDirect3DDevice9 虚表的两种办法要 HookEndScene先得拿到设备对象的虚表地址。有两种常见办法。第一种是创建一个临时的 D3D9 设备从它的虚表里读出EndScene的地址然后把这个地址作为「特征」去游戏进程里搜索。第二种是直接 HookIDirect3DDevice9::Present或Direct3DCreate9等游戏自己创建设备时再替换。第一种更主动第二种更稳。下面演示第一种创建一个隐藏窗口和临时设备读出虚表第 42 号槽位EndScene在 D3D9 虚表中的索引是 42。// 获取 EndScene 在虚表中的地址 typedef HRESULT(WINAPI* EndScene_t)(LPDIRECT3DDEVICE9); EndScene_t GetEndSceneAddress() { // 创建隐藏窗口 HWND hwnd CreateWindowA(STATIC, , WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, nullptr, nullptr); IDirect3D9* d3d Direct3DCreate9(D3D_SDK_VERSION); D3DPRESENT_PARAMETERS pp {}; pp.Windowed TRUE; pp.SwapEffect D3DSWAPEFFECT_DISCARD; pp.hDeviceWindow hwnd; IDirect3DDevice9* device nullptr; d3d-CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, pp, device); // 虚表指针在对象的前 4 字节32 位或前 8 字节64 位 void** vtable *reinterpret_castvoid***(device); EndScene_t addr reinterpret_castEndScene_t(vtable[42]); device-Release(); d3d-Release(); DestroyWindow(hwnd); return addr; }逻辑说明vtable[42]是 D3D9 头文件里EndScene的固定索引不同 SDK 版本可能有细微差别但 42 是通用值。参数D3DCREATE_SOFTWARE_VERTEXPROCESSING是为了兼容性实际游戏里可能用硬件顶点处理但这里只是拿地址不影响。注意 64 位下指针是 8 字节reinterpret_castvoid***的写法要相应调整。3.3 替换虚表指针并写自己的 EndScene拿到地址后把虚表里那一项改成我们自己的函数地址。为了能调用原始函数需要保存原地址。下面是一个完整的 Hook 骨架。EndScene_t oEndScene nullptr; // 保存原始 EndScene HRESULT WINAPI hkEndScene(LPDIRECT3DDEVICE9 device) { // 先让游戏自己画完这一帧 HRESULT hr oEndScene(device); // 在这里做透视绘制遍历实体、转屏幕坐标、画框 // DrawBox(device, ...); return hr; } void InstallHook() { EndScene_t target GetEndSceneAddress(); oEndScene target; // 修改虚表内存属性为可写 DWORD oldProtect; VirtualProtect(((void**)target)[42], sizeof(void*), PAGE_EXECUTE_READWRITE, oldProtect); ((void**)target)[42] reinterpret_castvoid*(hkEndScene); VirtualProtect(((void**)target)[42], sizeof(void*), oldProtect, oldProtect); }逻辑说明VirtualProtect把虚表那一页改成可读写改完再改回去避免长期暴露写权限。hkEndScene里先调用oEndScene保证游戏画面正常再叠加自己的绘制。参数device是游戏传进来的设备指针直接拿来画线即可。注意不要在hkEndScene里做耗时操作否则帧率会掉。4. 避坑与排查D3D Hook 透视最常见的五个翻车点4.1 现象注入后游戏直接闪退没有任何报错原因最常见的是在DllMain里做了重操作或者 Hook 时机太早游戏还没创建设备就去改虚表导致访问了空指针。另一个原因是 32 位 DLL 注入到了 64 位进程或者反过来。解决把初始化逻辑全部放到独立线程里并且加一个循环等待直到GetEndSceneAddress返回非空再继续。注入前确认目标进程的位数用对应的编译配置。如果还是闪退用调试器附加看崩溃在哪个模块。4.2 现象方框画出来了但位置整体偏移或者只在屏幕左上角原因屏幕宽高取错了。很多人直接用GetSystemMetrics(SM_CXSCREEN)那是显示器分辨率不是游戏窗口的客户区。游戏可能窗口化运行或者有黑边客户区尺寸和显示器尺寸不一致。解决用GetClientRect拿窗口客户区再配合ClientToScreen换算。如果游戏用了缩放还要考虑 DPI 感知。参数上screenW和screenH应该等于客户区宽高而不是分辨率。4.3 现象目标在相机背后时方框出现在屏幕另一侧原因世界坐标转屏幕坐标时没有判断w分量。相机背后的点经过透视除法会得到一个「镜像」的坐标看起来就像穿到了另一边。解决在WorldToScreen里加if (pos.w 0.01f) return false;并且调用方要检查返回值返回 false 就不画。这个 0.01f 是经验值太小会漏掉近处目标太大会误杀。4.4 现象游戏画面变花UI 闪烁或者帧率骤降原因绘制时改了渲染状态没恢复。D3D9 的状态是全局的你关了光照、改了剔除模式游戏后面的绘制就会受影响。另一个原因是每帧遍历实体太多或者每帧都重新创建顶点缓冲。解决在hkEndScene开头保存关键状态结尾恢复。常见要保存的有D3DRS_LIGHTING、D3DRS_CULLMODE、D3DRS_ZENABLE、SetFVF和纹理。顶点数据用栈上的数组不要每帧new。如果实体多做距离裁剪只画视野内的。4.5 现象换了一台机器或换了个游戏版本Hook 失效原因虚表索引变了或者游戏用了 D3D11/12EndScene根本不存在。另一个原因是游戏加了完整性校验发现虚表被改就重置。解决先确认游戏的渲染 APID3D9 用EndSceneD3D11 用Present配合IDXGISwapChain。如果是校验考虑用更隐蔽的 detour或者 Hook 更底层的函数。参数上D3D11 的Present在交换链虚表的第 8 号槽位和 D3D9 完全不同不能混用。5. 进阶技巧让透视更稳、更准、更难被察觉5.1 用矩阵缓存减少每帧开销每帧都调用GetTransform拿矩阵是有开销的而且有些游戏在EndScene时矩阵已经切回了 UI 矩阵。更稳的做法是在 Hook 到SetTransform时缓存视图和投影矩阵绘制时直接用缓存。下面是一个缓存结构。struct MatrixCache { D3DXMATRIX view; D3DXMATRIX proj; bool valid; }; MatrixCache g_cache {}; // Hook SetTransform缓存视图和投影 HRESULT WINAPI hkSetTransform(LPDIRECT3DDEVICE9 device, D3DTRANSFORMSTATETYPE state, const D3DXMATRIX* matrix) { if (state D3DTS_VIEW) g_cache.view *matrix; if (state D3DTS_PROJECTION) g_cache.proj *matrix; g_cache.valid true; return oSetTransform(device, state, matrix); }逻辑说明D3DTS_VIEW和D3DTS_PROJECTION分别对应视图和投影矩阵。缓存后WorldToScreen直接用g_cache.view和g_cache.proj不用再问设备要。参数state是变换类型D3D9 里还有D3DTS_WORLD但世界矩阵每个物体不同一般不缓存。5.2 用深度排序避免方框重叠错乱多个目标在屏幕上重叠时后画的会盖住先画的。如果想让近处的目标盖住远处的需要按深度排序。WorldToScreen返回的screen.z就是w分量可以当深度用。把目标收集到一个数组里按z从小到大排序再依次绘制。参数含义建议值screen.z透视除法前的 w近似距离越小越近排序方式升序近处先画远处后画最大绘制数每帧最多画多少个3264视性能而定5.3 验证 Hook 是否生效的三个手段第一在hkEndScene里加一个计数器用OutputDebugString每 60 帧打印一次看调试器里有没有输出。第二画一个固定的屏幕中心十字如果能看到说明绘制链路通了。第三用D3DCOLOR_ARGB(255, 0, 255, 0)画一个绿色方框在固定屏幕坐标确认颜色和位置都对。这三个手段按顺序做能快速定位是 Hook 没生效、还是坐标算错、还是绘制状态有问题。我自己做这类东西的习惯是先把 Hook 跑通画一个不依赖任何游戏数据的固定方框再把坐标转换跑通画一个已知世界坐标的点最后才去遍历实体。跳过前两步直接上实体翻车了根本不知道是哪一层的问题。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

3步搞定中国最早的电商平台源码下载安全
3步搞定中国最早的电商平台源码下载安全

3步搞定中国最早的电商平台源码下载安全 域名服务器搞不懂?别慌,这行水比你想象的深。很多项目经理拿到【中国最早的电商平台】的【源码下载】包,第一反应不是看代码,而是问:“这玩意儿怎么部署?SSL怎么配?备案卡在哪?”… · 2026/9/28 1:10:40

基于SpringBoot的阿尔茨海默病健康管理APP毕设全解
基于SpringBoot的阿尔茨海默病健康管理APP毕设全解

做毕设最怕的从来不是代码写不出来,而是选题一眼看过去就知道是"老古董":又是学生管理系统,又是图书借阅系统,评委老师看了都想睡觉。阿尔茨海默病健康管理APP这个方向,我前后带过好几个学生落地&#xff0c… · 2026/9/28 1:10:34

能源科技网站建设图解步骤:域名服务器避坑全攻略
能源科技网站建设图解步骤:域名服务器避坑全攻略

能源科技网站建设图解步骤:域名服务器避坑全攻略 做能源科技行业的网站,最头疼的不是代码怎么写,而是域名和服务器这一套流程,很多设计师转前端的同行在这里卡了三天三夜。我见过太多项目因为DNS解析配置错误,导致客户访问超时,最后只能紧急回滚。别… · 2026/9/28 1:10:34

Python搭建QQ聊天机器人极简教程
Python搭建QQ聊天机器人极简教程

随着QQ粉丝群管理需求的不断增长,简单的群管工具难以满足复杂的信息响应和自动化需求。现有的自动回复机器人虽然功能强大,但其高昂的年费成为不少用户的顾虑。因此,通过搭建一个自定义机器人来实现自动回复,成为解决这一问题的有效途径。 基于此需求,本文介绍了使用go-c… · 2026/9/28 2:14:08

Python整理百度云盘文件大量重复无用文件
Python整理百度云盘文件大量重复无用文件

百度云盘容量有限,当文件数量逐渐增多,空间很容易被填满。删除重复文件可以帮助释放大量空间。通过获取云盘缓存目录并使用Python脚本来整理数据,可以高效识别重复文件并避免手动操作的繁琐。 此方法基于 sqlite3 和 pandas 进行数据处理,简单快捷。 文章目录 云盘数据整理… · 2026/9/28 2:14:07

Python实现将图片转化为具有视觉震撼效果的字符图
Python实现将图片转化为具有视觉震撼效果的字符图

字符画是一种将图片转化为字符的艺术表现形式,它通过字符的密度和排列来模拟图片的色彩和形状效果。这种技术不仅在视觉上充满了创造力,还在文字处理领域展示了字符的丰富表现力。通过Python,可以将图片转换为字符画,生成具有视觉冲击力的字符艺术。 本文将通过具体步骤和… · 2026/9/28 2:13:48

Python实现将目录下的图片合并成PDF文件
Python实现将目录下的图片合并成PDF文件

在图像处理和文档管理中,经常需要将一系列图片文件合并为PDF格式,以便于传输、存档和阅读。Python凭借其丰富的第三方库,为图像处理和PDF操作提供了便捷的解决方案。 本文将详细介绍如何通过Python脚本,将目录中的所有图片合并为一个PDF文件,内容包括从基础环境配置到代码… · 2026/9/28 2:13:48

Python实现文件移动到指定文件夹
Python实现文件移动到指定文件夹

在编程过程中,经常需要对文件进行整理和管理,将不同类型的文件分类存放在指定文件夹中。Python提供了强大的文件操作模块,使得文件的移动操作变得简单高效。这篇教程将详细讲解如何使用Python实现将文件移动到指定文件夹的功能,帮助理解并掌握文件操作的基本方法和常见应用… · 2026/9/28 2:13:47

【PyQt】PyQT6制作一个Django项目启动器
【PyQt】PyQT6制作一个Django项目启动器

在现代的桌面和Web应用开发中,Python以其简单高效的特点获得了广泛的应用。通过集成PyQt和Django框架,将桌面应用的便捷操作与Django项目的后端处理相结合,不仅能够提升用户体验,更能显著提高开发的便利性和效率。 本文将聚焦于如何构建一个基于PyQt的Django项目启动器,实… · 2026/9/28 2:13:40

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

制作网页比较方便的软件怎么选?一文搞懂避坑指南
制作网页比较方便的软件怎么选?一文搞懂避坑指南

制作网页比较方便的软件怎么选?一文搞懂避坑指南 很多老板一上来就问:做个网站多少钱?但我反问他:你的域名买了吗?服务器租了吗?他一脸懵。这就是典型的“域名服务器搞不懂”。别急,今天咱们不聊虚的,直接 一文搞懂 那些让你头秃的技术名词。… · 2026/9/28 0:00:06

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量
婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量

婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 找婚恋网站建站公司,最怕的就是被坑高价。很多同行跟我吐槽,报价单上写得模棱两可,功能栏里全是“高级定制”、“专属UI”,结果落地全是套壳。今天不聊虚的,直接甩几个我经手的 实战案例… · 2026/9/28 0:00:19

济南做网站多少钱:3个案例拆解,防黑源码下载全攻略
济南做网站多少钱:3个案例拆解,防黑源码下载全攻略

济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 上周济南一个做建材的老板找我,脸都绿了。他的官网首页弹出了赌博广告,后台被植入了挖矿脚本。他慌得问我:“网站被黑挂马不知道怎么办?能不能直接找之前的外包公司要源码下载,看看哪里被动了手脚?… · 2026/9/28 0:00:25

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码