Creating "Ransomware" Using WinRT
This isn't ransomware.
This is the blueprint for a ransomware testing payload for a "Purple Team" scenario. I am curious of EDR visibility into WinRT (Universal Windows Platform (UWP) apps) — so I crafted a C++ application, which strictly uses WinRT functionality from WINAPI-like-C++, compiled as a WIN32 app, to see how it looks.
This proof-of-concept is essentially a glorified asychronous file string console printer. What makes it unique is it relying entirely on WinRT from a Win32 app.
WinRT possesses the ability to encrypt files. I opted to not introduce file encryption functionality (although it would be bare-bones, plain password protected) into this proof-of-concept because I think ransomware in general is highly susceptible to abuse even in its most basic forms.
Regardless, I think this code is interesting and I wanted to share it. Maybe it'll inspire someone else to review WinRT more, or someone will pick up this code and experiment with it in an enterprise environment. - smelly smellington
#include <windows.h>
#include <stdio.h>
#include <roapi.h>
#include <windows.storage.h>
#include <windows.storage.search.h>
#include <windows.foundation.h>
#include <windows.system.threading.h>
#pragma comment(lib, "runtimeobject.lib")
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Storage::Search;
using namespace ABI::Windows::System::Threading;
using namespace ABI::Windows::Foundation;
typedef __FIAsyncOperation_1___FIVectorView_1_Windows__CStorage__CIStorageItem IAsyncOperationOfFiles;
typedef __FIVectorView_1_Windows__CStorage__CIStorageItem IAsyncItems;
class ThreadFileProcessor : public IWorkItemHandler {
public:
ThreadFileProcessor(IStorageItem* FileObject) : ReferenceCount(1), File(FileObject)
{
if (File)
File->AddRef();
}
virtual ~ThreadFileProcessor()
{
if (File)
File->Release();
}
HRESULT __stdcall QueryInterface(REFIID Riid, PVOID* ppv)
{
if (!ppv)
return E_POINTER;
if (Riid == __uuidof(IUnknown) || Riid == __uuidof(IWorkItemHandler))
{
*ppv = (IWorkItemHandler*)this;
AddRef();
return S_OK;
}
*ppv = NULL;
return E_NOINTERFACE;
}
ULONG __stdcall AddRef() { return InterlockedIncrement(&ReferenceCount); }
ULONG __stdcall Release()
{
ULONG Result = _InterlockedDecrement(&ReferenceCount);
if (Result == 0)
delete this;
return Result;
}
HRESULT __stdcall Invoke(IAsyncAction* Action)
{
HSTRING FileName = NULL;
HRESULT Result = S_OK;
if (!File)
return E_ABORT;
Result = File->get_Name(&FileName);
if (SUCCEEDED(Result))
{
UINT32 Length = 0;
LPCWSTR Buffer = NULL;
Buffer = WindowsGetStringRawBuffer(FileName, &Length);
printf("File processing: %ws\r\n", Buffer);
}
if (FileName)
WindowsDeleteString(FileName);
if (File)
File->Release();
return S_OK;
}
private:
LONG ReferenceCount;
IStorageItem* File;
};
SIZE_T StringLengthW(_In_ LPCWSTR String)
{
LPCWSTR String2;
for (String2 = String; *String2; ++String2);
return (String2 - String);
}
INT main(VOID)
{
HRESULT Result = S_OK;
IKnownFoldersStatics* KnownFolders = NULL;
IStorageFolder* DocumentsFolder = NULL;
IInspectable* Inspectable = NULL;
IQueryOptions* Options = NULL;
IStorageItemQueryResult* ItemResult = NULL;
IStorageFolderQueryOperations* Operation = NULL;
IAsyncOperationOfFiles* AsyncOperation = NULL;
IAsyncItems* Items = NULL;
IAsyncInfo* Information = NULL;
IThreadPoolStatics* ThreadPoolStatics = NULL;
WCHAR StorageString[] = L"Windows.Storage.KnownFolders";
WCHAR QueryString[] = L"Windows.Storage.Search.QueryOptions";
WCHAR ThreadString[] = L"Windows.System.Threading.ThreadPool";
HSTRING KnownFolderClassId = NULL;
HSTRING QueryOptionsClassId = NULL;
HSTRING ThreadPoolClassId = NULL;
UINT32 ObjectCount = 0;
Result = RoInitialize(RO_INIT_MULTITHREADED);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = WindowsCreateString(StorageString, (UINT32)StringLengthW(StorageString), &KnownFolderClassId);
if (!SUCCEEDED(Result) || !KnownFolderClassId)
goto EXIT_ROUTINE;
Result = RoGetActivationFactory(KnownFolderClassId, IID_IKnownFoldersStatics, (PVOID*)&KnownFolders);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = KnownFolders->get_DocumentsLibrary(&DocumentsFolder);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = WindowsCreateString(QueryString, (UINT32)StringLengthW(QueryString), &QueryOptionsClassId);
if (!SUCCEEDED(Result) || !QueryOptionsClassId)
goto EXIT_ROUTINE;
Result = RoActivateInstance(QueryOptionsClassId, &Inspectable);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = Inspectable->QueryInterface(IID_IQueryOptions, (PVOID*)&Options);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = Options->put_FolderDepth(FolderDepth_Deep);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = DocumentsFolder->QueryInterface(IID_IStorageFolderQueryOperations, (PVOID*)&Operation);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = Operation->CreateItemQueryWithOptions(Options, &ItemResult);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = ItemResult->GetItemsAsyncDefaultStartAndCount(&AsyncOperation);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = AsyncOperation->QueryInterface(IID_IAsyncInfo, (PVOID*)&Information);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = WindowsCreateString(ThreadString, (UINT32)StringLengthW(ThreadString), &ThreadPoolClassId);
if (!SUCCEEDED(Result) || !ThreadPoolClassId)
goto EXIT_ROUTINE;
while (TRUE)
{
AsyncStatus Status;
Result = Information->get_Status(&Status);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
if (Status == AsyncStatus::Completed)
break;
}
Result = AsyncOperation->GetResults(&Items);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = Items->get_Size(&ObjectCount);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
Result = RoGetActivationFactory(ThreadPoolClassId, IID_IThreadPoolStatics, (PVOID*)&ThreadPoolStatics);
if (!SUCCEEDED(Result))
goto EXIT_ROUTINE;
for (UINT32 i = 0; i < ObjectCount; i++)
{
IStorageItem* File = NULL;
Result = Items->GetAt(i, &File);
if (SUCCEEDED(Result) && File)
{
IAsyncAction* Action = NULL;
ThreadFileProcessor* FileProcessor = new ThreadFileProcessor(File);
Result = ThreadPoolStatics->RunAsync(FileProcessor, &Action);
if (FileProcessor)
FileProcessor->Release();
if (Action)
Action->Release();
}
if (File)
File->Release();
}
Sleep(1);
EXIT_ROUTINE:
if (KnownFolderClassId)
WindowsDeleteString(KnownFolderClassId);
if (QueryOptionsClassId)
WindowsDeleteString(QueryOptionsClassId);
if (ThreadPoolClassId)
WindowsDeleteString(ThreadPoolClassId);
if (KnownFolders)
KnownFolders->Release();
if (DocumentsFolder)
DocumentsFolder->Release();
if (Inspectable)
Inspectable->Release();
if (Operation)
Operation->Release();
if (ItemResult)
ItemResult->Release();
if (AsyncOperation)
AsyncOperation->Release();
if (Items)
Items->Release();
if (Information)
Information->Release();
if (ThreadPoolStatics)
ThreadPoolStatics->Release();
RoUninitialize();
return ERROR_SUCCESS;
}
Last updated