Перехватчик WSARecv: предотвратить получение пакета исполняемым файлом

Я работаю над dll, которая перехватывает функции winsock2, используя C++ и обходные пути. Моя цель — изменить TCP-трафик, который идет от и к исходному исполняемому файлу. В какой-то момент мне нужно остановить доставку определенного пакета (чтобы исходный исполняемый файл вообще не знал об этом пакете, но все еще сохранял соединение).

С хуком WSASend все ясно (вы просто не вызываете исходный WSASend и возвращаете 0). Но я понятия не имею, как это сделать в хуке WSARecv, используя структуру WSAOVERLAPPED.

Я надеюсь, что этот код ниже демонстрирует, что я хочу:

__declspec(dllexport) int WINAPI WSARecv_hook(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    // Recieve real data
    int ret = WSARecv_real(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);

    // Loop over lpBuffers and analyze it
    for(int i=0; i < dwBufferCount; i++)
    {
        // analyze it
        if(packet_should_be_blocked(lpBuffers[i].buf, lpBuffers[i].len))
        {
            // Do or return what?
        } else {
            // Otherwise, just process as usual
        }
    }
    return ret;
}

Как сделать вид, что ничего не произошло и пакет не получен (типа поддельного WSA_IO_PENDING)? Любые идеи/мысли?

P.S. Насколько я знаю, исполняемый файл не использует процедуру завершения (lpCompletionRoutine всегда имеет значение NULL), а только перекрывающуюся структуру.


person splattru    schedule 06.08.2014    source источник
comment
Хм. Я думал, что написал комментарий, спрашивающий, что вы хотите, чтобы приложение на самом деле делало, когда вы отбрасываете пакет? Полагаете, что это был тайм-аут или сеть вышла из строя?   -  person Mats Petersson    schedule 07.08.2014
comment
Нет, я просто хочу, чтобы он продолжал ждать других пакетов, как будто ничего не произошло.   -  person splattru    schedule 07.08.2014
comment
Обратите внимание, что packet_should_be_blocked не может работать, так как TCP не ориентирован на сообщения. Вам придется буферизовать данные, пока у вас не будет достаточно для анализа, а затем, возможно, удалить только часть данных, которые вы получили за один вызов. Это относится и к блокировке входящих вызовов.   -  person Ben Voigt    schedule 07.08.2014
comment
@BenVoigt Я знаком с протоколом, который я изменяю (первые два байта каждого пакета/сообщения определяют тип пакета/сообщения, каждый тип пакета имеет фиксированную длину), так что это совсем не проблема. В любом случае, спасибо.   -  person splattru    schedule 07.08.2014
comment
@splattru: это проблема, потому что вы предполагаете, что заголовок и полезная нагрузка поступают вместе в один буфер. Это предположение ошибочно для TCP.   -  person Ben Voigt    schedule 07.08.2014
comment
@BenVoigt О, хорошо, теперь я понимаю, почему это проблема. Еще раз спасибо за вашу помощь.   -  person splattru    schedule 07.08.2014


Ответы (2)


Основное препятствие заключается в том, что перекрывающиеся операции должны выполняться в фоновом режиме после того, как вызывающая функция завершила работу со статусом ожидания. Если вызывающая сторона просит WSARecv() выполнить чтение с перекрытием, она ожидает, что данные поступят в фоновом режиме, и вы не сможете проверить данные внутри вашего хука напрямую, потому что они еще не были получены. Вам придется использовать свой собственный частный WSAOVERLAPPED для выполнения собственного перекрывающегося чтения, используя поток или обратный вызов завершения, чтобы определить, когда это чтение заканчивается, чтобы вы могли затем анализировать данные. Если данные приемлемы, скопируйте их в буфер вызывающей стороны и сообщите вызывающей стороне WSAOVERLAPPED. В противном случае отправьте еще одно чтение и дождитесь поступления этих данных, повторяя по мере необходимости, пока вы, наконец, не получите некоторые данные, которые хотите передать вызывающей стороне.

person Remy Lebeau    schedule 06.08.2014
comment
Это не такая уж проблема. Если вы получаете сообщение, которое не хотите передавать исходной программе, вы оставляете первоначальный запрос в ожидании, пока снова вызываете WSARecv(), давая возможность следующему входящему пакету выполнить запрос. - person Ben Voigt; 07.08.2014

Гораздо более простой способ изменить TCP-трафик — перехватить только connect семейство функций и заставить приложение подключаться к прозрачному прокси-серверу под вашим контролем, который выполняет реальную модификацию потока.

Хотя приложение может записать в поток свой собственный номер порта для удаленного конца, чтобы сравнить его с адресом источника пакета, на практике это не проблема, поскольку

  1. Это также сломает шлюзы NAT-PAT, которые очень распространены в домашних интернет-соединениях.
  2. Вы можете переписать содержимое и отправить адрес прокси, чтобы проверка прошла

На самом деле прокси-серверы FTP должны перезаписывать эту команду, потому что они создают подчиненные соединения для передачи файлов. Но большинство современных приложений написаны так, чтобы быть PAT-совместимыми.

person Ben Voigt    schedule 07.08.2014
comment
Перезапись содержимого пакета для замены IP-адреса клиента на IP-адрес прокси-сервера может быть опасной, если вы не будете осторожны. Делайте это только для тех протоколов, с которыми вы знакомы, например FTP. Если прокси-сервер слепо изменяет произвольные данные, которые выглядят как IP-адрес клиента, прокси-сервер может повредить данные, которые не имеют ничего общего с IP-адресами. Известно, что некоторые прокси демонстрируют именно эту проблему. - person Remy Lebeau; 07.08.2014
comment
@Remy: я совершенно уверен, что в этом вопросе известен протокол; в противном случае модификация потока не работала бы. - person Ben Voigt; 07.08.2014
comment
@Remy: Спасибо, что заметили опечатку, я действительно имел в виду FTP в последнем абзаце. - person Ben Voigt; 07.08.2014