Results 1 to 7 of 7

Thread: Hooking and Named Pipes in plain C, help appreciated

  1. #1
    Administrator JoTo's Avatar
    Join Date
    May 2010
    Location
    www.scapp.net
    Posts
    1,953

    Default Hooking and Named Pipes in plain C, help appreciated

    So Im requesting help with hooking and named pipes in plain C language.

    I need to hook CreateFile and WriteFile and report via Named pipe to Named Pipe server process (GsControl in my case).
    The named pipe server is setup so Im looking only at the client implementation here.
    I need to implement it without any 3rd libraries and in plain C.

    I think I should go with hooking by IAT and as IPC mechanism using named pipes as it seems easier and is sufficient for my needs, though open to other techniques if you suggest I should.
    No need to cover injecting mechanism as GsP is allready loaded at start time into the target process. (here gameserver)

    Would like to go step by step and at the end of this thread hopefully have this working.
    Gamers Network - www.scapp.net

  2. #2
    Administrator JoTo's Avatar
    Join Date
    May 2010
    Location
    www.scapp.net
    Posts
    1,953

    Default

    Modifies to the above approach:

    Using IAT hooking would be "not hard" todo but I found that it not catches all functions e.g. writefile in some cases where those functions are implemented without using IAT table. So I need to use the ms-detours way, inline hooking using jmp.
    I understand the concept of inline hooking but doing the coding actually of this is to complicated for me and using the ms-detours lib is no option for me (licence issues and I need it also for 64bit processes), but I found a promising alternative which is mhook.

    Now the next modification is I probalbly cannot launch the hook from inside GsP as GsP is only another .dll so when then loader loads GsP other .dlls might not yet be loaded and I would miss certain WriteFile hooks. So I need to wait until the whole process is loaded and then apply the hooks. Which requires me to use a separate .dll and inject into the target process after the target process has been created.

    What I want to achieve with this whole stuff is for example capturing write lines to qconsole.log, send them in real-time to my .net app and do there some fancy stuff like real time analysis, chat monitor, player stats, game events, etc. with the lines monitored.

    So the concept would look like this:

    Write to be monitored files to .ini file (e.g. qconsole.log)
    Determine if target process is 32 or 64 bit.
    Start the target process (gameserver).
    Inject either the hook32.dll or hook64.dll.

    hook.dll will do this:

    Read to be monitored files from ini.files.
    Apply MyCreateFile and MyWriteFile hooks with the help of mhook.
    In case MyCreatefile event is called check with the to be monitored files and store file handle. Call original createfile.
    In case MyWritefile event is called check the file handle and if it is in our list send the captured data via named pipe. Call original writefile.

    Pitfalls and considerations:

    As named pipes are memory based I think it is fast enough that captured data can be sended immediately without using buffering. (I hope that)

    A problem might be missing a CreateFile. The process might be quicker with creating file than me with injecting and applying hook so my hook.dll would not be aware that a file has been created.
    Possible solutions might be that I start the process in suspended state (However mhook is suspending also the process respectively each thread so no idea if that might throw unhandled errors) and the other solution is that I get the filename on MyWriteFile via the filehandle and compare if the filehandle is unknown yet. The latter might miss first lines though.



    If this all fails I would go back to simple approach and just read the logfile in determined intervals, however doing it the hooking way seems to be more elegant and effective to me. (I always thought the qconsole.log file is locked on windows for reading, but it appeared that its not readable only if I try open it with notepad or wordpad, notepad++ has no problems open it so its probably just a matter of open method)

  3. #3
    Administrator JoTo's Avatar
    Join Date
    May 2010
    Location
    www.scapp.net
    Posts
    1,953

    Default

    So far got the injector and the hook coded (not tested for the moment though), but Im struggling over a "simple" problem and cant figure it out whats wrong,
    its about the function "GetFinalPathNameByHandle" to retrieve the filename (or path) of a given filehandle.

    Im getting the error: "error C3861: 'GetFinalPathNameByHandle': identifier not found"

    The function is described here: http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx

    Code:
    //(c++, using visual studio 2008)
    
    #include <stdio.h>
    #include <windows.h>
    #include <tchar.h>
    
    #define BUFSIZE MAX_PATH
    
    //helper function to retrieve filename from given filehandle
    
    char *getFilename(HANDLE fhandle){
    	TCHAR Path[BUFSIZE];
    	DWORD dwRet;
    	dwRet=GetFinalPathNameByHandle(fhandle,Path,BUFSIZE,VOLUME_NAME_NT);
        
            return (char *)Path;
    }
    any ideas ?

    -------
    I just tested the example and its running fine, still dont see where Im going wrong...

  4. #4
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    Try adding this globally up top:
    Code:
    #include <kernel32.dll>
    #pragma comment(lib,"kernel32.lib")

  5. #5
    Administrator JoTo's Avatar
    Join Date
    May 2010
    Location
    www.scapp.net
    Posts
    1,953

    Default

    It made no difference but thanks anyway, I narrowed it down meanwhile to "stafx.h". As soon as I have #include "stdafx.h" at the beginning it throws that error no matter of the content of "stdafx.h", if no include of stdafx.h it compiles successfully.

    -----
    Edit: ok, did a bit of research and it has to do with the use of precompiled headers, I disabled them and not using stdafx.h anymore and it compiles now. I assume that in the precompiled hearder of windows.h simply that function is missing.
    Meanwhile found another solution though for the get file name by file handle problem which seems to be more reliable for that task called "NtQueryInformationFile", lets see how that works out.

  6. #6
    Administrator James's Avatar
    Join Date
    May 2010
    Location
    on the intraweb
    Posts
    3,180

    Default

    Strange, but glad you figured it out.

  7. #7
    Administrator JoTo's Avatar
    Join Date
    May 2010
    Location
    www.scapp.net
    Posts
    1,953

    Default

    yes, but pure coincidence I found it, if I hadn't the working example I would have never found out, thats the big problem with c++ so much jazz around the core stuff, headers, defines, strings, compiler options and and and all there to confuse the brave coder lol.

    So lets start posting the first pieces of this project:

    The injector from .net:

    Code:
    public class cl_Injector
    'platform calls to perform dll injection
        Private Const PROCESS_VM_OPERATION As Int32 = &H8
        Private Const PROCESS_VM_WRITE As Int32 = &H20
        Private Const PROCESS_VM_READ As Int32 = &H10
        Private Const MEM_COMMIT As Int32 = &H1000
        Private Const MEM_RELEASE As Int32 = &H8000
        Private Const PAGE_READWRITE As Int32 = &H4
        'CreateRemoteThread for calling loadlibrary in the target process address space to load our Dll
        Private Declare Function CreateRemoteThread Lib "kernel32.dll" (ByVal hProcess As Int32, ByVal lpThreadAttributes As Int32, ByVal dwStackSize As Int32, ByVal lpStartAddress As Int32, ByVal lpParameter As Int32, ByVal dwCreationFlags As Int32, ByRef lpThreadId As Int32) As Int32
        'VirtualAllocEx to allocate space in our target process so that we can write the path to our Dll
        Private Declare Function VirtualAllocEx Lib "kernel32.dll" (ByVal hProcess As Int32, ByVal lpAddress As Int32, ByVal dwSize As Int32, ByVal flAllocationType As Int32, ByVal flProtect As Int32) As Int32
        'WriteProcessMemory to write the path to our Dll in the target process address space
        Private Declare Function WriteProcessMemory Lib "kernel32.dll" (ByVal hProcess As Int32, ByVal lpBaseAddress As Int32, ByVal lpBuffer As String, ByVal nSize As Int32, ByRef lpNumberOfBytesWritten As Int32) As Int32
        'VirtualFreeEx to clean up when done
        Private Declare Function VirtualFreeEx Lib "kernel32.dll" (ByVal hProcess As Int32, ByVal lpAddress As Int32, ByRef dwSize As Int32, ByVal dwFreeType As Int32) As Int32
        'Get ModuleHandle to get a handle to LoadLibrary so we can use the Handle to get its Address in the target Process' space
        Private Declare Function GetModuleHandle Lib "kernel32.dll" Alias "GetModuleHandleA" (ByVal lpModuleName As String) As Int32
        'GetProcAddress to get the address that LoadLibraryA resides at
        Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Int32, ByVal lpProcName As String) As Int32
        'OpenProcess to get a handle to our target process and open it with the rights we require
        Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccess As Int32, ByVal bInheritHandle As Int32, ByVal dwProcessId As Int32) As Int32
        'CloseHandle to Close all open handles we needed
        Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Int32) As Int32
    
        Public Enum eDllInjectStatus
            GenerelError = 0
            NoHandleToKernel
            NoHandleToTargetProc
            NoSpaceInTargetProc
            ErrorWriteToTargetProc
            ErrorCreateRemoteThread
            OK
        End Enum
        Public Function InjectSingleDll(ByVal PID As Integer, ByVal DllPath As String) As eDllInjectStatus
            Dim ProcHandle As Int32  ' Handle to our Process
            Dim DllVirtLoc As Int32  ' The Location we will end up writing out Dll's Path to
            Dim Inject As Int32      ' For Error Checking
            Dim CreateThread As Int32 ' For Error Cheacking
            Dim ThreadID As Int32    ' The ThreadID our created thread
            Dim MHandle As Int32     ' Handle to LoadLibrary
    
            MHandle = GetModuleHandle("Kernel32.dll") 'Handle to Kernel32.dll
            If MHandle = Nothing Then
                Return eDllInjectStatus.NoHandleToKernel
            Else
                ProcHandle = OpenProcess(PROCESS_VM_READ Or PROCESS_VM_WRITE Or PROCESS_VM_OPERATION, 0, PID) 'Gets Handle to Target process with required rights
                If ProcHandle = 0 Then
                    CloseHandle(MHandle) ' Closes our Handle to Kernel32.dll because we could not open Target Process
                    Return eDllInjectStatus.NoHandleToTargetProc
                Else
                    DllVirtLoc = VirtualAllocEx(ProcHandle, 0, DllPath.Length + 1, MEM_COMMIT, PAGE_READWRITE) ' Returns the Address of our Dll's Path in the target Process
                    If DllVirtLoc = 0 Then
                        CloseHandle(MHandle) ' Closes Handle to Kernel32.dll because we could not allocate space in Target Process
                        CloseHandle(ProcHandle) ' Closes Handle to Target Process because we could not allocate space in Target Process
                        Return eDllInjectStatus.NoSpaceInTargetProc
                    Else
                        Inject = WriteProcessMemory(ProcHandle, DllVirtLoc, DllPath, DllPath + 1, Nothing) ' Writes Our Dll's Path to our allocated Space
                        If Inject = 0 Then
                            VirtualFreeEx(ProcHandle, DllVirtLoc, 0, MEM_RELEASE) ' Frees Allocated Space in Target Process because we could not write our Dll's Path
                            CloseHandle(MHandle) ' Closes Handle to Kernel32.dll because we could not write our Dll's Path to Target Process
                            CloseHandle(ProcHandle) ' Closes Handle to Target Process because we could not write our Dll's Path to it
                            Return eDllInjectStatus.ErrorWriteToTargetProc
                        Else
                            CreateThread = CreateRemoteThread(ProcHandle, 0, 0, GetProcAddress(MHandle, "LoadLibraryA"), DllVirtLoc, 0, ThreadID) ' Calls LoadLibraryA in Target Process to load our Dll
                            If CreateThread = 0 Then
                                VirtualFreeEx(ProcHandle, DllVirtLoc, 0, MEM_RELEASE) ' Frees Allocated Space in Target Process because we could not create our remote thread
                                CloseHandle(MHandle) ' Closes handle to Kernel32.dll because we could not create our remote thread
                                CloseHandle(ProcHandle) ' Closes handle to Target Process because we could not create our remote thread
                                Return eDllInjectStatus.ErrorCreateRemoteThread
                            End If
                        End If
                    End If
                End If
            End If
            VirtualFreeEx(ProcHandle, DllVirtLoc, 0, MEM_RELEASE) 'Frees Allocated space because we are done
            CloseHandle(MHandle) ' Closes handle to Kernel32.dll because we are done
            CloseHandle(ProcHandle) ' Closes handle to Target Process because we are done
            Return eDllInjectStatus.OK
        End Function
    End Class

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •