当前位置: 首页 > news >正文

Win32汇编学习笔记10.OD插件

Win32汇编学习笔记10.OD插件-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net

筛选器异常插件

被调试程序: 📎TestUnh.zip

我们用OD条试试发现,无法断下 筛选器异常

异常产生之后 异常首先会给调试器 调试器不处理就会给 SEH , SEH 不处理的话有又给调试器, 调试器不处理的话就会给筛选器 , 筛选器不处理的就会给操作系统,直接退进程

这里面是2次的异常派发流程 第一次 是 到 给SHE 之后属于第二次 派发流程

第二次派发是一个分支,会判断是否有调试器,有的话就给调试器,没有的话直接给筛选器,因此系统会检查软件是否处于调试状态 即检查调试端口是否存在,如果存在,异常就会给调试器,否则给筛选器,所以我们在用 OD 调试筛选器异常时,是不可能再筛选器这下断点的,因此系统检测到了调试器,异常就不会给筛选器

因此我们可以欺骗系统,告诉系统,不存在调试器,直接给筛选器,因此我们需要找到 异常派发时,系统在哪判断是否有调试器存在的,找到后我们可以更改判断结果 或者跳转 的地方

这个在 msdn中有明确的说明 UnhandledExceptionFilter 来判断的

img

img

img

img

接下来我们只需要 更改条件跳转 ,看 筛选器异常能否断下来 ,就可以判断是在哪 判断是否有 调试器的

img

img

img

img

跳过测试可知,当 call 函数 返回值 为0 就可以收到 筛选器异常,为1就无法收到,那么位置我们已经找到了,接下来我们只需要改 判断 函数下一行 把 eax 的值 改为0 就可以 收到 筛选器异常了 即改成 xor eax,eax

img

因此我们只需要写一个插件让他自己去改

img

img

img

接下来就是写插件了

#include <windows.h>
#include "Plugin.h"int ODBG_Plugindata(char* shortname) {strcpy_s(shortname, 32,"筛选器异常修复");return PLUGIN_VERSION;}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) {return 0;
}

生成解决方案时

img

img

把生成的 dll 放到指定目录,再打开 OD,发现我们的插件已经 加载进来了

img

既然插件可以识别那下面就是增加功能了

img

我们的目标把红框的代码改成 xor ,eax,eax 即 把 76A6D810 处的 值 改成 33 ,如果直接写固定地址,那么电脑重启后dll 的路径就发生过了改变,即 该处地址也变化了,Name插件也用不了了,因此我们需要用相对地址,可以函数地址+偏移 或者 模块地址 + 偏移

img

我们可以看到 kernelbase 的 地址是 768B0000 那么 跟 76A6D81B 的偏移值位为 0x1BD81B

#include <windows.h>
#include "Plugin.h"void  FixUnHandledException();int ODBG_Plugindata(char* shortname) 
{strcpy_s(shortname, 32,"筛选器异常修复");FixUnHandledException() ;return PLUGIN_VERSION;}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) 
{return 0;
}void  FixUnHandledException() 
{//1.定位 test eax,eax的地址HMODULE hKernelbase = GetModuleHandle("Kernelbase");   LPBYTE pDst = (LPBYTE)hKernelbase + 0x1BD81B;//2.修改   test eax,eax  位 xor eax,eaxDWORD dwOldPro = 0;//修改内存属性VirtualProtect(pDst, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pDst = 0x33;//还原内存属性VirtualProtect(pDst, 1, dwOldPro, &dwOldPro);
}

img

运行发现并没有被修改,猜想可能是因为 修改的太早,程序还没有运行

img

img

#include <windows.h>
#include "Plugin.h"void  FixUnHandledException();
int ODBG_Paused(int reason, t_reg* reg);int ODBG_Plugindata(char* shortname) 
{strcpy_s(shortname, 32,"筛选器异常修复");return PLUGIN_VERSION;}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) 
{return 0;
}int ODBG_Paused(int reason, t_reg* reg)
{if (reason == PP_EVENT){FixUnHandledException();}return 1;
}void  FixUnHandledException() 
{//1.定位 test eax,eax的地址HMODULE hKernelbase = GetModuleHandle("Kernelbase");   LPBYTE pDst = (LPBYTE)hKernelbase + 0x1BD81B;//2.修改   test eax,eax  位 xor eax,eaxDWORD dwOldPro = 0;//修改内存属性VirtualProtect(pDst, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pDst = 0x33;//还原内存属性VirtualProtect(pDst, 1, dwOldPro, &dwOldPro);//用于判断dll有没有被加载MessageBox(NULL, "这是我的插件", "提示", MB_OK);
}

调试发现还是没改成功

那是因为 OD 调试时有2个进程 , 我们修改时 修改的是 OD 的进程 , 并没有修改到被调试的进程,但是地址是对的,因为在同一台电脑, kernelbase 的 地址是固定的 , 因此我们需要跨进程修改 内存 OD 提供了 对应的 api

内存函数

结构

OILYDBG为被调试程序保存了一份已分配内存块的信息表,它由TMG

MEMORY

MEMORY*FINDMEMORY(ULONG ADDR);

VOID HAVECOPYOFMEMORY(CHAR *COPY,ULONG BASE,ULONG SIZE);

ULONG READMEMORY(VOID *BUF.ULONG ADDR.ULONG SIZE.INT MODE):

WRITEMEMORY(VOID*BUF ULONG ADDR,ULONG SIZE,INT MODE):

ULONG W

INT LISTMEMORY(VOID);

image.png

image.png

#include <windows.h>
#include "Plugin.h"#pragma comment(lib,"Ollydbg.lib")
void  FixUnHandledException();
int ODBG_Paused(int reason, t_reg* reg);int ODBG_Plugindata(char* shortname) 
{strcpy_s(shortname, 32,"筛选器异常修复");  return PLUGIN_VERSION;}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) 
{return 0;
}int ODBG_Paused(int reason, t_reg* reg)
{if (reason == PP_EVENT){FixUnHandledException();}return 1;
}void  FixUnHandledException() 
{//1.定位 test eax,eax的地址HMODULE hKernelbase = GetModuleHandle("Kernelbase");   LPBYTE pDst = (LPBYTE)hKernelbase + 0x1BD81B;#if 0//2.修改   test eax,eax  位 xor eax,eaxDWORD dwOldPro = 0;//修改内存属性VirtualProtect(pDst, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pDst = 0x33;//还原内存属性VirtualProtect(pDst, 1, dwOldPro, &dwOldPro);
#endif // 0BYTE btCode = 0x33;Writememory(&btCode, (ulong)pDst, 1, MM_SILENT);//用于判断dll有没有被加载;MessageBox(NULL, "这是我的插件", "提示", MB_OK);
}

img

再次调试,可以发现我们成功修改了,筛选器异常也可以成功调试了

上面虽然成功了,但是兼容性还存在问题,要求二进制文件必须是一样,但是不同的电脑,编译出来的二进制文件是可能不一样的,到时兼容性还是出问题,这种处理方式是搜机器码, 先找到特征码(离修改代码最近的唯一值) ,再去寻找要修改的代码,不然直接搜要修改代码可能会有多个 ,类似于切割出指定字符串

窗口过程函数地址错误

OD 如果没有安装修复插件啊,有些 窗口的过程函数地址是错误的 看雪下载的已经修复

img

获取过程函数的地址有2种

一种是通过 GetWindowLong 获得 一种是通过 GetClassLong

通过OD 调 OD 对 GetWindowLong 和 GetClassLong 下断点

可以知道是通过 GetClassLongA 拿到的,因此可以猜想 是因为 GetClassLongA 拿的是 多字节的窗口过程函数 而Unicode 窗口 获取 过程函数需要用 GetClassLongW,因此只需要在获取 Unicode 窗口 过程函数是是 用 GetClassLongW 就可以了

跟窗口相关的函数都在 user32 里面 ,跟界面相关的 都在 user32 里面

img

调试可知 GetClassLong 调取的都是该处的 GetClassLongA ,因此我们只需要改动这里就可以了

img

img

jmp是一个间接调,先取地址,在跳到目标位置,因此我们改该处地址就可以了,

我们自己可以实现一个 MyGetClassLong 然后把地址传过来这样他就会调我们的函数,我们只需要做一下判断是 多字节窗口还是 Unicode 就可以了

该处地址的我们还是可以 通过算偏移得到 ,因为 OD 版本一样,所以偏移也是一样的

img

所以偏移是 0x0050D858 - 0x00400000 = 0x0010D858

#include <windows.h>
#include "Plugin.h"#pragma comment(lib,"Ollydbg.lib")
void  FixUnHandledException();
int ODBG_Paused(int reason, t_reg* reg);
void FixGetClassLong();int ODBG_Plugindata(char* shortname) 
{strcpy_s(shortname, 32,"筛选器异常修复");  return PLUGIN_VERSION;}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) 
{FixGetClassLong();return 0;
}int ODBG_Paused(int reason, t_reg* reg)
{if (reason == PP_EVENT){FixUnHandledException();}return 1;
}void  FixUnHandledException() 
{//1.定位 test eax,eax的地址HMODULE hKernelbase = GetModuleHandle("Kernelbase");   LPBYTE pDst = (LPBYTE)hKernelbase + 0x1BD81B;#if 0//2.修改   test eax,eax  位 xor eax,eaxDWORD dwOldPro = 0;//修改内存属性VirtualProtect(pDst, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pDst = 0x33;//还原内存属性VirtualProtect(pDst, 1, dwOldPro, &dwOldPro);
#endif // 0BYTE btCode = 0x33;Writememory(&btCode, (ulong)pDst, 1, MM_SILENT);//用于判断dll有没有被加载//MessageBox(NULL, "这是我的插件", "提示", MB_OK);
}LONG MyGetClassLong(HWND hWnd,int nIndex)
{if (IsWindowUnicode(hWnd))  // 判断一个窗口是否是 unicode窗口{return GetClassLongW(hWnd, nIndex);}else{return GetClassLongA(hWnd, nIndex);}}void FixGetClassLong()
{//1.定位地址HMODULE Hod = GetModuleHandle(NULL);  //获取主模块基址(OD)LPDWORD pAddr =(LPDWORD)((LPBYTE)Hod + 0x10D858);//2.修改为自己的地址DWORD dwOldPro = 0;//修改内存属性VirtualProtect(pAddr, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pAddr = (DWORD)MyGetClassLong;//还原内存属性VirtualProtect(pAddr, 1, dwOldPro, &dwOldPro);}

调试会发现会崩, 代码没崩,但是运行了一段时间就崩一般情况下是栈歪了

经过调试,还有2个参数在栈上

系统的api 一般都是标准调用约定, 但是我们自己的代码需要自己去平栈, 因此要改动调用约定 改成 stdcall

#include <windows.h>
#include "Plugin.h"#pragma comment(lib,"Ollydbg.lib")
void  FixUnHandledException();
int ODBG_Paused(int reason, t_reg* reg);
void FixGetClassLong();int ODBG_Plugindata(char* shortname) 
{strcpy_s(shortname, 32,"筛选器异常修复");  return PLUGIN_VERSION;}int ODBG_Plugininit(int ollydbgversion, HWND hw, ulong* features) 
{FixGetClassLong();return 0;
}int ODBG_Paused(int reason, t_reg* reg)
{if (reason == PP_EVENT){FixUnHandledException();}return 1;
}void  FixUnHandledException() 
{//1.定位 test eax,eax的地址HMODULE hKernelbase = GetModuleHandle("Kernelbase");   LPBYTE pDst = (LPBYTE)hKernelbase + 0x1BD81B;#if 0//2.修改   test eax,eax  位 xor eax,eaxDWORD dwOldPro = 0;//修改内存属性VirtualProtect(pDst, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pDst = 0x33;//还原内存属性VirtualProtect(pDst, 1, dwOldPro, &dwOldPro);
#endif // 0BYTE btCode = 0x33;Writememory(&btCode, (ulong)pDst, 1, MM_SILENT);//用于判断dll有没有被加载//MessageBox(NULL, "这是我的插件", "提示", MB_OK);
}LONG WINAPI MyGetClassLong(HWND hWnd,int nIndex)
{if (IsWindowUnicode(hWnd))  // 判断一个窗口是否是 unicode窗口{return GetClassLongW(hWnd, nIndex);}else{return GetClassLongA(hWnd, nIndex);}
}void FixGetClassLong()
{//1.定位地址HMODULE Hod = GetModuleHandle(NULL);  //获取主模块基址(OD)LPDWORD pAddr =(LPDWORD)((LPBYTE)Hod + 0x10D858);//2.修改为自己的地址DWORD dwOldPro = 0;//修改内存属性VirtualProtect(pAddr, 1, PAGE_EXECUTE_READWRITE, &dwOldPro);*pAddr = (DWORD)MyGetClassLong;//还原内存属性VirtualProtect(pAddr, 1, dwOldPro, &dwOldPro);}

再去调试,发现可以获取正确的 窗口过程函数地址了

img

x32dbg 也可以写插件

img

img

相关文章:

Win32汇编学习笔记10.OD插件

Win32汇编学习笔记10.OD插件-C/C基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net 筛选器异常插件 被调试程序: &#x1f4ce;TestUnh.zip 我们用OD条试试发现,无法断下 筛选器异常 异常产生之后 异常首先会给调试器 调试器不处理就会给 SEH , SEH 不处理的话有又给…...

在vscode中已经安装了插件Live Server,但是在命令面板确找不到

​​​​​ 1、VS Code缓存问题&#xff1a; 有时VS Code的缓存可能导致插件无法正确加载。尝试删除VS Code缓存文件夹&#xff08;如C:\Users\你的用户名\AppData\Roaming\Code&#xff09;中的文件&#xff0c;并重启VS Code。 2、重新安装插件&#xff1a; 尝试卸载Live S…...

C# SQL ASP.NET Web

留学生的课程答疑 按照要求完成程序设计、数据库设计、用户手册等相关技术文档&#xff1b; 要求 1. 计算机相关专业&#xff0c;本科以上学历&#xff0c;至少有1年以上工作经验或实习经历。 2. 熟练掌握WinForm程序开发&#xff0c;或ASP.NET Web编程。 3. 熟悉C#中网络…...

联想java开发面试题及参考答案

IP 协议是哪一层的? IP 协议(Internet Protocol)属于网络层协议。 网络层主要负责将数据从源节点传输到目标节点,它在整个网络通信体系中起到了承上启下的关键作用。在分层网络模型中,下层(如数据链路层)为网络层提供物理链路的连接和帧传输服务。数据链路层关注的是在相…...

Node.js中的fs模块:文件与目录操作(写入、读取、复制、移动、删除、重命名等)

在Node.js中&#xff0c;fs模块提供了多种方法来处理文件和目录操作&#xff0c;使得数据的持久性保存和文件管理变得简单。下面将介绍文件读写、文件复制、文件移动、文件重命名、文件删除、文件夹创建与删除以及查看资源状态等常用操作。 首先&#xff0c;在使用写入和读取功…...

代码的形状:重构的方向

大概2周前写了一篇《代码的形状:从外到内的探索与实践》 涵树&#xff1a;代码的形状:从外到内的探索与实践 觉得这个话题还可以继续&#xff0c;它是一个从无形到有形的过程&#xff0c;而这个过程感觉就是王阳明先生说的“心即理”的探寻过程。 我讨论代码的形状&#xff…...

2021 年 3 月青少年软编等考 C 语言五级真题解析

目录 T1. 红与黑思路分析T2. 密室逃脱思路分析T3. 求逆序对数思路分析T4. 最小新整数思路分析T1. 红与黑 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻的黑色瓷砖移动。请写一个程序,计算你总共能够到达多少块黑色的…...

华为C语言编程规范总结

1.头文件更改会导致所有直接或间接包含该头文件的的C文件重新编译&#xff0c;会增加大量编译工作量&#xff0c;延长编译时间&#xff0c;因此&#xff1a; 1.1 头文件里尽量少包含头文件 1.2 头文件应向稳定的方向包含 2.每一个.c文件应有一个同名.h文件&#xff0c…...

XML 解析器:深入解析与高效应用

XML 解析器&#xff1a;深入解析与高效应用 引言 XML&#xff08;可扩展标记语言&#xff09;作为一种重要的数据交换格式&#xff0c;被广泛应用于各种系统和平台中。为了有效地处理和解析XML数据&#xff0c;XML解析器发挥着至关重要的作用。本文将深入探讨XML解析器的原理…...

《系统爆破:MD5易破,后台登录可爆破?》

声明&#xff1a;笔记的只是方便各位师傅学习知识&#xff0c;以下代码、网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 爆破Sales系统 一、爆破MD5 场景&#xff1a;已知MD5的加密字符串&#xff0c;如何得知明…...

基于微信小程序的书籍销售系统设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

SpringData-Redis缓存

Spring Framework是领先的全堆栈Java/JEE应用程序框架。它提供了一个轻量级容器和一个通过使用依赖注入、AOP和可移植服务抽象实现的非侵入性编程模型。 NoSQL存储系统为传统RDBMS提供了一种横向可扩展性和速度的替代方案。就实现而言&#xff0c;键值存储代表NoSQL空间中最大…...

Hadoop3.3.4伪分布式环境搭建

文章目录 前言一、准备1. 下载Hadoop2. 配置环境变量3. 配置免密 二、Hadoop配置1. hadoop-env.sh2. hdfs-site.xml3. core-site.xml4. mapred-site.xml5. yarn-site.xml 三、格式化四、启动 前言 hadoop学习——伪分布式环境——普通用户搭建 一、准备 1. 下载Hadoop 2. 配…...

【VUE 指令学习笔记】

v-bind :单向绑定解析表达式&#xff0c;可简写为:xxx v-model :双向数据绑定。 v-for&#xff1a;遍历数组/对象/字符串 v-on&#xff1a;绑定事件监听&#xff0c;可简写为。 v-if:条件渲染(动态控制节点是否存存在) v-else:条件渲染(动态控制节点是否存存在) v-show:条件渲染…...

【深度学习】布匹寻边:抓边误差小于3px【附完整链接】

布匹寻边 项目简介 布匹寻边是指布料裁剪过程中&#xff0c;通过AI寻边技术自动识别布匹的边缘&#xff0c;将检测到的边缘信息输出&#xff0c;确保裁剪的准确性&#xff0c;减少浪费&#xff0c;并提高生产效率。 项目需求 将打满针眼的布匹边缘裁剪掉&#xff0c;且误差小…...

【学习笔记】理解深度学习的基础:机器学习

1. 机器学习基础 1.1 机器学习的定义与重要性 定义&#xff1a;深度学习是机器学习的一种特定形式。为了深入理解深度学习&#xff0c;必须牢固掌握机器学习的基本原理。机器学习算法是一种能够从数据中学习的算法&#xff0c;通过经验E在任务T上提高性能度量P&#xff08;Mi…...

提升租赁效率的租赁小程序全解析

内容概要 在如今快节奏的生活中&#xff0c;租赁小程序俨然成为了提升租赁效率的一把利器。无论是个人还是企业&#xff0c;都会因其便捷的功能而受益。简单来说&#xff0c;租赁小程序能让繁琐的租赁流程变得轻松、高效。在这里&#xff0c;我们将带您畅游租赁小程序的海洋&a…...

Windows自动化Python pyautogui RPA操作

依赖包 import time import pyautogui import pyperclip import os import psutil from pywinauto.application import Application睡眠&#xff1a; pyautogui.sleep(1)鼠标事件&#xff1a; pyautogui.moveTo(100, 100, duration0.25) pyautogui.click(100, 100, duration0.…...

蓝桥杯_B组_省赛_2022(用作博主自己学习)

题目链接算法11.九进制转十进制 - 蓝桥云课 进制转换 21.顺子日期 - 蓝桥云课 时间与日期 31.刷题统计 - 蓝桥云课 时间与日期 41.修剪灌木 - 蓝桥云课 思维 51.X 进制减法 - 蓝桥云课 贪心 61.统计子矩阵 - 蓝桥云课 二维前缀和 71.积木画 - 蓝桥云课 动态规划 82.扫雷 - 蓝桥…...

RK3568 Android 13 内置搜狗输入法小计

问&#xff1a;为什么写&#xff1f; 答&#xff1a;网上搜出来的都试过了&#xff0c;不行&#xff01;下面直接上代码和注意事项&#xff01; 首先到这个目录&#xff08;/RK3568/Rockchip_Android13_SDK_Release/device/rockchip/rk356x/tl3568_evm/preinstall&#xff09…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...