微软对于DACLs 和 ACEs描述
Windows 访问控制机制:
每个 Windows 内核对象(例如文件、进程、线程等)都有一个安全描述符(Security Descriptor)。
安全描述符包含了自主访问控制列表(DACL)以及其他安全信息。
DACL 是一系列访问控制条目(ACE)的列表,每个 ACE 定义了特定的用户或组对该对象的操作权限。
DACL 和 ACE 的工作原理:
DACL: DACL 就像一个对象的“访问权限清单”,它决定了谁可以对这个对象执行哪些操作。
ACE: 每个 ACE 都是 DACL 中的一个条目,它包含以下信息:
受托人 (Trustee): 可以是用户、组或特殊账户(例如“Everyone”、“SYSTEM”)。
访问权限 (Access Mask): 指定允许或拒绝的操作类型(例如读取、写入、执行、删除、查询信息等)。
ACE 类型 (Type): 可以是允许访问(Allow ACE)或拒绝访问(Deny ACE)。
访问控制过程:
当一个进程尝试访问一个对象时,Windows 会检查对象的安全描述符。
系统会提取 DACL 并遍历其中的 ACE,检查 ACE 的受托人是否与请求进程的访问令牌匹配。
如果找到匹配的 允许 ACE,并且允许了请求的全部权限,则授予访问权限,并停止检查。
如果找到匹配的 拒绝 ACE,则拒绝访问权限,并停止检查。
如果检查完所有 ACE 都找不到匹配的允许 ACE,则拒绝访问。
拒绝 ACE 优先: 如果既有允许 ACE 也有拒绝 ACE,则拒绝 ACE 优先。
ACE 顺序重要: ACE 在 DACL 中的顺序很重要,因为系统是按照顺序检查 ACE,直到授予或拒绝访问。
如何阻止其他进程打开句柄:
要阻止其他进程打开你的进程句柄,你需要修改你进程的安全描述符中的 DACL,添加一个拒绝访问的 ACE。
这个 ACE 需要满足以下条件:
受托人: 你需要决定拒绝哪个用户或组的访问,通常拒绝当前用户本身或者所有用户的访问。
访问权限: 你需要拒绝所有进程访问权限 (PROCESS_ALL_ACCESS)。
使用 SetSecurityInfo 设置 DACL:
SetSecurityInfo 函数允许你修改内核对象的安全描述符,包括 DACL。
当使用 SetSecurityInfo 设置 DACL_SECURITY_INFORMATION 时,它会用你提供的新的 DACL 替换 原有的 DACL。
也是正因为如此,原有的全部被替换,所以仅仅剩下一个拒绝的.

最后附上代码:
被替换DACL的进程(保护进程)
进行OpenProcess的进程(攻击进程):
void Cleaner(HANDLE TkHandle, PACL ProcACL, PTOKEN_USER UserTk) {
if (TkHandle) {
CloseHandle(TkHandle);
}
if (ProcACL) {
free(ProcACL);
}
if (UserTk) {
free(UserTk);
}
}
//获取当前进程令牌并设置拒绝访问权限
bool SetSecurityControls() {
HANDLE TkHandle = nullptr;
PTOKEN_USER UserTk = nullptr;
PACL ProcACL = nullptr;
DWORD CbBuffer = 0;
DWORD CbACL = 0;
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&TkHandle)) Cleaner(TkHandle, ProcACL, UserTk);
GetTokenInformation(TkHandle, TokenUser, nullptr, 0, &CbBuffer);
UserTk = static_cast<PTOKEN_USER>(malloc(CbBuffer));
if (UserTk == nullptr) Cleaner(TkHandle, ProcACL, UserTk);
if (!GetTokenInformation(
TkHandle,
TokenUser,
UserTk,
CbBuffer,
&CbBuffer
)) {
Cleaner(TkHandle, ProcACL, UserTk);
}
if (!IsValidSid(UserTk->User.Sid)) {
Cleaner(TkHandle, ProcACL, UserTk);
}
CbACL = sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(UserTk->User.Sid);
ProcACL = static_cast<PACL>(malloc(CbACL));
if (ProcACL == nullptr) Cleaner(TkHandle, ProcACL, UserTk);
if (!InitializeAcl(ProcACL, CbACL, ACL_REVISION)) Cleaner(TkHandle, ProcACL, UserTk);
// 添加拒绝访问的 ACE
if (!AddAccessDeniedAce(
ProcACL,
ACL_REVISION,
PROCESS_ALL_ACCESS, //拒绝所有权限
UserTk->User.Sid
)) {
Cleaner(TkHandle, ProcACL, UserTk);
}
if (ERROR_SUCCESS == SetSecurityInfo(
GetCurrentProcess(),
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
nullptr, nullptr,
ProcACL,
nullptr
)) {
printf("Successfully set security controls.\n");
}
else {
printf("Failed to set security controls.\n");
}
Cleaner(TkHandle, nullptr, UserTk);
free(ProcACL);
system("pause");
return true;
}
int main() {
if (!SetSecurityControls()) {
printf("SetSecurityControls failed\n");
system("pause");
return 1;
}
system("pause");
return 0;
}
void Cleaner(HANDLE TkHandle, PACL ProcACL, PTOKEN_USER UserTk) {
if (TkHandle) {
CloseHandle(TkHandle);
}
if (ProcACL) {
free(ProcACL);
}
if (UserTk) {
free(UserTk);
}
}
//获取当前进程令牌并设置拒绝访问权限
bool SetSecurityControls() {
HANDLE TkHandle = nullptr;
PTOKEN_USER UserTk = nullptr;
PACL ProcACL = nullptr;
DWORD CbBuffer = 0;
DWORD CbACL = 0;
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&TkHandle)) Cleaner(TkHandle, ProcACL, UserTk);
GetTokenInformation(TkHandle, TokenUser, nullptr, 0, &CbBuffer);
UserTk = static_cast<PTOKEN_USER>(malloc(CbBuffer));
if (UserTk == nullptr) Cleaner(TkHandle, ProcACL, UserTk);
if (!GetTokenInformation(
TkHandle,
TokenUser,
UserTk,
CbBuffer,
&CbBuffer
)) {
Cleaner(TkHandle, ProcACL, UserTk);
}
if (!IsValidSid(UserTk->User.Sid)) {
Cleaner(TkHandle, ProcACL, UserTk);
}
CbACL = sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(UserTk->User.Sid);
ProcACL = static_cast<PACL>(malloc(CbACL));
if (ProcACL == nullptr) Cleaner(TkHandle, ProcACL, UserTk);
if (!InitializeAcl(ProcACL, CbACL, ACL_REVISION)) Cleaner(TkHandle, ProcACL, UserTk);
// 添加拒绝访问的 ACE
if (!AddAccessDeniedAce(
ProcACL,
ACL_REVISION,
PROCESS_ALL_ACCESS, //拒绝所有权限
UserTk->User.Sid
传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!