PE结构(十五)系统调用与函数地址动态寻找
双机调试
当需要分析一个程序时,这个程序一定是可以调试的,操作系统也不例外。在调试过程中下断点是很重要的
当我们对一个应用程序下断点时,应用程序是挂起的。但当我们对操作系统的内核程序下断点时,被挂起的不是内核程序而是整个操作系统。当操作系统被挂起时,网卡显卡等功能无法使用,进而无法在挂起的操作系统的机器上进行任何操作,也就无法调试内核程序了。
为了能够调试内核程序,Windows提供了一个调试子系统,它是一个独立于操作系统的的子系统,负责与调试器进行数据的交互进而实现调试内核程序。当内核程序下断点时,整个操作系统都被挂起,而这个调试子系统却不会被挂起。因此我们可以通过调试子系统去调试内核程序。
双机调试:由于挂起的操作系统我们无法进行任何操作,因此当调试内核程序时,我们需要在另一个机器上进行调试,这就是双机调试的由来。但我们使用两台物理机器来调试内核程序,这显然不现实,因此我们通常在本机上再运行一个虚拟机从而达到双机的效果。虚拟机上运行我们要调试的内核程序的机器,而我们在本机上进行调试内核程序。
调试过程:本机中的windbg首先连接到被调试的内核程序的机器的调试子系统,然后虚拟机通过串口把被调试的内核程序的数据发送给本机的windbg中从而进行信息的交互,进而实现调试。而我们在windbg发送的指令实际上是给调试子系统发送指令
注意:我们需要在操作系统刚开始运行时被迅速打开windbg,否则可能出现无法连接调试子系统的情况
此处具体双击调试环境配置步骤就不多说了,诸位自行百度
驱动开发
大多的驱动程序的启动是基于服务加载,服务基于注册表。驱动程序不像我们写的应用程序,关闭窗口就关闭程序,它必须有一个卸载,才可以关闭程序
一般的驱动程序都是用C写到,因为足够底层。但也可以用C++写,不过不建议
接下来我们在本机上写一个简单的驱动程序:
C驱动程序
#include <ntifs.h>//SYS 驱动程序后缀:.SYSVOID DriverUnload(PDRIVER_OBJECT pDriverObject)//卸载函数,名字自定义
{DbgPrint("Hello DriverUnload\r\n");//打印一句话
}NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)//参数:驱动对象 注册表路径
{pDriverObject->DriverUnload = DriverUnload;//指向卸载函数DbgPrint("Hello DriverEntry\r\n");//一定要加上\r\n,否则可能打印失败return STATUS_SUCCESS;//必须返回成功
}
C++驱动程序
#include <ntifs.h>EXTERN_C VOID DriverUnload(PDRIVER_OBJECT pDriverObject)//由于C++具有名称粉碎机制,因此以C的形式导出,保留名称
{DbgPrint("Hello C++ DriverUnload\r\n");
}EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegPath)
{pDriverObject->DriverUnload = DriverUnload;DbgPrint("Hello C++ DriverEntry\r\n");return STATUS_SUCCESS;
}
系统调用
大多数的应用程序的函数调用无疑是调用了系统调用(内核函数),而使用系统调用则需要进入内核,进入内核有如下几种方式:
1.int 2E(比较早期)
2.sysenter(x86)
3.syscall(x64)
注意:在进入内核前,通常需要携带参数:系统服务号,有时候也需要携带其他的参数,如进程ID等等。系统服务号用于在内核的SSDT表(系统描述符表)中进行对照寻找系统调用,其充当了索引的作用
在我们日常使用的应用程序,分为x86应用程序和x64应用程序,不同的应用程序有不同的运行环境:x86的应用程序可以在x86操作系统上运行,也在x64操作系统上运行。而x64的应用程序只能在x64的操作系统上运行。
在不同的操作系统上,应用程序的函数调用有不同的情况,接下来我们观察这两种不同情况的应用程序的函数调用流程,也就是观察如何调用系统调用。
现我们写如下程序并生成x86和x64版本的exe
#include<iostream>
#include<Windows.h>int main()
{OpenProcess(PROCESS_ALL_ACCESS, FALSE, 1234)system("pause");return 0;
}
x86应用程序
我们将上文的exe文件拖入x32dbg中进行观察,接下来我们将通过一步步的步入观察该函数由表入里的调用过程:从函数到系统调用
x86OS
1.我们搜索所有用户模块的跨模块调用找到OpenProcess的调用处。
2.跟进该函数,我们发现程序来到Kernel32.dll模块进行一个跳转
3.程序来到kernelbase.dll模块,调用ZwOpenProcess(同NTOpenProcess)
4.程序来到ntdll.dll模块,调用KiFastSystemCall
5.程序在ntdll.dll模块,调用sysenter进入内核
x64OS
1. 我们搜索所有用户模块的跨模块调用找到OpenProcess的调用处。
2.步入该函数,我们发现程序来到Kernel32.dll模块进行一个跳转
3.程序来到kernelbase.dll模块,调用NTOpenProcess
4.程序来到ntdll.dll模块,调用Wow64Transition
Wow64Transition用于处理64位操作系统下32位程序,实现模拟的32位环境并进行转发,然后调用64位函数进入内核
x64应用程序
1. 我们搜索所有用户模块的跨模块调用找到OpenProcess的调用处。
2.步入该函数,我们发现程序来到Kernel32.dll模块进行一个跳转
3.程序来到kernelbase.dll模块,调用NTOpenProcess
4.程序在ntdll.dll模块,调用syscall或int 2E进入内核
函数地址动态寻找
所谓的壳不过是在目标程序中加一个区段使得程序可以执行我们自己的代码,从而达到加密的效果。但在这个实现的过程中,存在一个问题:我们无法知晓目标程序中是否包含我们自己的代码中所使用的一些函数的相关库。如果没有相关库的话,也就无法在我们的代码中使用相关函数。为保险起见,我们需要自己加载相关的动态链接库。但由于我们并不清楚目标程序中包含了哪些头文件,因此也无法使用LoadLibrary加载动态链接库。因此我们便需要动态寻找函数地址,从而实现加载动态链接库,进而实现我们自己的代码书写
为实现以上操作,有以下两个结构很重要:
1.TEB(线程环境块):描述线程的关键成员
2.PEB(进程环境块):描述进程的关键成员
x86应用程序
x86OS
接下来我们将针对x86程序在x86环境下,通过这两个结构,完成函数地址动态寻找
一.我们通过双机调试寻找Kernel32的地址
1.Windbg中输入命令!Process 0 0:显示简略的系统进程相关信息
此处我们找到了目标程序INSTDRV.EXE
2.输入命令.process /i 切换到目标程序环境下
注意:结束以后需要F5重新加载一下上下文
3.输入命令! process,查看目标程序信息
4.输入命令dt _TEB 0x7ffde00,获取TEB结构,从而获取PEB结构
5.查看PEB结构:获取_PEB_LDR_DATA结构
6.查看_PEB_LDR_DATA结构,其中存在三个重要的双向链表
7._LIST_ENTRY结构记录了双向链表的信息。
如InLoadOrderModuleList的_LIST_ENTRY记录了加载模块列表的相关信息
8.查看InLoadOrderModuleList的第一个_LDR_DATA_TABLE_ENTRY结构,观察第一个进程加载的模块信息
9.查看InLoadOrderModuleList的第二个_LDR_DATA_TABLE_ENTRY结构
10.查看InLoadOrderModuleList的第三个_LDR_DATA_TABLE_ENTRY结构,此处我们找到了Kernel32模块的相关信息
二.在Kernel32的导出表中寻找到GetProcAddress,该函数用于获取动态链接库(DLL)中指定导出函数的地址
三.找到LoadLibrary地址,该函数用于加载动态链接库
四.加载动态链接库
代码实现
#include <iostream>
#include <Windows.h>DWORD GetKernel32Address() {DWORD dwKernel32 = 0;//获取当前线程的TEB指针_TEB *pTeb = NtCurrentTeb();//在TEB中找到PEB,于TEB+0x30位置PDWORD pPeb = (PDWORD)*(PDWORD)((DWORD)pTeb + 0x30);//PEB中找到PEB_LDR_DATA,于PEB+0xC位置PDWORD pLdr = (PDWORD)*(PDWORD)((DWORD)pPeb + 0xC);//PEB_LDR_DATA中找到InLoadOrderModuleList,于PEB_LDR_DATA+0xC的位置PDWORD InLoadOrderModuleList = (PDWORD)((DWORD)pLdr + 0xC);//找到exe模块PDWORD pModuleExe = (PDWORD)*InLoadOrderModuleList;//找到Ntdll模块PDWORD pModuleNtdll = (PDWORD)*pModuleExe;//找到Kernel32模块PDWORD pModuleKernel32 = (PDWORD)*pModuleNtdll;//保存Kernel32模块基址dwKernel32 = pModuleKernel32[4];//返回Kernel32模块基址/模块基址也就是模块句柄return dwKernel32;
}//获取GetProcAddress函数地址
DWORD GrkGetProcessAddress() {//获取Kernel32基址DWORD dwBase = GetKernel32Address();//获取DOS头PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwBase;//获取NT头PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);//获取PE可选头PIMAGE_OPTIONAL_HEADER pOptionalHeader = &pNtHeaders->OptionalHeader;//获取Kernel32的导出表PIMAGE_DATA_DIRECTORY pExportDir = &(pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(dwBase + pExportDir->VirtualAddress);DWORD dwFuncCount = pExport->NumberOfFunctions;DWORD dwFuncNameCount = pExport->NumberOfNames;//导出地址表PDWORD pEAT = (PDWORD)(dwBase + pExport->AddressOfFunctions);//导出名称表PDWORD pENT = (PDWORD)(dwBase + pExport->AddressOfNames);//导出序号表PWORD pEIT = (PWORD)(dwBase + pExport->AddressOfNameOrdinals);//遍历导出表,获取我们需要的函数地址for (size_t i = 0; i < dwFuncCount; i++){if (!pEAT[i]){continue;}DWORD dwFunAddrOffset = pEAT[i];for (size_t index = 0; index < dwFuncNameCount; index++){if (pEIT[index] == i){DWORD dwNameOffset = pENT[index];char * szFuncName = (char *)(((DWORD)dwBase) + dwNameOffset);if (strcmp(szFuncName,"GetProcAddress") == 0){return dwBase + dwFunAddrOffset;}}}}
}EXTERN_C typedef HMODULE
(WINAPI *
fnLoadLibraryA)(_In_ LPCSTR lpLibFileName
);EXTERN_C typedef FARPROC
(WINAPI *
fnGetProcAddress)(_In_ HMODULE hModule,_In_ LPCSTR lpProcName
);EXTERN_C typedef int
(WINAPI *
fnMessageBoxA)(_In_opt_ HWND hWnd,_In_opt_ LPCSTR lpText,_In_opt_ LPCSTR lpCaption,_In_ UINT uType);EXTERN_C typedef VOID
(WINAPI *
fnExitProcess)(_In_ UINT uExitCode
);int main()
{fnGetProcAddress pfnGetProcAddress = (fnGetProcAddress)GrkGetProcessAddress();//获取Kernel32.dll基址HMODULE hKernel32 = (HMODULE)GetKernel32Address();//获取LoadLibraryA地址fnLoadLibraryA pfnLoadLibraryA = (fnLoadLibraryA)pfnGetProcAddress(hKernel32, "LoadLibraryA");//加载user32.dllHMODULE hUesr32 = pfnLoadLibraryA("user32.dll");//获取MessageBoxA地址fnMessageBoxA pfnMessageBoxA = (fnMessageBoxA)pfnGetProcAddress(hUesr32, "MessageBoxA");//获取ExitProcess地址,用于退出进程fnExitProcess pfnExitProcess = (fnExitProcess)pfnGetProcAddress(hKernel32, "ExitProcess");//调用MessageBoxApfnMessageBoxA(NULL, "rkvir", "Msg", MB_OK);//调用ExitProcess,退出进程pfnExitProcess(0);system("pause");return 0;
}
x64OS
双机调试流程同x86大致一样,只是地址由32位变为64位,以及系统进入内核方式由Kernel32所在库变为wow64库。具体流程此处不再演示。
代码实现同上
x64应用程序
代码实现
此处代码实现与x86的代码实现一致,只需把DWORD改为ULONGLONG即可
#include <iostream>
#include <Windows.h>ULONGLONG GetKernel32Address()
{ULONGLONG dwKernel32 = 0;_TEB *pTeb = NtCurrentTeb();PULONGLONG pPeb = (PULONGLONG)*(PULONGLONG)((ULONGLONG)pTeb + 0x60);PULONGLONG pLdr = (PULONGLONG)*(PULONGLONG)((ULONGLONG)pPeb + 0x18);PULONGLONG InLoadOrderModuleList = (PULONGLONG)((ULONGLONG)pLdr + 0x10);PULONGLONG pModuleExe = (PULONGLONG)*InLoadOrderModuleList;PULONGLONG pModuleNtdll = (PULONGLONG)*pModuleExe;PULONGLONG pModuleKernel32 = (PULONGLONG)*pModuleNtdll;dwKernel32 = pModuleKernel32[6];return dwKernel32;
}ULONGLONG GrkGetProcessAddress()
{ULONGLONG dwBase = GetKernel32Address();PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)dwBase;PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + dwBase);PIMAGE_DATA_DIRECTORY pExportDir = pNt->OptionalHeader.DataDirectory;pExportDir = &(pExportDir[IMAGE_DIRECTORY_ENTRY_EXPORT]);DWORD dwOffset = pExportDir->VirtualAddress;PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(dwBase + dwOffset);DWORD dwFuncCount = pExport->NumberOfFunctions;DWORD dwFuncNameCount = pExport->NumberOfNames;DWORD dwModOffset = pExport->Name;PDWORD pEAT = (PDWORD)(dwBase + pExport->AddressOfFunctions);PDWORD pENT = (PDWORD)(dwBase + pExport->AddressOfNames);PWORD pEIT = (PWORD)(dwBase + pExport->AddressOfNameOrdinals);for (size_t i = 0; i < dwFuncCount; i++){if (!pEAT[i]){continue;}DWORD dwOrdinal = pExport->Base + i;ULONGLONG dwFunAddrOffset = pEAT[i];for (size_t index = 0; index < dwFuncNameCount; index++){if (pEIT[index] == i){ULONGLONG dwNameOffset = pENT[index];char * szFuncName = (char *)(((ULONGLONG)dwBase) + dwNameOffset);if (strcmp(szFuncName,"GetProcAddress") == 0){return dwBase + dwFunAddrOffset;}}}}
}EXTERN_C typedef HMODULE
(WINAPI *
fnLoadLibraryA)(_In_ LPCSTR lpLibFileName
);EXTERN_C typedef FARPROC
(WINAPI *
fnGetProcAddress)(_In_ HMODULE hModule,_In_ LPCSTR lpProcName
);EXTERN_C typedef int
(WINAPI *
fnMessageBoxA)(_In_opt_ HWND hWnd,_In_opt_ LPCSTR lpText,_In_opt_ LPCSTR lpCaption,_In_ UINT uType);EXTERN_C typedef VOID
(WINAPI *
fnExitProcess)(_In_ UINT uExitCode
);int main()
{fnGetProcAddress pfnGetProcAddress = (fnGetProcAddress)GrkGetProcessAddress();HMODULE hKernel32 = (HMODULE)GetKernel32Address();fnLoadLibraryA pfnLoadLibraryA = (fnLoadLibraryA)pfnGetProcAddress(hKernel32, "LoadLibraryA");HMODULE hUesr32 = pfnLoadLibraryA("user32.dll");fnMessageBoxA pfnMessageBoxA = (fnMessageBoxA)pfnGetProcAddress(hUesr32, "MessageBoxA");fnExitProcess pfnExitProcess = (fnExitProcess)pfnGetProcAddress(hKernel32, "ExitProcess");pfnMessageBoxA(NULL, "rkvir", "Msg", MB_OK);pfnExitProcess(0);system("pause");return 0;
}
相关文章:
PE结构(十五)系统调用与函数地址动态寻找
双机调试 当需要分析一个程序时,这个程序一定是可以调试的,操作系统也不例外。在调试过程中下断点是很重要的 当我们对一个应用程序下断点时,应用程序是挂起的。但当我们对操作系统的内核程序下断点时,被挂起的不是内核程序而是…...
verilog状态机思想编程流水灯
目录 一、状态机1. 状态机基本概念2. 状态机类型3. Verilog 状态机设计要点 二、状态机实现一个1s流水灯三、DE2-115实物演示 一、状态机 1. 状态机基本概念 状态机(Finite State Machine, FSM)是数字电路设计中用于描述系统状态转换的核心组件&#x…...
Java实现N皇后问题的双路径探索:递归回溯与迭代回溯算法详解
N皇后问题要求在NN的棋盘上放置N个皇后,使得她们无法互相攻击。本文提供递归和循环迭代两种解法,并通过图示解释核心逻辑。 一、算法核心思想 使用回溯法逐行放置皇后,通过冲突检测保证每行、每列、对角线上只有一个皇后。发现无效路径时回退…...
#SVA语法滴水穿石# (000)断言基本概念和背景
一、前言 随着数字电路规模越来越大、设计越来越复杂,使得对设计的功能验证越来越重要。首先,我们要明白为什么要对设计进行验证?验证有什么作用?例如,在用FPGA进行设计时,我们并不能确保设计出来的东西没有功能上的漏洞,因此在设计后我们都会对其进行验证仿真。换句话说…...
【Android Studio 下载 Gradle 失败】
路虽远行则将至,事虽难做则必成 一、事故现场 下载Gradle下载不下来,没有Gradle就无法把项目编译为Android应用。 二、问题分析 观察发现下载时长三分钟,进度条半天没动,说明这个是国外的东西,被墙住了,需…...
贪心算法之Huffman编码
1. 算法推理 Huffman 编码的目标是为给定字符构造一种前缀码,使得整体编码长度最短。基本思想是: 贪心选择:每次选择频率最小的两个节点合并。合并后的节点的权值为两个子节点权值之和,代表这部分子树出现的总频率。 局部最优导…...
Flask学习笔记 - 表单
表单处理 基本表单处理:使用 request.form 获取表单数据。使用 Flask-WTF:结合 WTForms 进行表单处理和验证,简化表单操作。表单验证:使用验证器确保表单数据的有效性。文件上传:处理文件上传和保存文件。CSRF 保护&a…...
指针的补充(用于学习笔记的记录)
1.指针基础知识 1.1 指针变量的定义和使用 指针也是一种数据类型,指针变量也是一种变量 指针变量指向谁,就把谁的地址赋值给指针变量 #include<stdio.h>int main() {int a 0;char b 100;printf("%p,%p \n", &a,&b); // …...
【mongodb】mongodb的字段类型
目录 1. 基本数据类型1.1 String1.2 Number1.3 Boolean1.4 Date1.5 Null1.6 ObjectId1.7 Array1.8 Binary Data1.9 Object 2. 特殊数据类型2.1 Regular Expression2.2 JavaScript2.3 Symbol2.4 Decimal1282.5 Timestamp2.6 MinKey/MaxKey2.7 DBPointer 3. 常用字段类型示例4. 注…...
计算机视觉图像处理基础系列:滤波、边缘检测与形态学操作
计算机视觉图像处理基础系列:滤波、边缘检测与形态学操作 一、前言二、滤波:图像的精细化处理2.1 滤波基础概念2.1.1 滤波的本质2.1.2 图像噪声来源与类型 2.2 线性滤波2.2.1 均值滤波2.2.2 高斯滤波 2.3 非线性滤波2.3.1 中值滤波 三…...
实用的alias别名命令——比2=1+1简单的基础命令
目录 alias命令的用处alias命令的写法让alias别名永久存在的办法下篇预告 alias命令的用处 别名,就是linux系统中的命令的别称,而alias命令,可以显示linux系统当前设定的全部别名,当然,也可以自己定义一个别名。 ali…...
JAVA单例模式
目录 一、什么是单例模式: 二、饿汉模式: 代码示例: 饿汉模式的特点: 三、懒汉模式: 正确代码示例(双重检查锁): 一、什么是单例模式: 一个类,在语法角度…...
k8s安装cri驱动创建storageclass动态类
部署nfs服务器 #所有k8s节点安装nfs客户端 yum install -y nfs-utils mkdir -p /nfs/share echo "/nfs/share *(rw,sync,no_root_squash)" >> /etc/exports systemctl enable --now nfs-serverhelm部署nfs的provisioner&sc 所有k8s节点安装客户端 yu…...
嵌入式Linux驱动—— 1 GPIO配置
目录 1.GPIO操作 1.1 IO命名 1.2 GPIO 时钟使能(CCM) 1.3 IO 复用(IOMUXC) 1.4 IO 配置 1.5 GPIO 配置 1.GPIO操作 GPIO操作主要是以下流程: 使能某组GPIO模块(GPIO1、2、...)&#…...
【C++11】lambda
lambda lambda表达式语法 lambda表达式本质是一个匿名函数对象,跟普通函数不同的是它可以定义在函数内部。lambda表达式语法使用层而言没有类型,所以一般是用auto或者模板参数定义的对象去接收lambda对象。 lambda表达式的格式:[capture-l…...
自旋锁(C++实现)
1 简介 自旋锁是一种典型的无锁算法,在任何时刻,它都最多只能有一个保持者。当有一个线程试图获得一个已经被占用的锁时,该线程就会一直进行循环等待,直到该锁被释放。自旋锁的优点是不会使线程状态发生切换,一直处于用…...
python基础-11-调试程序
文章目录 【README】【11】调试【11.1】抛出异常【11.1.1】抛出异常代码块 【11.2】获取回溯字符串【11.2.1】traceback获取异常回溯信息 【11.3】断言【11.3.1】断言代码示例 【11.4】日志(使用logging模块)【11.4.1】使用logging模块操作日志【11.4.3】…...
我的创作历程:从不情愿到主动分享的成长
🌅主页:猫咪-9527-CSDN博客 “欲穷千里目,更上一层楼。会当凌绝顶,一览众山小。” 目录 二、转变:从被动到主动的心路历程 三、挑战:时间的压力与写作的坚持 四、收获:分享与成长 五、展望…...
uniapp地图导航及后台百度地图回显(v2/v3版本)
百度地图申请地址:控制台 | 百度地图开放平台 效果: 1.后台 1.1申请百度地图APi 1.2 引入百度地图 <script type"text/javascript" src"//api.map.baidu.com/api?v3.0&ak自己百度生气apikey"></script> 1.3 v2组…...
多layout 布局适配
安卓多布局文件适配方案操作流程 以下为通过多套布局文件适配不同屏幕尺寸/密度的详细步骤,结合主流适配策略及最佳实践总结: 一、创建多套布局资源目录 按屏幕尺寸划分 在 res 目录下创建以下文件夹(根据设备特性自动匹配ÿ…...
马斯克 AI 超算
超算建设情况:马斯克旗下人工智能初创公司 xAI 正在田纳西州孟菲斯市建造世界上最大的超级计算机2。自 2024 年 6 月首次宣布这笔工程以来,xAI 已向当地规划和发展机构提交了 14 份施工许可申请,合计代表了 4.059 亿美元的预计项目成本2。该超…...
大模型学习四:DeepSeek Janus-Pro 多模态理解和生成模型 本地部署指南(折腾版)
一、说明简介 DeepSeek Janus-Pro是一款先进的多模态理解和生成模型,旨在实现高质量的文本-图像生成与多模态理解。它是由DeepSeek团队研发的,是之前Janus模型的升级版,能够同时处理文本和图像,即可以理解图片内容,…...
《AI大模型应知应会100篇》第3篇:大模型的能力边界:它能做什么,不能做什么
第3篇:大模型的能力边界:它能做什么,不能做什么 摘要 在人工智能飞速发展的今天,大语言模型(LLM)已经成为许多领域的核心技术。然而,尽管它们展现出了惊人的能力,但也有明显的局限性…...
MySQL 面试知识点详解(索引、存储引擎、事务与隔离级别、MVCC、锁机制、优化)
一、索引基础概念 1 索引是什么? 定义:索引是帮助MySQL高效获取数据的有序数据结构,类似书籍的目录。核心作用:减少磁盘I/O次数,提升查询速度(以空间换时间)。 2 索引的优缺点 优点缺点加速…...
JS API
const变量优先 即对象、数组等引用类型数据可以用const声明 API作用和分类 DOM (ducument object model) 操作网页内容即HTML标签的 树状模型 HTML中标签 JS中对象 最大对象 document 其次大 html 以此类推 获取DOM对象 CSS 中 使用选择器 JS 中 选多个 时代的眼泪 修…...
hackmyvm-Principle
近况: 很难受、 也很累。 但是庆幸靶机很好 正值清明时节 清明时节雨纷纷 🌧️,路上行人欲断魂 😢。 靶机地址 信息收集 主机发现 端口扫描 80端口仅仅是一个nginx 的欢迎界面而已 robots.txt的内容 hi.html的内容 hackme不存在 investigat…...
小刚说C语言刷题——第14讲 逻辑运算符
当我们需要将一个表达式取反,或者要判断两个表达式组成的大的表达式的结果时,要用到逻辑运算符。 1.逻辑运算符的分类 (1)逻辑非(!) !a,当a为真时,!a为假。当a为假时,!a为真。 例…...
池化技术的深度解析与实践指南【大模型总结】
池化技术的深度解析与实践指南 池化技术作为计算机系统中的核心优化手段,通过资源复用和预分配机制显著提升系统性能。本文将从原理、实现到最佳实践,全方位剖析池化技术的核心要点,并结合实际案例说明其应用场景与调优策略。 一、池化技术的…...
基于Java的区域化智慧养老系统(源码+lw+部署文档+讲解),源码可白嫖!
摘 要 时代在飞速进步,每个行业都在努力发展现在先进技术,通过这些先进的技术来提高自己的水平和优势,区域化智慧养老系统当然不能排除在外。区域化智慧养老系统是在实际应用和软件工程的开发原理之上,运用Java语言、JSP技术以及…...
2025年3月 Scratch 图形化(一级)真题解析 中国电子学会全国青少年软件编程等级考试
2025.03 Scratch图形化编程等级考试一级真题试卷 一、选择题 第 1 题 气球初始位置如下图所示,scratch运行下列程序,气球会朝哪个方向移动?( ) A.水平向右 B.垂直向下 C.水平向左 D.垂直向上 答案:…...
Docker 命令简写配置
alias dpsdocker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" 配置好后,需要输入: source ~/.bashrc 后生效...
linux signal up/down/down_interruptiable\down_uninterruptiable使用
在Linux内核中,down, down_interruptible, down_killable, 和 up 是用于操作信号量(semap hores)的函数,它们用于进程同步和互斥。以下是对这些函数的简要说明。 1,down(&sem): 这个函数用于获取信号量。如果信号…...
【嵌入式-stm32电位器控制以及旋转编码器控制LED亮暗】
嵌入式-stm32电位器控制LED亮暗 任务1代码1Key.cKey.hTimer.cTimer.hPWM.cPWM.hmain.c 实验现象1任务2代码2Key.cKey.hmain.c 实验现象2问题与解决总结 源码框架取自江协科技,在此基础上做扩展开发。 任务1 本文主要介绍利用stm32f103C8T6实现电位器控制PWM的占空比…...
Mysql 中 ACID 背后的原理
在 MySQL 中,ACID 是事务处理的核心原则,用于保证数据库在执行事务时的可靠性、数据一致性和稳定性。ACID 是四个关键特性的首字母缩写,分别是:Atomicity(原子性)、Consistency(一致性ÿ…...
【算法】简单数论
模运算 a m o d b a − ⌊ a / b ⌋ b a\ mod \ b a - \lfloor a / b \rfloor \times b a mod ba−⌊a/b⌋b n m o d p n \ mod\ p n mod p得到的结果的正负至于被除数 n n n有关 模运算的性质: ( a b ) m o d m ( ( a m o d m ) ( b m o d m ) ) m o d m …...
mybatis慢sql无所遁形
痛点问题: 扫描项目的慢sql 并提出优化建议 开源项目地址:gitee:mybatis-sql-optimizer-spring-boot-starter: 这个starter可以帮助开发者在开发阶段发现SQL性能问题,并提供优化建议,从而提高应用程序的数据库访问效…...
MCP有哪些比较好的资源?
MCP(Model Context Protocol)是一种由Anthropic公司推出的开放协议,旨在为AI模型与开发环境之间提供统一的上下文交互接口。目前,围绕MCP协议的资源非常丰富,以下是一些比较好的MCP资源推荐: Smithery Smit…...
Nginx功能及应用全解:从负载均衡到反向代理的全面剖析
Nginx作为一款开源的高性能HTTP服务器和反向代理服务器,凭借其高效的资源利用率和灵活的配置方式,已成为互联网领域中最受欢迎的Web服务器之一。无论是作为HTTP服务器、负载均衡器,还是作为反向代理和缓存服务器,Nginx的多种功能广…...
FreeRTOS/任务创建和删除的API函数
任务的创建和删除本质就是调用FreeRTOS的API函数 API函数描述xTaskCreate()动态方式创建任务xTaskCreateStatic()静态方式创建任务vTaskDelete()删除任务 动态创建任务 任务的任务控制块以及任务的占空间所需的内存,均由FreeRTOS从FreeRTOS管理的堆中分配 静态创建…...
【jvm】GC评估指标
目录 1. 说明2. 吞吐量(Throughput)3. 暂停时间(Pause Time)4. 内存占用(Footprint)5. 频率(Frequency)6. 对象晋升率(Promotion Rate)7. 内存分配速率&#…...
数据集(Dataset)和数据加载器(DataLoader)-pytroch学习3
pytorch网站学习 处理数据样本的代码往往会变得很乱、难以维护;理想情况下,我们希望把数据部分的代码和模型训练部分分开写,这样更容易阅读、也更好维护。 简单说:数据和模型最好“分工明确”,不要写在一起。 PyTor…...
影响RTOS实时性的因素有哪些?
目录 1、任务调度延迟 2、中断处理延迟 3、系统负载 4、任务优先级反转 5、时钟精度 6、内存管理 影响RTOS实时性的因素主要包括任务调度延迟、中断处理延迟、系统负载、任务优先级反转、时钟精度、内存管理等。 1、任务调度延迟 任务调度器是RTOS的核心,当…...
二叉树 递归
本篇基于b站灵茶山艾府的课上例题与课后作业。 104. 二叉树的最大深度 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出&…...
ZLMediaKit 源码分析——[5] ZLToolKit 中EventPoller之延时任务处理
系列文章目录 第一篇 基于SRS 的 WebRTC 环境搭建 第二篇 基于SRS 实现RTSP接入与WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建 第四篇 WebRTC学习一:获取音频和视频设备 第五篇 WebRTC学习二:WebRTC音视频数据采集 第六篇 WebRTC学习三…...
【51单片机】2-6【I/O口】电动车简易防盗报警器实现
1.硬件 51最小系统继电器模块震动传感器模块433M无线收发模块 2.软件 #include "reg52.h" #include<intrins.h> #define J_ON 1 #define J_OFF 0sbit switcher P1^0;//继电器 sbit D0_ON P1^1;//433M无线收发模块 sbit D1_OFF P1^2; sbit vibrate …...
windows下载安装远程桌面工具RealVNC-Server教程(RealVNC_E4_6_1版带注册码)
文章目录 前言一、下载安装包二、安装步骤三、使用VNC-Viewer客户端远程连接,输入ip地址,密码完成连接 前言 在现代工作和生活中,远程控制软件为我们带来了极大的便利。RealVNC - Server 是一款功能强大的远程控制服务器软件,通过…...
C语言的操作系统
C语言的操作系统 引言 操作系统是一种系统软件,它管理计算机硬件和软件资源,并为计算机程序提供公共服务。在现代计算机科学中,操作系统是不可或缺的组成部分,而C语言则是实现高效操作系统的主要编程语言之一。本文将探讨C语言在…...
selectdb修改表副本
如果想修改doris(也就是selectdb数据库)表的副本数需要首先确定是否分区表,当前没有数据字典得知哪个表是分区的,只能先show partitions看结果 首先,副本数不应该大于be节点数 其次,修改期间最好不要跑业务…...
leetcode数组-有序数组的平方
题目 题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/ 给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。 输入:nums [-4,-1,0,3,10] 输出ÿ…...
【python中级】关于Cython 的源代码pyx的说明
【python中级】关于Cython 的源代码pyx的说明 1.背景2.编译3.语法1.背景 Cython 是一个编程语言和工具链,用于将 Python 代码(或类 Python 的代码)编译成 C 语言,再进一步生成高性能的 Python 扩展模块(.so 或 .pyd 文件)。 在 Python 中,.pyx 文件是 Cython 的源代码文…...