Merge pull request #13 from hypervis0r/fix-release

Fix release builds by removing all instances of ucrtbased.dll
This commit is contained in:
batsec
2021-10-22 08:27:58 +01:00
committed by GitHub
8 changed files with 110 additions and 73 deletions
Binary file not shown.
Binary file not shown.
+8 -4
View File
@@ -1,6 +1,8 @@
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "Shlwapi.lib")
#define LOAD_LOCAL_FILE 0x00000001
#define LOAD_REMOTE_FILE 0x00000002
#define LOAD_MEMORY 0x00000003
@@ -14,9 +16,8 @@ typedef DWORD(WINAPI* GETFILESIZE)(HANDLE hFile, LPDWORD lpFileSizeHigh);
typedef BOOL(WINAPI* READFILE)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
typedef BOOL(WINAPI* CLOSEHANDLE)(HANDLE hObject);
typedef BOOL(WINAPI* HEAPFREE)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
typedef void(__cdecl* _WSPLITPATH)(const wchar_t* _FullPath, wchar_t* _Drive, wchar_t* _Dir, wchar_t* _Filename, wchar_t* _Ext);
typedef wchar_t*(_cdecl* WCSCPY)(wchar_t* Dest, const wchar_t* _Source);
typedef wchar_t* (__cdecl* WCSCAT)(wchar_t* _dst, const wchar_t* __src);
typedef LPCWSTR(WINAPI *PATHFINDFILENAMEW)(LPCWSTR pszPath);
typedef int(__cdecl *WSPRINTFW)(LPWSTR, LPCWSTR, ...);
#pragma once
typedef struct _DARKMODULE {
@@ -36,4 +37,7 @@ PDARKMODULE DarkLoadLibrary(
LPVOID lpFileBuffer,
DWORD dwLen,
LPCWSTR lpwName
);
);
SIZE_T WideStringLength(LPWSTR str);
BOOL WideStringCompare(LPWSTR lpwStr1, LPWSTR lpwStr2, SIZE_T cbMaxCount);
+9 -1
View File
@@ -1,4 +1,5 @@
#include <windows.h>
#include <malloc.h>
#include "pebstructs.h"
#include "darkloadlibrary.h"
@@ -16,7 +17,14 @@ typedef NTSTATUS(NTAPI* RTLHASHUNICODESTRING)(UNICODE_STRING* String, BOOLEAN Ca
typedef SIZE_T(NTAPI* RTLCOMPAREMEMORY)(const VOID* Source1, const VOID* Source2, SIZE_T Length);
typedef int(__cdecl* _WCSNICMP)(const wchar_t* _Str1, const wchar_t* _Str2, size_t _MaxCount);
typedef int(__cdecl* STRCMP)(const char* _Str1, const char* _Str2);
typedef size_t(__cdecl* MBSTOWCS)(wchar_t* Dest, const char* _Source, size_t _MaxCount);
typedef int(WINAPI *MULTIBYTETOWIDECHAR)(
UINT CodePage,
DWORD dwFlags,
LPCCH lpMultiByteStr,
int cbMultiByte,
LPWSTR lpWideCharStr,
int cchWideChar
);
typedef int(__cdecl* _WCSICMP)(const wchar_t* _Str1, const wchar_t* _Str2);
#ifdef _WIN64
+60 -58
View File
@@ -1,6 +1,40 @@
#include "darkloadlibrary.h"
#include "ldrutils.h"
SIZE_T WideStringLength(LPWSTR str)
{
SIZE_T len = 0;
SIZE_T i = 0;
while (str[i++])
++len;
return len;
}
BOOL WideStringCompare(LPWSTR lpwStr1, LPWSTR lpwStr2, SIZE_T cbMaxCount)
{
BOOL match = TRUE;
for (SIZE_T i = 0; i < cbMaxCount; i++)
{
WCHAR a, b;
a = lpwStr1[i];
b = lpwStr2[i];
if (a >= 'A' && a <= 'Z')
a += 32;
if (b >= 'A' && b <= 'Z')
b += 32;
if (a != b)
{
match = FALSE;
break;
}
}
return match;
}
BOOL ParseFileName(
PDARKMODULE pdModule,
LPWSTR lpwFileName
@@ -8,9 +42,7 @@ BOOL ParseFileName(
{
HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
_WSPLITPATH p_wsplitpath = (_WSPLITPATH)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "_wsplitpath");
WCSCPY pwcscpy = (WCSCPY)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "wcscpy");
WCSCAT pwcscat = (WCSCAT)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "wcscat");
PATHFINDFILENAMEW pPathFindFileNameW = (PATHFINDFILENAMEW)GetFunctionAddress(IsModulePresent(L"Shlwapi.dll"), "PathFindFileNameW");
if (lpwFileName == NULL)
{
@@ -33,53 +65,21 @@ BOOL ParseFileName(
MAX_PATH * 2
);
PWCHAR lpwExt = (PWCHAR)pHeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
PWCHAR lpwFilename = (PWCHAR)pHeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
if (!pdModule->CrackedDLLName || !lpwExt || !lpwFilename)
if (!pdModule->CrackedDLLName)
{
pdModule->ErrorMsg = L"Failed to allocate memory";
return FALSE;
}
p_wsplitpath(
lpwFileName,
NULL,
NULL,
lpwFilename,
lpwExt
);
LPWSTR lpwFileNameLocation = pPathFindFileNameW(lpwFileName);
if (lpwFilename == NULL || lpwExt == NULL)
{
pdModule->ErrorMsg = L"Failed to crack filename";
return FALSE;
}
PCHAR lpCpy = (PCHAR)pwcscpy(
pdModule->CrackedDLLName,
lpwFilename
);
PCHAR lpCat = (PCHAR)pwcscat(
pdModule->CrackedDLLName,
lpwExt
);
if (!lpCpy || !lpCat)
{
pdModule->ErrorMsg = L"Failed to format cracked path";
return FALSE;
}
/*
Copy the length of the filename modulo sizeof pdModule->CrackedDLLName - 1 for null byte.
TODO:
Get a working wstrcpy implementation
*/
memcpy(pdModule->CrackedDLLName, lpwFileNameLocation, (WideStringLength(lpwFileNameLocation) % (MAX_PATH - 1)) * 2);
return TRUE;
}
@@ -170,7 +170,16 @@ PDARKMODULE DarkLoadLibrary(
{
HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
WCSCAT pwcscat = (WCSCAT)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "wcscat");
/*
TODO:
I would really love to stop using error messages that need this.
All the other safe versions of wsprintfW are located in the CRT,
which is an issue if there is no CRT in the process.
For now let us hope nobody will pass a name larger than 500 bytes. :/
*/
WSPRINTFW pwsprintfW = (WSPRINTFW)GetFunctionAddress(IsModulePresent(L"User32.dll"), "wsprintfW");
PDARKMODULE dModule = (DARKMODULE*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DARKMODULE));
if (!dModule)
@@ -217,9 +226,7 @@ PDARKMODULE DarkLoadLibrary(
lpwName = dModule->CrackedDLLName;
}
HMODULE hModule = IsModulePresent(
lpwName
);
HMODULE hModule = IsModulePresent(lpwName);
if (hModule != NULL)
{
@@ -236,8 +243,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg)
goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Data is an invalid PE: ");
pwcscat(dModule->ErrorMsg, lpwName);
pwsprintfW(dModule->ErrorMsg, TEXT("Data is an invalid PE: %s"), lpwName);
goto Cleanup;
}
@@ -248,8 +254,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg)
goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to map sections: ");
pwcscat(dModule->ErrorMsg, lpwName);
pwsprintfW(dModule->ErrorMsg, TEXT("Failed to map sections: %s"), lpwName);
goto Cleanup;
}
@@ -260,8 +265,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg)
goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to resolve imports: ");
pwcscat(dModule->ErrorMsg, lpwName);
pwsprintfW(dModule->ErrorMsg, TEXT("Failed to resolve imports: %s"), lpwName);
goto Cleanup;
}
@@ -274,8 +278,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg)
goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to link module to PEB: ");
pwcscat(dModule->ErrorMsg, lpwName);
pwsprintfW(dModule->ErrorMsg, TEXT("Failed to link module to PEB: %s"), lpwName);
goto Cleanup;
}
}
@@ -287,8 +290,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg)
goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to execute: ");
pwcscat(dModule->ErrorMsg, lpwName);
pwsprintfW(dModule->ErrorMsg, TEXT("Failed to execute: %s"), lpwName);
goto Cleanup;
}
+1 -1
View File
@@ -13,7 +13,7 @@ VOID main()
PDARKMODULE DarkModule = DarkLoadLibrary(
LOAD_LOCAL_FILE,
L"TestDLL.dll",
L".\\amsi.dll",
NULL,
0,
NULL
+32 -9
View File
@@ -26,8 +26,6 @@ PLDR_DATA_TABLE_ENTRY2 FindLdrTableEntry(
PPEB2 pPeb;
PLDR_DATA_TABLE_ENTRY2 pCurEntry;
PLIST_ENTRY pListHead, pListEntry;
_WCSNICMP p_wcsnicmp = (_WCSNICMP)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "_wcsnicmp");
pPeb = (PPEB2)READ_MEMLOC(PEB_OFFSET);
@@ -44,10 +42,10 @@ PLDR_DATA_TABLE_ENTRY2 FindLdrTableEntry(
pCurEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY2, InLoadOrderLinks);
pListEntry = pListEntry->Flink;
INT BaseName1 = p_wcsnicmp(BaseName, pCurEntry->BaseDllName.Buffer, (pCurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4);
INT BaseName2 = p_wcsnicmp(BaseName, pCurEntry->BaseDllName.Buffer, pCurEntry->BaseDllName.Length / sizeof(wchar_t));
//BOOL BaseName1 = WideStringCompare(BaseName, pCurEntry->BaseDllName.Buffer, (pCurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4);
BOOL BaseName2 = WideStringCompare(BaseName, pCurEntry->BaseDllName.Buffer, WideStringLength(BaseName));
if (!BaseName1 || !BaseName2)
if (BaseName2 == TRUE)
{
return pCurEntry;
}
@@ -64,6 +62,11 @@ PRTL_RB_TREE FindModuleBaseAddressIndex()
PRTL_BALANCED_NODE pNode = NULL;
PRTL_RB_TREE pModBaseAddrIndex = NULL;
/*
TODO:
Implement these manually cause these could totally be hooked
and various other reasons
*/
RTLCOMPAREMEMORY pRtlCompareMemory = (RTLCOMPAREMEMORY)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "RtlCompareMemory");
STRCMP pstrcmp = (STRCMP)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "strcmp");
@@ -307,11 +310,27 @@ HMODULE IsModulePresentA(
char* Name
)
{
MBSTOWCS pmbstowcs = (MBSTOWCS)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "mbstowcs");
MULTIBYTETOWIDECHAR pMultiByteToWideChar = (MULTIBYTETOWIDECHAR)GetFunctionAddress(IsModulePresent(L"kernel32.dll"), "MultiByteToWideChar");
wchar_t wtext[500];
pmbstowcs(wtext, Name, strlen(Name) + 1);
return IsModulePresent(wtext);
WCHAR* wideName = NULL;
DWORD wideNameSize = 0;
// MultiByteToWideChar returns size in characters, not bytes
wideNameSize = pMultiByteToWideChar(CP_UTF8, 0, Name, -1, NULL, 0) * 2;
/*
Attempt to allocate this on the stack, seeing as it's faster and we can attempt
to avoid funny shit like heap fragmentation on a simple temp var
*/
wideName = (WCHAR*)_malloca(wideNameSize);
pMultiByteToWideChar(CP_UTF8, 0, Name, -1, wideName, wideNameSize);
HMODULE hModule = IsModulePresent(wideName);
_freea(wideName);
return hModule;
}
HMODULE IsModulePresent(
@@ -336,6 +355,10 @@ HMODULE IsModulePresent(
pLdrTbl = (PLDR_DATA_TABLE_ENTRY2)ucModPtrOff;
/*
TODO:
Make this its own ANSI case-insensitive string compare function
*/
BOOL match = TRUE;
for (int i = 0; i < pLdrTbl->BaseDllName.Length/2; i++)
{
Binary file not shown.