Results 1 to 1 of 1
  1. #1
    .::SCHiM::.'s Avatar
    Join Date
    Sep 2010
    Gender
    male
    Posts
    733
    Reputation
    180
    Thanks
    880
    My Mood
    Twisted

    Hook dynamic linkage

    If you already know how the export/import scheme works in windows you can scroll to the bottom of the page for the source code involved.

    Ever had problems hooking targets that use dynamic linking to call their functions? If you have, you probably used the round about way of hooking LoadLibrary() and GetProcAddress() to see when your target function is being loaded, and then replace the return address with that of your own.

    However there's a more elegant way to hook functions that are imported through dynamic linking. You sill need a launcher and some research beforehand for a 100% reliable method, but that is a requisite for the alternative too.

    So how do we pull this of?

    It's very simple, when an application calls GetProcAddress() on a module, windows searches the export header of that module for the module name supplied in the call. The export header links the function names with their respective addresses(relative to the module base address). When windows finds the name in the export header it returns the corresponding address to the caller.

    Since we are not going to hook this function, further internal explanation is not needed. What is important however is the step before calling GetProcAddress(), more specifically the call to GetModuleHandle().

    GetModuleHandle() searches a struct called the peb for the module, the PEB is located somewhere in the address space of the calling process. In th PEB is a struct called the ldr. The ldr links the names of all the dlls loaded with their corresponding base addresses in the calling process. So when you load a library with LoadLibrary() it's address and name are recored in the ldr. When GetModuleHandle() searches the PEB there's no guarantee that the address returned corresponds to the name supplied. The PEB isn't even write protected so you can mess with it all you want.

    The more absolute readers will probably know what's next. But I just love windows paint so I've painted you guys a picture


    So this is what we are going to do:

    We are going to change the address in the ldr corresponding to User32.dll. So when our target application calls GetModuleHandle() our base address will be returned instead of that of the real module.

    To insure success in a real application you may want to call LoadLibrary() on the module you want to hook yourself. Since you can't hook an entry that isn't there, right? What's more if the library is already loaded LoadLibrary() proceeds as GetModuleHandle and returns the address found in the peb->ldr, which is perfect for us since we can insure that the program only uses our library!

    To avoid race conditions however, you'll need to call LoadLibrary() before your target does. And the only way to do that is to inject your dll in a suspended process which created using a launcher.

    There are only two more things left to talk about before I can show you the code, so hang in tight!

    We've replaced our dll base address with that of user32.dll so all calls to LoadLibrary and GetModuleHandle will return our address. This is all very nice, but how will this help us??

    Very simple, remember that GetProcAddres() is called on the base address of a module in memory? And that it returns the address of the function found in the export header?

    If you do then the path is clear, if you don't I'll explain one more time below.

    When your target calls GetProcAddress() on the address returned by a call to GetModuleHandle() windows will start looking for a function origionaly exported by User32.dll (let's say MessageBoxA). The only problem is that our dll does not export MessageBoxA, so GetProcAddress will fail and your target with it probably. However we can compile our dll to export a function named MessageBoxA, and we can chose what this function does. If we inject this new dll exporting MessageBoxA GetProcAddress() will not fail, and the address of our function is returned to the caller, instead of the address of the real MessageBoxA().

    So to sum it all up:

    Our target dynamically links to User32.dll importing MessageBoxA().
    We can change the PEB address of User32.dll to that of our own.
    When GetProcAddress() is called on our dll code of our choosing gets executed.

    There are only 3 downsides to this hooking method

    You'll need to dig into the target application to see which functions are dynamically linked, if you don't and the target calls a function you haven't exported GetProcAddress() fails, you can of course dissolve these issues by hooking GetProcAddress() but that defeats the purpose.

    To avoid race conditions or failed hooks you'll need a launcher to insure that the peb is patched before the target application starts importing it's addresses.

    While the peb is not a section which anti-cheat programs generally cover, virus scanners get really, really paranoid with programs modifying their PEB. This is because computer viruses often need to make use of the PEB to create offset independent code. So therefore an anti-virus program is likely to flag your program as a virus, just because it reads and changes entries in the ldr.

    Now that's finally over, we can move to the S0uRc3 c0d3S!

    Target.exe!main.cpp
    new console project main.cpp:

    Code:
    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    int main(){
    
    	LoadLibrary("User32.dll");
    
    	printf("Waiting for keypress\n");
    	cin.ignore();
    
    	printf("Base address of User32.dll: 0x%.8x\n", GetModuleHandle("User32.dll"));
    	printf("Base address of MessageBoxA: 0x%.8x\n", GetProcAddress( GetModuleHandle("User32.dll"), "MessageBoxA" ) );
    
    
    
    	system("pause");
    
    return 0;
    }
    New dll project: DllMain.cpp:

    Code:
    #include "Main.h"
    #include <iostream>
    
    void MainThread();
    
    extern int PatchPeb(char* ModuleName, DWORD* NewBase);
    
    CALLBACK DllMain( HANDLE hModule, DWORD  fdwReason, LPVOID lpReserved ){
    
    	if( fdwReason == DLL_PROCESS_ATTACH){
    
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)&MainThread, NULL, NULL, NULL);
    	     return TRUE;
    	}
    
        return TRUE;
    }
    
    
    void MainThread(){
    	printf("The result: 0x%.8x\n", LoadLibrary("User32.dll"));
    	PatchPeb("User32.dll", (DWORD*)GetModuleHandle("pebHook.dll") );
    	printf("The result: 0x%.8x\n", LoadLibrary("User32.dll"));
    return;
    }
    In the same dll project: Main.h

    Code:
    #ifndef MAIN_H_INC
    #define MAIN_H_INC
    
    #include <windows.h>
    
    typedef struct _LSA_UNICODE_STRING {
      USHORT Length;
      USHORT MaximumLength;
      PWSTR  Buffer;
    } LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING;
    
    
    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;
    
    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 struct _RTL_USER_PROCESS_PARAMETERS
    {
    PVOID NuLL;
    } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
    
    
    
    typedef struct _PEB {
      BYTE                          Reserved1[2];
      BYTE                          BeingDebugged;
      BYTE                          Reserved2[1];
      PVOID                         Reserved3[2];
      PPEB_LDR_DATA                 Ldr;
      PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
      BYTE                          Reserved4[104];
      PVOID                         Reserved5[52];
      PVOID							PostProcessInitRoutine;
      BYTE                          Reserved6[128];
      PVOID                         Reserved7[1];
      ULONG                         SessionId;
    } PEB, *PPEB;
    
    #endif
    in the same dll project: Patcher.cpp

    Code:
    #include "Main.h"
    
    char* ANSI_STR(UNICODE_STRING wstr){
    	char* TempStr = new char[wstr.Length];
    	
    	if( WideCharToMultiByte(CP_ACP, 0, wstr.Buffer, (UINT)wstr.Length, TempStr, MAX_PATH, NULL, NULL) == 0){
    		return "ERROR";
    	} else {
    		return TempStr;
    	}
    
    }
    
    int PatchPeb(char* ModuleName, DWORD* NewBase){
    
    PLDR_MODULE LdMod;
    unsigned long* ldr_addr;
    PPEB_LDR_DATA ldr_data;
    char* Str;	
    
    	__asm{
    		 mov eax, fs:[0x30]  
    		 add eax, 0xc            
    		 mov eax, [eax]    
    	     mov ldr_addr, eax    
        }
    
    	
    	__try{
    
            ldr_data = (PPEB_LDR_DATA)ldr_addr;
            LdMod = (PLDR_MODULE)ldr_data->InLoadOrderModuleList.Flink;
    
    	if( LdMod == NULL){
    		return -1;
    	}
    
    
    		 	while( LdMod->BaseAddress != 0){
    				
    				LdMod = (PLDR_MODULE)LdMod->InLoadOrderModuleList.Flink;
    
    					 Str = ANSI_STR( LdMod->BaseDllName );
    
    					//	printf("Does %s == %s?\n", Str,  ModuleName);
    					if( strcmp( Str , ModuleName) == 0){
    							LdMod->BaseAddress = (PVOID)NewBase;
    							delete [] Str;
    							break;
    							
    					} else {
    						delete [] Str;
    					}
    	
    			}
    
    			__asm{
    				 mov eax, fs:[0x30]  
    				 add eax, 0xc            
    				 mov eax, [eax]    
    				 mov ldr_addr, eax    
    			}
    
    		 ldr_data = (PPEB_LDR_DATA)ldr_addr;
    		 LdMod = (PLDR_MODULE)ldr_data->InInitializationOrderModuleList.Flink;
    
    
    		if( ldr_data->Initialized == FALSE ){
    
    				while( LdMod->BaseAddress != 0){
    				
    						 LdMod = (PLDR_MODULE)LdMod->InInitializationOrderModuleList.Flink;
    						 Str = ANSI_STR( LdMod->BaseDllName );
    
    
    
    				//			printf("Does %s == %s?\n", Str,  ModuleName);
    
    						if( strcmp( Str , ModuleName) == 0){
    								LdMod->BaseAddress = (PVOID)NewBase;
    								delete [] Str;
    								break;
    								
    						} else {
    							delete [] Str;
    						}
    		
    				}
    
    	
    
    			__asm{
    				 mov eax, fs:[0x30]  
    				 add eax, 0xc            
    				 mov eax, [eax]    
    				 mov ldr_addr, eax    
    			}
    
    		 ldr_data = (PPEB_LDR_DATA)ldr_addr;
    		LdMod = (PLDR_MODULE)ldr_data->InMemoryOrderModuleList.Flink;
    
    			while( LdMod->BaseAddress != 0){
    				
    						LdMod = (PLDR_MODULE)LdMod->InMemoryOrderModuleList.Flink;
    	        			Str = ANSI_STR( LdMod->BaseDllName );
    				//		printf("Does %s == %s?\n", Str,  ModuleName);
    
    					if( strcmp( Str , ModuleName) == 0){
    							LdMod->BaseAddress = (PVOID)NewBase;
    							delete [] Str;
    							break;
    							
    					} else {
    						delete [] Str;
    					}
    			}
    
    		}
    
    
    	} __except(EXCEPTION_EXECUTE_HANDLER){
    		     return -2;
    	}
    
    
    return 0;
    }
    In the same dll project: Exports.cpp

    Code:
    #define DllExport   __declspec( dllexport )
    
    extern "C" DllExport unsigned long MessageBoxA(unsigned long hwnd, char* Text, char* Title, unsigned long Mask){
     	return 0;
    }
    Example output:


    Credits

    While the code is mostly mine and copied from an old project, I got the idea from: Shearer and Dreg
    For those interested in the original article I can only say: Phrack-65:10
    Last edited by .::SCHiM::.; 08-28-2011 at 09:37 AM.

    I'm SCHiM

    Morals derive from the instinct to survive. Moral behavior is survival behavior above the individual level.

    Polymorphic engine
    Interprocess callback class
    SIN
    Infinite-precision arithmetic
    Hooking dynamic linkage
    (sloppy)Kernel mode Disassembler!!!

    Semi debugger




  2. The Following 2 Users Say Thank You to .::SCHiM::. For This Useful Post:

    Hassan (08-28-2011),_Fk127_ (09-04-2011)

Similar Threads

  1. WR D3D Hook - =o - 03/22/07
    By Dave84311 in forum Hack/Release News
    Replies: 14
    Last Post: 10-06-2007, 09:59 AM
  2. Dynamic Pulse/Blue Ice
    By -[standoff]- in forum Art & Graphic Design
    Replies: 20
    Last Post: 03-13-2007, 03:37 AM
  3. New Hacks Announced & Warrock DX Hook Update
    By Dave84311 in forum Hack/Release News
    Replies: 17
    Last Post: 03-02-2007, 03:54 PM
  4. Changing MAC and Dynamic IP Manually
    By MagikBullet in forum WarRock - International Hacks
    Replies: 32
    Last Post: 12-27-2006, 10:33 PM
  5. Dynamic IP?
    By aldregon in forum General Game Hacking
    Replies: 2
    Last Post: 04-10-2006, 07:31 AM