Code:
typedef struct _RTL_USER_PROCESS_PARAMETERS {
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StdInputHandle;
HANDLE StdOutputHandle;
HANDLE StdErrorHandle;
UNICODE_STRING CurrentDirectoryPath;
HANDLE CurrentDirectoryHandle;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingPositionLeft;
ULONG StartingPositionTop;
ULONG Width;
ULONG Height;
ULONG CharWidth;
ULONG CharHeight;
ULONG ConsoleTextAttributes;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopName;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20];
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB_FREE_BLOCK {
_PEB_FREE_BLOCK *Next;
ULONG Size;
} PEB_FREE_BLOCK, *PPEB_FREE_BLOCK;
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef void (*PPEBLOCKROUTINE)(PVOID PebLock);
typedef PVOID *PPVOID;
typedef struct _PEB {
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
BOOLEAN Spare;
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA LoaderData;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PPEBLOCKROUTINE FastPebLockRoutine;
PPEBLOCKROUTINE FastPebUnlockRoutine;
ULONG EnvironmentUpdateCount;
PPVOID KernelCallbackTable;
PVOID EventLogSection;
PVOID EventLog;
PPEB_FREE_BLOCK FreeList;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PPVOID ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
BYTE Spare2[0x4];
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PPVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubSystem;
ULONG ImageSubSystemMajorVersion;
ULONG ImageSubSystemMinorVersion;
ULONG GdiHandleBuffer[0x22];
ULONG PostProcessInitRoutine;
ULONG TlsExpansionBitmap;
BYTE TlsExpansionBitmapBits[0x80];
ULONG SessionId;
} PEB, *PPEB;
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation = 0,
ProcessWow64Information = 26
} PROCESSINFOCLASS;
typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
SIZE_T ReadProcessUnicodeString(HANDLE hProcess, UNICODE_STRING *inString, UNICODE_STRING *outString){
SIZE_T dwRead;
outString->Length = inString->Length;
outString->MaximumLength = inString->MaximumLength;
outString->Buffer = (PWSTR)malloc(inString->MaximumLength);
ReadProcessMemory(hProcess, inString->Buffer, outString->Buffer, inString->MaximumLength, &dwRead);
return dwRead;
}
DWORD LoadLibraryInjection(HANDLE proc, PCHAR dllName){
LPVOID RemoteString, LoadLibAddy;
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(proc, NULL, strlen(dllName), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(RemoteString == NULL){
CloseHandle(proc); // Close the process handle.
ErrorExit(TEXT("VirtualAllocEx"), NULL);
}
if(WriteProcessMemory(proc, (LPVOID)RemoteString, dllName,strlen(dllName), NULL) == 0){
VirtualFreeEx(proc, RemoteString, 0, MEM_RELEASE); // Free the memory we were going to use.
CloseHandle(proc); // Close the process handle.
ErrorExit(TEXT("WriteProcessMemory"), NULL);
}
HANDLE hThread;
if((hThread = CreateRemoteThread(proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL)) == NULL){
VirtualFreeEx(proc, RemoteString, 0, MEM_RELEASE); // Free the memory we were going to use.
CloseHandle(proc); // Close the process handle.
ErrorExit(TEXT("CreateRemoteThread"), NULL);
}
DWORD dwThreadExitCode=0;
// Lets wait for the thread to finish 10 seconds is our limit.
// During this wait, DllMain is running in the injected DLL, so
// DllMain has 10 seconds to run.
WaitForSingleObject(hThread, 10000);
// Lets see what it says...
GetExitCodeThread(hThread, &dwThreadExitCode);
// No need for this handle anymore, lets get rid of it.
CloseHandle(hThread);
// Lets clear up that memory we allocated earlier.
VirtualFreeEx(proc, RemoteString, 0, MEM_RELEASE);
// Alright lets remove this DLL from the loaded DLL list!
WCHAR dllNameW[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, dllName, strlen(dllName)+1, dllNameW, MAX_PATH);
typedef NTSTATUS (WINAPI *fpNtQueryInformationProcess)(
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);
fpNtQueryInformationProcess NtQueryInformationProcess = (fpNtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"),"NtQueryInformationProcess");
PROCESS_BASIC_INFORMATION procinfo;
NtQueryInformationProcess(proc, ProcessBasicInformation, &procinfo, sizeof(procinfo), NULL);
PEB peb;
PEB_LDR_DATA ldrData;
SIZE_T dwRead;
ReadProcessMemory(proc, procinfo.PebBaseAddress, &peb, sizeof(peb), &dwRead);
ReadProcessMemory(proc, peb.LoaderData, &ldrData, sizeof(ldrData), &dwRead);
LDR_MODULE ldrModuleA = {0};
LDR_MODULE ldrModuleOfInterest = {0};
LIST_ENTRY *Flink=ldrData.InInitializationOrderModuleList.Flink;
LIST_ENTRY *Start=Flink;
LIST_ENTRY *Blink = 0;
do{
// Lets find the entry in the InInitializationOrderModuleList first.
ReadProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InInitializationOrderModuleList), &ldrModuleA, sizeof(ldrModuleA), &dwRead);
Blink = ldrModuleA.InInitializationOrderModuleList.Blink;
Flink = ldrModuleA.InInitializationOrderModuleList.Flink;
if(ldrModuleA.InInitializationOrderModuleList.Flink == Start)
break;
UNICODE_STRING FullDllName;
ReadProcessUnicodeString(proc, &ldrModuleA.FullDllName, &FullDllName);
if(wcscmp(FullDllName.Buffer, dllNameW)==0){
// BINGO!
printf("FullDllName: %wZ\n", FullDllName);
// Lets remove this list entry.
LDR_MODULE Previous;
LDR_MODULE Next;
// Overwriting the entry at Flink, so it points to the one behind us.
ReadProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InInitializationOrderModuleList), &Next, sizeof(Next), &dwRead);
Next.InInitializationOrderModuleList.Blink = Blink;
WriteProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InInitializationOrderModuleList), &Next, sizeof(Next), NULL);
// Overwriting the entry at Blink, so it points to the one in front of us.
ReadProcessMemory(proc, CONTAINING_RECORD(Blink, LDR_MODULE, InInitializationOrderModuleList), &Previous, sizeof(Previous), &dwRead);
Previous.InInitializationOrderModuleList.Flink = Flink;
WriteProcessMemory(proc, CONTAINING_RECORD(Blink, LDR_MODULE, InInitializationOrderModuleList), &Previous, sizeof(Previous), NULL);
// Break out, to continue on to the next list...
break;
}
free(FullDllName.Buffer);
}while(TRUE);
Flink=ldrData.InLoadOrderModuleList.Flink;
Start=Flink;
Blink = 0;
do{
// Lets find the entry in the InInitializationOrderModuleList first.
ReadProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InLoadOrderModuleList), &ldrModuleA, sizeof(ldrModuleA), &dwRead);
Blink = ldrModuleA.InLoadOrderModuleList.Blink;
Flink = ldrModuleA.InLoadOrderModuleList.Flink;
if(ldrModuleA.InLoadOrderModuleList.Flink == Start)
break;
UNICODE_STRING FullDllName;
ReadProcessUnicodeString(proc, &ldrModuleA.FullDllName, &FullDllName);
if(wcscmp(FullDllName.Buffer, dllNameW)==0){
// BINGO!
printf("FullDllName: %wZ\n", FullDllName);
// Lets remove this list entry.
LDR_MODULE Previous;
LDR_MODULE Next;
// Overwriting the entry at Flink, so it points to the one behind us.
ReadProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InLoadOrderModuleList), &Next, sizeof(Next), &dwRead);
Next.InLoadOrderModuleList.Blink = Blink;
WriteProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InLoadOrderModuleList), &Next, sizeof(Next), NULL);
// Overwriting the entry at Blink, so it points to the one in front of us.
ReadProcessMemory(proc, CONTAINING_RECORD(Blink, LDR_MODULE, InLoadOrderModuleList), &Previous, sizeof(Previous), &dwRead);
Previous.InLoadOrderModuleList.Flink = Flink;
WriteProcessMemory(proc, CONTAINING_RECORD(Blink, LDR_MODULE, InLoadOrderModuleList), &Previous, sizeof(Previous), NULL);
// Break out, to continue on to the next list...
break;
}
free(FullDllName.Buffer);
}while(TRUE);
Flink=ldrData.InMemoryOrderModuleList.Flink;
Start=Flink;
Blink = 0;
do{
// Lets find the entry in the InInitializationOrderModuleList first.
ReadProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InMemoryOrderModuleList), &ldrModuleA, sizeof(ldrModuleA), &dwRead);
Blink = ldrModuleA.InMemoryOrderModuleList.Blink;
Flink = ldrModuleA.InMemoryOrderModuleList.Flink;
if(ldrModuleA.InMemoryOrderModuleList.Flink == Start)
break;
UNICODE_STRING FullDllName;
ReadProcessUnicodeString(proc, &ldrModuleA.FullDllName, &FullDllName);
if(wcscmp(FullDllName.Buffer, dllNameW)==0){
// BINGO!
printf("FullDllName: %wZ\n", FullDllName);
// Lets remove this list entry.
LDR_MODULE Previous;
LDR_MODULE Next;
// Overwriting the entry at Flink, so it points to the one behind us.
ReadProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InMemoryOrderModuleList), &Next, sizeof(Next), &dwRead);
Next.InMemoryOrderModuleList.Blink = Blink;
WriteProcessMemory(proc, CONTAINING_RECORD(Flink, LDR_MODULE, InMemoryOrderModuleList), &Next, sizeof(Next), NULL);
// Overwriting the entry at Blink, so it points to the one in front of us.
ReadProcessMemory(proc, CONTAINING_RECORD(Blink, LDR_MODULE, InMemoryOrderModuleList), &Previous, sizeof(Previous), &dwRead);
Previous.InMemoryOrderModuleList.Flink = Flink;
WriteProcessMemory(proc, CONTAINING_RECORD(Blink, LDR_MODULE, InMemoryOrderModuleList), &Previous, sizeof(Previous), NULL);
// Break out, to continue on to the next list...
break;
}
free(FullDllName.Buffer);
}while(TRUE);
return dwThreadExitCode;
}
Please note that when running on WoW64, there are actually TWO process environment blocks, this only clear out the 32 bit one, and on normal 64-bit it clears out the ONLY one (which is the 64-bit one). Sorry if that is confusing... (I'm proud of my code