Created
February 20, 2024 14:19
-
-
Save jun-lsh/5e8e1a3558c3ae86cd3e443344c81278 to your computer and use it in GitHub Desktop.
A Naive Implementation of the Magistr/Shoerec Payload
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <Windows.h> | |
| #include <ExDisp.h> | |
| #include <atlbase.h> | |
| #include <Shlwapi.h> | |
| #include <atlalloc.h> | |
| #include <ShlObj.h> | |
| #include <cmath> | |
| #include <vector> | |
| #include <algorithm> | |
| #include <string> | |
| #include <Psapi.h> | |
| #include <RestartManager.h> | |
| #pragma comment(lib, "Rstrtmgr.lib") | |
| #define DESKTOP_KEY L"SOFTWARE\\Microsoft\\Windows\\Shell\\Bags\\1\\Desktop" | |
| class CCoInitialize { | |
| public: | |
| CCoInitialize() : m_hr(CoInitialize(NULL)) { } | |
| ~CCoInitialize() { if (SUCCEEDED(m_hr)) CoUninitialize(); } | |
| operator HRESULT() const { return m_hr; } | |
| HRESULT m_hr; | |
| }; | |
| RM_UNIQUE_PROCESS GetExplorerApplication() | |
| { | |
| RM_UNIQUE_PROCESS result = { 0 }; | |
| DWORD bytesReturned = 0; | |
| DWORD processIdSize = 4096; | |
| std::vector<DWORD> processIds; | |
| processIds.resize(1024); | |
| // Get the list of process identifiers. | |
| EnumProcesses(processIds.data(), processIdSize, &bytesReturned); | |
| while (bytesReturned == processIdSize) | |
| { | |
| processIdSize += processIdSize; | |
| processIds.resize(processIdSize / 4); | |
| EnumProcesses(processIds.data(), processIdSize, &bytesReturned); | |
| } | |
| std::for_each(processIds.begin(), processIds.end(), [&result](DWORD processId) { | |
| HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId); | |
| if (hProcess) { | |
| std::wstring imageName; | |
| imageName.resize(4096); | |
| if (GetProcessImageFileName(hProcess, (LPWSTR)imageName.data(), 4096) > 0) | |
| { | |
| if (wcscmp(L"explorer.exe", PathFindFileName(imageName.data())) == 0) | |
| { | |
| //this is assmuing the user is not running elevated and won't see explorer processes in other sessions | |
| FILETIME ftCreate, ftExit, ftKernel, ftUser; | |
| if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) | |
| { | |
| if (result.dwProcessId == 0) | |
| { | |
| result.dwProcessId = processId; | |
| result.ProcessStartTime = ftCreate; | |
| } | |
| // we opt for the older process | |
| else if (CompareFileTime(&result.ProcessStartTime, &ftCreate) > 0) | |
| { | |
| result.dwProcessId = processId; | |
| result.ProcessStartTime = ftCreate; | |
| } | |
| } | |
| } | |
| } | |
| CloseHandle(hProcess); | |
| } | |
| }); | |
| return result; | |
| } | |
| bool FindDesktopFolderView(REFIID riid, void** ppv) | |
| { | |
| // All open shell windows (explorer windows) | |
| CComPtr<IShellWindows> spShellWindows; | |
| // Class ID: CLSID, Interface ID: IID | |
| // | |
| // To get the explorer windows, we use CoCreateInstance, which creates an object of the class associated with the CLSID and IID | |
| // To get all shell windows: hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_IShellWindows, (void**) &psw); | |
| // CLSCTX_ALL means we're fine with all contexts | |
| HRESULT hResult = spShellWindows.CoCreateInstance(CLSID_ShellWindows); | |
| if (hResult != S_OK) return false; | |
| // CSIDLs are "constant special item ID list", a unique system-independent way to ID special folders | |
| // In the docs, the example given is C:\Windows. Turns out, you can name it whatever the hell you want | |
| // CSIDL_DESKTOP is the virtual folder that represents the desktop. | |
| //CComVariant vtLoc(CSIDL_DESKTOP); | |
| CComVariant vtLoc(CSIDL_DESKTOP); | |
| CComVariant vtEmpty; | |
| long lhwnd; | |
| CComPtr<IDispatch> spdisp; | |
| // Finds a window in the Shell collection, returns the handle and IDispatch interface | |
| // https://learn.microsoft.com/en-us/windows/win32/api/exdisp/nf-exdisp-ishellwindows-findwindowsw | |
| // we set swClass to SWC_DESKTOP so that we are only looking at... desktop windows | |
| // lhwnd is the corresponding handle, but what we really want is spdisp, the IDispatch interface | |
| hResult = spShellWindows->FindWindowSW ( | |
| &vtLoc, &vtEmpty, | |
| SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp); | |
| if (hResult != S_OK) return false; | |
| // IShellBrowser gives us some helpful methods, and the one we want is QueryActiveShellView. Quite self-explanatory | |
| // https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ishellbrowser-queryactiveshellview | |
| CComPtr<IShellBrowser> spBrowser; | |
| // CComQIPtr is a smart pointer class and we use the QueryService method to get a reference to the browser | |
| // | |
| // "Objects that have access to the site chain of the browser can get a reference to the browser on IShellBrowser | |
| // using IServiceProvider::QueryService, with Service IDs such as SID_STopLevelBrowser and SID_SCommDlgBrowser." | |
| hResult = CComQIPtr<IServiceProvider>(spdisp)-> | |
| QueryService(SID_STopLevelBrowser, // GUID for the browser | |
| IID_PPV_ARGS(&spBrowser)); | |
| if (hResult != S_OK) return false; | |
| CComPtr<IShellView> spView; | |
| hResult = spBrowser->QueryActiveShellView(&spView); | |
| if (hResult != S_OK) return false; | |
| // Lastly, we can apply QueryInterface to get our interface of choice from the Desktop object by passing in an RIID | |
| hResult = spView->QueryInterface(riid, ppv); | |
| if (hResult != S_OK) return false; | |
| return true; | |
| } | |
| void RestartExplorer() { | |
| DWORD dwSession = 0; | |
| WCHAR szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 }; | |
| // create a Restart Manager session | |
| DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey); | |
| if (dwError == ERROR_SUCCESS) { | |
| // isolate the explorer process | |
| RM_UNIQUE_PROCESS rgApplications[1] = { GetExplorerApplication() }; | |
| dwError = RmRegisterResources(dwSession, 0, NULL, 1, rgApplications, 0, NULL); | |
| DWORD dwReason; | |
| UINT nProcInfoNeeded; | |
| UINT nProcInfo = 10; | |
| RM_PROCESS_INFO rgpi[10]; | |
| // get the current status of registered items | |
| dwError = RmGetList(dwSession, &nProcInfoNeeded, | |
| &nProcInfo, rgpi, &dwReason); | |
| if (dwReason == RmRebootReasonNone) //now free to restart explorer | |
| { | |
| RmShutdown(dwSession, RmForceShutdown, NULL); | |
| RmRestart(dwSession, 0, NULL); | |
| } | |
| } | |
| RmEndSession(dwSession); | |
| } | |
| // out of laziness, we copy and paste and overload this function. | |
| void RestartExplorer(HKEY hKey, DWORD target) { | |
| DWORD dwSession = 0; | |
| WCHAR szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 }; | |
| // create a Restart Manager session | |
| DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey); | |
| if (dwError == ERROR_SUCCESS) { | |
| // isolate the explorer process | |
| RM_UNIQUE_PROCESS rgApplications[1] = { GetExplorerApplication() }; | |
| dwError = RmRegisterResources(dwSession, 0, NULL, 1, rgApplications, 0, NULL); | |
| DWORD dwReason; | |
| UINT nProcInfoNeeded; | |
| UINT nProcInfo = 10; | |
| RM_PROCESS_INFO rgpi[10]; | |
| // get the current status of registered items | |
| dwError = RmGetList(dwSession, &nProcInfoNeeded, | |
| &nProcInfo, rgpi, &dwReason); | |
| if (dwReason == RmRebootReasonNone) //now free to restart explorer | |
| { | |
| RmShutdown(dwSession, RmForceShutdown, NULL); | |
| RegSetValueEx(hKey, L"FFlags", NULL, REG_DWORD, (const BYTE*)&target, sizeof(target)); | |
| RmRestart(dwSession, 0, NULL); | |
| } | |
| } | |
| RmEndSession(dwSession); | |
| } | |
| int __cdecl wmain(int argc, wchar_t** argv) | |
| { | |
| FreeConsole(); | |
| // wtf is CCoInitialize? | |
| // it ensures CoUnitialize is called after your CCom ptrs are destroyed | |
| // https://devblogs.microsoft.com/oldnewthing/20040520-00/?p=39243 | |
| CCoInitialize init; | |
| RestartExplorer(); | |
| Sleep(2000); | |
| // Using our function, we get a reference to the desktop's IFolderView | |
| CComPtr<IFolderView> spView; | |
| while(!FindDesktopFolderView(IID_PPV_ARGS(&spView))); | |
| // The IShellFolder object will let us get attributes to do with the files in the folder | |
| CComPtr<IShellFolder> spFolder; | |
| spView->GetFolder(IID_PPV_ARGS(&spFolder)); | |
| POINT cursor_pt; | |
| int pushRad = 125; | |
| DWORD desktopFflags{}; | |
| DWORD pcbData = sizeof(desktopFflags); | |
| WCHAR targetFlag[11]; | |
| swprintf_s(targetFlag, 11, L"%d", 1075839520); | |
| DWORD target = 1075839520; | |
| HKEY hKey = NULL; | |
| RegOpenKeyExW(HKEY_CURRENT_USER, DESKTOP_KEY, 0, KEY_WRITE, &hKey); | |
| RegGetValue(HKEY_CURRENT_USER, DESKTOP_KEY, L"FFlags", RRF_RT_REG_DWORD, NULL, &desktopFflags, &pcbData); | |
| wprintf(L"Regvalue: %d %d\n", desktopFflags, pcbData); | |
| if (desktopFflags != target) { | |
| wprintf(L"Changed the regkey!\n"); | |
| RestartExplorer(hKey, target); | |
| RegCloseKey(hKey); | |
| } | |
| wprintf(L"Continuing...\n"); | |
| Sleep(2000); | |
| while (true) { | |
| if (GetCursorPos(&cursor_pt)) | |
| { | |
| CComPtr<IEnumIDList> spEnum; | |
| // Items lets us enumerate across... the items. | |
| // SVGIO is a flag here that just says gimme everything! | |
| // "Used with the IFolderView::Items, IFolderView::ItemCount, and IShellView::GetItemObject methods to restrict or control the items in their collections." | |
| HRESULT hResult = spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum)); | |
| if (hResult != S_OK) { | |
| // for posterity | |
| spView.Release(); | |
| spFolder.Release(); | |
| if (FindDesktopFolderView(IID_PPV_ARGS(&spView))) { | |
| spView->GetFolder(IID_PPV_ARGS(&spFolder)); | |
| } | |
| } | |
| else { | |
| // Now we iterate through the objects | |
| for (CComHeapPtr<ITEMID_CHILD> spidl; | |
| spEnum->Next(1, &spidl, nullptr) == S_OK; | |
| spidl.Free()) { | |
| POINT icon_pt; | |
| spView->GetItemPosition(spidl, &icon_pt); // This gives us the coordinates of the icons! | |
| // Check if our icon is within the cursor's forcefield radius | |
| double distance = pow(((icon_pt.x + 38 - 1920) - cursor_pt.x), 2) + pow(((icon_pt.y + 54) - cursor_pt.y), 2); | |
| // wprintf(L"Icon is %d %d away\n", (icon_pt.x - cursor_pt.x), (icon_pt.y - cursor_pt.y)); | |
| if (distance <= pushRad * pushRad) { | |
| double multiplier = pushRad / sqrt((distance)) - 1; | |
| icon_pt.x += (int)(((icon_pt.x + 38 - 1920) - cursor_pt.x) * multiplier); | |
| icon_pt.y += (int)(((icon_pt.y + 54) - cursor_pt.y) * multiplier); | |
| } | |
| PCITEMID_CHILD apidl[1] = { spidl }; | |
| spView->SelectAndPositionItems( | |
| 1, apidl, &icon_pt, SVSI_POSITIONITEM | |
| ); | |
| } | |
| } | |
| } | |
| } | |
| return 0; | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment