Files
2021-04-20 12:15:03 +08:00

242 lines
7.6 KiB
C++

#include "stdafx.h"
#include <string>
#include <chrono>
#include <shlwapi.h>
using namespace Microsoft::WRL;
using namespace std::chrono;
using namespace std;
HMODULE g_currentModule;
BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
g_currentModule = module;
DisableThreadLibraryCalls(module);
Module<InProc>::GetModule().Create();
break;
case DLL_PROCESS_DETACH:
Module<InProc>::GetModule().Terminate();
break;
}
return TRUE;
}
#pragma region COM server boilerplate
HRESULT WINAPI DllCanUnloadNow()
{
return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
}
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv)
{
return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
}
#pragma endregion
// Simple RAII class to ensure memory is freed.
template<typename T>
class HeapMemPtr
{
public:
HeapMemPtr() { }
HeapMemPtr(const HeapMemPtr& other) = delete;
HeapMemPtr(HeapMemPtr&& other) : p(other.p) { other.p = nullptr; }
HeapMemPtr& operator=(const HeapMemPtr& other) = delete;
HeapMemPtr& operator=(HeapMemPtr&& other) {
auto t = p; p = other.p; other.p = t;
}
~HeapMemPtr()
{
if (p) HeapFree(GetProcessHeap(), 0, p);
}
HRESULT Alloc(size_t size)
{
p = reinterpret_cast<T*>(HeapAlloc(GetProcessHeap(), 0, size));
return p ? S_OK : E_OUTOFMEMORY;
}
T* Get() { return p; }
operator bool() { return p != nullptr; }
private:
T* p = nullptr;
};
class
// Register it as the top provider (top-down)
DECLSPEC_UUID("00000000-0000-0000-0000-000000000000")
AmsiTracer : public RuntimeClass<RuntimeClassFlags<ClassicCom>, IAntimalwareProvider, FtmBase>
{
public:
IFACEMETHOD(Scan)(_In_ IAmsiStream* stream, _Out_ AMSI_RESULT* result) override;
IFACEMETHOD_(void, CloseSession)(_In_ ULONGLONG session) override;
IFACEMETHOD(DisplayName)(_Outptr_ LPWSTR* displayName) override;
private:
LONG m_requestNumber = 0;
wstring processId = to_wstring(GetCurrentProcessId());
wstring threadId = to_wstring(GetCurrentThreadId());
};
template<typename T>
T GetFixedSizeAttribute(_In_ IAmsiStream* stream, _In_ AMSI_ATTRIBUTE attribute)
{
T result;
ULONG actualSize;
if (SUCCEEDED(stream->GetAttribute(attribute, sizeof(T), reinterpret_cast<PBYTE>(&result), &actualSize)) &&
actualSize == sizeof(T))
{
return result;
}
return T();
}
HeapMemPtr<wchar_t> GetStringAttribute(_In_ IAmsiStream* stream, _In_ AMSI_ATTRIBUTE attribute)
{
HeapMemPtr<wchar_t> result;
ULONG allocSize;
ULONG actualSize;
if (stream->GetAttribute(attribute, 0, nullptr, &allocSize) == E_NOT_SUFFICIENT_BUFFER &&
SUCCEEDED(result.Alloc(allocSize)) &&
SUCCEEDED(stream->GetAttribute(attribute, allocSize, reinterpret_cast<PBYTE>(result.Get()), &actualSize)) &&
actualSize <= allocSize)
{
return result;
}
return HeapMemPtr<wchar_t>();
}
HRESULT AmsiTracer::Scan(_In_ IAmsiStream* stream, _Out_ AMSI_RESULT* result)
{
LONG requestNumber = InterlockedIncrement(&m_requestNumber);
auto epoch = duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
).count();
wchar_t processFilePath[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, processFilePath, MAX_PATH);
wstring processFileName = PathFindFileNameW(processFilePath);
wstring fileName = to_wstring(epoch) + L"_"
+ processFileName + L"_"
+ processId + L"_"
+ threadId + L"_"
+ to_wstring(requestNumber)
+ L".dmp";
auto appName = GetStringAttribute(stream, AMSI_ATTRIBUTE_APP_NAME);
auto contentName = GetStringAttribute(stream, AMSI_ATTRIBUTE_CONTENT_NAME);
auto contentSize = GetFixedSizeAttribute<ULONGLONG>(stream, AMSI_ATTRIBUTE_CONTENT_SIZE);
auto session = GetFixedSizeAttribute<ULONGLONG>(stream, AMSI_ATTRIBUTE_SESSION);
auto contentAddress = GetFixedSizeAttribute<PBYTE>(stream, AMSI_ATTRIBUTE_CONTENT_ADDRESS);
// Create base folder if it doesn't exist
wstring baseFolder = L"C:\\amsi_tracer";
CreateDirectoryW(baseFolder.c_str(), NULL);
// Dump into file
wstring traceFilePath = baseFolder + L"\\" + fileName;
HANDLE h = CreateFile(traceFilePath.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
WriteFile(h, contentAddress, contentSize, NULL, nullptr);
CloseHandle(h);
// AMSI_RESULT_NOT_DETECTED means "We did not detect a problem but let other providers scan it, too."
*result = AMSI_RESULT_NOT_DETECTED;
return S_OK;
}
void AmsiTracer::CloseSession(_In_ ULONGLONG session)
{
}
HRESULT AmsiTracer::DisplayName(_Outptr_ LPWSTR *displayName)
{
*displayName = const_cast<LPWSTR>(L"AMSI Tracer");
return S_OK;
}
CoCreatableClass(AmsiTracer);
#pragma region Install / uninstall
HRESULT SetKeyStringValue(_In_ HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR valueName, _In_ PCWSTR stringValue)
{
LONG status = RegSetKeyValue(key, subkey, valueName, REG_SZ, stringValue, (wcslen(stringValue) + 1) * sizeof(wchar_t));
return HRESULT_FROM_WIN32(status);
}
STDAPI DllRegisterServer()
{
wchar_t modulePath[MAX_PATH];
if (GetModuleFileName(g_currentModule, modulePath, ARRAYSIZE(modulePath)) >= ARRAYSIZE(modulePath))
{
return E_UNEXPECTED;
}
// Create a standard COM registration for our CLSID.
// The class must be registered as "Both" threading model
// and support multithreaded access.
wchar_t clsidString[40];
if (StringFromGUID2(__uuidof(AmsiTracer), clsidString, ARRAYSIZE(clsidString)) == 0)
{
return E_UNEXPECTED;
}
wchar_t keyPath[200];
HRESULT hr = StringCchPrintf(keyPath, ARRAYSIZE(keyPath), L"Software\\Classes\\CLSID\\%ls", clsidString);
if (FAILED(hr)) return hr;
hr = SetKeyStringValue(HKEY_LOCAL_MACHINE, keyPath, nullptr, L"AmsiTracer");
if (FAILED(hr)) return hr;
hr = StringCchPrintf(keyPath, ARRAYSIZE(keyPath), L"Software\\Classes\\CLSID\\%ls\\InProcServer32", clsidString);
if (FAILED(hr)) return hr;
hr = SetKeyStringValue(HKEY_LOCAL_MACHINE, keyPath, nullptr, modulePath);
if (FAILED(hr)) return hr;
hr = SetKeyStringValue(HKEY_LOCAL_MACHINE, keyPath, L"ThreadingModel", L"Both");
if (FAILED(hr)) return hr;
// Register this CLSID as an anti-malware provider.
hr = StringCchPrintf(keyPath, ARRAYSIZE(keyPath), L"Software\\Microsoft\\AMSI\\Providers\\%ls", clsidString);
if (FAILED(hr)) return hr;
hr = SetKeyStringValue(HKEY_LOCAL_MACHINE, keyPath, nullptr, L"AmsiTracer");
if (FAILED(hr)) return hr;
return S_OK;
}
STDAPI DllUnregisterServer()
{
wchar_t clsidString[40];
if (StringFromGUID2(__uuidof(AmsiTracer), clsidString, ARRAYSIZE(clsidString)) == 0)
{
return E_UNEXPECTED;
}
// Unregister this CLSID as an anti-malware provider.
wchar_t keyPath[200];
HRESULT hr = StringCchPrintf(keyPath, ARRAYSIZE(keyPath), L"Software\\Microsoft\\AMSI\\Providers\\%ls", clsidString);
if (FAILED(hr)) return hr;
LONG status = RegDeleteTree(HKEY_LOCAL_MACHINE, keyPath);
if (status != NO_ERROR && status != ERROR_PATH_NOT_FOUND) return HRESULT_FROM_WIN32(status);
// Unregister this CLSID as a COM server.
hr = StringCchPrintf(keyPath, ARRAYSIZE(keyPath), L"Software\\Classes\\CLSID\\%ls", clsidString);
if (FAILED(hr)) return hr;
status = RegDeleteTree(HKEY_LOCAL_MACHINE, keyPath);
if (status != NO_ERROR && status != ERROR_PATH_NOT_FOUND) return HRESULT_FROM_WIN32(status);
return S_OK;
}
#pragma endregion