Charlie Hopperson
Charlie Hopperson

Reputation: 415

Reading outgoing packets from selected process

Is it possible to read outgoing packets from selected process in C#? If yes, what api should I use? Thanks in advance.

Upvotes: 4

Views: 2648

Answers (3)

Erik
Erik

Reputation: 12858

I assume you're trying to do something similar to WireShark or Winsock Packet Editor.

The short answer is no. There's definitely no namespace or assembly with the functionality built-in.

The long answer is yes, but you'll have to get your hands a little dirty. You will more than likely have to make a C++ DLL to inject into the process to 'spy' on it. However, you can interface this DLL via C# and make your interface all in .NET.

Your first step would be to create the C++ DLL, which would just need a few exports:

bool InitialzeHook()
{
  // TODO: Patch the Import Address Table (IAT) to overwrite
  //       the address of Winsock's send/recv functions
  //       with your SpySend/SpyRecv ones instead.
}

bool UninitializeHook()
{
  // TODO: Restore the Import Address Table (IAT) to the way you found it.
}

// This function will be called instead of Winsock's recv function once hooked.
int SpySend(SOCKET s, const char *buf, int len, int flags)
{
  // TODO: Do something with the data to be sent, like logging it.

  // Call the real Winsock send function.
  int numberOfBytesSent = send(s, buf, len, flags);

  // Return back to the calling process.
  return numberOfBytesSent;
}

// This function will be called instead of Winsock's recv function once hooked.
int SpyRecv(SOCKET s, char *buf, int len, int flags)
{
  // Call the real Winsock recv function to get the data.
  int numberOfBytesReceived = recv(s, buf, len, flags);

  // TODO: Do something with the received data, like logging it.

  // Return back to the calling process.
  return numberOfBytesReceived;
}

The most difficult part of this all is the function that will patch the Import Address Table (IAT). There are various resources on how to traverse it and find function imports inside of it. TIP: You will have to patch Winsock imports by ordinal, not name.

Check out Inside the Windows PE Format (Part 2) and C++ Code Example.

Once you have all that done, you'll have to inject the DLL you made into the target process. Here is the C++ psuedo-code to do that (off the top of my head):

// Get the target window handle (if you don't have the process ID handy).
HWND hWnd = FindWindowA(NULL, "Your Target Window Name");

// Get the process ID from the target window handle.
DWORD processId = 0;
DWORD threadId = GetWindowThreadProcessId(hWnd, &processId);

// Open the process for reading/writing memory.
DWORD accessFlags = PROCESS_VM_OPERATION | 
                    PROCESS_VM_READ | 
                    PROCESS_VM_WRITE | 
                    PROCESS_QUERY_INFORMATION;

HANDLE hProcess = OpenProcess(accessFlags, false, processId);

// Get the base address for Kernel32.dll (always the same for each process).
HMODULE hKernel32 = GetModuleHandleA("kernel32");

// Get the address of LoadLibraryA (always the same for each process).
DWORD loadLibraryAddr = GetProcAddress(hKernel32, "LoadLibraryA");

// Allocate some space in the remote process and write the library string to it.
LPVOID libraryNameBuffer = VirtualAllocEx(hProcess, NULL, 256, 
                                          MEM_COMMIT | MEM_RESERVE,
                                          PAGE_EXECUTE_READWRITE);

LPCSTR libraryName = L"MySpyLibrary.dll\0";
DWORD numberOfBytesWritten = 0;
BOOL writeResult = WriteProcessMemory(hProcess, libraryNameBuffer,
                                                (LPCVOID)libraryName,
                                                strlen(libraryName) + 1,
                                                &numberOfBytesWritten);

// Create a thread in the remote process, using LoadLibraryA as the procedure,
// and the parameter is the library name we just wrote to the remote process.
DWORD remoteThreadId = 0;
HANDLE hRemoteThread = CreateRemoteThread(hProcess, NULL, 0,
                                          (LPTHREAD_START_ROUTINE)loadLibraryAddr,
                                          libraryNameBuffer,
                                          0, &remotThreadId);

// Wait for our thread to complete and get the exit code (which is the return value).
DWORD loadedLibraryAddr = 0;
BOOL waitResult = WaitForSingleObject(hRemoteThread, INFINITE); 
BOOL exitResult = GetExitCodeThread(hRemoteThread, &loadedLibraryAddr);

// TODO: Check that it was loaded properly
// if(lodadedLibraryAddr == NULL) { ... }

// Cleanup our loose ends here.
VirtualFreeEx(hProcess, libraryNameBuffer, 256, MEM_RELEASE);
CloseHandle(hRemoteThread);
CloseHandle(hProcess);

You can do the same thing via C# platform invoke (pInvoke) though. It's up to you how you want to log and transmit the data back to your C# monitoring program. You could use some interprocess communication like Named Pipes, NamedPipeClientStream in C#.

However, this will do it and the beautiful part is that it will work for nearly any program. This same technique can be applied for any type of sniffing, not just Winsock.

Upvotes: 2

Tommaso Belluzzo
Tommaso Belluzzo

Reputation: 23675

Of course you can... but only if the process has a "public hook" to it's listener. Otherwise, you would have to create a sniffer: debugging the executable, finding the offset of the socket send buffer and hooking a reader to it. Easier to do it though a firewall-like application.

Upvotes: 1

bbennoun
bbennoun

Reputation: 1

You can use TPL dataflow to do that.

Upvotes: 0

Related Questions