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.
+7 -3
View File
@@ -1,6 +1,8 @@
#include <stdio.h> #include <stdio.h>
#include <windows.h> #include <windows.h>
#pragma comment(lib, "Shlwapi.lib")
#define LOAD_LOCAL_FILE 0x00000001 #define LOAD_LOCAL_FILE 0x00000001
#define LOAD_REMOTE_FILE 0x00000002 #define LOAD_REMOTE_FILE 0x00000002
#define LOAD_MEMORY 0x00000003 #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* READFILE)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
typedef BOOL(WINAPI* CLOSEHANDLE)(HANDLE hObject); typedef BOOL(WINAPI* CLOSEHANDLE)(HANDLE hObject);
typedef BOOL(WINAPI* HEAPFREE)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); 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 LPCWSTR(WINAPI *PATHFINDFILENAMEW)(LPCWSTR pszPath);
typedef wchar_t*(_cdecl* WCSCPY)(wchar_t* Dest, const wchar_t* _Source); typedef int(__cdecl *WSPRINTFW)(LPWSTR, LPCWSTR, ...);
typedef wchar_t* (__cdecl* WCSCAT)(wchar_t* _dst, const wchar_t* __src);
#pragma once #pragma once
typedef struct _DARKMODULE { typedef struct _DARKMODULE {
@@ -37,3 +38,6 @@ PDARKMODULE DarkLoadLibrary(
DWORD dwLen, DWORD dwLen,
LPCWSTR lpwName 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 <windows.h>
#include <malloc.h>
#include "pebstructs.h" #include "pebstructs.h"
#include "darkloadlibrary.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 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* _WCSNICMP)(const wchar_t* _Str1, const wchar_t* _Str2, size_t _MaxCount);
typedef int(__cdecl* STRCMP)(const char* _Str1, const char* _Str2); 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); typedef int(__cdecl* _WCSICMP)(const wchar_t* _Str1, const wchar_t* _Str2);
#ifdef _WIN64 #ifdef _WIN64
+59 -57
View File
@@ -1,6 +1,40 @@
#include "darkloadlibrary.h" #include "darkloadlibrary.h"
#include "ldrutils.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( BOOL ParseFileName(
PDARKMODULE pdModule, PDARKMODULE pdModule,
LPWSTR lpwFileName LPWSTR lpwFileName
@@ -8,9 +42,7 @@ BOOL ParseFileName(
{ {
HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc"); HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap"); GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap");
_WSPLITPATH p_wsplitpath = (_WSPLITPATH)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "_wsplitpath"); PATHFINDFILENAMEW pPathFindFileNameW = (PATHFINDFILENAMEW)GetFunctionAddress(IsModulePresent(L"Shlwapi.dll"), "PathFindFileNameW");
WCSCPY pwcscpy = (WCSCPY)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "wcscpy");
WCSCAT pwcscat = (WCSCAT)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "wcscat");
if (lpwFileName == NULL) if (lpwFileName == NULL)
{ {
@@ -33,53 +65,21 @@ BOOL ParseFileName(
MAX_PATH * 2 MAX_PATH * 2
); );
PWCHAR lpwExt = (PWCHAR)pHeapAlloc( if (!pdModule->CrackedDLLName)
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
PWCHAR lpwFilename = (PWCHAR)pHeapAlloc(
hHeap,
HEAP_ZERO_MEMORY,
MAX_PATH
);
if (!pdModule->CrackedDLLName || !lpwExt || !lpwFilename)
{ {
pdModule->ErrorMsg = L"Failed to allocate memory"; pdModule->ErrorMsg = L"Failed to allocate memory";
return FALSE; return FALSE;
} }
p_wsplitpath( LPWSTR lpwFileNameLocation = pPathFindFileNameW(lpwFileName);
lpwFileName,
NULL,
NULL,
lpwFilename,
lpwExt
);
if (lpwFilename == NULL || lpwExt == NULL) /*
{ Copy the length of the filename modulo sizeof pdModule->CrackedDLLName - 1 for null byte.
pdModule->ErrorMsg = L"Failed to crack filename";
return FALSE;
}
PCHAR lpCpy = (PCHAR)pwcscpy( TODO:
pdModule->CrackedDLLName, Get a working wstrcpy implementation
lpwFilename */
); memcpy(pdModule->CrackedDLLName, lpwFileNameLocation, (WideStringLength(lpwFileNameLocation) % (MAX_PATH - 1)) * 2);
PCHAR lpCat = (PCHAR)pwcscat(
pdModule->CrackedDLLName,
lpwExt
);
if (!lpCpy || !lpCat)
{
pdModule->ErrorMsg = L"Failed to format cracked path";
return FALSE;
}
return TRUE; return TRUE;
} }
@@ -170,7 +170,16 @@ PDARKMODULE DarkLoadLibrary(
{ {
HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc"); HEAPALLOC pHeapAlloc = (HEAPALLOC)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "HeapAlloc");
GETPROCESSHEAP pGetProcessHeap = (GETPROCESSHEAP)GetFunctionAddress(IsModulePresent(L"Kernel32.dll"), "GetProcessHeap"); 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)); PDARKMODULE dModule = (DARKMODULE*)pHeapAlloc(pGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DARKMODULE));
if (!dModule) if (!dModule)
@@ -217,9 +226,7 @@ PDARKMODULE DarkLoadLibrary(
lpwName = dModule->CrackedDLLName; lpwName = dModule->CrackedDLLName;
} }
HMODULE hModule = IsModulePresent( HMODULE hModule = IsModulePresent(lpwName);
lpwName
);
if (hModule != NULL) if (hModule != NULL)
{ {
@@ -236,8 +243,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg) if (!dModule->ErrorMsg)
goto Cleanup; goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Data is an invalid PE: "); pwsprintfW(dModule->ErrorMsg, TEXT("Data is an invalid PE: %s"), lpwName);
pwcscat(dModule->ErrorMsg, lpwName);
goto Cleanup; goto Cleanup;
} }
@@ -248,8 +254,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg) if (!dModule->ErrorMsg)
goto Cleanup; goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to map sections: "); pwsprintfW(dModule->ErrorMsg, TEXT("Failed to map sections: %s"), lpwName);
pwcscat(dModule->ErrorMsg, lpwName);
goto Cleanup; goto Cleanup;
} }
@@ -260,8 +265,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg) if (!dModule->ErrorMsg)
goto Cleanup; goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to resolve imports: "); pwsprintfW(dModule->ErrorMsg, TEXT("Failed to resolve imports: %s"), lpwName);
pwcscat(dModule->ErrorMsg, lpwName);
goto Cleanup; goto Cleanup;
} }
@@ -274,8 +278,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg) if (!dModule->ErrorMsg)
goto Cleanup; goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to link module to PEB: "); pwsprintfW(dModule->ErrorMsg, TEXT("Failed to link module to PEB: %s"), lpwName);
pwcscat(dModule->ErrorMsg, lpwName);
goto Cleanup; goto Cleanup;
} }
} }
@@ -287,8 +290,7 @@ PDARKMODULE DarkLoadLibrary(
if (!dModule->ErrorMsg) if (!dModule->ErrorMsg)
goto Cleanup; goto Cleanup;
pwcscat(dModule->ErrorMsg, L"Failed to execute: "); pwsprintfW(dModule->ErrorMsg, TEXT("Failed to execute: %s"), lpwName);
pwcscat(dModule->ErrorMsg, lpwName);
goto Cleanup; goto Cleanup;
} }
+1 -1
View File
@@ -13,7 +13,7 @@ VOID main()
PDARKMODULE DarkModule = DarkLoadLibrary( PDARKMODULE DarkModule = DarkLoadLibrary(
LOAD_LOCAL_FILE, LOAD_LOCAL_FILE,
L"TestDLL.dll", L".\\amsi.dll",
NULL, NULL,
0, 0,
NULL NULL
+32 -9
View File
@@ -27,8 +27,6 @@ PLDR_DATA_TABLE_ENTRY2 FindLdrTableEntry(
PLDR_DATA_TABLE_ENTRY2 pCurEntry; PLDR_DATA_TABLE_ENTRY2 pCurEntry;
PLIST_ENTRY pListHead, pListEntry; PLIST_ENTRY pListHead, pListEntry;
_WCSNICMP p_wcsnicmp = (_WCSNICMP)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "_wcsnicmp");
pPeb = (PPEB2)READ_MEMLOC(PEB_OFFSET); pPeb = (PPEB2)READ_MEMLOC(PEB_OFFSET);
if (pPeb == NULL) if (pPeb == NULL)
@@ -44,10 +42,10 @@ PLDR_DATA_TABLE_ENTRY2 FindLdrTableEntry(
pCurEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY2, InLoadOrderLinks); pCurEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY2, InLoadOrderLinks);
pListEntry = pListEntry->Flink; pListEntry = pListEntry->Flink;
INT BaseName1 = p_wcsnicmp(BaseName, pCurEntry->BaseDllName.Buffer, (pCurEntry->BaseDllName.Length / sizeof(wchar_t)) - 4); //BOOL BaseName1 = WideStringCompare(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 BaseName2 = WideStringCompare(BaseName, pCurEntry->BaseDllName.Buffer, WideStringLength(BaseName));
if (!BaseName1 || !BaseName2) if (BaseName2 == TRUE)
{ {
return pCurEntry; return pCurEntry;
} }
@@ -64,6 +62,11 @@ PRTL_RB_TREE FindModuleBaseAddressIndex()
PRTL_BALANCED_NODE pNode = NULL; PRTL_BALANCED_NODE pNode = NULL;
PRTL_RB_TREE pModBaseAddrIndex = 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"); RTLCOMPAREMEMORY pRtlCompareMemory = (RTLCOMPAREMEMORY)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "RtlCompareMemory");
STRCMP pstrcmp = (STRCMP)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "strcmp"); STRCMP pstrcmp = (STRCMP)GetFunctionAddress(IsModulePresent(L"ntdll.dll"), "strcmp");
@@ -307,11 +310,27 @@ HMODULE IsModulePresentA(
char* Name char* Name
) )
{ {
MBSTOWCS pmbstowcs = (MBSTOWCS)GetFunctionAddress(IsModulePresent(L"ucrtbased.dll"), "mbstowcs"); MULTIBYTETOWIDECHAR pMultiByteToWideChar = (MULTIBYTETOWIDECHAR)GetFunctionAddress(IsModulePresent(L"kernel32.dll"), "MultiByteToWideChar");
wchar_t wtext[500]; WCHAR* wideName = NULL;
pmbstowcs(wtext, Name, strlen(Name) + 1); DWORD wideNameSize = 0;
return IsModulePresent(wtext);
// 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( HMODULE IsModulePresent(
@@ -336,6 +355,10 @@ HMODULE IsModulePresent(
pLdrTbl = (PLDR_DATA_TABLE_ENTRY2)ucModPtrOff; pLdrTbl = (PLDR_DATA_TABLE_ENTRY2)ucModPtrOff;
/*
TODO:
Make this its own ANSI case-insensitive string compare function
*/
BOOL match = TRUE; BOOL match = TRUE;
for (int i = 0; i < pLdrTbl->BaseDllName.Length/2; i++) for (int i = 0; i < pLdrTbl->BaseDllName.Length/2; i++)
{ {
Binary file not shown.