#include "StdAfx.h" #include "TWProcHelper.h" CTWProcHelper::CTWProcHelper(void) :m_hJob(NULL) { } CTWProcHelper::CTWProcHelper(HANDLE hJob) :m_hJob(hJob) { } CTWProcHelper::~CTWProcHelper(void) { if (m_hJob != NULL) { CloseHandle(m_hJob); m_hJob = NULL; } } // PrintError support function. // Simple wrapper function for error output. void CTWProcHelper::PrintError(LPCTSTR errDesc) { DWORD dwErrCode = GetLastError(); LPCTSTR errMsg = ErrorMessage(dwErrCode); Dbg(TEXT("** ERROR ** %s: %s(%d)."), errDesc, errMsg, dwErrCode); LocalFree((LPVOID)errMsg); } void CTWProcHelper::PrintInfo(LPCTSTR lpszDesc) { Dbg("ProcHelper: %s.", lpszDesc); return; } // ErrorMessage support function. // Retrieves the system error message for the GetLastError() code. // Note: caller must use LocalFree() on the returned LPCTSTR buffer. LPCTSTR CTWProcHelper::ErrorMessage(DWORD error) { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); return((LPCTSTR)lpMsgBuf); } //===== Below is Functions about Job ======================== BOOL CTWProcHelper::Create(PSECURITY_ATTRIBUTES psa, PCTSTR pszName) { m_hJob = CreateJobObject(psa, pszName); return(m_hJob != NULL); } BOOL CTWProcHelper::Open(PCTSTR pszName, DWORD dwDesiredAccess, BOOL fInheritHandle) { m_hJob = OpenJobObject(dwDesiredAccess, fInheritHandle, pszName); return(m_hJob != NULL); } BOOL CTWProcHelper::AssignProcess(HANDLE hProcess) { return(AssignProcessToJobObject(m_hJob, hProcess)); } BOOL CTWProcHelper::AssignProcess(DWORD dwProcessId) { HANDLE hProcess = OpenProcess( PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, dwProcessId); if(hProcess == NULL) { PrintError("The hProcess is null which get from ProcessId"); return FALSE; } return (AssignProcess(hProcess)); } BOOL CTWProcHelper::SetBasicLimitInfo(PJOBOBJECT_BASIC_LIMIT_INFORMATION pjobli) { return(SetInformationJobObject(m_hJob, JobObjectBasicLimitInformation, pjobli, sizeof(*pjobli))); } BOOL CTWProcHelper::SetExtendedLimitInfo(PJOBOBJECT_EXTENDED_LIMIT_INFORMATION pjobeli) { return(SetInformationJobObject(m_hJob, JobObjectExtendedLimitInformation, pjobeli, sizeof(*pjobeli))); } BOOL CTWProcHelper::SetBasicUIRestrictions(DWORD fdwLimits) { JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir = { fdwLimits }; return(SetInformationJobObject(m_hJob, JobObjectBasicUIRestrictions, &jobuir, sizeof(jobuir))); } BOOL CTWProcHelper::QueryEndOfJobTimeInfo(PDWORD pfdwEndOfJobTimeInfo) { JOBOBJECT_END_OF_JOB_TIME_INFORMATION joeojti; BOOL bRet = QueryInformationJobObject(m_hJob, JobObjectBasicUIRestrictions, &joeojti, sizeof(joeojti), NULL); if (bRet) *pfdwEndOfJobTimeInfo = joeojti.EndOfJobTimeAction; return(bRet); } BOOL CTWProcHelper::SetSecurityLimitInfo(PJOBOBJECT_SECURITY_LIMIT_INFORMATION pjobsli) { return(SetInformationJobObject(m_hJob, JobObjectSecurityLimitInformation, pjobsli, sizeof(*pjobsli))); } BOOL CTWProcHelper::SetEndOfJobInfo(DWORD fdwEndOfJobInfo) { JOBOBJECT_END_OF_JOB_TIME_INFORMATION joeojti; joeojti.EndOfJobTimeAction = fdwEndOfJobInfo; return(SetInformationJobObject(m_hJob, JobObjectEndOfJobTimeInformation, &joeojti, sizeof(joeojti))); } BOOL CTWProcHelper::QueryBaseAndIOInfo(PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION pjobai) { return(QueryInformationJobObject(m_hJob, JobObjectBasicAndIoAccountingInformation, pjobai, sizeof(*pjobai), NULL)); } BOOL CTWProcHelper::QueryExtendLimitInfo(PJOBOBJECT_EXTENDED_LIMIT_INFORMATION pjobeli) { return(QueryInformationJobObject(m_hJob, JobObjectExtendedLimitInformation, pjobeli, sizeof(*pjobeli), NULL)); } BOOL CTWProcHelper::QueryBasicProcessIdList(DWORD dwMaxProcesses, PDWORD pdwProcessIdList, PDWORD pdwProcessesReturned) { // Calculate the # of bytes necessary DWORD cb = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + (sizeof(DWORD) * (dwMaxProcesses - 1)); // Allocate those bytes from the stack PJOBOBJECT_BASIC_PROCESS_ID_LIST pjobProIdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) _alloca(cb); if(pjobProIdList == NULL) return FALSE; pjobProIdList->NumberOfProcessIdsInList = dwMaxProcesses; BOOL bRet = QueryInformationJobObject(m_hJob, JobObjectBasicProcessIdList, pjobProIdList, cb, NULL); if(bRet) { if(pdwProcessesReturned != NULL) { *pdwProcessesReturned = pjobProIdList->NumberOfProcessIdsInList; } CopyMemory(pdwProcessIdList, pjobProIdList->ProcessIdList, sizeof(DWORD) * pjobProIdList->NumberOfProcessIdsInList); } return bRet; } BOOL CTWProcHelper::QueryBasicUIRestrictions(PDWORD pfdwRestrictions) { JOBOBJECT_BASIC_UI_RESTRICTIONS jobuir; BOOL bRet = QueryInformationJobObject(m_hJob, JobObjectBasicUIRestrictions, &jobuir, sizeof(jobuir), NULL); if (bRet) *pfdwRestrictions = jobuir.UIRestrictionsClass; return(bRet); } BOOL CTWProcHelper::QuerySecurityLimitInfo( PJOBOBJECT_SECURITY_LIMIT_INFORMATION pjosli) { return(QueryInformationJobObject(m_hJob, JobObjectSecurityLimitInformation, pjosli, sizeof(*pjosli), NULL)); } BOOL CTWProcHelper::Terminate(UINT uExitCode) { return(TerminateJobObject(m_hJob, uExitCode)); } BOOL CTWProcHelper::AssociateCompletionPort(HANDLE hIOCP, ULONG_PTR CompKey) { JOBOBJECT_ASSOCIATE_COMPLETION_PORT joacp = { (PVOID) CompKey, hIOCP }; return(SetInformationJobObject(m_hJob, JobObjectAssociateCompletionPortInformation, &joacp, sizeof(joacp))); } BOOL CTWProcHelper::QueryAssociatedCompletionPort (PJOBOBJECT_ASSOCIATE_COMPLETION_PORT pjoacp) { return(QueryInformationJobObject(m_hJob, JobObjectAssociateCompletionPortInformation, pjoacp, sizeof(*pjoacp), NULL)); } void CTWProcHelper::GetProcessName(DWORD PID, PTSTR szProcessName, size_t cchSize) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID); if (hProcess == NULL) { _tcscpy_s(szProcessName, cchSize, TEXT("???")); return; } if (GetModuleFileNameEx(hProcess, (HMODULE)0, szProcessName, cchSize) == 0) { // GetModuleFileNameEx could fail when the address space // is not completely initialized. This occurs when the job // notification happens. // Hopefully, GetProcessImageFileNameW still works even though // the obtained path is more complication to decipher // \Device\HarddiskVolume1\Windows\System32\notepad.exe //if (!GetProcessImageFileName(hProcess, szProcessName, cchSize)) { // _tcscpy_s(szProcessName, cchSize, TEXT("???")); //} DWORD dwSize = (DWORD) cchSize; if(QueryFullProcessImageName(hProcess, 0, szProcessName, &dwSize) == 0) { if (!GetProcessImageFileName(hProcess, szProcessName, cchSize)) { _tcscpy_s(szProcessName, cchSize, TEXT("???")); } } } // but it is easier to call this function instead that works fine // in all situations. // Don't forget to close the process handle CloseHandle(hProcess); } BOOL CTWProcHelper::DestoryProcess(DWORD dwProcessId) { HANDLE hProcess = OpenProcess( PROCESS_SET_QUOTA | PROCESS_TERMINATE, FALSE, dwProcessId); if(hProcess == NULL) { PrintError("The hProcess is null which get from ProcessId"); return FALSE; } BOOL bRet = TerminateProcess(hProcess, 0); if(!bRet) { PrintError("TerminateProcess failed"); } return bRet; } //===== Above is Functions about Job ======================== DWORD CTWProcHelper::ModifyDefaultDacl(HANDLE hProcess) { int i; ACL_SIZE_INFORMATION asi; ACCESS_ALLOWED_ACE *pTempAce; DWORD dwNewAclSize; DWORD dwSize = 0; DWORD dwTokenInfoLength = 0; DWORD dwResult = -1; HANDLE hToken = NULL; PACL pNewAcl = NULL; PSID pEveryoneSID = NULL; SID_IDENTIFIER_AUTHORITY sidAuthWorld = SECURITY_WORLD_SID_AUTHORITY; TOKEN_DEFAULT_DACL tddNew; TOKEN_DEFAULT_DACL *ptdd = NULL; TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl; __try { //获取与进程关联的令牌 if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &hToken)) { dwResult = GetLastError(); __leave; } if (!GetTokenInformation(hToken, tic, (LPVOID)NULL, dwTokenInfoLength, &dwSize)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize); if (ptdd == NULL) { dwResult = GetLastError(); __leave; } //直接获取令牌的缺省 DACL if (!GetTokenInformation(hToken, tic, (LPVOID)ptdd, dwSize, &dwSize)) { dwResult = GetLastError(); __leave; } } else { dwResult = GetLastError(); __leave; } } //获取访问控制列表信息 if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID)&asi, (DWORD)sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) { dwResult = GetLastError(); __leave; } // // Create a well-known SID for the Everyone group. // if (!AllocateAndInitializeSid(&sidAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID)) { dwResult = GetLastError(); __leave; } // // Compute the size of the new ACL. // dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pEveryoneSID) - sizeof(DWORD); // // Allocate buffer for the new ACL. // pNewAcl = (PACL) LocalAlloc(LPTR, dwNewAclSize); if (pNewAcl == NULL) { dwResult = GetLastError(); __leave; } // // Intialize the ACL. // if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) { dwResult = GetLastError(); __leave; } // // Loop through all the ACEs. // 轮询所有的访问控制项 // for (i = 0; i < (int) asi.AceCount; i++) { // // Get current ACE. // if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *)&pTempAce)) { dwResult = GetLastError(); __leave; } // // 添加访问控制项到指定的访问控制列表 // if (!AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize)) { dwResult = GetLastError(); __leave; } } // // 添加任意访问控制项到访问控制项列表的末尾 // if (!AddAccessAllowedAce(pNewAcl, ACL_REVISION, GENERIC_ALL,/*访问权限掩码指定ACE控制的访问权限*/ pEveryoneSID)) { dwResult = GetLastError(); __leave; } // // Set the new Default DACL. // tddNew.DefaultDacl = pNewAcl; if (!SetTokenInformation(hToken, tic, (LPVOID)&tddNew, dwNewAclSize)) { dwResult = GetLastError(); __leave; } dwResult = 0; } __finally { // // Free the buffer for the sid. // if (pEveryoneSID) { FreeSid(pEveryoneSID); } // // Free the buffers. // if (pNewAcl) { LocalFree((HLOCAL)pNewAcl); } if (ptdd) { LocalFree((HLOCAL)ptdd); } // // Close the access token. // if (hToken) { CloseHandle(hToken); } } return dwResult; } BOOL CTWProcHelper::SetPrivilege(LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { HANDLE hToken = NULL; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { PrintError("OpenProcessToken failed"); return FALSE; } return SetPrivilege(hToken, lpszPrivilege, bEnablePrivilege); } BOOL CTWProcHelper::SetPrivilege(HANDLE hToken, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege) { TOKEN_PRIVILEGES tp; LUID luid; if ( !LookupPrivilegeValue( NULL, // lookup privilege on local system lpszPrivilege, // privilege to lookup &luid ) ) // receives LUID of privilege { Dbg("LookupPrivilegeValue error: %u\n", GetLastError() ); return FALSE; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; if (bEnablePrivilege) tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; else tp.Privileges[0].Attributes = 0; // Enable the privilege or disable all privileges. if ( !AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL) ) { Dbg("AdjustTokenPrivileges error: %u\n", GetLastError() ); return FALSE; } if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { Dbg("The token does not have the specified privilege. \n"); return FALSE; } return TRUE; } BOOL CTWProcHelper::CreateLowerProcess(LPTSTR lpCommandLine) { BOOL bResult = 0; HANDLE hToken = NULL; HANDLE hNewToken = NULL; // Low integrity SID CHAR szIntegritySid[20] = "S-1-16-4096"; PSID pIntegritySid = NULL; TOKEN_MANDATORY_LABEL tml = {0}; PROCESS_INFORMATION pi = {0}; STARTUPINFO si = {0}; ULONG exitCode = 0; __try { if (!OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hToken)) __leave; if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) { if (ConvertStringSidToSid(szIntegritySid, &pIntegritySid)) { tml.Label.Attributes = SE_GROUP_INTEGRITY; tml.Label.Sid = pIntegritySid; // Set the process integrity level if (SetTokenInformation(hNewToken, TokenIntegrityLevel, &tml, sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid))) { bResult = CreateProcessAsUser( hNewToken, // access token NULL, // file to execute lpCommandLine, // command line NULL, // pointer to process SECURITY_ATTRIBUTES NULL, // pointer to thread SECURITY_ATTRIBUTES FALSE, // handles are not inheritable 0, // creation flags NULL, // pointer to new environment block NULL, // name of current directory &si, // pointer to STARTUPINFO structure &pi // receives information about new process ); //DWORD dw=GetLastError(); //CHAR ch[100]; //sDbg(ch, "CreateProcessAsUser getlasterror =%d",dw); //MessageBox(NULL,ch,"13",MB_OK); RevertToSelf(); if(bResult) { if (pi.hProcess != INVALID_HANDLE_VALUE) { //WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } if (pi.hThread != INVALID_HANDLE_VALUE) CloseHandle(pi.hThread); } } } } } __finally { if(pIntegritySid) { LocalFree(pIntegritySid); } // // Close the access token. // if (hToken) { CloseHandle(hToken); } if(hNewToken) { CloseHandle(hNewToken); } } return bResult; } BOOL CTWProcHelper::LowerThreadIntegirtyLevel() { if(!ImpersonateSelf(SecurityIdentification)) { PrintError("ImpersonateSelf(SecurityIdentification)"); return FALSE; } return TRUE; HANDLE hToken = NULL; HANDLE hNewToken = NULL; BOOL bResult = FALSE; PSID pEveryoneSID = NULL; SID_IDENTIFIER_AUTHORITY sidManLabel = SECURITY_MANDATORY_LABEL_AUTHORITY; PSID pIntegritySid = NULL; TOKEN_MANDATORY_LABEL tml = { 0 }; __try { //获取与进程关联的令牌 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY, &hToken)) { PrintError("OpenProcessToken failed"); __leave; } // Duplicate the primary token of the current process. if (!DuplicateTokenEx(hToken, 0, NULL, SecurityImpersonation, TokenPrimary, &hNewToken)) { PrintError("DuplicateTokenEx failed"); __leave; } // Create the low integrity SID. if (!AllocateAndInitializeSid(&sidManLabel, 1, SECURITY_MANDATORY_LOW_RID, 0, 0, 0, 0, 0, 0, 0, &pIntegritySid)) { PrintError("AllocateAndInitializeSid failed"); __leave; } tml.Label.Attributes = SE_GROUP_INTEGRITY; tml.Label.Sid = pIntegritySid; // Set the integrity level in the access token to low. if (!SetTokenInformation(hNewToken, TokenIntegrityLevel, &tml, (sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid)))) { PrintError("SetTokenInformation failed"); __leave; } HANDLE hThread = GetCurrentThread(); if (!SetThreadToken(&hThread, hNewToken)) { PrintError("SetThreadToken failed"); __leave; } RevertToSelf(); bResult = TRUE; } __finally { if(pIntegritySid) { LocalFree(pIntegritySid); } // // Close the access token. // if (hToken) { CloseHandle(hToken); } if(hNewToken) { CloseHandle(hNewToken); } } return bResult; } void CTWProcHelper::SetLowLabelToFile(LPCTSTR lpszFileName) { if(lpszFileName == NULL || strlen(lpszFileName) <= 0) return; // The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity #define LOW_INTEGRITY_SDDL_SACL_W "S:(ML;;NW;;;LW)" DWORD dwErr = ERROR_SUCCESS; PSECURITY_DESCRIPTOR pSD = NULL; //SECURITY_MANDATORY_LOW_RID PACL pSacl = NULL; // not allocated BOOL fSaclPresent = FALSE; BOOL fSaclDefaulted = FALSE; CHAR szPath[MAX_PATH] = {0}; _tcscpy_s(szPath, lpszFileName); Dbg("szPath:%s", szPath); if (ConvertStringSecurityDescriptorToSecurityDescriptorA( LOW_INTEGRITY_SDDL_SACL_W, SDDL_REVISION_1, &pSD, NULL)) { //Dbg("enter 1"); if (GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted)) { //Dbg("enter 2"); // Note that psidOwner, psidGroup, and pDacl are // all NULL and set the new LABEL_SECURITY_INFORMATION dwErr = SetNamedSecurityInfoA((LPSTR)szPath, SE_FILE_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl); //Dbg("enter 3: %d.", dwErr); } LocalFree(pSD); } } BOOL CTWProcHelper::GetProcessIntegrityLevel(HANDLE hProcess, PDWORD pIntegrityLevel, PDWORD pPolicy, PDWORD pResourceIntegrityLevel, PDWORD pResourcePolicy) { HANDLE hToken = NULL; if (!OpenProcessToken(hProcess, TOKEN_READ, &hToken)) { return(FALSE); } BOOL bReturn = FALSE; // First, compute the size of the buffer to get the Integrity level DWORD dwNeededSize = 0; if (!GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &dwNeededSize)) { PTOKEN_MANDATORY_LABEL pTokenInfo = NULL; if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { pTokenInfo = (PTOKEN_MANDATORY_LABEL)LocalAlloc(0, dwNeededSize); if (pTokenInfo != NULL) { if (GetTokenInformation(hToken, TokenIntegrityLevel, pTokenInfo, dwNeededSize, &dwNeededSize)) { *pIntegrityLevel = *GetSidSubAuthority( pTokenInfo->Label.Sid, (*GetSidSubAuthorityCount(pTokenInfo->Label.Sid)-1) ); bReturn = TRUE; } LocalFree(pTokenInfo); } } } // Try to get the policy if the integrity level was available if (bReturn) { *pPolicy = TOKEN_MANDATORY_POLICY_OFF; dwNeededSize = sizeof(DWORD); GetTokenInformation(hToken, TokenMandatoryPolicy, pPolicy, dwNeededSize, &dwNeededSize); } // Look for the resource policy *pResourceIntegrityLevel = 0; // 0 means none explicitely set *pResourcePolicy = 0; PACL pSACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; DWORD dwResult = ERROR_SUCCESS; // Look for the no-read-up/no-write-up policy in the SACL if (hToken != NULL) { dwResult = GetSecurityInfo( hProcess, SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSACL, &pSD ); if (dwResult == ERROR_SUCCESS) { if (pSACL != NULL) { SYSTEM_MANDATORY_LABEL_ACE* pACE = NULL; if ((pSACL->AceCount > 0) && (GetAce(pSACL, 0, (PVOID*)&pACE))) { if (pACE != NULL) { SID* pSID = (SID*)(&pACE->SidStart); *pResourceIntegrityLevel = pSID->SubAuthority[0]; *pResourcePolicy = pACE->Mask; } } } } // Cleanup memory allocated on our behalf if (pSD != NULL) LocalFree(pSD); } // Don't forget to close the token handle. CloseHandle(hToken); return(bReturn); } BOOL CTWProcHelper::GetProcessIntegrityLevel(DWORD PID, PDWORD pIntegrityLevel, PDWORD pPolicy, PDWORD pResourceIntegrityLevel, PDWORD pResourcePolicy) { // Sanity checks if ((PID <= 0) || (pIntegrityLevel == NULL)) return(FALSE); // Check if we can get information for this process HANDLE hProcess = OpenProcess( READ_CONTROL | PROCESS_QUERY_INFORMATION, FALSE, PID); if (hProcess == NULL) return(FALSE); BOOL bReturn = GetProcessIntegrityLevel(hProcess, pIntegrityLevel, pPolicy, pResourceIntegrityLevel, pResourcePolicy); // Don't forget to release the process handle CloseHandle(hProcess); return(bReturn); } BOOL CTWProcHelper::CreateSecurityDescriptor() { BOOL bRet = FALSE; DWORD dwRes, dwDisposition; PSID pEveryoneSID = NULL, pAdminSID = NULL; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea[2]; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; SECURITY_ATTRIBUTES sa; LONG lRes; HKEY hkSub = NULL; // Create a well-known SID for the Everyone group. if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID)) { Dbg(_T("AllocateAndInitializeSid Error %u\n"), GetLastError()); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow Everyone read access to the key. ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS)); ea[0].grfAccessPermissions = KEY_READ; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance= NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR) pEveryoneSID; // Create a SID for the BUILTIN\Administrators group. if(! AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID)) { Dbg(_T("AllocateAndInitializeSid Error %u\n"), GetLastError()); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the Administrators group full access to // the key. ea[1].grfAccessPermissions = KEY_ALL_ACCESS; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance= NO_INHERITANCE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = (LPTSTR) pAdminSID; // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(2, ea, NULL, &pACL); if (ERROR_SUCCESS != dwRes) { Dbg(_T("SetEntriesInAcl Error %u\n"), GetLastError()); goto Cleanup; } // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (NULL == pSD) { Dbg(_T("LocalAlloc Error %u\n"), GetLastError()); goto Cleanup; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { Dbg(_T("InitializeSecurityDescriptor Error %u\n"), GetLastError()); goto Cleanup; } // Add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, // bDaclPresent flag pACL, FALSE)) // not a default DACL { Dbg(_T("SetSecurityDescriptorDacl Error %u\n"), GetLastError()); goto Cleanup; } // Initialize a security attributes structure. sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; // Use the security attributes to set the security descriptor // when you create a key. lRes = RegCreateKeyEx(HKEY_CURRENT_USER, _T("TWKey"), 0, _T(""), 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); Dbg(_T("RegCreateKeyEx result %u\n"), lRes ); /* // 运行进程并等待其正常结束 PROCESS_INFORMATION ProcessInfo; STARTUPINFO StartupInfo; ZeroMemory(&StartupInfo, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); if (CreateProcess("c:\\winnt\\notepad.exe", NULL, &sa, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo)) { WaitForSingleObject(ProcessInfo.hProcess, INFINITE); CloseHandle(ProcessInfo.hThread); CloseHandle(ProcessInfo.hProcess); } else { Dbg("CreateProcess failed!\n"); goto Cleanup; } */ if(lRes == ERROR_SUCCESS) bRet = TRUE; Cleanup: if (pEveryoneSID) FreeSid(pEveryoneSID); if (pAdminSID) FreeSid(pAdminSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); if (hkSub) RegCloseKey(hkSub); return bRet; } DWORD CTWProcHelper::AddAceToObjectsSecurityDescriptor( LPTSTR pszObjName, SE_OBJECT_TYPE ObjectType, LPTSTR pszTrustee, TRUSTEE_FORM TrusteeForm, DWORD dwAccessRights, ACCESS_MODE AccessMode, DWORD dwInheritance) { DWORD dwRes = 0; PACL pOldDACL = NULL, pNewDACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea; if (NULL == pszObjName) return ERROR_INVALID_PARAMETER; // Get a pointer to the existing DACL. dwRes = GetNamedSecurityInfo(pszObjName, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD); if (ERROR_SUCCESS != dwRes) { Dbg( "GetNamedSecurityInfo Error %u\n", dwRes ); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for the new ACE. ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = dwAccessRights; ea.grfAccessMode = AccessMode; ea.grfInheritance= dwInheritance; ea.Trustee.TrusteeForm = TrusteeForm; ea.Trustee.ptstrName = pszTrustee; // Create a new ACL that merges the new ACE // into the existing DACL. dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL); if (ERROR_SUCCESS != dwRes) { Dbg( "SetEntriesInAcl Error %u\n", dwRes ); goto Cleanup; } // Attach the new ACL as the object's DACL. dwRes = SetNamedSecurityInfo(pszObjName, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL); if (ERROR_SUCCESS != dwRes) { Dbg( "SetNamedSecurityInfo Error %u\n", dwRes ); goto Cleanup; } Cleanup: if(pSD != NULL) LocalFree((HLOCAL) pSD); if(pNewDACL != NULL) LocalFree((HLOCAL) pNewDACL); return dwRes; } BOOL CTWProcHelper::TakeOwnership(LPTSTR lpszOwnFile) { BOOL bRetval = FALSE; HANDLE hToken = NULL; PSID pSIDAdmin = NULL; PSID pSIDEveryone = NULL; PACL pACL = NULL; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; const int NUM_ACES = 2; EXPLICIT_ACCESS ea[NUM_ACES]; DWORD dwRes; // Specify the DACL to use. // Create a SID for the Everyone group. if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSIDEveryone)) { Dbg("AllocateAndInitializeSid (Everyone) error %u\n", GetLastError()); goto Cleanup; } // Create a SID for the BUILTIN\Administrators group. if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSIDAdmin)) { Dbg("AllocateAndInitializeSid (Admin) error %u\n", GetLastError()); goto Cleanup; } ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS)); // Set read access for Everyone. ea[0].grfAccessPermissions = GENERIC_READ; //指定ACE允许,否认或审查受托人权限的位标志 ea[0].grfAccessMode = SET_ACCESS; //对于DACL, 指定ACL是否允许或者拒绝指定访问权限 ea[0].grfInheritance = NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone; // Set full control for Administrators. ea[1].grfAccessPermissions = GENERIC_ALL; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance = NO_INHERITANCE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin; if (ERROR_SUCCESS != SetEntriesInAcl(NUM_ACES, ea, NULL, &pACL)) { Dbg("Failed SetEntriesInAcl\n"); goto Cleanup; } // Try to modify the object's DACL. dwRes = SetNamedSecurityInfo( lpszOwnFile, // name of the object SE_FILE_OBJECT, // type of object DACL_SECURITY_INFORMATION, // change only the object's DACL NULL, NULL, // do not change owner or group pACL, // DACL specified NULL); // do not change SACL if (ERROR_SUCCESS == dwRes) { Dbg("Successfully changed DACL\n"); bRetval = TRUE; // No more processing needed. goto Cleanup; } if (dwRes != ERROR_ACCESS_DENIED) { Dbg("First SetNamedSecurityInfo call failed: %u\n", dwRes); goto Cleanup; } // If the preceding call failed because access was denied, // enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for // the Administrators group, take ownership of the object, and // disable the privilege. Then try again to set the object's DACL. // Open a handle to the access token for the calling process. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { Dbg("OpenProcessToken failed: %u\n", GetLastError()); goto Cleanup; } // Enable the SE_TAKE_OWNERSHIP_NAME privilege. if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE)) { Dbg("You must be logged on as Administrator.\n"); goto Cleanup; } // Set the owner in the object's security descriptor. dwRes = SetNamedSecurityInfo( lpszOwnFile, // name of the object SE_FILE_OBJECT, // type of object OWNER_SECURITY_INFORMATION, // change only the object's owner pSIDAdmin, // SID of Administrator group NULL, NULL, NULL); if (dwRes != ERROR_SUCCESS) { Dbg("Could not set owner. Error: %u\n", dwRes); goto Cleanup; } // Disable the SE_TAKE_OWNERSHIP_NAME privilege. if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE)) { Dbg("Failed SetPrivilege call unexpectedly.\n"); goto Cleanup; } // Try again to modify the object's DACL, // now that we are the owner. dwRes = SetNamedSecurityInfo( lpszOwnFile, // name of the object SE_FILE_OBJECT, // type of object DACL_SECURITY_INFORMATION, // change only the object's DACL NULL, NULL, // do not change owner or group pACL, // DACL specified NULL); // do not change SACL if (dwRes == ERROR_SUCCESS) { Dbg("Successfully changed DACL\n"); bRetval = TRUE; } else { Dbg("Second SetNamedSecurityInfo call failed: %u\n", dwRes); } Cleanup: if (pSIDAdmin) FreeSid(pSIDAdmin); if (pSIDEveryone) FreeSid(pSIDEveryone); if (pACL) LocalFree(pACL); if (hToken) CloseHandle(hToken); return bRetval; } BOOL CTWProcHelper::FindOwnerOfFile(LPCTSTR lpszOwnFile, LPTSTR lpszOwnerAccount) { DWORD dwRtnCode = 0; PSID pSidOwner = NULL; BOOL bRtnBool = TRUE; LPTSTR AcctName = NULL; LPTSTR DomainName = NULL; DWORD dwAcctName = 1, dwDomainName = 1; SID_NAME_USE eUse = SidTypeUnknown; HANDLE hFile; PSECURITY_DESCRIPTOR pSD = NULL; // Get the handle of the file object. hFile = CreateFile( lpszOwnFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // Check GetLastError for CreateFile error code. if (hFile == INVALID_HANDLE_VALUE) { DWORD dwErrorCode = 0; dwErrorCode = GetLastError(); Dbg(TEXT("CreateFile error = %d\n"), dwErrorCode); return FALSE; } // Get the owner SID of the file. dwRtnCode = GetSecurityInfo( hFile, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION, &pSidOwner, NULL, NULL, NULL, &pSD); // Check GetLastError for GetSecurityInfo error condition. if (dwRtnCode != ERROR_SUCCESS) { DWORD dwErrorCode = 0; dwErrorCode = GetLastError(); Dbg(TEXT("GetSecurityInfo error = %d\n"), dwErrorCode); return FALSE; } // First call to LookupAccountSid to get the buffer sizes. bRtnBool = LookupAccountSid( NULL, // local computer pSidOwner, AcctName, (LPDWORD)&dwAcctName, DomainName, (LPDWORD)&dwDomainName, &eUse); // Reallocate memory for the buffers. AcctName = (LPTSTR)GlobalAlloc( GMEM_FIXED, dwAcctName); // Check GetLastError for GlobalAlloc error condition. if (AcctName == NULL) { DWORD dwErrorCode = 0; dwErrorCode = GetLastError(); Dbg(TEXT("GlobalAlloc error = %d\n"), dwErrorCode); return FALSE; } DomainName = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwDomainName); // Check GetLastError for GlobalAlloc error condition. if (DomainName == NULL) { DWORD dwErrorCode = 0; dwErrorCode = GetLastError(); Dbg(TEXT("GlobalAlloc error = %d\n"), dwErrorCode); return FALSE; } // Second call to LookupAccountSid to get the account name. bRtnBool = LookupAccountSid( NULL, // name of local or remote computer pSidOwner, // security identifier AcctName, // account name buffer (LPDWORD)&dwAcctName, // size of account name buffer DomainName, // domain name (LPDWORD)&dwDomainName, // size of domain name buffer &eUse); // SID type // Check GetLastError for LookupAccountSid error condition. if (bRtnBool == FALSE) { DWORD dwErrorCode = 0; dwErrorCode = GetLastError(); if (dwErrorCode == ERROR_NONE_MAPPED) Dbg(TEXT("Account owner not found for specified SID.\n")); else Dbg(TEXT("Error in LookupAccountSid.\n")); return FALSE; } else if (bRtnBool == TRUE) // Print the account name. sprintf(lpszOwnerAccount, "Account owner = %s", AcctName); return TRUE; } BOOL CTWProcHelper::CustomAccessCheck(LPTSTR lpszFileName) { BOOL bRet = FALSE; DWORD dwAccessDesired = GENERIC_READ | GENERIC_WRITE; GENERIC_MAPPING GenericMapping; PSECURITY_DESCRIPTOR pSD = NULL; if(!GetSecurityDescriptorOfFile(lpszFileName, &pSD)) { PrintError("GetSecurityDescriptorOfFile failed."); if(pSD) TWHeapFree(pSD); return FALSE; } //mapping of generic access types to specific and standard access types //将通用访问类型映射到特定的标准访问类型 //将通用权限控制标志和特定类型对象权限控制标志挂钩,即通用读写的映射,对于文件来说就是FILE_*** GenericMapping.GenericRead = FILE_GENERIC_READ; GenericMapping.GenericWrite = FILE_GENERIC_WRITE; GenericMapping.GenericExecute = FILE_GENERIC_EXECUTE; GenericMapping.GenericAll = FILE_ALL_ACCESS; DWORD dwAccessAllow; bRet = ImpersonateAndCheckAccess(pSD, dwAccessDesired, &GenericMapping, &dwAccessAllow); if(pSD) TWHeapFree(pSD); return bRet; } BOOL CTWProcHelper::GetSecurityDescriptorOfFile(LPCSTR lpszFileName, PSECURITY_DESCRIPTOR *ppSD) { BOOL bRes = FALSE; DWORD dwNeeded = 0; //请求的安全信息类型 SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; bRes = GetFileSecurity(lpszFileName, si, *ppSD, 0, &dwNeeded); if(!bRes) { if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { *ppSD = (PSECURITY_DESCRIPTOR *)TWHeapAlloc(dwNeeded); if(!GetFileSecurity(lpszFileName, si, *ppSD, dwNeeded, &dwNeeded)) { PrintError("GetFileSecurity failed."); return FALSE; } return TRUE; } } return FALSE; } BOOL CTWProcHelper::ImpersonateAndCheckAccess( PSECURITY_DESCRIPTOR pSD, // security descriptor to check DWORD dwAccessDesired, // access rights to check PGENERIC_MAPPING pGeneric, // generic mapping for object PDWORD pdwAccessAllowed // returns allowed access rights ) { HANDLE hToken; HANDLE hImpersonatedToken = NULL; DWORD dwResult = -1; PRIVILEGE_SET PrivilegeSet; DWORD dwPrivSetSize = sizeof( PRIVILEGE_SET ); BOOL fAccessGranted=FALSE; *pdwAccessAllowed = 0; // Get an impersonation token with the client's security context. if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE|TOKEN_QUERY, TRUE, &hToken)) { PrintError("Warning: OpenProcessToken for GetCurrentThread failed."); if (GetLastError() != ERROR_NO_TOKEN) { goto Cleanup; } if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_QUERY, &hToken)) { dwResult = GetLastError(); PrintError("OpenProcessToken for GetCurrentProcess failed."); goto Cleanup; } } if(!DuplicateToken(hToken, SecurityImpersonation, &hImpersonatedToken)) { dwResult = GetLastError(); PrintError("DuplicateToken failed."); goto Cleanup; } // Use the GENERIC_MAPPING structure to convert any // generic access rights to object-specific access rights. // 函数返回后 dwAccessDesired 中无通用占用位和未定义位集 MapGenericMask(&dwAccessDesired, pGeneric); // Check the client's access rights. if( !AccessCheck( pSD, // security descriptor to check hImpersonatedToken, // impersonation token dwAccessDesired, // requested access rights pGeneric, // pointer to GENERIC_MAPPING &PrivilegeSet, // receives privileges used in check &dwPrivSetSize, // size of PrivilegeSet buffer pdwAccessAllowed, // receives mask of allowed access rights &fAccessGranted )) // receives results of access check { dwResult = GetLastError(); if(dwResult == ERROR_INVALID_SECURITY_DESCR ) { PrintError("The security descriptor does not contain owner and group SIDs."); } else { PrintError("AccessCheck failed."); } goto Cleanup; } Cleanup: RevertToSelf(); if (hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken); if (hImpersonatedToken != INVALID_HANDLE_VALUE) CloseHandle(hImpersonatedToken); return fAccessGranted; } BOOL CTWProcHelper::SearchTokenGroupsForSID(VOID) { DWORD i, dwSize = 0, dwResult = 0; HANDLE hToken; PTOKEN_GROUPS pGroupInfo; SID_NAME_USE SidType; char lpName[MAX_NAME]; char lpDomain[MAX_NAME]; PSID pSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY; // Open a handle to the access token for the calling process. if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken )) { Dbg( "OpenProcessToken Error %u\n", GetLastError() ); return FALSE; } // Call GetTokenInformation to get the buffer size. if(!GetTokenInformation(hToken, TokenGroups, NULL, dwSize, &dwSize)) { dwResult = GetLastError(); if( dwResult != ERROR_INSUFFICIENT_BUFFER ) { Dbg( "GetTokenInformation Error %u\n", dwResult ); return FALSE; } } // Allocate the buffer. pGroupInfo = (PTOKEN_GROUPS) GlobalAlloc( GPTR, dwSize ); // Call GetTokenInformation again to get the group information. if(! GetTokenInformation(hToken, TokenGroups, pGroupInfo, dwSize, &dwSize ) ) { Dbg( "GetTokenInformation Error %u\n", GetLastError() ); return FALSE; } // Create a SID for the BUILTIN\Administrators group. if(! AllocateAndInitializeSid( &SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSID) ) { Dbg( "AllocateAndInitializeSid Error %u\n", GetLastError() ); return FALSE; } // Loop through the group SIDs looking for the administrator SID. for(i=0; iGroupCount; i++) { if ( EqualSid(pSID, pGroupInfo->Groups[i].Sid) ) { // Lookup the account name and print it. dwSize = MAX_NAME; if( !LookupAccountSid( NULL, pGroupInfo->Groups[i].Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) ) { dwResult = GetLastError(); if( dwResult == ERROR_NONE_MAPPED ) strcpy_s (lpName, dwSize, "NONE_MAPPED" ); else { Dbg("LookupAccountSid Error %u\n", GetLastError()); return FALSE; } } Dbg( "Current user is a member of the %s\\%s group\n", lpDomain, lpName ); // Find out whether the SID is enabled in the token. if (pGroupInfo->Groups[i].Attributes & SE_GROUP_ENABLED) Dbg("The group SID is enabled.\n"); else if (pGroupInfo->Groups[i].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) Dbg("The group SID is a deny-only SID.\n"); else Dbg("The group SID is not enabled.\n"); } // Loop through the groups to find the logon SID. if ((pGroupInfo->Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID) { DWORD dwLength = GetLengthSid(pGroupInfo->Groups[i].Sid); //*ppsid = (PSID) HeapAlloc(GetProcessHeap(), // HEAP_ZERO_MEMORY, dwLength); //if (*ppsid == NULL) // goto Cleanup; //if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid)) //{ // HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); // goto Cleanup; //} dwSize = MAX_NAME; if( !LookupAccountSid( NULL, pGroupInfo->Groups[i].Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) ) { dwResult = GetLastError(); if( dwResult == ERROR_NONE_MAPPED ) strcpy_s (lpName, dwSize, "NONE_MAPPED" ); else { Dbg("LookupAccountSid Error %u\n", GetLastError()); return FALSE; } } Dbg( "Current logon user is a member of the %s\\%s group\n", lpDomain, lpName ); } } if (pSID) FreeSid(pSID); if ( pGroupInfo ) GlobalFree( pGroupInfo ); return TRUE; } BOOL CTWProcHelper::AddUserAccount() { #ifndef UNICODE #define UNICODE #define NOT_UNICODE_BEFORE #endif BOOL bRet = FALSE; USER_INFO_1 ui; DWORD dwLevel = 1; DWORD dwError = 0; NET_API_STATUS nStatus; // // Set up the USER_INFO_1 structure. // USER_PRIV_USER: name identifies a user, // rather than an administrator or a guest. // UF_SCRIPT: required // ui.usri1_name = L"cmbzephyr"; ui.usri1_password = L"Cmb@1111"; ui.usri1_priv = USER_PRIV_USER; ui.usri1_home_dir = NULL; ui.usri1_comment = L"cmbzephyr"; ui.usri1_flags = UF_SCRIPT|UF_DONT_EXPIRE_PASSWD|UF_PASSWD_CANT_CHANGE; ui.usri1_script_path = NULL; // // Call the NetUserAdd function, specifying level 1. // nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&ui, &dwError); // // If the call succeeds, inform the user. // #ifdef NOT_UNICODE_BEFORE #undef UNICODE #endif if (nStatus == NERR_Success || NERR_UserExists == nStatus) { if(NERR_UserExists == nStatus) { Dbg("User has been added already"); } else { Dbg("User has been successfully added"); } bRet = TRUE; } // // Otherwise, print the system error. // else Dbg("A system error has occurred: %d", nStatus); return bRet; } BOOL CTWProcHelper::AddMemberToGroup() { #ifndef UNICODE #define UNICODE #define NOT_UNICODE_BEFORE #endif BOOL bRet = FALSE; NET_API_STATUS nStatus; DWORD dwLevel = 1; DWORD dwError = 0; LOCALGROUP_MEMBERS_INFO_3 memberInfo = {0}; memberInfo.lgrmi3_domainandname = L"cmbzephyr"; nStatus = NetLocalGroupAddMembers(NULL, L"Users", 3, (LPBYTE)&memberInfo, 1); // // If the call succeeds, inform the user. // #ifdef NOT_UNICODE_BEFORE #undef UNICODE #endif if (nStatus == NERR_Success) { Dbg("User is added to group successfully"); bRet = TRUE; } // // Otherwise, print the system error. // else { if(ERROR_MEMBER_IN_ALIAS == nStatus) { Dbg("The specified account name is already a member of the group."); } else { Dbg("A system error has occurred: %d", nStatus); } } return bRet; } //winlogon.exe BOOL CTWProcHelper::GetTokenByName(HANDLE &hToken, LPSTR lpName) { if(!lpName) { return FALSE; } HANDLE hProcessSnap = NULL; BOOL bRet = FALSE; PROCESSENTRY32 pe32 = {0}; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return (FALSE); pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hProcessSnap, &pe32)) { do { if(!strcmp(_strupr(pe32.szExeFile), _strupr(lpName))) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); bRet = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken); CloseHandle (hProcessSnap); return (bRet); } } while (Process32Next(hProcessSnap, &pe32)); } CloseHandle (hProcessSnap); return (bRet); } BOOL CTWProcHelper::CreateSystemProcess(LPTSTR szProcessName) { HANDLE hProcess; HANDLE hToken, hNewToken; PACL pOldDAcl = NULL; PACL pNewDAcl = NULL; BOOL bDAcl; BOOL bDefDAcl; DWORD dwRet; PACL pSacl = NULL; PSID pSidOwner = NULL; PSID pSidPrimary = NULL; DWORD dwAclSize = 0; DWORD dwSaclSize = 0; DWORD dwSidOwnLen = 0; DWORD dwSidPrimLen = 0; DWORD dwSDLen; EXPLICIT_ACCESS ea; PSECURITY_DESCRIPTOR pOrigSd = NULL; PSECURITY_DESCRIPTOR pNewSd = NULL; STARTUPINFO si; PROCESS_INFORMATION pi; BOOL bError; // Get the current process - IEExplore.exe hProcess = GetCurrentProcess(); // Open IE process token and specify the access types to IE token if ( !OpenProcessToken( hProcess, READ_CONTROL | WRITE_DAC, &hToken ) ) { Dbg( "OpenProcessToken() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } // Create a new access control information that includes all access permissions. ZeroMemory( &ea, sizeof( EXPLICIT_ACCESS ) ); BuildExplicitAccessWithName( &ea, "CURRENT_USER", // Note: if you specified other trustee name, it would fail at subsequent code TOKEN_ALL_ACCESS, GRANT_ACCESS, 0 ); if ( !GetKernelObjectSecurity( hToken, DACL_SECURITY_INFORMATION, pOrigSd, 0, &dwSDLen ) ) { // We first get the length of original security descriptor to IE token if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { pOrigSd = ( PSECURITY_DESCRIPTOR ) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSDLen ); if ( pOrigSd == NULL ) { Dbg( "Allocate pSd memory to failed!\n" ); bError = TRUE; goto Cleanup; } if ( !GetKernelObjectSecurity( hToken, DACL_SECURITY_INFORMATION, pOrigSd, dwSDLen, &dwSDLen ) ) { Dbg( "GetKernelObjectSecurity() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } } else { Dbg( "GetKernelObjectSecurity() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } } // Getting ACL of original security descriptor if ( !GetSecurityDescriptorDacl( pOrigSd, &bDAcl, &pOldDAcl, &bDefDAcl ) ) { Dbg( "GetSecurityDescriptorDacl() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } // Using the created access control information - EXPLICIT_ACCESS, // and the original ACL to generate a new ACL dwRet = SetEntriesInAcl( 1, &ea, pOldDAcl, &pNewDAcl ); if ( dwRet != ERROR_SUCCESS ) { Dbg( "SetEntriesInAcl() = %d\n", GetLastError() ); pNewDAcl = NULL; bError = TRUE; goto Cleanup; } // Create a new security descriptor that refers // to original security descriptor. if ( !MakeAbsoluteSD( pOrigSd, pNewSd, &dwSDLen, pOldDAcl, &dwAclSize, pSacl, &dwSaclSize, pSidOwner, &dwSidOwnLen, pSidPrimary, &dwSidPrimLen ) ) { if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { pOldDAcl = ( PACL ) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwAclSize ); pSacl = ( PACL ) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSaclSize ); pSidOwner = ( PSID ) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSidOwnLen ); pSidPrimary = ( PSID ) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSidPrimLen ); pNewSd = ( PSECURITY_DESCRIPTOR ) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSDLen ); if ( pOldDAcl == NULL || pSacl == NULL || pSidOwner == NULL || pSidPrimary == NULL || pNewSd == NULL ) { Dbg( "Allocate SID or ACL to failed!\n" ); bError = TRUE; goto Cleanup; } if ( !MakeAbsoluteSD( pOrigSd, pNewSd, &dwSDLen, pOldDAcl, &dwAclSize, pSacl, &dwSaclSize, pSidOwner, &dwSidOwnLen, pSidPrimary, &dwSidPrimLen ) ) { Dbg( "MakeAbsoluteSD() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } } else { Dbg( "MakeAbsoluteSD() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } } // Well, we have owned a new security descriptor & a new ACL, // all we have to do is fetch the new ACL into the new security descriptor! if ( !SetSecurityDescriptorDacl( pNewSd, bDAcl, pNewDAcl, bDefDAcl ) ) { Dbg( "SetSecurityDescriptorDacl() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } // // Injects the new security descriptor into IE token // if ( !SetKernelObjectSecurity( hToken, DACL_SECURITY_INFORMATION, pNewSd ) ) { Dbg( "SetKernelObjectSecurity() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } // // When we open IE process again, the hToken has all access permissions. // if ( !OpenProcessToken( hProcess, TOKEN_ALL_ACCESS, &hToken ) ) { Dbg( "OpenProcessToken() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } // // Then, make a duplicate from IE token // if ( !DuplicateTokenEx( hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &hNewToken ) ) { Dbg( "DuplicateTokenEx() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } ZeroMemory( &si, sizeof( STARTUPINFO ) ); si.cb = sizeof( STARTUPINFO ); // Now, we impersonate the security context of a // logged-on user using the token. // Note: if you didn't, the below CreateProcessAsUser // will report 1314 no permission error. ImpersonateLoggedOnUser( hNewToken ); // Finally, we use the token to create new process. if ( !CreateProcessAsUser( hNewToken, NULL, szProcessName, NULL, NULL, FALSE, NULL, //NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi) ) { Dbg( "CreateProcessAsUser() = %d\n", GetLastError() ); bError = TRUE; goto Cleanup; } bError = FALSE; Cleanup: if ( pOrigSd ) { HeapFree( GetProcessHeap(), 0, pOrigSd ); } if ( pNewSd ) { HeapFree( GetProcessHeap(), 0, pNewSd ); } if ( pSidPrimary ) { HeapFree( GetProcessHeap(), 0, pSidPrimary ); } if ( pSidOwner ) { HeapFree( GetProcessHeap(), 0, pSidOwner ); } if ( pSacl ) { HeapFree( GetProcessHeap(), 0, pSacl ); } if ( pOldDAcl ) { HeapFree( GetProcessHeap(), 0, pOldDAcl ); } if (!bError) { CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); CloseHandle( hToken ); CloseHandle( hNewToken ); CloseHandle( hProcess ); } if ( bError ) { return FALSE; } return TRUE; } BOOL CTWProcHelper::GetPrivilegeLUIDWithSID(PSID pSID, PLUID *pLUID, PDWORD pDwCount) { LOG_FUNCTION(); LSA_OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS ntsResult; LSA_HANDLE lsahPolicyHandle; // Object attributes are reserved, so initialize to zeros. ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes)); // Get a handle to the Policy object. ntsResult = LsaOpenPolicy( NULL, //Name of the target system. &ObjectAttributes, //Object attributes. POLICY_ALL_ACCESS, //Desired access permissions. &lsahPolicyHandle //Receives the policy handle. ); if (ntsResult != STATUS_SUCCESS) { Dbg("OpenPolicy failed returned %lu", LsaNtStatusToWinError(ntsResult)); return FALSE; } PLSA_UNICODE_STRING UserRights = NULL; ULONG uRightCount; ntsResult = LsaEnumerateAccountRights(lsahPolicyHandle, pSID, &UserRights, &uRightCount); if (ntsResult != STATUS_SUCCESS) { Dbg("LsaEnumerateAccountRights failed returned %lu", LsaNtStatusToWinError(ntsResult)); LsaClose(lsahPolicyHandle); return FALSE; } Dbg("LsaEnumerateAccountRights returned Right count: %lu", uRightCount); (*pDwCount) = 0; //pLUID = (PLUID)HeapAlloc(GetProcessHeap(), 0, uRightCount*sizeof(LUID)); (*pLUID) = (PLUID)LocalAlloc(LPTR, uRightCount*sizeof(LUID)); if((*pLUID) == NULL) { Dbg("HeapAlloc for PLUID failed returned %u", GetLastError()); LsaClose(lsahPolicyHandle); return FALSE; } for(ULONG uIdx=0; UserRights != NULL && uIdxhStdError; si.hStdOutput = psi->hStdOutput; si.hStdInput = psi->hStdInput; si.dwFlags = psi->dwFlags; si.wShowWindow = psi->wShowWindow; // Launch the process in the client's logon session. bResult = CreateProcessAsUser( hToken, // client's access token NULL, // file to execute lpCommandLine, // command line NULL, // pointer to process SECURITY_ATTRIBUTES NULL, // pointer to thread SECURITY_ATTRIBUTES FALSE, // handles are not inheritable fdwCreate, // creation flags NULL, // pointer to new environment block NULL, // name of current directory &si, // pointer to STARTUPINFO structure &pi // receives information about new process ); // End impersonation of client. RevertToSelf(); if (bResult && pi.hProcess != INVALID_HANDLE_VALUE) { //WaitForSingleObject(pi.hProcess, INFINITE); if((fdwCreate & CREATE_SUSPENDED) == CREATE_SUSPENDED) { *pDwProcessId = pi.dwProcessId; ResumeThread(pi.hThread); } CloseHandle(pi.hProcess); } else { Dbg("CreateProcessAsUser failed GLE=%u.", GetLastError()); } if (pi.hThread != INVALID_HANDLE_VALUE) CloseHandle(pi.hThread); Cleanup: if (hwinstaSave != NULL) SetProcessWindowStation (hwinstaSave); // Free the buffer for the logon SID. if (pSid) FreeLogonSID(&pSid); // Close the handles to the interactive window station and desktop. if (hwinsta) CloseWindowStation(hwinsta); if (hdesk) CloseDesktop(hdesk); // Close the handle to the client's access token. if (hToken != INVALID_HANDLE_VALUE) CloseHandle(hToken); return bResult; } BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid) { ACCESS_ALLOWED_ACE *pace = NULL; ACL_SIZE_INFORMATION aclSizeInfo; BOOL bDaclExist; BOOL bDaclPresent; BOOL bSuccess = FALSE; DWORD dwNewAclSize; DWORD dwSidSize = 0; DWORD dwSdSizeNeeded; PACL pacl; PACL pNewAcl = NULL; PSECURITY_DESCRIPTOR psd = NULL; PSECURITY_DESCRIPTOR psdNew = NULL; PVOID pTempAce; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; unsigned int i; __try { // Obtain the DACL for the window station. if (!GetUserObjectSecurity( hwinsta, &si, psd, dwSidSize, &dwSdSizeNeeded) ) if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { psd = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded); if (psd == NULL) __leave; psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded); if (psdNew == NULL) __leave; dwSidSize = dwSdSizeNeeded; if (!GetUserObjectSecurity( hwinsta, &si, psd, dwSidSize, &dwSdSizeNeeded) ) __leave; } else __leave; // Create a new DACL. if (!InitializeSecurityDescriptor( psdNew, SECURITY_DESCRIPTOR_REVISION) ) __leave; // Get the DACL from the security descriptor. if (!GetSecurityDescriptorDacl( psd, &bDaclPresent, &pacl, &bDaclExist) ) __leave; // Initialize the ACL. ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION)); aclSizeInfo.AclBytesInUse = sizeof(ACL); // Call only if the DACL is not NULL. if (pacl != NULL) { // get the file ACL size info if (!GetAclInformation( pacl, (LPVOID)&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation) ) __leave; } // Compute the size of the new ACL. dwNewAclSize = aclSizeInfo.AclBytesInUse + (2*sizeof(ACCESS_ALLOWED_ACE)) + (2*GetLengthSid(psid)) - (2*sizeof(DWORD)); // Allocate memory for the new ACL. pNewAcl = (PACL)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwNewAclSize); if (pNewAcl == NULL) __leave; // Initialize the new DACL. if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) __leave; // If DACL is present, copy it to a new DACL. if (bDaclPresent) { // Copy the ACEs to the new ACL. if (aclSizeInfo.AceCount) { for (i=0; i < aclSizeInfo.AceCount; i++) { // Get an ACE. if (!GetAce(pacl, i, &pTempAce)) __leave; // Add the ACE to the new ACL. if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize) ) __leave; } } } // Add the first ACE to the window station. pace = (ACCESS_ALLOWED_ACE *)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD)); if (pace == NULL) __leave; pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE; pace->Header.AceFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE; pace->Header.AceSize = LOWORD(sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD)); pace->Mask = GENERIC_ACCESS; if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid)) __leave; if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, (LPVOID)pace, pace->Header.AceSize) ) __leave; // Add the second ACE to the window station. pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE; pace->Mask = WINSTA_ALL; if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, (LPVOID)pace, pace->Header.AceSize) ) __leave; // Set a new DACL for the security descriptor. if (!SetSecurityDescriptorDacl( psdNew, TRUE, pNewAcl, FALSE) ) __leave; // Set the new security descriptor for the window station. if (!SetUserObjectSecurity(hwinsta, &si, psdNew)) __leave; // Indicate success. bSuccess = TRUE; } __finally { // Free the allocated buffers. if (pace != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pace); if (pNewAcl != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl); if (psd != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psd); if (psdNew != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew); } return bSuccess; } BOOL GetLogonSID (HANDLE hToken, PSID *ppsid) { BOOL bSuccess = FALSE; DWORD dwIndex; DWORD dwLength = 0; PTOKEN_GROUPS ptg = NULL; // Verify the parameter passed in is not NULL. if (NULL == ppsid) goto Cleanup; // Get required buffer size and allocate the TOKEN_GROUPS buffer. if (!GetTokenInformation( hToken, // handle to the access token TokenGroups, // get information about the token's groups (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer 0, // size of buffer &dwLength // receives required buffer size )) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto Cleanup; ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); if (ptg == NULL) goto Cleanup; } // Get the token group information from the access token. if (!GetTokenInformation( hToken, // handle to the access token TokenGroups, // get information about the token's groups (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer dwLength, // size of buffer &dwLength // receives required buffer size )) { goto Cleanup; } // Loop through the groups to find the logon SID. for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID) { // Found the logon SID; make a copy of it. dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid); *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); if (*ppsid == NULL) goto Cleanup; if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid)) { HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); goto Cleanup; } break; } bSuccess = TRUE; Cleanup: // Free the buffer for the token groups. if (ptg != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)ptg); return bSuccess; } VOID FreeLogonSID (PSID *ppsid) { HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); } BOOL AddAceToDesktop(HDESK hdesk, PSID psid) { ACL_SIZE_INFORMATION aclSizeInfo; BOOL bDaclExist; BOOL bDaclPresent; BOOL bSuccess = FALSE; DWORD dwNewAclSize; DWORD dwSidSize = 0; DWORD dwSdSizeNeeded; PACL pacl; PACL pNewAcl = NULL; PSECURITY_DESCRIPTOR psd = NULL; PSECURITY_DESCRIPTOR psdNew = NULL; PVOID pTempAce; SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION; unsigned int i; __try { // Obtain the security descriptor for the desktop object. if (!GetUserObjectSecurity( hdesk, &si, psd, dwSidSize, &dwSdSizeNeeded)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { psd = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded ); if (psd == NULL) __leave; psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSdSizeNeeded); if (psdNew == NULL) __leave; dwSidSize = dwSdSizeNeeded; if (!GetUserObjectSecurity( hdesk, &si, psd, dwSidSize, &dwSdSizeNeeded) ) __leave; } else __leave; } // Create a new security descriptor. if (!InitializeSecurityDescriptor( psdNew, SECURITY_DESCRIPTOR_REVISION) ) __leave; // Obtain the DACL from the security descriptor. if (!GetSecurityDescriptorDacl( psd, &bDaclPresent, &pacl, &bDaclExist) ) __leave; // Initialize. ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION)); aclSizeInfo.AclBytesInUse = sizeof(ACL); // Call only if NULL DACL. if (pacl != NULL) { // Determine the size of the ACL information. if (!GetAclInformation( pacl, (LPVOID)&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation) ) __leave; } // Compute the size of the new ACL. dwNewAclSize = aclSizeInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - sizeof(DWORD); // Allocate buffer for the new ACL. pNewAcl = (PACL)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwNewAclSize); if (pNewAcl == NULL) __leave; // Initialize the new ACL. if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION)) __leave; // If DACL is present, copy it to a new DACL. if (bDaclPresent) { // Copy the ACEs to the new ACL. if (aclSizeInfo.AceCount) { for (i=0; i < aclSizeInfo.AceCount; i++) { // Get an ACE. if (!GetAce(pacl, i, &pTempAce)) __leave; // Add the ACE to the new ACL. if (!AddAce( pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER)pTempAce)->AceSize) ) __leave; } } } // Add ACE to the DACL. if (!AddAccessAllowedAce( pNewAcl, ACL_REVISION, DESKTOP_ALL, psid) ) __leave; // Set new DACL to the new security descriptor. if (!SetSecurityDescriptorDacl( psdNew, TRUE, pNewAcl, FALSE) ) __leave; // Set the new security descriptor for the desktop object. if (!SetUserObjectSecurity(hdesk, &si, psdNew)) __leave; // Indicate success. bSuccess = TRUE; } __finally { // Free buffers. if (pNewAcl != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl); if (psd != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psd); if (psdNew != NULL) HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew); } return bSuccess; }