mirror of
https://github.com/bats3c/DarkLoadLibrary
synced 2026-06-06 15:14:33 +00:00
Merge pull request #13 from hypervis0r/fix-release
Fix release builds by removing all instances of ucrtbased.dll
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ VOID main()
|
||||
|
||||
PDARKMODULE DarkModule = DarkLoadLibrary(
|
||||
LOAD_LOCAL_FILE,
|
||||
L"TestDLL.dll",
|
||||
L".\\amsi.dll",
|
||||
NULL,
|
||||
0,
|
||||
NULL
|
||||
|
||||
@@ -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.
Reference in New Issue
Block a user