[Help] Detach DLL from Process

03/02/2013 04:45 iCraziE#1
Ok so I created my dll to inject.

But I have an issue. Since I have injected my dll, when ever the target process is open. I can't rename the dll, it says that the dll is open in the process.

What do I have to do to make it so that it will detach itself?

Here is my APIENTRY code.

Code:
BOOL APIENTRY DllMain(HMODULE hModule, DWORD _reason, LPVOID lpReserved)
{
	if(_reason == DLL_PROCESS_ATTACH)
	{
		CreateThread(0, 0x1000, &Main_Thread, 0, 0, NULL);
	}

	return TRUE;
}
PS. It is saying that the dll is open in the process, even if I don't inject it.

As long as the process is open, it will say its running in the process and cant be deleted or renamed etc.

Same result if I close the process and open it again. Also same after restart computer.

Please if anyone has a solution, i'd appreciate it :)
03/02/2013 09:08 Nightblizard#2
Simply clean everything up that you've done and call [Only registered and activated users can see links. Click Here To Register...] from inside the program.
03/02/2013 12:34 iCraziE#3
Where would I declare Free Library, from what I see, it isnt safe to declare it in the DLLMain.

I also use an injector? Should I create my own injector and add the freelibrary function there?
03/02/2013 14:54 Nightblizard#4
Well, you shouldn't execute any code within DllMain to begin with (yea I know, kernel32 stuff is okay to some degree, but it is still bad practise).

What I've done in a library of mine is the following:
I've exported two functions (Start and End) inside the dll. My injector looks for these functions, injects the dll, recalculates the procedures addresses (injector space to the other programs space) and then calls Start.
Upon unloading I call "End" inside the process which cleans everything up and then I call FreeLibrary (via. CreateRemoteThread).

Works pretty well that way and isn't that hacky.

Some Code:
Code:
	void Injector::UnloadDll(Process const& process, Module const& dll)
	{
		//Loads the injected dll into the injector (LoadLibrary)
		auto lib = Module::FromLibrary(Process::GetCurrentProcess(), dll.GetPath());
		//Where is the function that does all the cleanup?
		UINT_PTR endAddr = lib.GetProcAddress("End");
		//We have to recalculate the procedures address, since it isn't guaranteed to be at the same location inside the other process
		auto diff = reinterpret_cast<UINT_PTR>(dll.GetHandle()) - reinterpret_cast<UINT_PTR>(lib.GetHandle());
		endAddr = endAddr + diff;
		//Call End
		auto thread = process.CreateRemoteThread(endAddr);
		thread.WaitForSingleObject();
		//After everything got cleaned up, unload the dll
		auto thread2 = process.CreateRemoteThread(reinterpret_cast<UINT_PTR>(FreeLibrary), reinterpret_cast<LPVOID>(dll.GetHandle()));
		thread2.WaitForSingleObject();
	}
Calling "Start" works pretty much the same way, except that I don't call FreeLibrary (for obvious reasons). This won't work, however, if you do scary stuff inside DllMain!
03/02/2013 15:50 iCraziE#5
I havent really done anything inside dll main. Here is my dll main..

Code:
BOOL APIENTRY DllMain(HMODULE hModule, DWORD _reason, LPVOID lpReserved)
{
	if(_reason == DLL_PROCESS_ATTACH)
	{
		CreateThread(0, 0x1000, &Main_Thread, 0, 0, NULL);
	}

	return TRUE;
}
03/02/2013 17:15 Nightblizard#6
That's already too much for my way of doing things.
03/02/2013 17:43 iCraziE#7
So what do you suggest?

I create my own Injector, and also include your code snippet to unload the dll.

But what should happen with DLLMain?
03/02/2013 18:20 MrSm!th#8
You leave it empty.
Without Nightblizard's includes that snippet won't work btw :p
03/03/2013 03:01 Master674b#9
Quote:
Originally Posted by Nightblizard View Post
Well, you shouldn't execute any code within DllMain to begin with (yea I know, kernel32 stuff is okay to some degree, but it is still bad practise).

What I've done in a library of mine is the following:
I've exported two functions (Start and End) inside the dll. My injector looks for these functions, injects the dll, recalculates the procedures addresses (injector space to the other programs space) and then calls Start.
Upon unloading I call "End" inside the process which cleans everything up and then I call FreeLibrary (via. CreateRemoteThread).

Works pretty well that way and isn't that hacky.
You should also use DONT_RESOLVE_DLL_REFERENCES when loading a dll only for export lookups if you're not doing that already. Also you don't need to do a module lookup because you can simply get the return value of LoadLibrary in the remote process with GetExitCodeThread =)

Some Code:
Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

#if WIN32
using DWORD_PTR = System.UInt32;
#elif WIN64
using DWORD_PTR = System.UInt64;
#endif

namespace supdoodcoolparty
{
    public static class Memory
    {

        #region Constants
        private const int MaxStringLength = 512;
        #endregion

        #region Helper functions
        public static uint Reverse( uint uData )
        {
            byte[] bNewBytes = new byte[4];
            bNewBytes[0] = (byte)( uData << 24 >> 24 );
            bNewBytes[1] = (byte)( uData << 16 >> 24 );
            bNewBytes[2] = (byte)( uData << 08 >> 24 );
            bNewBytes[3] = (byte)( uData << 00 >> 24 );

            return BitConverter.ToUInt32( bNewBytes, 0 );
        }
        #endregion

        #region Open/Close
        public static IntPtr OpenProcess( int nProcessId )
        {
            return WinAPI.OpenProcess( ProcessAccessFlags.CreateThread | ProcessAccessFlags.VMOperation |
                                       ProcessAccessFlags.VMRead | ProcessAccessFlags.VMWrite |
                                       ProcessAccessFlags.QueryInformation, false, nProcessId );
        }

        public static IntPtr OpenThread( int nThreadId )
        {
            return WinAPI.OpenThread( ThreadAccessFlags.AllAccess, false, (uint) nThreadId );
        }
        #endregion

        #region Write
        public static unsafe bool Write<T>( IntPtr hProcess, DWORD_PTR dwAddress, T tData )
        {
            Type tParamType = typeof( T );
            if( tParamType == typeof( string ) )
                return Write( hProcess, dwAddress, (string)(object) tData, CharSet.Ansi );
            
            byte[] bBuffer;
            uint uTypeSize = (uint) Marshal.SizeOf( typeof( T ) );

            if( tParamType == typeof( bool ) )
                bBuffer = BitConverter.GetBytes( (bool)(object) tData );
            else if( tParamType == typeof( byte ) )
                bBuffer = BitConverter.GetBytes( (byte)(object) tData );
            else if( tParamType == typeof( char ) )
                bBuffer = BitConverter.GetBytes( (char)(object) tData );
            else if( tParamType == typeof( short ) )
                bBuffer = BitConverter.GetBytes( (short)(object) tData );
            else if( tParamType == typeof( ushort ) )
                bBuffer = BitConverter.GetBytes( (ushort)(object) tData );
            else if( tParamType == typeof( int ) )
                bBuffer = BitConverter.GetBytes( (int)(object) tData );
            else if( tParamType == typeof( uint ) )
                bBuffer = BitConverter.GetBytes( (uint)(object) tData );
            else if( tParamType == typeof( long ) )
                bBuffer = BitConverter.GetBytes( (long)(object) tData );
            else if( tParamType == typeof( ulong ) )
                bBuffer = BitConverter.GetBytes( (ulong)(object) tData );
            else if( tParamType == typeof( float ) )
                bBuffer = BitConverter.GetBytes( (float)(object) tData );
            else if( tParamType == typeof( double ) )
                bBuffer = BitConverter.GetBytes( (double)(object) tData );
            else
                throw new Exception( "Memory.Write Exception: Invalid type!" );

            bool bResult = false;
            uint dwBytesWritten = 0;

            fixed( byte* bMemoryBuffer = bBuffer )
                bResult = WinAPI.WriteProcessMemory( hProcess, dwAddress, (IntPtr) bMemoryBuffer, uTypeSize, out dwBytesWritten );

            return bResult && dwBytesWritten == uTypeSize;
        }

        public static unsafe bool Write( IntPtr hProcess, DWORD_PTR dwAddress, string sString, CharSet sCharacterSet )
        {
            byte[] bBuffer;
            if( sCharacterSet == CharSet.None || sCharacterSet == CharSet.Ansi )
                bBuffer = Encoding.ASCII.GetBytes( sString );
            else
                bBuffer = Encoding.Unicode.GetBytes( sString );

            bool bResult = false;
            uint dwBytesWritten = 0;
            uint dwStringLength = (uint) bBuffer.Length;

            fixed( byte* bMemoryBuffer = bBuffer )
                bResult = WinAPI.WriteProcessMemory( hProcess, dwAddress, (IntPtr) bMemoryBuffer, dwStringLength, out dwBytesWritten );

            return bResult && dwBytesWritten == dwStringLength;
        }
        #endregion

        #region Read
        public static T Read<T>( IntPtr hProcess, DWORD_PTR dwAddress )
        {
            if( typeof( T ) == typeof( string ) )
                return (T)(object) Read( hProcess, dwAddress, CharSet.Ansi );

            IntPtr lpBuffer = IntPtr.Zero;
            bool bResult = false;
            uint dwSize = 0;
            uint dwBytesRead = 0;

            try
            {
                dwSize = (uint) Marshal.SizeOf( typeof( T ) );
                lpBuffer = Marshal.AllocHGlobal( (int) dwSize );
                
                bResult = WinAPI.ReadProcessMemory( hProcess, dwAddress, lpBuffer, dwSize, out dwBytesRead );

                if( bResult && dwBytesRead == dwSize )
                    return (T) Marshal.PtrToStructure( lpBuffer, typeof( T ) );
            }
            catch { }

            if( lpBuffer != IntPtr.Zero )
                Marshal.FreeHGlobal( lpBuffer );

            return default( T );
        }

        public static string Read( IntPtr hProcess, DWORD_PTR dwAddress, CharSet sCharacterSet )
        {
            if( sCharacterSet == CharSet.None || sCharacterSet == CharSet.Ansi )
            {
                // One byte character set
                uint uCurrentPosition = 0;
                uint uMaxLength = MaxStringLength;

                byte[] bStringBuffer = new byte[uMaxLength];
                byte bCurrentByte = Read<byte>( hProcess, dwAddress );

                while( bCurrentByte != 0 && uCurrentPosition < uMaxLength )
                {
                    bStringBuffer[uCurrentPosition++] = bCurrentByte;
                    bCurrentByte = Read<byte>( hProcess, dwAddress + uCurrentPosition );
                }

                return Encoding.ASCII.GetString( bStringBuffer );
            }
            else
            {
                // Two byte character set
                uint uCurrentPosition = 0;
                uint uMaxLength = MaxStringLength * 2;

                byte[] bStringBuffer = new byte[uMaxLength];
                byte bFirstByte = Read<byte>( hProcess, dwAddress );
                byte bSecondByte = Read<byte>( hProcess, dwAddress + 1 );

                while( bFirstByte != 0 && bSecondByte != 0 && uCurrentPosition < uMaxLength )
                {
                    bStringBuffer[uCurrentPosition++] = bFirstByte;
                    bStringBuffer[uCurrentPosition++] = bSecondByte;

                    bFirstByte = Read<byte>( hProcess, dwAddress + uCurrentPosition );
                    bSecondByte = Read<byte>( hProcess, dwAddress + uCurrentPosition + 1 );
                }

                return Encoding.Unicode.GetString( bStringBuffer );
            }
        }

        public static byte[] Read( IntPtr hProcess, DWORD_PTR dwAddress, uint dwLength )
        {
            byte[] bBuffer = new byte[dwLength];
            IntPtr lpBuffer = IntPtr.Zero;
            bool bResult = false;
            uint dwBytesRead = 0;

            try
            {
                lpBuffer = Marshal.AllocHGlobal( (int) dwLength );
                bResult = WinAPI.ReadProcessMemory( hProcess, dwAddress, lpBuffer, dwLength, out dwBytesRead );

                if( bResult && dwBytesRead == dwLength )
                    Marshal.Copy( lpBuffer, bBuffer, 0, (int) dwLength );
            }
            catch { }

            if( lpBuffer != IntPtr.Zero )
                Marshal.FreeHGlobal( lpBuffer );

            return bBuffer;
        }
        #endregion

        #region Allocate/Free
        public static DWORD_PTR Allocate( IntPtr hProcess, uint dwSize )
        {
            return WinAPI.VirtualAllocEx( hProcess, 0, dwSize,
                    AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ExecuteReadWrite );
        }

        public static bool Free( IntPtr hProcess, DWORD_PTR dwAddress )
        {
            return WinAPI.VirtualFreeEx( hProcess, dwAddress,
                    0, FreeType.Release );
        }
        #endregion

        #region DLL Injection/Loading
        public static IntPtr LoadLibraryEx( IntPtr hProcess, string sModule )
        {
            uint dwResult = 0;
            IntPtr hKernel32 = WinAPI.GetModuleHandleW( "kernel32.dll" );
            if( hKernel32 != IntPtr.Zero )
            {
                DWORD_PTR dwLoadLibrary = WinAPI.GetProcAddress( hKernel32, "LoadLibraryW" );
                if( dwLoadLibrary != 0 )
                {
                    byte[] bBuffer = Encoding.Unicode.GetBytes( sModule );
                    uint dwBufferLength = (uint) bBuffer.Length + 2;
                    DWORD_PTR dwCodeCave = Memory.Allocate( hProcess, dwBufferLength );
                    if( dwCodeCave != 0 )
                    {
                        if( Memory.Write( hProcess, dwCodeCave, sModule, CharSet.Unicode ) )
                        {
                            uint dwThreadId = 0;
                            IntPtr hThread = WinAPI.CreateRemoteThread( hProcess, 0, 0,
                                    dwLoadLibrary, dwCodeCave, 0, out dwThreadId );

                            if( hThread != IntPtr.Zero )
                            {
                                uint dwWaitResult = WinAPI.WaitForSingleObject( hThread, 0xFFFFFFFF );
                                if( dwWaitResult == 0 )
                                    WinAPI.GetExitCodeThread( hThread, out dwResult );

                                WinAPI.CloseHandle( hThread );
                            }
                        }

                        Memory.Free( hProcess, dwCodeCave );
                    }
                }
            }
            
            return (IntPtr) dwResult;
        }

        public static IntPtr Import( string sModule )
        {
            return WinAPI.LoadLibraryW( sModule );
        }
        #endregion

        #region DLL Ejection/Unloading
        public static bool FreeLibraryEx( IntPtr hProcess, IntPtr hRemoteModule )
        {
            uint dwResult = 0;
            IntPtr hKernel32 = WinAPI.GetModuleHandleW( "kernel32.dll" );
            if( hKernel32 != IntPtr.Zero )
            {
                DWORD_PTR dwFreeLibrary = WinAPI.GetProcAddress( hKernel32, "FreeLibrary" );
                if( dwFreeLibrary != 0 )
                {
                    uint dwThreadId = 0;
                    IntPtr hThread = WinAPI.CreateRemoteThread(hProcess, 0, 0,
                            dwFreeLibrary, (DWORD_PTR) hRemoteModule, 0, out dwThreadId );

                    if( hThread != IntPtr.Zero )
                    {
                        uint dwWaitResult = WinAPI.WaitForSingleObject( hThread, 0xFFFFFFFF );
                        if( dwWaitResult == 0 )
                            WinAPI.GetExitCodeThread( hThread, out dwResult );

                        WinAPI.CloseHandle( hThread );
                    }
                }
            }

            return dwResult != 0;
        }
        #endregion

        #region Internal calls
        public static string Call( IntPtr hProcess, CallingConvention cCallingConvention, CharSet cCharacterSet, DWORD_PTR dwAddress, params object[] oParams )
        {
            return Read( hProcess, Call<DWORD_PTR>( hProcess, cCallingConvention, dwAddress, oParams ), cCharacterSet );
        }

        public static T Call<T>( IntPtr hProcess, CallingConvention cCallingConvention, DWORD_PTR dwAddress, params object[] oParams )
        {
            Type tManagedType = typeof( T );

            DWORD_PTR dwExecuteCave = Allocate( hProcess, 1024 );
            DWORD_PTR dwReturnCave = Allocate( hProcess, 12 );
            uint uByteIndex = 0;

            List<object> lsParams = new List<object>( oParams );

            if( cCallingConvention == CallingConvention.ThisCall ||
                cCallingConvention == CallingConvention.FastCall ||
                cCallingConvention == CallingConvention.StdCall )
            {
                // MOV ECX, lsParams[0]
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xB9 );
                Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, Reverse( (DWORD_PTR) lsParams[0] ) );
                uByteIndex += sizeof( DWORD_PTR );
                lsParams.RemoveAt( 0 );
            }

            lsParams.Reverse();
            foreach( object oParam in lsParams )
            {
                // PUSH oParam
                Type tParamType = oParam.GetType();
                int nSize = Marshal.SizeOf( tParamType );

                if( nSize == 1 )
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x6A );
                else
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x68 );

                if( tParamType == typeof( bool ) )
                     Write<bool>( hProcess, dwExecuteCave + uByteIndex, (bool) oParam );
                else if( tParamType == typeof( byte ) )
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex, (byte) oParam );
                else if( tParamType == typeof( char ) )
                    Write<char>( hProcess, dwExecuteCave + uByteIndex, (char) oParam );
                else if( tParamType == typeof( short ) )
                    Write<short>( hProcess, dwExecuteCave + uByteIndex, (short) oParam );
                else if( tParamType == typeof( ushort ) )
                    Write<ushort>( hProcess, dwExecuteCave + uByteIndex, (ushort) oParam );
                else if( tParamType == typeof( int ) )
                    Write<int>( hProcess, dwExecuteCave + uByteIndex, (int) oParam );
                else if( tParamType == typeof( uint ) )
                    Write<uint>( hProcess, dwExecuteCave + uByteIndex, (uint) oParam );
                else if( tParamType == typeof( long ) )
                    Write<long>( hProcess, dwExecuteCave + uByteIndex, (long) oParam );
                else if( tParamType == typeof( ulong ) )
                    Write<ulong>( hProcess, dwExecuteCave + uByteIndex, (ulong) oParam );
                else if( tParamType == typeof( float ) )
                    Write<float>( hProcess, dwExecuteCave + uByteIndex, (float) oParam );
                else if( tParamType == typeof( double ) )
                    Write<double>( hProcess, dwExecuteCave + uByteIndex, (double) oParam );

                uByteIndex += (uint) nSize;
            }

            // MOV EAX, dwAddress
            Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xB8 );
            Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, Reverse( dwAddress ) );
            uByteIndex += sizeof( DWORD_PTR );

            // CALL EAX
            Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xFF );
            Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xD0 );

            if( cCallingConvention == CallingConvention.Cdecl )
            {
                // ADD ESP, lsParams.Count * 4
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x83 );
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xC4 );
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, (byte)( lsParams.Count * 4 ) );
            }

            if( tManagedType == typeof( float ) )
            {
                // FSTP DWORD [dwReturnCave]
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xD9 );
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x1D );
                Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, Reverse( dwReturnCave ) );
                uByteIndex += sizeof( DWORD_PTR );
            }
            else
            {
                // MOV DWORD [dwReturnCave], EAX
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xA3 );
                Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, Reverse( dwReturnCave ) );
                uByteIndex += sizeof( DWORD_PTR );

                // MOV DWORD [dwReturnCave + 4], EDX
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x89 );
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x15 );
                Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, Reverse( dwReturnCave + 4 ) );
                uByteIndex += sizeof( DWORD_PTR );
            }

            // RET
            Write<byte>( hProcess, dwExecuteCave + uByteIndex, 0xC3 );

            uint dwThreadId = 0;
            IntPtr hThread = WinAPI.CreateRemoteThread( hProcess, 0, 0,
                    dwExecuteCave, 0, 0, out dwThreadId );

            if( hThread == IntPtr.Zero )
                throw new Exception( "Memory.Call Exception: Could not call function!" );
            
            WinAPI.WaitForSingleObject( hThread, 0xFFFFFFFF );
            WinAPI.CloseHandle( hThread );

            T tReturn = default( T );
            if( tManagedType == typeof( bool ) )
                tReturn = (T) (object) Read<bool>( hProcess, dwReturnCave );
            if( tManagedType == typeof( byte ) )
                tReturn = (T) (object) Read<byte>( hProcess, dwReturnCave );
            if( tManagedType == typeof( char ) )
                tReturn = (T) (object) Read<char>( hProcess, dwReturnCave );
            if( tManagedType == typeof( short ) )
                tReturn = (T) (object) Read<short>( hProcess, dwReturnCave );
            if( tManagedType == typeof( ushort ) )
                tReturn = (T) (object) Read<ushort>( hProcess, dwReturnCave );
            if( tManagedType == typeof( int ) )
                tReturn = (T) (object) Read<int>( hProcess, dwReturnCave );
            if( tManagedType == typeof( uint ) )
                tReturn = (T) (object) Read<uint>( hProcess, dwReturnCave );
            if( tManagedType == typeof( long ) )
                tReturn = (T) (object) Read<long>( hProcess, dwReturnCave );
            if( tManagedType == typeof( ulong ) )
                tReturn = (T) (object) Read<ulong>( hProcess, dwReturnCave );
            if( tManagedType == typeof( float ) )
                tReturn = (T) (object) Read<float>( hProcess, dwReturnCave );
            if( tManagedType == typeof( double ) )
                tReturn = (T) (object) Read<double>( hProcess, Read<DWORD_PTR>( hProcess, dwReturnCave ) );

            Free( hProcess, dwReturnCave );
            Free( hProcess, dwExecuteCave );

            return tReturn;
        }
        #endregion

        #region External Calls
        public static T CallExport<T>( IntPtr hProcess, IntPtr hImportModule, IntPtr hExportModule, string sExportFunction, uint dwParam = 0 )
        {
            uint dwExitCode = 0;
            DWORD_PTR dwAddress = WinAPI.GetProcAddress( hImportModule, sExportFunction );
            if( dwAddress == 0 )
                throw new Exception( "Memory.CallExport Exception: Export function was not found in import module!" );

            uint dwThreadId = 0;
            dwAddress = dwAddress - (DWORD_PTR) hImportModule + (DWORD_PTR) hExportModule;
            IntPtr hThread = WinAPI.CreateRemoteThread( hProcess, 0, 0,
                    dwAddress, dwParam, 0, out dwThreadId );

            if( hThread == IntPtr.Zero )
                throw new Exception( "Memory.CallExport Exception: Could not call export function!" );

            uint uWaitResult = WinAPI.WaitForSingleObject( hThread, 0xFFFFFFFF );
            if( uWaitResult == 0 )
                WinAPI.GetExitCodeThread( hThread, out dwExitCode );

            WinAPI.CloseHandle( hThread );
            if( uWaitResult != 0 )
                throw new Exception( "Memory.CallExport Exception: Export function never returned!" );

            if( typeof( T ) == typeof( string ) )
                return (T)(object) Read( hProcess, (DWORD_PTR) dwExitCode, CharSet.Ansi );
            else if( typeof( T ) == typeof( byte ) )
                return (T)(object)(byte) dwExitCode;
            else if( typeof( T ) == typeof( char ) )
                return (T)(object)(char) dwExitCode;
            else if( typeof( T ) == typeof( short ) )
                return (T)(object)(short) dwExitCode;
            else if( typeof( T ) == typeof( ushort ) )
                return (T)(object)(ushort) dwExitCode;
            else if( typeof( T ) == typeof( int ) )
                return (T)(object)(int) dwExitCode;
            else if( typeof( T ) == typeof( uint ) )
                return (T)(object)(uint) dwExitCode;
            else if( typeof( T ) == typeof( long ) )
                return (T)(object)(long) dwExitCode;
            else if( typeof( T ) == typeof( ulong ) )
                return (T)(object)(ulong) dwExitCode;
            else if( typeof( T ) == typeof( bool ) )
                return (T)(object) Convert.ToBoolean( dwExitCode );

            throw new Exception( "Memory.CallExport Exception: Could not identify return type!" );
        }

        public static void CallExport( IntPtr hProcess, IntPtr hImportModule, IntPtr hExportModule, string sExportFunction, uint dwParam = 0 )
        {
            DWORD_PTR dwAddress = WinAPI.GetProcAddress( hImportModule, sExportFunction );
            if( dwAddress == 0 )
                throw new Exception( "Memory.CallExport Exception: Export function was not found in import module!" );

            uint dwThreadId = 0;
            dwAddress = dwAddress - (DWORD_PTR) hImportModule + (DWORD_PTR) hExportModule;
            IntPtr hThread = WinAPI.CreateRemoteThread( hProcess, 0, 0,
                    dwAddress, dwParam, 0, out dwThreadId );

            if( hThread == IntPtr.Zero )
                throw new Exception( "Memory.CallExport Exception: Could not call export function!" );

            WinAPI.CloseHandle( hThread );
        }
        #endregion

    }
}
03/03/2013 13:04 Nightblizard#10
Quote:
Originally Posted by MrSm!th View Post
You leave it empty.
Without Nightblizard's includes that snippet won't work btw :p
Yea, of course not as this is just a snippet from my library to show what I've meant. But it should be pretty obious what's going on under the hood, since my functions names are pretty close to those from the WinAPI.

Quote:
Originally Posted by Master674b View Post
You should also use DONT_RESOLVE_DLL_REFERENCES when loading a dll only for export lookups if you're not doing that already.
Nah, I guess it is pretty obvious that I don't want you to do anything inside DllMain. And loading a module without setting said flag will simply fuck your program up, if still decide to do so and put all your Code inside DllMain.
And afterall my library is open source so you can change it, if you really want to do hacky shit.

Quote:
Originally Posted by Master674b View Post
Also you don't need to do a module lookup because you can simply get the return value of LoadLibrary in the remote process with GetExitCodeThread =)
I'm not so sure about that. Is it guaranteed that your Dll will be loaded < 0x100000000 inside an x64 environment? I don't know for sure, so I'll stick with the safe way. ;)
03/03/2013 15:42 link#11
Quote:
Originally Posted by Nightblizard View Post
I'm not so sure about that. Is it guaranteed that your Dll will be loaded < 0x100000000 inside an x64 environment? I don't know for sure, so I'll stick with the safe way. ;)
Only if your Dll is a x86 binary, otherwise your Dll might get any imagebase if its default one is taken and GetExitCodeThread would only return the lower dword of it. Means your code is both x64- and x86-compliant.

DONT_RESOLVE_DLL_REFERENCES will make the Dll-loader not resolve any imports, so you won't be able to call any code inside your Dll unless you do the resolving yourself.

Btw. you could also call FreeLibraryAndExitThread from within your Dll and implement some quit-switch with it.

@Nightblizard:
There is nothing wrong with creating a thread inside DllMain, it will work.
It's just not recommended as putting code into DllMain may tempt to use more and more code in DllMain, even communication, loading or synchronizing stuff which might result in a deadlock or race conditions, if you're careless.
If you know what you're doing and what you can and cannot do, there won't be a problem.

Also if you clean up your stuff in End by creating it in a thread without pausing/synchronizing the rest, you could create race conditions depending on what you're doing in your End.
03/03/2013 15:47 iCraziE#12
:( this is starting to go a little too far over my head. i think i willl try a different approach to get what i need done
thanks for all your help anyway.
03/04/2013 11:54 Mi4uric3#13
What about "[Only registered and activated users can see links. Click Here To Register...]"? You can call this from your DLL, make sure all other threads which belong to the dll have exited before