Windows 进程权限浅谈 -- 提权 / 降权

       在 Windows 上,用户对权限并不敏感,可能最为直观的是 UAC ,但相信很多人已经关掉了它的提示。

        

        但其实安全性早已深入了 Windows 的方方面面。Windows Vista 引入了一个称为强制完整性控制(Mandatory Integrity Controls,MIC)的新安全结构,类似于 Linux/Unix 中可用的完整性功能。在 Windows Vista 以及后续版本如Windows 11/10和Windows 8/7中,所有安全主体(用户、计算机、服务等)和对象(文件、注册表键、文件夹和资源)都被赋予MIC标签。

权限由高到低分别为Low、Medium、High、System。

如多登录用户是管理员账户,且开启了UAC,那么默认情况下双击一个程序时是以medium权限运行,称为受限的管理员权限,如果右键程序“以管理员权限运行”,那么程序是high权限,称为不受限的管理员权限。Low权限很少见,浏览器的某些进程就是Low权限的。Windows服务一般是System权限。

        

创建进程

        当用户尝试启动可执行文件时,会使用最低用户完整性级别和文件完整性级别创建新进程。 这意味着新进程永远不会以比可执行文件更高的完整性执行。 如果管理员用户执行低完整性程序,则新进程的令牌会以低完整性级别运行。 

        简单来说,进程启动的子进程,默认情况下权限只会等于或小于其父进程。

        如何以编程方式控制进程的执行级别?当用户启动应用程序时,其提升级别由其清单中 requestedExecutionLevel 属性的值确定,Windows 的用户帐户控制 (UAC) 会根据它采取适当的操作(例如,在需要时显示提升提示等)。但是,如果应用程序需要启动与应用程序本身执行级别不同的新进程,该怎么办?

获取当前进程执行级别

         通过 GetTokenInformation 即可获取 TOKEN_ELEVATION_TYPE。

	HANDLE hToken = NULL;
	TOKEN_ELEVATION_TYPE  tet_{};

	if (::OpenProcessToken(
		::GetCurrentProcess(),
		TOKEN_QUERY,
		&hToken))
	{

		DWORD dwReturnLength = 0;

		if (::GetTokenInformation(
			hToken,
			TokenElevationType,
			&tet_,
			sizeof(*ptet),
			&dwReturnLength)) {
			//
		}
	}

	::CloseHandle(hToken);

TOKEN_ELEVATION_TYPE  的取值分别是:

TokenElevationTypeDefault        The token does not have a linked token.        

UAC 已禁用,或者进程由标准用户(不是 Administrators 组的成员)启动。

TokenElevationTypeFull          The token is an elevated token.

 进程正在提升运行。

TokenElevationTypeLimited        The token is a limited token.

进程未提升运行。

仅当 UAC 都已启用且用户是管理员组的成员(即用户具有“拆分”令牌)时,才能返回最后两个值。

提权

        有的时候我们需要子进程以较高的权限执行以完成其功能。于是,我们需要提升子进程的权限。

        以产品更新为例,大部分时候产品主程序以在标准(非提升)级别运行,为了能够自我更新,它需要启动一个单独的更新进程,该更新进程需要提升才能正确执行升级。在这种情况下,非提升进程需要启动新的提升进程,则需要提权。

       

提升到管理员权限

  • ShellExecute

       很简单,通过 ShellExecute ,将 lpOperation 参数设置为 "runas" 即可

HINSTANCE hRet = ::ShellExecute(NULL, L"runas", pszFileName, NULL, NULL, SW_SHOWNORMAL);
if (32 < (DWORD)hRet)
{
  return TRUE;
}
return FALSE;

        当然,如果当前用户不属于管理员组,则会弹出 UAC 提示 -- 我们并不是为了绕过系统限制,仅仅是合理的请求高权限执行。

提升到 System 权限

  • PsExec 工具

PsExec 是一个轻量级的 telnet-replacement,允许您在其他系统上执行进程。PsExec 最强大的用途包括在远程系统上启动交互式命令提示符。

其中,它提供了一个非常有用的参数 

-s在系统帐户中运行远程进程。

如下命令即可将 foo.exe 以管理员权限启动,但需要首先以管理员权限执行这条命令:

PsExec.exe -i -s foo.exe

  • 系统服务

        系统中的服务进程默认都是运行在session 0下,具有 system 权限,如服务宿主进程 svchost.exe,其 Integrity 为 System。

        创建一个服务,再通过服务启动子进程,则子进程默认就是 system 权限,当然创建、启动服务也需要管理员权限。

  • 计划任务

可以通过批处理加创建最高权限(system)的计划任务

schtasks /Create /TN footask /SC DAILY /ST 01:00 /TR notepad.exe /RL HIGHEST

降权

        还是以产品更新为例,当以提升级别运行的更新程序完成更新任务,需要启动产品主进程,以标准(非提升)级别运行,此时则需要降权。

        和常识可能有点相悖,相对提权,降权难度更大一些。

降至指定权限

  • 设置ProcessToken的IntegrityLevel
#include <Windows.h>
#include <sddl.h>

#pragma comment(lib, "Advapi32.lib")

void CreateIntegritySidProcess(WCHAR* wszIntegritySid)
{
  BOOL bRet = FALSE;
  HANDLE hToken = NULL;
  HANDLE hNewToken = NULL;

  // Notepad is used as an example
  WCHAR wszProcessName[MAX_PATH] =L"C:\\Windows\\System32\\Notepad.exe";

  PSID pIntegritySid = NULL;

  TOKEN_MANDATORY_LABEL TIL = { 0 };
  PROCESS_INFORMATION ProcInfo = { 0 };
  STARTUPINFO StartupInfo = { 0 };
  ULONG ExitCode = 0;

  __try
  {
    if (FALSE == OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hToken))
    {
      __leave;
    }
    if (FALSE == DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
      SecurityImpersonation, TokenPrimary, &hNewToken))
    {
      __leave;
    }
    if (FALSE == ConvertStringSidToSid(wszIntegritySid, &pIntegritySid))
    {
      __leave;
    }
    TIL.Label.Attributes = SE_GROUP_INTEGRITY;
    TIL.Label.Sid = pIntegritySid;

    // Set the process integrity level
    if (FALSE == SetTokenInformation(hNewToken, TokenIntegrityLevel, &TIL,
      sizeof(TOKEN_MANDATORY_LABEL)+GetLengthSid(pIntegritySid)))
    {
      __leave;
    }
    bRet = CreateProcessAsUser(hNewToken, NULL,
      wszProcessName, NULL, NULL, FALSE,
      0, NULL, NULL, &StartupInfo, &ProcInfo);
  }
  __finally
  {
    if (NULL != pIntegritySid)
    {
      LocalFree(pIntegritySid);
      pIntegritySid = NULL;
    }
    if (NULL != hNewToken)
    {
      CloseHandle(hNewToken);
      hNewToken = NULL;
    }
    if (NULL != hToken)
    {
      CloseHandle(hToken);
      hToken = NULL;
    }
  }
  printf("%ls bRet:%d\n", wszIntegritySid, bRet);//%ls打印宽字符
}


int _tmain(int argc, _TCHAR* argv[])
{
  /*
  Low (SID: S-1-16-4096),
  Medium (SID: S-1-16-8192),
  High (SID: S-1-16-12288)
  System (SID: S-1-16-16384).
  */
  //创建不同权限的进程  
  CreateIntegritySidProcess(L"S-1-16-4096");//low权限进程
  CreateIntegritySidProcess(L"S-1-16-8192");//medium权限进程
  CreateIntegritySidProcess(L"S-1-16-12288");//high权限进程
  CreateIntegritySidProcess(L"S-1-16-16384");//system权限进程
  printf("end\n");
  getchar();
  return 0;
}

        通过上述代码可知,关键是获取适当的  IntegrityLevel 。举一反三,如果我们获取到 explorer.exe 进程的Token 的 IntegrityLevel,就可以以 explorer.exe 的权限启动新进程,效果和桌面双击程序启动一样。

        另外,也可以通过 AllocateAndInitializeSid 指定 SECURITY_MANDATORY_LOW_RID 创建一个低权限的SID,这里用武稀松前辈的 Delphi 代码演示:

uses
  WinApi.Windows;

const
  SECURITY_MANDATORY_UNTRUSTED_RID = $00000000;
  SECURITY_MANDATORY_LOW_RID = $00001000;
  SECURITY_MANDATORY_MEDIUM_RID = $00002000;
  SECURITY_MANDATORY_HIGH_RID = $00003000;
  SECURITY_MANDATORY_SYSTEM_RID = $00004000;
  SECURITY_MANDATORY_PROTECTED_PROCESS_RID = $00005000;

function CreateLowIntegrityProcess(const ExeName: string;
  const Params: string = ”; TimeOut: DWORD = 0): HResult;
function GetIntegrityLevel(): DWORD;

implementation

type
  PTokenMandatoryLabel = ^TTokenMandatoryLabel;

  TTokenMandatoryLabel = packed record
    Label_: TSidAndAttributes;
  end;

function GetIntegrityLevel(): DWORD;
var
  hProcess, hToken: THandle;
  pTIL: PTokenMandatoryLabel;
  dwReturnLength: DWORD;
  dwTokenUserLength: DWORD;
  psaCount: PUCHAR;
  SubAuthority: DWORD;
begin
  Result := 0;
  dwReturnLength := 0;
  dwTokenUserLength := 0;
  pTIL := nil;

  hProcess := GetCurrentProcess();
  OpenProcessToken(hProcess, TOKEN_QUERY or TOKEN_QUERY_SOURCE, hToken);
  if hToken = 0 then
    Exit;
  if not GetTokenInformation(hToken, WinApi.Windows.TTokenInformationClass
    (TokenIntegrityLevel), pTIL, dwTokenUserLength, dwReturnLength) then
  begin
    if GetLastError = ERROR_INSUFFICIENT_BUFFER then
    Begin
      pTIL := Pointer(LocalAlloc(0, dwReturnLength));
      if pTIL = nil then
        Exit;
      dwTokenUserLength := dwReturnLength;
      dwReturnLength := 0;

      if GetTokenInformation(hToken, WinApi.Windows.TTokenInformationClass
        (TokenIntegrityLevel), pTIL, dwTokenUserLength, dwReturnLength) and
        IsValidSid((pTIL.Label_).Sid) then
      begin
        psaCount := GetSidSubAuthorityCount((pTIL.Label_).Sid);
        SubAuthority := psaCount^;
        SubAuthority := SubAuthority – 1;
        Result := GetSidSubAuthority((pTIL.Label_).Sid, SubAuthority)^;
      end;
      LocalFree(Cardinal(pTIL));
    End;
  end;

  CloseHandle(hToken);
end;

const
  userenvlib = ‘ userenv.dll ’;

function CreateEnvironmentBlock(lpEnvironment: PPointer; hToken: THandle;
  bInherit: BOOL): BOOL; stdcall; external userenvlib;
function DestroyEnvironmentBlock(lpEnvironment: Pointer): BOOL; stdcall;
  external userenvlib;

function CreateLowIntegrityProcess(const ExeName, Params: string;
  TimeOut: DWORD): HResult;
type
  _TOKEN_MANDATORY_LABEL = Record
    Label_: SID_AND_ATTRIBUTES;
  End;

  TOKEN_MANDATORY_LABEL = _TOKEN_MANDATORY_LABEL;
  PTOKEN_MANDATORY_LABEL = ^TOKEN_MANDATORY_LABEL;

const
  SECURITY_MANDATORY_LABEL_AUTHORITY: TSidIdentifierAuthority =
    (Value: (0, 0, 0, 0, 0, 16));
  SE_GROUP_INTEGRITY = $00000020;
  SE_GROUP_INTEGRITY_ENABLED = $00000040;
var
  hToken, hNewToken: THandle;
  MLAuthority: SID_IDENTIFIER_AUTHORITY;
  pIntegritySid: PSID;
  tml: TOKEN_MANDATORY_LABEL;
  si: TStartupInfo;
  pi: PROCESS_INFORMATION;
  pszCommandLine: string;
  dwCreationFlag: DWORD;
  pEnvironment: LPVOID;
begin

  Result := ERROR_SUCCESS;
  pszCommandLine := ExeName + Params;
  hToken := 0;
  hNewToken := 0;
  MLAuthority := SECURITY_MANDATORY_LABEL_AUTHORITY;
  pIntegritySid := nil;
  FillChar(tml, sizeof(tml), 0);
  FillChar(si, sizeof(si), 0);
  FillChar(pi, sizeof(pi), 0);

  si.cb := sizeof(si);
  si.lpDesktop := ‘ Winsta0 \ Default ’;
  dwCreationFlag := NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE;
  pEnvironment := nil;

  try
    // 从自己获取一个令牌
    if (not OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE or
      TOKEN_QUERY or TOKEN_ADJUST_DEFAULT or TOKEN_ASSIGN_PRIMARY, hToken)) then
    begin
      Result := GetLastError();
      Exit;
    end;

    // 复制令牌
    if (not DuplicateTokenEx(hToken, 0, nil, SecurityImpersonation,
      TokenPrimary, hNewToken)) then
    begin
      Result := GetLastError();
      Exit;
    end;

    // 创建一个低权限的SID
    if (not AllocateAndInitializeSid(MLAuthority, 1, SECURITY_MANDATORY_LOW_RID,
      0, 0, 0, 0, 0, 0, 0, pIntegritySid)) then
    begin
      Result := GetLastError();
      Exit;
    end;

    tml.Label_.Attributes := SE_GROUP_INTEGRITY;
    tml.Label_.Sid := pIntegritySid;

    // 设置这个低权限SID到令牌
    if (not SetTokenInformation(hNewToken, TokenIntegrityLevel, @tml,
      (sizeof(tml) + GetLengthSid(pIntegritySid)))) then
    begin
      Result := GetLastError();
      Exit;
    end;

    // 创建一个环境变量
    if (CreateEnvironmentBlock(@pEnvironment, hToken, FALSE)) then
      dwCreationFlag := dwCreationFlag or CREATE_UNICODE_ENVIRONMENT
    else
      pEnvironment := nil;

    // 创建一个低权限的进程
    if (not CreateProcessAsUser(hNewToken, nil, PChar(pszCommandLine), nil, nil,
      FALSE, dwCreationFlag, pEnvironment, nil, si, pi)) then
    begin
      Result := GetLastError();
      Exit;
    end;

    WaitForSingleObject(pi.hProcess, TimeOut);
  finally
    // 清理现场
    if pEnvironment <> nil then
    begin
      DestroyEnvironmentBlock(pEnvironment);
      pEnvironment := nil;
    end;

    if (hToken <> 0) then
    begin
      CloseHandle(hToken);
      hToken := 0;
    end;
    if (hNewToken <> 0) then
    begin
      CloseHandle(hNewToken);
      hNewToken := 0;
    end;
    if (pIntegritySid <> nil) then
    begin
      FreeSid(pIntegritySid);
      pIntegritySid := nil;
    end;
    if (pi.hProcess <> 0) then
    begin
      CloseHandle(pi.hProcess);
      pi.hProcess := 0;
    end;
    if (pi.hThread <> 0) then
    begin
      CloseHandle(pi.hThread);
      pi.hThread := 0;
    end;

    if (ERROR_SUCCESS <> Result) then
    begin
      SetLastError(Result);
    end
    else
    begin
      Result := ERROR_SUCCESS;
    end;
  end;
end;

  • 计划任务

        没错,还是它,创建计划任务默认不要求高权限时就可以当前用户权限启动指定程序

schtasks /Create /TN footask /SC DAILY /ST 01:00 /TR notepad.exe

        当然,创建、启动计划任务本身需要管理员权限。

像桌面一样启动进程

        

        如果当前进用户本身是低权限,但当前进程是高权限运行,需要新的子进程以当前用户身份启动,那我们就可以让 explorer 帮我们以它的上下文方式启动子进程,这里依然用 Delphi 代码演示:


uses
  ComObj, ShlObj, ActiveX, SHDocVw;


function IUnknown_QueryService(punk: IUnknown; const guidService: TGUID;
  const IID: TGUID; out Obj): HRESULT; stdcall;
  external 'ShLwApi' name 'IUnknown_QueryService';

procedure TForm1.Button1Click(Sender: TObject);
var
  hDesk: Integer;
  psw: IShellWindows;
  v, dummy: OleVariant;
  disp, pdispBackground, pdisp2: IDispatch;
  psb: IShellBrowser;
  psv: IShellView;
  psfvd: IShellFolderViewDual;
  psd: IShellDispatch2;
begin
  CoInitialize(nil);
  try
    OleCheck(CoCreateInstance(CLASS_ShellWindows, nil, CLSCTX_LOCAL_SERVER,
      IShellWindows, psw));
    disp := psw.FindWindowSW(v, dummy, SWC_DESKTOP, hDesk, SWFO_NEEDDISPATCH);
    OleCheck(IUnknown_QueryService(disp, SID_STopLevelBrowser,
      IID_IShellBrowser, psb));
    OleCheck(psb.QueryActiveShellView(psv));
    OleCheck(psv.GetItemObject(SVGIO_BACKGROUND, IDispatch,
      Pointer(pdispBackground)));
    OleCheck(pdispBackground.QueryInterface(IShellFolderViewDual, psfvd));
    OleCheck(psfvd.get_Application(pdisp2));
    OleCheck(pdisp2.QueryInterface(IShellDispatch2, psd));
    psd.ShellExecute('notepad.exe', 'C:\Windows\WindowsUpdate.log', EmptyParam,
      'open', SW_SHOWNORMAL)
  finally
    CoUninitialize;
  end;
end;

 C++ 版本示例:

#include <windows.h>
#include <shlwapi.h>
#include <shlobj.h>

#pragma comment(lib, "shlwapi.lib")

// use the shell view for the desktop using the shell windows automation to find the
// desktop web browser and then grabs its view
//
// returns:
//      IShellView, IFolderView and related interfaces

HRESULT GetShellViewForDesktop(REFIID riid, void **ppv)
{
    *ppv = NULL;

    IShellWindows *psw;
    HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
    if (SUCCEEDED(hr))
    {
        HWND hwnd;
        IDispatch* pdisp;
        VARIANT vEmpty = {}; // VT_EMPTY
        if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
        {
            IShellBrowser *psb;
            hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
            if (SUCCEEDED(hr))
            {
                IShellView *psv;
                hr = psb->QueryActiveShellView(&psv);
                if (SUCCEEDED(hr))
                {
                    hr = psv->QueryInterface(riid, ppv);
                    psv->Release();
                }
                psb->Release();
            }
            pdisp->Release();
        }
        else
        {
            hr = E_FAIL;
        }
        psw->Release();
    }
    return hr;
}

// From a shell view object gets its automation interface and from that gets the shell
// application object that implements IShellDispatch2 and related interfaces.

HRESULT GetShellDispatchFromView(IShellView *psv, REFIID riid, void **ppv)
{
    *ppv = NULL;

    IDispatch *pdispBackground;
    HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
    if (SUCCEEDED(hr))
    {
        IShellFolderViewDual *psfvd;
        hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
        if (SUCCEEDED(hr))
        {
            IDispatch *pdisp;
            hr = psfvd->get_Application(&pdisp);
            if (SUCCEEDED(hr))
            {
                hr = pdisp->QueryInterface(riid, ppv);
                pdisp->Release();
            }
            psfvd->Release();
        }
        pdispBackground->Release();
    }
    return hr;
}

HRESULT ShellExecInExplorerProcess(PCWSTR pszFile)
{
    IShellView *psv;
    HRESULT hr = GetShellViewForDesktop(IID_PPV_ARGS(&psv));
    if (SUCCEEDED(hr))
    {
        IShellDispatch2 *psd;
        hr = GetShellDispatchFromView(psv, IID_PPV_ARGS(&psd));
        if (SUCCEEDED(hr))
        {
            BSTR bstrFile = SysAllocString(pszFile);
            hr = bstrFile ? S_OK : E_OUTOFMEMORY;
            if (SUCCEEDED(hr))
            {
                VARIANT vtEmpty = {}; // VT_EMPTY
                hr = psd->ShellExecuteW(bstrFile, vtEmpty, vtEmpty, vtEmpty, vtEmpty);
                SysFreeString(bstrFile);
            }
            psd->Release();
        }
        psv->Release();
    }
    return hr;
}

int WINAPI wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (SUCCEEDED(hr))
    {
        ShellExecInExplorerProcess(L"http://www.msn.com");
        CoUninitialize();
    }
    return 0;
}

        本篇内容介绍了几种提权、降权的方法,并不涉及到系统漏洞利用,抛砖引玉,希望对 Windows 进程权限方面感兴趣的朋友一起留言讨论,互相进步 🤝


参考

  • Mandatory Integrity Control - Win32 apps | Microsoft Learn
  • PsExec - Sysinternals | Microsoft Learn
  • IShellDispatch2 object (Shldisp.h) - Win32 apps | Microsoft Learn
  • 以低用户权限启动一个进程.比如Vista或者WIN7中的IE | 武稀松(wr960204)的博客 (raysoftware.cn)

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

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

相关文章

BMS设计中的短路保护和MOSFET选型(上)

电池管理系统&#xff08;BMS&#xff09;是一种能够对电池进行监控和管理的电子装备&#xff0c;是电池与用户之间的纽带。通过对电压、电流、温度以及SOC等数据采集&#xff0c;计算进而控制电池的充放电过程&#xff0c;主要就是为了能够提高电池的利用率&#xff0c;防止电…

【Python从入门到进阶】51、电影天堂网站多页面下载实战

接上篇《50、当当网Scrapy项目实战&#xff08;三&#xff09;》 上一篇我们讲解了使用Scrapy框架在当当网抓取多页书籍数据的效果&#xff0c;本篇我们来抓取电影天堂网站的数据&#xff0c;同样采用Scrapy框架多页面下载的模式来实现。 一、抓取需求 打开电影天堂网站&…

Ubuntu Desktop 更改默认应用程序 (Videos -> SMPlayer)

Ubuntu Desktop 更改默认应用程序 [Videos -> SMPlayer] References System Settings -> Details -> Default Applications 概况、默认应用程序、可移动介质、法律声明 默认应用程序&#xff0c;窗口右侧列出了网络、邮件、日历、音乐、视频、照片操作的默认应用程序…

OCR如何解决字体多样性难题?

OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术的确是一项非常实用的技术&#xff0c;能够将图像中的文字转化为可编辑的文本&#xff0c;大大提高了工作效率。然而&#xff0c;你所遇到的问题——字体多样性导致的模型泛化能力不足&a…

AtCoder Regular Contest 175(A~B)

补题&#xff1a;A - Spoon Taking Problem 阅读理解就能劝退好多人&#xff0c;先看B题可能收益会更高。 N个人都是这么坐的&#xff0c;勺子标号也给你标好了。 如果 s[1]L&#xff0c;那么1这个人就要拿左边的勺子&#xff0c;如果左边没有就拿右边的&#xff0c;右边也没…

[AutoSar]BSW_ OS CORE, Physical core,EcuC core,EcuC partition,OSApplication的关系

目录 关键词平台说明一、总体依赖关系二、相关概念三、在配置中的实现3.1 EcucPartition3.2 OsApplication3.3 Ecu core 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c; EB芯片厂商TI 英飞凌编程语言C&#xff0c;C…

Centos7 防火墙iptables?

Centos7 防火墙iptables&#xff1f; 文章目录 Centos7 防火墙iptables&#xff1f;1. 介绍2. firewalld 和 iptables区别3. 区域管理概念区域管理有如下几种不同的初始化区域&#xff1a; 4.iptables的配置1.简述2.基本原理3.iptables传输数据包的过程4. iptables规则表和链5.…

C++初阶:STL容器list的使用与初版自实现

目录 1. list的接口与使用1.1 默认成员函数1.2 迭代器与容量相关成员函数1.3 存储数据操作相关成员函数1.4 其他list操作成员函数 2. list的自实现2.1 list的自实现功能2.2 list的结点结构2.3 list的迭代器2.3 list的结构2.4 list迭代器的运算符重载2.5 list的成员函数 3. cons…

python绘图matplotlib——使用记录2

本博文来自于网络收集&#xff0c;如有侵权请联系删除 三维图绘制 1 三维散点图2 三维柱状图三维曲面 1 三维散点图 import matplotlib.pyplot as plt import numpy as npfrom mpl_toolkits.mplot3d import Axes3Dfig plt.figure() # ax fig.gca(projection"3d")…

javase day11笔记

第十一天课堂笔记 构造代码块 { } 给 所有对象 共性特点 进行初始化操作 创建对象时在堆区对象中存放实例变量,同时执行构造代码块 执行顺序:静态代码块—>非静态代码块—>构造方法 继承★★★ 将多个类中相同的实例变量和实例方法 , 单独存放到一个类中,成为父类…

【Linux】写个日志和再谈线程池

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;信号量和线程池 目录 &#x1f449;&#x1f3fb;日志代码Log.cppMain.cc &#x1f449;&#x1f3fb;线程池代码LockGuard.hpp(自定义互斥锁&#xff0c;进…

网易web安全工程师进阶版课程

课程介绍 《Web安全工程师&#xff08;进阶&#xff09;》是由“ i春秋学院联合网易安全部”出品&#xff0c;资深讲师团队通过精炼的教学内容、丰富的实际场景及综合项目实战&#xff0c;帮助学员纵向提升技能&#xff0c;横向拓宽视野&#xff0c;牢靠掌握Web安全工程师核心…

Python6:Socket编程初步学习笔记

Socket协议概要 创建socket的时候&#xff0c;需要一些选项来说明本次使用协议具体是什么&#xff0c;常用的两个&#xff1a; 由此产生的不同组合&#xff1a; 但目前TCP(IPV4)是主流&#xff0c;SOCK_STREAMAF_INET 创建和使用Socket socket模块中有socket类&#xff1a…

51单片机学习笔记——LED闪烁和流水灯

任务分析 首先要知道LED闪烁主要是怎么工作的&#xff0c;闪烁亮灭自然是一下为高一下为低&#xff0c;亮灭的频率则需要延时来进行控制。 上节已经知道了如何点亮那延时如何做呢首先先编写主框架 这样是否可以通过循环将LED灯一直循环闪烁。 以为while一直在循环所以其实是可…

向开发板上移植ip工具:交叉编译 ip工具

一. 简介 前面几篇文章学习了 CAN设备节点的创建&#xff0c;以及如何使能 CAN驱动。 本文学习向开发板上移植ip工具。 二. 向开发板上移植ip工具&#xff1a;交叉编译 ip工具 注意&#xff1a;在移植 ip 命令的时候必须先对根文件系统做个备份&#xff01;防止操作失误导…

力扣74---搜索二维矩阵

目录 题目描述&#xff1a; 思路&#xff1a; 代码&#xff1a; 题目描述&#xff1a; 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 targ…

c#绘制图形

窗体工具控件 如果选纹理 ,需要在ImageList中选择图像(点击添加选择图片路径) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.…

【Redis教程0x03】详解Redis的基本数据类型

引言 根据【Redis教程0x02】中介绍的&#xff0c;Redis的数据类型可分为5种基本数据类型&#xff08;String、Hash、List、Set、Zset&#xff09;和4种高级数据类型&#xff08;BitMap、HyperLogLog、GEO、Stream&#xff09;。在本篇博客中&#xff0c;我们将详解这9种数据类…

分类预测 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积神经网络-长短期记忆网络融合多头注意力机制多特征分类预测

分类预测 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积神经网络-长短期记忆网络融合多头注意力机制多特征分类预测 目录 分类预测 | Matlab实现CNN-LSTM-Mutilhead-Attention卷积神经网络-长短期记忆网络融合多头注意力机制多特征分类预测分类效果基本介绍模型描述程序设计参…

Springboot做分组校验

目录 分组校验 Insert分组 Upload分组 测试接口 测试结果 添加测试 更新测试 顺序校验GroupSequence 自定义分组校验 自定义分组表单 CustomSequenceProvider 测试接口 测试结果 Type类型为A Type类型为B 总结&#xff1a; 前文提到了做自定义的校验注解&#xff…