4

I've got an application, which uses Winsock 2.0 recv function, and I can catch the output by Redox Packet Editor for example, it confirms that version is 2.0.

I have this code to hook the function:

#define _CRT_SECURE_NO_DEPRECATE
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <WinSock2.h>
#include <detours.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")


FILE *pSendLogFile;
FILE *pRecvLogFile;

int (WINAPI *pSend)(SOCKET s, const char* buf, int len, int flags) = send;
int WINAPI MySend(SOCKET s, const char* buf, int len, int flags);
int (WINAPI *pRecv)(SOCKET s, char *buf, int len, int flags) = recv;
int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags);


INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
    switch(Reason)
    {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hDLL);

            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourAttach(&(PVOID&)pSend, MySend);
            if(DetourTransactionCommit() == NO_ERROR)
                MessageBox(0,"send() detoured successfully","asd",MB_OK);

            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourAttach(&(PVOID&)pRecv, MyRecv);
            if(DetourTransactionCommit() == NO_ERROR)
                MessageBox(0,"recv() detoured successfully","asd",MB_OK);
            break;

    case DLL_PROCESS_DETACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        break;
    }
    return TRUE;
}


int WINAPI MySend(SOCKET s, const char* buf, int len, int flags)
{
    MessageBox(0,"sent","sent",MB_OK);
    return pSend(s, buf, len, flags);
}

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags)
{
    MessageBox(0,"recvd","recvd",MB_OK);
    return pRecv(s, buf, len, flags);
}

For send, everything works perfectly, but I don't get any output for recv. I tried in another application using 1.1 version of Winsock and it works ok. Tried to hook WSARecv, WSARecvEx without any luck.

Checked the app with WinAPIOverride32, it clearly says that it using recv function, and successfuly logs the usage. Winsock Packet Editor is reading the data well too.

Any ideas?

methyl
  • 3,272
  • 2
  • 25
  • 34
  • 1
    My advice: write an LSP (Layered Service Provider) instead. Modifying one of the LSP samples will get you a lot further and might be more encompassing than the hooking approach. Imagine it as a user mode alternative to TDI drivers and friends. – 0xC0000022L Apr 09 '12 at 00:17
  • Any article or sample code for this LSP? I hope it's not so complicated. – methyl Apr 09 '12 at 08:34
  • Sure, this one is still valid for the most part: https://www.microsoft.com/msj/0599/layeredservice/layeredservice.aspx and of course: http://msdn.microsoft.com/en-us/library/windows/desktop/bb513664(v=vs.85).aspx – 0xC0000022L Apr 09 '12 at 11:50
  • Or maybe there's other way to send packets as application and read incoming? Nothing more is needed. – methyl Apr 09 '12 at 11:51
  • There are probably half a dozen ways. If I was tasked the thing that you are trying to achieve I'd go for an LSP. If I was tasked to write a firewall I'd write a TDI or NDIS filter, depending on the target OS version. – 0xC0000022L Apr 09 '12 at 11:53
  • 1
    @methyl please provide (edit) a concise, compilable code. Otherwise, without actually debugging, it's useless. – Poni Apr 11 '12 at 20:40

3 Answers3

4

Are you sure that you are hooking the correct dll? I'd double check which dll is actually used by the program: WSOCK32.dll or ws2_32.dll.

Edit:

Maybe try something like this:

typedef int (WINAPI *SendPtr)(SOCKET s, const char* buf, int len, int flags);
HMODULE hLib = LoadLibrary("wsock32.dll");
SendPtr pSend = (SendPtr)GetProcAddress(hLib, "send");

And then use pSend with that value (same thing for recv). Don't forget to call FreeLibrary in the end. If you are sure that the dll is already loaded, then it's probably better to use GetModuleHandle("wsock32.dll") since you don't have to call FreeLibrary in that case.

newgre
  • 5,245
  • 4
  • 31
  • 41
  • Yes, I checked it and tried to change header and lib in injected dll to winsock32 without any result. – methyl Apr 12 '12 at 08:40
  • I think it's good trace, because in EasyHook i have to set `[Dllimport]` to `wsock32.dll` instead of `ws2_32.dll`. How to do it in detours? – methyl Apr 16 '12 at 12:10
  • You right, but Ivarpoiss first came with exact solution, so bounty is his. Thanks for help! – methyl Apr 17 '12 at 17:02
  • Erm, nope. He copied from me. Look into my edit history! Unfortunately, I cannot prove it because edits don't contain exact timestamps as it seems. – newgre Apr 17 '12 at 17:22
  • Im almost sure that i saw his post earlier, but sorry if I am wrong. – methyl Apr 17 '12 at 17:52
  • No worries. My last edit was on 04/16 at 14:53:48. His post was created on 04/16 at 21:35:07. – newgre Apr 18 '12 at 12:16
1

you problem stems from trying to write out an empty (or even uninitialized buffer):

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags)
{
    fopen_s(&pRecvLogFile, "C:\\RecvLog.txt", "a+");
    fprintf(pRecvLogFile, "%s\n", buf);
    fclose(pRecvLogFile);
    return pRecv(s, buf, len, flags); //you need to call recv first
}

instead do something like this:

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags)
{
    int read = pRecv(s, buf, len, flags);
    if(read <= 0)
    {
        //read error/connection closed
        return read;
    }

    fopen_s(&pRecvLogFile, "C:\\RecvLog.txt", "a+");
    fwrite(buf,sizeof(char),read,pRecvLogFile);
    fclose(pRecvLogFile);
    return read;
}

as a secondary problem, you seem to be assuming that sent or received data is purely string based, but generally packets may contain zero bytes here and there which will prematurely end the fprintf output, you should rather use fwrite instead, passing the the send/receive size (this also implies opening the file in binary mode).

Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • Don't think it's a problem, send works fine and looks identically, tried to debug it by MessageBox as the first call in MyRecv, nothing shows for one application, on the other everything works perfect - message shows and data is dumped. – methyl Apr 09 '12 at 06:41
  • @methyl: but `send` is *not* identical, with send you have the data, with `recv` you need to *receive it* first... anything that you would see its remains of a previous call to `recv`. It would be a good idea to run this through a debugger tbh. – Necrolis Apr 09 '12 at 08:59
  • But, the problem is that function isn't detoured. The log isn't even created. – methyl Apr 09 '12 at 09:06
  • 1
    @methyl: then thats something to check with a debugger, but there are more problems than it not being detoured – Necrolis Apr 09 '12 at 10:25
  • Can you point me how to check it? Any tutorial or something where to start? – methyl Apr 09 '12 at 11:00
0

I think you should certainly use GetProcAddress to get the address to hook.

Something like:

int (WINAPI *pRecv)(SOCKET s, char *buf, int len, int flags) = GetProcAddress(GetModuleHandle("ws2_32.dll"), "recv");

Compiler could come up with all kinds of wild routes from your 'recv' to the one loaded with the dll. So these two addresses may vary. To test if that's the case, just use recv from your dll.

You may also want to keep your eye on ReadFile/WriteFile.

And also expect hooking to be unreliable. For example, a target can remove the hook at will and do a lot more.

Ivarpoiss
  • 1,025
  • 1
  • 10
  • 18