[C#] Standalone memory reads, writes, calls, and more menu

User Tag List

Results 1 to 9 of 9
  1. #1
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1515
    Join Date
    May 2008
    Posts
    2,433
    Thanks G/R
    81/336
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)

    [C#] Standalone memory reads, writes, calls, and more

    I'm looking at BlackMagic/fasmmanaged - although I don't discourage use of these libs, I don't understand why people require them for a few simple memory reads here and there. So here's some code which you can freely edit and distribute as you like.


    It currently handles:


    • Opening and obtaining process and thread handles
    • Managed type memory reads
    • Managed type memory writes
    • Memory allocation
    • Memory freeing
    • DLL importing
    • DLL injection
    • DLL ejection
    • Thread suspending
    • Thread resuming
    • Complete external memory function calls
    • Complete external export function calls



    Things you should know:

    • You must obtain the opened process handle for use with any of these functions.
    • You must specify "this" as the first parameter, for class calls (__thiscall, __stdcall, __fastcall). It will be placed in ecx.
    • Memory calls are NOT thread-safe by any means - you need to manage this yourself. Thread suspend and resume will work in most cases.
    • I'll try to answer any questions you have in this thread.



    Try to understand the code as much as possible - it will help you in the long run. Some knowledge in memory and assembly will help a great deal.

    Regarding the external function caller; I have no clue about 64-bit assembly, so stick to using 32-bit builds (make sure you define WIN32 when compiling!) Otherwise you will probably have problems.


    Code:
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using System.Text;
    
    #if WIN32
    using DWORD_PTR = System.UInt32;
    #elif WIN64
    using DWORD_PTR = System.UInt64;
    #endif
    
    using JaddMem.Imports;
    
    namespace JaddMem
    {
        internal static class Memory
        {
    
            #region Constants
            private const int MaxStringLength = 512;
            #endregion
    
            #region Helper functions
            /// <summary>
            /// Reverses the byte order of an integer.
            /// </summary>
            public static T Reverse<T>( T tData )
            {
                int nSize = Marshal.SizeOf( typeof( T ) );
    
                byte[] bOldBytes = Functions.ConvertType( tData );
                byte[] bNewBytes = new byte[nSize];
    
                for( int i = 0; i < nSize; i++ )
                    bNewBytes[i] = bOldBytes[nSize - i - 1];
    
                return Functions.ConvertType<T>( bNewBytes );
            }
            #endregion
    
            #region Open/Close
            /// <summary>
            /// Obtains a privileged handle to the specified process.
            /// </summary>
            public static IntPtr OpenProcess( int nProcessId )
            {
                return WinAPI.OpenProcess( ProcessAccessFlags.CreateThread | ProcessAccessFlags.VMOperation |
                                           ProcessAccessFlags.VMRead | ProcessAccessFlags.VMWrite |
                                           ProcessAccessFlags.QueryInformation, false, nProcessId );
            }
    
            /// <summary>
            /// Obtains a privileged handle to the specified thread.
            /// </summary>
            public static IntPtr OpenThread( int nThreadId )
            {
                return WinAPI.OpenThread( ThreadAccessFlags.AllAccess, false, (uint) nThreadId );
            }
    
            /// <summary>
            /// Closes a handle to a process or thread.
            /// </summary>
            public static void CloseHandle( IntPtr hObject )
            {
                WinAPI.CloseHandle( hObject );
            }
            #endregion
    
            #region Write
            /// <summary>
            /// Writes memory to the specified process.
            /// </summary>
            public static unsafe bool Write<T>( IntPtr hProcess, DWORD_PTR dwAddress, T tData, CharSet eCharacterSet = CharSet.Unicode )
            {
                byte[] bBuffer = Functions.ConvertType( tData, eCharacterSet );
                bool bResult = false;
                uint dwBytesWritten = 0;
    
                fixed( byte* bMemoryBuffer = bBuffer )
                    bResult = WinAPI.WriteProcessMemory( hProcess, dwAddress, (IntPtr) bMemoryBuffer, (uint) bBuffer.Length, out dwBytesWritten );
    
                if( typeof( T ) == typeof( string ) )
                {
                    int nStringLength = ( (string)(object) tData ).Length;
                    if( eCharacterSet == CharSet.Auto || eCharacterSet == CharSet.Unicode )
                        bResult &= Write<short>( hProcess, dwAddress + (uint) nStringLength, 0 );
                    else
                        bResult &= Write<byte>( hProcess, dwAddress + (uint) nStringLength, 0 );
                }
    
                return bResult && dwBytesWritten == bBuffer.Length;
            }
            #endregion
    
            #region Read
            /// <summary>
            /// Reads a byte buffer from memory from the specified process.
            /// </summary>
            public static byte[] Read( IntPtr hProcess, DWORD_PTR dwAddress, int nLength )
            {
                byte[] bBuffer = new byte[nLength];
                IntPtr lpBuffer = IntPtr.Zero;
                bool bResult = false;
                uint dwBytesRead = 0;
    
                try
                {
                    lpBuffer = Marshal.AllocHGlobal( nLength );
                    bResult = WinAPI.ReadProcessMemory( hProcess, dwAddress, lpBuffer, (uint) nLength, out dwBytesRead );
    
                    if( bResult && dwBytesRead == nLength )
                        Marshal.Copy( lpBuffer, bBuffer, 0, nLength );
                }
                catch { }
    
                if( lpBuffer != IntPtr.Zero )
                    Marshal.FreeHGlobal( lpBuffer );
    
                return bBuffer;
            }
    
            /// <summary>
            /// Reads memory from the specified process.
            /// </summary>
            public static T Read<T>( IntPtr hProcess, DWORD_PTR dwAddress, CharSet eCharacterSet = CharSet.Unicode, int nLength = MaxStringLength )
            {
                uint dwSize = (uint) Marshal.SizeOf( typeof( T ) );
                byte[] bResult = Read( hProcess, dwAddress, nLength );
    
                return Functions.ConvertType<T>( bResult, eCharacterSet, nLength );
            }
            #endregion
    
            #region Allocate/Free
            /// <summary>
            /// Allocates memory in the specified process.
            /// </summary>
            public static DWORD_PTR Allocate( IntPtr hProcess, uint dwSize )
            {
                return WinAPI.VirtualAllocEx( hProcess, 0, dwSize,
                        AllocationType.Commit | AllocationType.Reserve, MemoryProtection.ExecuteReadWrite );
            }
    
            /// <summary>
            /// Frees memory from the specified process.
            /// </summary>
            public static bool Free( IntPtr hProcess, DWORD_PTR dwAddress )
            {
                return WinAPI.VirtualFreeEx( hProcess, dwAddress, 0, FreeType.Release );
            }
            #endregion
    
            #region Suspend/Resume Thread
            /// <summary>
            /// Suspends the specified thread.
            /// </summary>
            public static bool SuspendThread( IntPtr hThread )
            {
                return (int) WinAPI.SuspendThread( hThread ) != -1;
            }
    
            /// <summary>
            /// Resumes the specified thread.
            /// </summary>
            public static bool ResumeThread( IntPtr hThread )
            {
                return (int) WinAPI.ResumeThread( hThread ) != -1;
            }
            #endregion
    
            #region DLL Injection/Loading
            /// <summary>
            /// Loads a library into the specified process.
            /// </summary>
            public static DWORD_PTR 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 dwResult;
            }
    
            /// <summary>
            /// Imports and obtains the handle to a library.
            /// </summary>
            public static IntPtr Import( string sModule )
            {
                return WinAPI.LoadLibraryW( sModule );
            }
            #endregion
    
            #region DLL Ejection/Unloading
            /// <summary>
            /// Frees a library from the specified process.
            /// </summary>
            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
            /// <summary>
            /// Calls a function and obtains the result from the specified process.
            /// </summary>
            public static T Call<T>( IntPtr hProcess, CallingConvention eCallingConvention, 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( eCallingConvention == CallingConvention.ThisCall ||
                    eCallingConvention == CallingConvention.FastCall ||
                    eCallingConvention == CallingConvention.StdCall )
                {
                    // MOV ECX, lsParams[0]
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xB9 );
                    Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, (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, dwAddress );
                uByteIndex += sizeof( DWORD_PTR );
    
                // CALL EAX
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xFF );
                Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xD0 );
    
                if( eCallingConvention == 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, dwReturnCave );
                    uByteIndex += sizeof( DWORD_PTR );
                }
                else
                {
                    // MOV DWORD [dwReturnCave], EAX
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x89 );
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0x05 );
                    Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, 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, 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;
            }
    
            /// <summary>
            /// Calls a function and obtains the result from the specified process.
            /// </summary>
            public static string Call( IntPtr hProcess, CallingConvention eCallingConvention, CharSet eCharacterSet, DWORD_PTR dwAddress, params object[] oParams )
            {
                return Read<string>( hProcess, Call<DWORD_PTR>( hProcess, eCallingConvention, dwAddress, oParams ), eCharacterSet );
            }
            
            /// <summary>
            /// Calls a function in the specified process.
            /// </summary>
            public static void Call( IntPtr hProcess, CallingConvention eCallingConvention, DWORD_PTR dwAddress, params object[] oParams )
            {
                Call<uint>( hProcess, eCallingConvention, dwAddress, oParams );
            }
            #endregion
    
            #region External Calls
            /// <summary>
            /// Calls an export function and obtains the result from the specified process.
            /// </summary>
            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<string>( 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!" );
            }
    
            /// <summary>
            /// Calls an export function in the specified process.
            /// </summary>
            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
    
        }
    }
    Some other info you need:
    - Functions.cs
    - Imports/Constants.cs
    - Imports/WinAPI.cs

    Credit isn't required, but would be appreciated.

    I'll post an out-of-process Lua wrapper shortly, so stay tuned!
    Last edited by Jadd; 08-27-2013 at 07:01 PM. Reason: Updated

    [C#] Standalone memory reads, writes, calls, and more
  2. #2
    miceiken's Avatar Contributor Authenticator enabled
    Reputation
    209
    Join Date
    Dec 2007
    Posts
    401
    Thanks G/R
    7/9
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice share

  3. #3
    JuJuBoSc's Avatar Banned for scamming CoreCoins Purchaser
    Reputation
    1019
    Join Date
    May 2007
    Posts
    922
    Thanks G/R
    1/3
    Trade Feedback
    1 (100%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    That's clean wrapper, I wonder how you will mess with thread synchronisation with this as it use CreateRemoteThread, interesting read anyway

  4. #4
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1515
    Join Date
    May 2008
    Posts
    2,433
    Thanks G/R
    81/336
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by JuJuBoSc View Post
    That's clean wrapper, I wonder how you will mess with thread synchronisation with this as it use CreateRemoteThread, interesting read anyway
    Oh yeah, thread safety is a big issue with this code. But luckily it's not a hard thing to get around, people could easily write a call queue hook in a main-thread function.

  5. #5
    ~Unknown~'s Avatar Contributor
    Reputation
    193
    Join Date
    Jan 2009
    Posts
    211
    Thanks G/R
    0/5
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice release. I look forward to the OOP Lua wrapper

  6. #6
    Apoc's Avatar Angry Penguin
    Reputation
    1388
    Join Date
    Jan 2008
    Posts
    2,750
    Thanks G/R
    0/13
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Clean code, but inherently slow.

    The reason I wrote GreyMagic in the first place, was to make a generic Read/Write wrapper, that didn't hit the marshaler. (Marshaling is incredibly slow. Tests with 100 million reads of an integer, showed a 12 second difference between using your method, vs the one I wrote for GreyMagic)

    I agree, fasm isn't *really* needed, but when you need to do more complex things (like calling a function a few hundred times [traceline]) being able to write the ASM that runs directly is always nice. (Plus, you don't need to remember the asm<->byte conversions!)

    For simple calls and the like, you're better off using something like what you wrote (if you don't care about thread safety).

  7. #7
    -Ryuk-'s Avatar Elite User CoreCoins Purchaser Authenticator enabled
    Reputation
    529
    Join Date
    Nov 2009
    Posts
    1,028
    Thanks G/R
    38/51
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Good job

    +Rep
    |Leacher:11/2009|Donor:02/2010|Established Member:09/2010|Contributor:09/2010|Elite:08/2013|

  8. #8
    Jadd's Avatar 🐸 Premium Seller
    Reputation
    1515
    Join Date
    May 2008
    Posts
    2,433
    Thanks G/R
    81/336
    Trade Feedback
    1 (100%)
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Updated. Much cleaner now.

  9. #9
    DarthTon's Avatar Contributor
    Reputation
    171
    Join Date
    Apr 2010
    Posts
    108
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I'm sorry if I understood code wrong, but here are few bugs:

    1.
    Code:
     if( eCallingConvention == CallingConvention.ThisCall ||
        eCallingConvention == CallingConvention.FastCall ||
        eCallingConvention == CallingConvention.StdCall )
                {
                    // MOV ECX, lsParams[0]
                    Write<byte>( hProcess, dwExecuteCave + uByteIndex++, 0xB9 );
                    Write<DWORD_PTR>( hProcess, dwExecuteCave + uByteIndex, (DWORD_PTR) lsParams[0] );
                    uByteIndex += sizeof( DWORD_PTR );
                    lsParams.RemoveAt( 0 );
                }
    in stdcall convention all arguments are passed via stack, ecx is ignored (even if its a class member function explicitly specified as stdcall). You also forgot to put second argument into edx for fastcall convention.

    2.
    Code:
    else if( tParamType == typeof( long ) )
        Write<long>( hProcess, dwExecuteCave + uByteIndex, (long) oParam );
     else if( tParamType == typeof( ulong ) )
        Write<ulong>( hProcess, dwExecuteCave + uByteIndex, (ulong) oParam );
    long and ulong are 8 bytes in size, right? You can't push 64bit arguments on stack using only one 'push' instruction in x86 assembly, push high DWORD and low DWORD separately or use MMX extension instructions.

    3.Floating point arguments.

    'double' is 8 bytes long, so apply rule from #2.

    4.
    Code:
    // ADD ESP, lsParams.Count * 4
    Again, if target function takes 64bit arguments, you have to add additional 4 bytes for each of those arguments. (This is true at least for MSVC. I don't know how other compilers pass 64bit integers.)

    5.
    Code:
    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, dwReturnCave );
        uByteIndex += sizeof( DWORD_PTR );
    }
    else
    {
        ....
    }
    FSTP must be executed for 'double' return type too.

    6.
    Code:
    if( tManagedType == typeof( double ) )
        tReturn = (T) (object) Read<double>( hProcess, Read<DWORD_PTR>( hProcess, dwReturnCave ) );
    Maybe I've missed something, but I hadn't found code that places pointer to 'double' result into dwReturnCave.

Similar Threads

  1. (Tutorial) Starting WoW-Memory Reading/Writing
    By Mrbrightside in forum WoW Memory Editing
    Replies: 198
    Last Post: 06-02-2017, 05:11 PM
  2. Replies: 2
    Last Post: 01-19-2012, 02:32 PM
  3. How do i know if a Bot is using memory reading / writing?
    By sturmtiger in forum WoW Bots Questions & Requests
    Replies: 1
    Last Post: 01-06-2011, 06:31 AM
  4. In process memory reading/writing
    By unbekannt1 in forum WoW Memory Editing
    Replies: 7
    Last Post: 06-08-2010, 06:52 PM
  5. Replies: 1
    Last Post: 07-23-2009, 01:17 PM
All times are GMT -5. The time now is 05:50 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search