Refactor process protection

This commit is contained in:
momo5502 2016-10-30 21:15:30 +01:00
parent 49d0528dfa
commit 3e95fe4344
2 changed files with 122 additions and 214 deletions

View File

@ -405,80 +405,61 @@ namespace Components
} }
} }
// TODO: Beautify that unsigned long AntiCheat::ProtectProcess()
DWORD AntiCheat::ProtectProcess()
{ {
// Returned to caller Utils::Memory::Allocator allocator;
DWORD dwResult = (DWORD)-1;
// Released on exit
HANDLE hToken = NULL;
PVOID pTokenInfo = NULL;
PSID psidEveryone = NULL;
PSID psidSystem = NULL;
PSID psidAdmins = NULL;
PACL pDacl = NULL;
PSECURITY_DESCRIPTOR pSecDesc = NULL;
__try
{
// Scratch
DWORD dwSize = 0;
BOOL bResult = FALSE;
// If this fails, you can try to fallback to OpenThreadToken // If this fails, you can try to fallback to OpenThreadToken
HANDLE hToken = nullptr;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
{ {
dwResult = GetLastError(); return GetLastError();
assert(FALSE);
__leave; /*failed*/
} }
bResult = GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize); auto freeSid = [] (void* sid)
dwResult = GetLastError(); {
assert(bResult == FALSE && ERROR_INSUFFICIENT_BUFFER == dwResult); if (sid)
if (!(bResult == FALSE && ERROR_INSUFFICIENT_BUFFER == dwResult)) { __leave; /*failed*/ } {
FreeSid(reinterpret_cast<PSID>(sid));
}
};
allocator.Reference(hToken, [] (void* hToken)
{
if (hToken)
{
CloseHandle(hToken);
}
});
DWORD dwSize = 0;
PVOID pTokenInfo = nullptr;
if (GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize) || GetLastError() != ERROR_INSUFFICIENT_BUFFER) return GetLastError();
if (dwSize) if (dwSize)
{ {
pTokenInfo = HeapAlloc(GetProcessHeap(), 0, dwSize); pTokenInfo = allocator.Allocate(dwSize);
dwResult = GetLastError(); if (!pTokenInfo) return GetLastError();
assert(NULL != pTokenInfo);
if (NULL == pTokenInfo) { __leave; /*failed*/ }
} }
bResult = GetTokenInformation(hToken, TokenUser, pTokenInfo, dwSize, &dwSize); if (!GetTokenInformation(hToken, TokenUser, pTokenInfo, dwSize, &dwSize) || !pTokenInfo) return GetLastError();
dwResult = GetLastError();
assert(bResult && pTokenInfo);
if (!(bResult && pTokenInfo)) { __leave; /*failed*/ }
PSID psidCurUser = ((TOKEN_USER*)pTokenInfo)->User.Sid; PSID psidCurUser = reinterpret_cast<TOKEN_USER*>(pTokenInfo)->User.Sid;
PSID psidEveryone = nullptr;
SID_IDENTIFIER_AUTHORITY sidEveryone = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY sidEveryone = SECURITY_WORLD_SID_AUTHORITY;
bResult = AllocateAndInitializeSid(&sidEveryone, 1, if (!AllocateAndInitializeSid(&sidEveryone, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone) || !psidEveryone) return GetLastError();
SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone); allocator.Reference(psidEveryone, freeSid);
dwResult = GetLastError();
assert(bResult && psidEveryone);
if (!(bResult && psidEveryone)) { __leave; /*failed*/ }
PSID psidSystem = nullptr;
SID_IDENTIFIER_AUTHORITY sidSystem = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY sidSystem = SECURITY_NT_AUTHORITY;
bResult = AllocateAndInitializeSid(&sidSystem, 1, if (!AllocateAndInitializeSid(&sidSystem, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem) || !psidSystem) return GetLastError();
SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &psidSystem); allocator.Reference(psidSystem, freeSid);
dwResult = GetLastError();
assert(bResult && psidSystem);
if (!(bResult && psidSystem)) { __leave; /*failed*/ }
PSID psidAdmins = nullptr;
SID_IDENTIFIER_AUTHORITY sidAdministrators = SECURITY_NT_AUTHORITY; SID_IDENTIFIER_AUTHORITY sidAdministrators = SECURITY_NT_AUTHORITY;
bResult = AllocateAndInitializeSid(&sidAdministrators, 2, if (!AllocateAndInitializeSid(&sidAdministrators, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmins) || !psidAdmins) return GetLastError();
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, allocator.Reference(psidAdmins, freeSid);
0, 0, 0, 0, 0, 0, &psidAdmins);
dwResult = GetLastError();
assert(bResult && psidAdmins);
if (!(bResult && psidAdmins)) { __leave; /*failed*/ }
const PSID psidArray[] = const PSID psidArray[] =
{ {
@ -502,15 +483,8 @@ namespace Components
dwSize += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD); dwSize += sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD);
} }
pDacl = (PACL)HeapAlloc(GetProcessHeap(), 0, dwSize); PACL pDacl = reinterpret_cast<PACL>(allocator.Allocate(dwSize));
dwResult = GetLastError(); if (!pDacl || !InitializeAcl(pDacl, dwSize, ACL_REVISION)) return GetLastError();
assert(NULL != pDacl);
if (NULL == pDacl) { __leave; /*failed*/ }
bResult = InitializeAcl(pDacl, dwSize, ACL_REVISION);
dwResult = GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
// Mimic Protected Process // Mimic Protected Process
// http://www.microsoft.com/whdc/system/vista/process_vista.mspx // http://www.microsoft.com/whdc/system/vista/process_vista.mspx
@ -525,17 +499,11 @@ namespace Components
// In addition to protected process // In addition to protected process
PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE; PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE;
bResult = AddAccessDeniedAce(pDacl, ACL_REVISION, dwPoison, psidArray[0]); if (!AddAccessDeniedAce(pDacl, ACL_REVISION, dwPoison, psidArray[0])) return GetLastError();
dwResult = GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
// Standard and specific rights not explicitly denied // Standard and specific rights not explicitly denied
static const DWORD dwAllowed = ~dwPoison & 0x1FFF; static const DWORD dwAllowed = ~dwPoison & 0x1FFF;
bResult = AddAccessAllowedAce(pDacl, ACL_REVISION, dwAllowed, psidArray[1]); if (!AddAccessAllowedAce(pDacl, ACL_REVISION, dwAllowed, psidArray[1])) return GetLastError();
dwResult = GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
// Because of ACE ordering, System will effectively have dwAllowed even // Because of ACE ordering, System will effectively have dwAllowed even
// though the ACE specifies PROCESS_ALL_ACCESS (unless software uses // though the ACE specifies PROCESS_ALL_ACCESS (unless software uses
@ -543,10 +511,7 @@ namespace Components
// As an exercise, check behavior of tools such as Process Explorer under XP, // As an exercise, check behavior of tools such as Process Explorer under XP,
// Vista, and above. Vista and above should exhibit slightly different behavior // Vista, and above. Vista and above should exhibit slightly different behavior
// due to Restricted tokens. // due to Restricted tokens.
bResult = AddAccessAllowedAce(pDacl, ACL_REVISION, PROCESS_ALL_ACCESS, psidArray[2]); if (!AddAccessAllowedAce(pDacl, ACL_REVISION, PROCESS_ALL_ACCESS, psidArray[2])) return GetLastError();
dwResult = GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
// Because of ACE ordering, Administrators will effectively have dwAllowed // Because of ACE ordering, Administrators will effectively have dwAllowed
// even though the ACE specifies PROCESS_ALL_ACCESS (unless the Administrator // even though the ACE specifies PROCESS_ALL_ACCESS (unless the Administrator
@ -554,30 +519,18 @@ namespace Components
// As an exercise, check behavior of tools such as Process Explorer under XP, // As an exercise, check behavior of tools such as Process Explorer under XP,
// Vista, and above. Vista and above should exhibit slightly different behavior // Vista, and above. Vista and above should exhibit slightly different behavior
// due to Restricted tokens. // due to Restricted tokens.
bResult = AddAccessAllowedAce(pDacl, ACL_REVISION, PROCESS_ALL_ACCESS, psidArray[3]); if (!AddAccessAllowedAce(pDacl, ACL_REVISION, PROCESS_ALL_ACCESS, psidArray[3])) return GetLastError();
dwResult = GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
pSecDesc = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH); PSECURITY_DESCRIPTOR pSecDesc = allocator.Allocate<SECURITY_DESCRIPTOR>();
dwResult = GetLastError(); if (!pSecDesc) return GetLastError();
assert(NULL != pSecDesc);
if (NULL == pSecDesc) { __leave; /*failed*/ }
// InitializeSecurityDescriptor initializes a security descriptor in // InitializeSecurityDescriptor initializes a security descriptor in
// absolute format, rather than self-relative format. See // absolute format, rather than self-relative format. See
// http://msdn.microsoft.com/en-us/library/aa378863(VS.85).aspx // http://msdn.microsoft.com/en-us/library/aa378863(VS.85).aspx
bResult = InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION); if (!InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)) return GetLastError();
dwResult = GetLastError(); if (!SetSecurityDescriptorDacl(pSecDesc, TRUE, pDacl, FALSE)) return GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
bResult = SetSecurityDescriptorDacl(pSecDesc, TRUE, pDacl, FALSE); return SetSecurityInfo(
dwResult = GetLastError();
assert(TRUE == bResult);
if (FALSE == bResult) { __leave; /*failed*/ }
dwResult = SetSecurityInfo(
GetCurrentProcess(), GetCurrentProcess(),
SE_KERNEL_OBJECT, // process object SE_KERNEL_OBJECT, // process object
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
@ -586,51 +539,6 @@ namespace Components
pDacl, pDacl,
NULL // SACL NULL // SACL
); );
dwResult = GetLastError();
assert(ERROR_SUCCESS == dwResult);
if (ERROR_SUCCESS != dwResult) { __leave; /*failed*/ }
dwResult = ERROR_SUCCESS;
}
__finally
{
if (NULL != pSecDesc)
{
HeapFree(GetProcessHeap(), 0, pSecDesc);
}
if (NULL != pDacl)
{
HeapFree(GetProcessHeap(), 0, pDacl);
}
if (psidAdmins)
{
FreeSid(psidAdmins);
}
if (psidSystem)
{
FreeSid(psidSystem);
}
if (psidEveryone)
{
FreeSid(psidEveryone);
}
if (NULL != pTokenInfo)
{
HeapFree(GetProcessHeap(), 0, pTokenInfo);
}
if (NULL != hToken)
{
CloseHandle(hToken);
}
}
return dwResult;
} }
AntiCheat::AntiCheat() AntiCheat::AntiCheat()

View File

@ -44,7 +44,7 @@ namespace Components
static void PerformCheck(); static void PerformCheck();
static void PatchWinAPI(); static void PatchWinAPI();
static DWORD ProtectProcess(); static unsigned long ProtectProcess();
static void NullSub(); static void NullSub();