53.网游逆向分析与插件开发-游戏反调试功能的实现-通过内核信息检测调试器

码云地址(master分支):https://gitee.com/dye_your_fingers/sro_-ex.git

码云版本号:b44fddef016fc1587eda40ca7f112f02a8289504

代码下载地址,在 SRO_EX 目录下,文件名为:SRO_Ex-通过内核信息检测调试器.zip

链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg

提取码:q9n5

--来自百度网盘超级会员V4的分享

HOOK引擎,文件名为:黑兔sdk.zip

链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw

提取码:78h8

--来自百度网盘超级会员V4的分享

以 检测调试器-CSDN博客 它的代码为基础进行修改

BeingDebugged的调试检测基本上用处不大,OD很多插件可以过掉,它核心根本的问题就是数据毕竟是在用户态(软件调试器设计的基本原理-CSDN博客通过它软件调试器设计的基本原理-CSDN博客里面写的peb的位置,然后通过汇编对它BeingDebugged这个字段进行修改成0就可以轻松破解,就一次性把 IsDebuggerPresent函数、CheckRemoteDebuggerPresent函数 这两个函数全部都过掉了),现在为了加强检测要去访问内核的数据,原则上用户态取不到内核的数据,好在微软还是留了口子,一个未公开的API(导出表里有文档里没有这样的函数就叫做未公开的API,ntdll文件里有很多未公开API),如图1。

图1:其中信息类型是一个枚举非常大,在不同操作系统下有不同的变化,我们要用的到它的值是0x07 DebugPort、0x1 EDebugObjectHandle、0x1F DebugFlags(它的值是0表示被调试,1表示未被调试),这样一般的调试器就躲不掉了,NtQueryInformationProcess能取很多内核中的数据,使用详情看下方代码

9a060b31a72f4731a6615cb31acb286b.png

24a825db3b8249d0b8332f7d77426146.jpg

 

GameEx.cpp文件的修改,修改了ExitGame函数

#include "pch.h"
#include "GameEx.h"
#include "htdHook2.h"
#include "GameProtect.h"extern int client;
extern GameProtect* _protect;
extern unsigned _stdcall GetFunctionAddress(int index);
htd::hook::htdHook2 hooker;#include <windows.h>
#include<stdio.h>
#include<TlHelp32.h>/**声明要拦截的函数地址
*/
auto h = GetModuleHandle(NULL);
DWORD address = (DWORD)h;
DWORD addRExit = address + 0x88C77E;size_t 被拦截修改的函数的地址 = (size_t)addRExit;LONG NTAPI 异常回调(struct _EXCEPTION_POINTERS* Excep)
{printf("异常回调1\n");/**判断出异常的地方是否为 我们修改的地方*/if ((size_t)Excep->ExceptionRecord->ExceptionAddress == 被拦截修改的函数的地址) {//const char* szStr = "nei Rong Bei Xiu Gai";//*(DWORD*)(Excep->ContextRecord->Esp + 0x8) = (DWORD)szStr;//szStr = "biao Ti Bei Xiu Gai";//*(DWORD*)(Excep->ContextRecord->Esp + 0xC) = (DWORD)szStr;AfxMessageBox(L"游戏退出!");DWORD* _esp = (DWORD*)Excep->ContextRecord->Esp;DWORD _val = _esp[1];if (_val == 0x1035D0C) {AfxMessageBox(L"游戏退出2!");auto hMuls = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"system_seamp");if (hMuls) ReleaseSemaphore(hMuls, 1, 0);ExitProcess(0);}Excep->ContextRecord->Eip = *(DWORD *) Excep->ContextRecord->Esp;Excep->ContextRecord->Esp += 8;return EXCEPTION_CONTINUE_EXECUTION;}else {/**防止被其它地方修改了函数地址*/Excep->ContextRecord->Dr0 = 被拦截修改的函数的地址;Excep->ContextRecord->Dr7 = 0x405;return EXCEPTION_CONTINUE_SEARCH;}}VOID 设置线程的dr寄存器(HANDLE 线程句柄) {printf("设置线程的dr寄存器1\n");CONTEXT ctx;ctx.ContextFlags = CONTEXT_ALL;GetThreadContext(线程句柄, &ctx);ctx.Dr0 = 被拦截修改的函数的地址;ctx.Dr7 = 0x1;SetThreadContext(线程句柄, &ctx);printf("设置线程的dr寄存器2\n");
}VOID 使用dr寄存器拦截修改函数() {printf("使用dr寄存器拦截修改函数1\n");HANDLE 线程快照句柄 = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId());if (线程快照句柄 == INVALID_HANDLE_VALUE) {printf("线程快照创建失败");return;}THREADENTRY32* 线程结构体 = new THREADENTRY32;线程结构体->dwSize = sizeof(THREADENTRY32);/**Thread32First获取快照中第一个线程返回值bool类型*/// Thread32First(线程快照句柄, &线程结构体);HANDLE 线程句柄 = NULL;printf("使用dr寄存器拦截修改函数2\n");/**Thread32Next获取线程快照中下一个线程*/while (Thread32Next(线程快照句柄, 线程结构体)){if (线程结构体->th32OwnerProcessID == GetCurrentProcessId()) {printf("使用dr寄存器拦截修改函数3\n");线程句柄 = OpenThread(THREAD_ALL_ACCESS, FALSE, 线程结构体->th32ThreadID);printf("使用dr寄存器拦截修改函数4\n");设置线程的dr寄存器(线程句柄);printf("使用dr寄存器拦截修改函数5\n");CloseHandle(线程句柄);}}
}bool ExitGame(HOOKREFS2) {if (_protect->CheckDebugByNT())AfxMessageBox(L"检测到了DEBUG程序的存在");// AfxMessageBox(L"游戏退出2222!");DWORD* _esp = (DWORD*)_ESP;DWORD _val = _esp[1];if (_val == 0x1035D0C) {// AfxMessageBox(L"游戏退出!");auto hMuls = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"system_seamp");if (hMuls) ReleaseSemaphore(hMuls, 1, 0);client--;ExitProcess(0);}return true;
}GameEx::GameEx()
{// AfxMessageBox(L"注册hook!");// auto h = GetModuleHandle(NULL);// DWORD address = (DWORD)h;// DWORD* addRExit = (DWORD*)(address + 0x88C77E);/**addRExit = 0;*/// CString txt;// txt.Format(L"addRExit[0]D:%d,addRExit[0]X:%X,addRExit:%X", addRExit[0], addRExit[0], addRExit);// AfxMessageBox(txt);// hooker.SetHook((LPVOID)addRExit, 3, ExitGame);//AddVectoredExceptionHandler(1, 异常回调);//设置线程的dr寄存器(GetCurrentThread());
}void GameEx::InitInterface()
{unsigned addr =  GetFunctionAddress(0);hooker.SetHook((LPVOID)(addr + 0x30 - 2), 0x3, ExitGame);hooker.SetHook((LPVOID)(addr + 0x51 - 2), 0x3, ExitGame);}

GameProtect.h文件的修改,新加 ZwSetInformationThread变量、NtQueryInformationProcess变量、hNtdll变量、HProcess变量、InitApiEx函数、CheckDebugByPEB函数、CheckDebugByNT函数,ZwSetInformationThreadPtr函数指针、NtQueryInformationProcessPtr函数指针

#pragma once/*第一个参数是线程的id第二个参数是给一个0x11,0x11就代表把线程设置成隐匿的状态*/
typedef NTSTATUS(NTAPI* ZwSetInformationThreadPtr)(DWORD, DWORD, DWORD, DWORD);
typedef NTSTATUS(NTAPI* NtQueryInformationProcessPtr)(HANDLE, DWORD, PVOID, ULONG, PULONG);typedef struct CODEContext {unsigned start;bool hide;unsigned short r_count; // 重定位信息,call、jmp这样的需要重定位的数据的个数unsigned short len; // 代码的长度
}*PCODEContext;typedef struct HIDE_CODE {unsigned Start;unsigned Index;
}*PHIDE_CODE;class GameProtect
{
public:unsigned GetAddress(int index);unsigned GetAddressHide(unsigned _eip);GameProtect();
private:int _HideCount = 0;PHIDE_CODE _HideCode;LPVOID* _EntryCode;int _CodeCount{};char _EntryCodeEx[8]{(char)0xE8, (char)0x00, (char)0x00,(char)0x00, (char)0x00, (char)0xFF, (char)0xE0};bool MulCheckBySempore();
public:void  CheckMult(); // 检测有没有多开
public:bool InitEntryCode(); // 释放保护代码数据BOOL CheckDebugByPEB(); // true表示存在debugBOOL CheckDebugByNT(); // true表示存在debug
private:void InitApiEx();HMODULE hNtdll;ZwSetInformationThreadPtr ZwSetInformationThread;NtQueryInformationProcessPtr NtQueryInformationProcess;void AntiDebug();HANDLE HProcess;
};

GameProtect.cpp文件的修改,修改了AntiDebug函数、GameProtect函数,新加 InitApiEx函数、CheckDebugByPEB函数、CheckDebugByNT函数,删除了 ZwSetInformationThreadPtr函数指针

#include "pch.h"
#include "GameProtect.h"GameProtect* _protect;
extern int client;unsigned _stdcall GetFunctionAddress(int index) {//CString txt;//txt.Format(L"接收到:%d", index);//AfxMessageBox(txt);return _protect->GetAddress(index);
}unsigned GameProtect::GetAddress(int index)
{//CString txt;unsigned result = (unsigned)this->_EntryCode[index];//txt.Format(L"index:%d获取地址:%x", index, result);// AfxMessageBox(txt);return result;
}unsigned GameProtect::GetAddressHide(unsigned _eip)
{//CString txt;for (int i = 0; i < _HideCount; i++){if (_HideCode[i].Start == _eip) {return (unsigned)_EntryCode[_HideCode[i].Index];}}//txt.Format(L"index:%d获取地址:%x", index, result);// AfxMessageBox(txt);return 0;
}GameProtect::GameProtect()
{//AfxMessageBox(L"122222");InitApiEx();_protect = this;// 为了后续内容 这里先注释掉// AntiDebug();if (!InitEntryCode()) {AfxMessageBox(L"程序加载失败!");ExitProcess(0);}CString txt;txt.Format(L"111");AfxMessageBox(txt);
}bool GameProtect::MulCheckBySempore()
{auto hMuls = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, L"system_seamp");if (!hMuls) {hMuls = CreateSemaphore(0, 3, 3, L"system_seamp");}if (WaitForSingleObject(hMuls, 0) == WAIT_TIMEOUT) return true;return false;
}void GameProtect::CheckMult()
{if (MulCheckBySempore()) {AfxMessageBox(L"当前客户端启动已经超过最大数量");ExitProcess(0);}
}LONG _stdcall PVEHandl(PEXCEPTION_POINTERS val) {if (val->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) {unsigned _eip = val->ContextRecord->Eip;unsigned _eipReal = _protect->GetAddressHide(_eip);/*	CString txt;txt.Format(L"PVEHandl当前地址:%X", _eipReal);AfxMessageBox(txt);*/if (_eipReal) {val->ContextRecord->Eip = _eipReal;return EXCEPTION_CONTINUE_EXECUTION; // 继续执行}else return EXCEPTION_CONTINUE_SEARCH;}return EXCEPTION_CONTINUE_SEARCH;
}bool GameProtect::InitEntryCode()
{TCHAR FileModule[0x100];GetModuleFileName(NULL, FileModule, 0x100);auto hFile = CreateFile(FileModule, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile == INVALID_HANDLE_VALUE) {return false;}DWORD dRead;DWORD filelen = GetFileSize(hFile, &dRead);char* _data = new char[filelen];if (ReadFile(hFile, _data, filelen, &dRead, NULL)) {char* _dataBegin = _data;unsigned* _uRead = (unsigned*)(_data + filelen - 4);for (int i = 0; i < filelen - _uRead[0]-4; i++) // 解密数据{_data[_uRead[0] + i] = _data[_uRead[0] + i] ^ 0x23;}//unsigned* _uRead = (unsigned*)_data[filelen - 4];filelen = _uRead[0];// 真实的文件大小_uRead = (unsigned*)(_data + filelen);unsigned code_count = _uRead[0];_data = _data + filelen + sizeof(code_count);PCODEContext _ContextArrys = (PCODEContext)_data;for (int i = 0; i < code_count; i++){if (_ContextArrys[i].hide) {_HideCount++;}}if (_HideCount > 0) {AddVectoredExceptionHandler(1, PVEHandl);_HideCode = new HIDE_CODE[_HideCount];_HideCount = 0;}_data = _data + sizeof(CODEContext) * code_count;_EntryCode = new LPVOID[code_count];for (int i = 0; i < code_count; i++){char* _tmpByte = new char[_ContextArrys[i].len + 2];_EntryCode[i] = _tmpByte;_tmpByte[0] = 0x9D;_tmpByte[1] = 0x61;/*CString txt;txt.Format(L"当前地址:%X", _EntryCode[i]);AfxMessageBox(txt);*/unsigned offset = sizeof(_ContextArrys[i].r_count) * _ContextArrys[i].r_count;memcpy((char*)_EntryCode[i] + 2, _data + offset, _ContextArrys[i].len);unsigned short* rel = (unsigned short*)_data;for (int x = 0; x < _ContextArrys[i].r_count; x++){unsigned* _callAddr = (unsigned*)((char*)_EntryCode[i] + rel[x] + 1 + 2);_callAddr[0] = _callAddr[0] - (unsigned)_callAddr - 4;// AfxMessageBox(L"这里代码存在问题,后面改");}_data = _data + offset + _ContextArrys[i].len;DWORD dOld;VirtualProtect(_EntryCode[i], _ContextArrys[i].len, PAGE_EXECUTE_READWRITE, &dOld);if (_ContextArrys[i].hide) {_EntryCode[i] = (LPVOID)((unsigned)_EntryCode[i] + 2);_HideCode[_HideCount].Index = i;_HideCode[_HideCount].Start = _ContextArrys[i].start;_HideCount++;}}delete[]_dataBegin;}else return false;auto hMod = GetModuleHandle(NULL);unsigned addMod = (unsigned)hMod;unsigned addReset = addMod + 0xC2EFFC;DWORD dOld = GetFunctionAddress(0);// ::VirtualProtect((LPVOID)addReset, 4, PAGE_EXECUTE_READWRITE, &dOld);// ::VirtualProtect(this->_GameCode, 0x1000, PAGE_EXECUTE_READWRITE, &dOld);unsigned* read = (unsigned*)addReset;read[0] = (unsigned)this->_EntryCodeEx;//_EntryCode[1] = GetFunctionAddress;read = (unsigned*)(this->_EntryCodeEx + 1);read[0] = (unsigned)GetFunctionAddress - 5 - (unsigned)(this->_EntryCodeEx);return true;
}/**下方的代码不猥琐因为用了 ZwSetInformationThread、NtQueryInformationProcess 这样的常量字符串然后可以在 ZwSetInformationThread、NtQueryInformationProcess 做HOOK,拦截我们这样我们可以把 ZwSetInformationThread、NtQueryInformationProcess 函数拷贝到我们的内存空间里去调用不再通过 GetProcAddress 方式去获取函数地址,直接通过我们复制到的地址调用它,最终这俩函数会去内核,我们也可以把进内核的逻辑自己实现,这样就让别人完全搞不定了
*/
void GameProtect::InitApiEx()
{hNtdll = LoadLibrary(L"ntdll.dll");if (hNtdll) {/**GetProcAddress通过导出表获取函数*/ZwSetInformationThread = (ZwSetInformationThreadPtr)GetProcAddress(hNtdll, "ZwSetInformationThread");NtQueryInformationProcess = (NtQueryInformationProcessPtr)GetProcAddress(hNtdll, "NtQueryInformationProcess");}HProcess = GetCurrentProcess();
}void GameProtect::AntiDebug()
{/**这个函数在ntdll..dll里这个位置真正使用时不能这样写,因为这样写了之后,会被人看出来最好的方式是通过启动器计算好传递过来,传递过来就是悄无声息了相当于调用了一个函数,但破解者不知道,调用函数还可以猥琐点把它拷贝到我们的内存空间里调用。*/if (ZwSetInformationThread) {ZwSetInformationThread((DWORD)GetCurrentThread(), 0x11, 0x0, 0x0);}}BOOL GameProtect::CheckDebugByPEB()
{/**IsDebuggerPresent 检测当前进程CheckRemoteDebuggerPresent 检测指定进程它俩检测的都是peb结构有的调试器会把它们给处理掉,比如OD,它有插件会把这个东西修复掉修复掉之后就检测不到了,它修复的原理就是把 BeingDebugged 这个字段给处理了就是说有调试器 BeingDebugged它的值是1,然后我再给BeingDebugged写成0就行了*/BOOL bResult = IsDebuggerPresent();if (bResult) {return bResult;}CheckRemoteDebuggerPresent(GetCurrentProcess(), &bResult);if (bResult) {AfxMessageBox(L"CheckRemoteDebuggerPresent 检测到调试器");bResult = TRUE;}return bResult;
}BOOL GameProtect::CheckDebugByNT()
{// DWORD debug_port = 0;//NtQueryInformationProcess(HProcess, 0x07, &debug_port, sizeof(debug_port), 0x0);//if (debug_port ) {//	return TRUE;//}// 在64位下这个Object是一个HANDLE结构HANDLE debug_object = 0;//NtQueryInformationProcess(HProcess, 0x1E, &debug_object, sizeof(debug_object), 0x0);//if (debug_object) {//	return TRUE;//}BOOL debug_flags = 0;NtQueryInformationProcess(HProcess, 0x1F, &debug_flags, sizeof(debug_flags), 0x0);if (!debug_flags) {return TRUE;}return FALSE;
}

 

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

取出一个时间序列中每一个元素里的日期Series.dt.date()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 取出一个时间序列中 每一个元素里的年月日 Series.dt.date [太阳]选择题 以下代码的输出结果中正确的是? import pandas as pd t pd.Series(pd.date_range("2023-12-28", periods4…

Java企业电子招投标系统源代码,支持二次开发,采用Spring cloud框架

在数字化采购领域&#xff0c;企业需要一个高效、透明和规范的管理系统。通过采用Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;我们打造了全过程数字化采购管理平台。该平台具备内外协同的能力&#xff0c;通过待办消息、招标公告、中标公告和信息发布等功能模块…

饥荒Mod 开发(二四):制作一把万能工具

饥荒Mod 开发(二三)&#xff1a;显示物品栏详细信息 饥荒Mod 开发(二五)&#xff1a;常用组件 总结 源码 饥荒中的每种工具都有独特的功能&#xff0c;比如 斧头用来砍树&#xff0c; 铲子用来 挖东西&#xff0c;鹤嘴锄用来挖矿&#xff0c; 锤子可以敲碎东西&#xff0c;所以…

2013年第二届数学建模国际赛小美赛A题数学与经济灾难解题全过程文档及程序

2013年第二届数学建模国际赛小美赛 A题 数学与经济灾难 原题再现&#xff1a; 2008年的市场崩盘使世界陷入经济衰退&#xff0c;目前世界经济仍处于低迷状态&#xff0c;其原因是多方面的。其中之一是数学。   当然&#xff0c;并非只有金融界依赖于并非总是可靠的数学模型…

postman使用-03发送请求

文章目录 请求1.新建请求2.选择请求方式3.填写请求URL4.填写请求参数get请求参数在params中填写&#xff08;填完后在url中会自动显示&#xff09;post请求参数在body中填写&#xff0c;根据接口文档请求头里面的content-type选择body中的数据类型post请求参数为json-选择raw-选…

Flask 与微信小程序对接

Flask 与微信小程序的对接 在 web/controllers/api中增建py文件&#xff0c;主要是给微信小程序使用的。 web/controllers/init.py # -*- coding: utf-8 -*- from flask import Blueprint route_api Blueprint( api_page,__name__ )route_api.route("/") def ind…

软件测试/测试开发丨Pytest测试用例生命周期管理-Fixture

1、Fixture 用法 Fixture 特点及优势 1&#xff64;命令灵活&#xff1a;对于 setup,teardown,可以不起这两个名字2&#xff64;数据共享&#xff1a;在 conftest.py 配置⾥写⽅法可以实现数据共享&#xff0c;不需要 import 导⼊。可以跨⽂件共享3&#xff64;scope 的层次及…

Linux内核中断

Linux内核中断 ARM里当按下按键的时候&#xff0c;他首先会执行汇编文件start.s里面的异常向量表里面的irq,在irq里面进行一些操作。 再跳转到C的do_irq(); 进行操作&#xff1a;1&#xff09;判断中断的序号&#xff1b;2&#xff09;处理中断&#xff1b;3&#xff09;清除中…

2024美赛数学建模思路A题B题C题D题E题F题思路汇总 选题分析

文章目录 1 赛题思路2 美赛比赛日期和时间3 赛题类型4 美赛常见数模问题5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 美赛比赛日期和时间 比赛开始时间&#xff1a;北京时间2024年2月2日&#xff08;周五&#xff…

【JavaScript】new原理解析

✨ 专栏介绍 在现代Web开发中&#xff0c;JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性&#xff0c;还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言&#xff0c;JavaScript具有广泛的应用场景&#x…

netty源码:(40)ReplayingDecoder

ReplayingDecoder是ByteToMessageDecoder的子类&#xff0c;我们继承这个类时&#xff0c;也要实现decode方法&#xff0c;示例如下&#xff1a; package cn.edu.tju;import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handle…

Ubuntu20.04服务器使用教程(安装教程、常用命令、故障排查)持续更新中.....

安装教程&#xff08;系统、驱动、CUDA、CUDNN、Pytorch、Timeshift、ToDesk&#xff09; 制作U盘启动盘&#xff0c;并安装系统 在MSDN i tell you下载Ubuntu20.04 Desktop 版本&#xff0c;并使用Rufus制作UEFI启动盘&#xff0c;参考UEFI安装Ubuntu使用GPTUEFI模式安装&am…

【IoT网络层】STM32 + ESP8266 +MQTT + 阿里云物联网平台 |开源,附资料|

目标&#xff1a;实现STM32连接阿里云物联网平台发送数据同时接收数据&#xff0c;IOT studio界面显示数据。具体来说&#xff1a;使用ESP8266 ESP-01来连接网络&#xff0c;获取设备数据发送到阿里云物联网平台并显示且oled显示屏当前的设备数据&#xff0c;通过IOT studio界面…

OpenHarmony城市技术论坛武汉站:探索大模型时代的终端操作系统创新

2023年12月23日下午,OpenHarmony城市技术论坛(以下简称“技术论坛”)——第6期(武汉站)于华中科技大学梧桐语问学中心明德报告厅圆满举办。本次技术论坛聚焦“大模型时代的系统软件”,旨在探索AI大模型在终端操作系统领域的创新趋势和挑战。论坛从“终端操作系统十大技术挑战”…

最适合学生用的台灯有哪些?分享高口碑的学生护眼台灯

台灯是我们日常比较实用的一盏桌面照明灯具&#xff0c;不管是休闲看书、学习、办公都会用得上。如果使用了一款光源不好的台灯&#xff0c;时间长了可能就会影响我们的眼睛健康&#xff0c;特别是孩子的眼睛&#xff0c;还没有发育完全&#xff0c;影响更大。因此孩子学习的台…

模式识别与机器学习-SVM(带软间隔的支持向量机)

SVM&#xff08;带软间隔的支持向量机&#xff09; 软间隔思想的由来软间隔的引入 谨以此博客作为复习期间的记录。 软间隔思想的由来 在上一篇博客中&#xff0c;回顾了线性可分的支持向量机,但在实际情况中&#xff0c;很少有完全线性可分的情况&#xff0c;大部分线性可分…

MYSQL高级SQL语句

目录 一、环境准备 二、高级SQL语句 三、通配符&#xff08;通常通配符都是跟 LIKE 一起使用的&#xff09; 四、函数 一、环境准备 create database kgc; use kgc; create table location (Region char(20),Store_Name char(20)); insert into location values(East,Bost…

【算法与数据结构】860、LeetCode柠檬水找零

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题的思路比较简单&#xff0c;首先要保存收到的零钱&#xff0c;其次计算找零&#xff0c;最后分解找…

前缀和——OJ题(二)

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、和为 k 的子数组1、题目讲解2、思路讲解3、代码实现 二、和可被 K 整除的⼦数组1、题目讲…

【Pytorch】学习记录分享9——PyTorch新闻数据集文本分类任务实战

【Pytorch】学习记录分享9——PyTorch新闻数据集文本分类任务 1. 认为主流程code2. NLP 对话和预测基本均属于分类任务详细见3. Tensorborad 1. 认为主流程code import time import torch import numpy as np from train_eval import train, init_network from importlib impo…