项目作者: gvanem

项目描述 :
Tracing library for Winsock calls.
高级语言: C
项目地址: git://github.com/gvanem/wsock-trace.git
创建时间: 2015-03-18T12:16:07Z
项目社区:https://github.com/gvanem/wsock-trace

开源协议:

下载


Wsock-trace v. 0.3.7:

Build Status

A drop-in tracing library / DLL for most normal Winsock calls.
It sits between your program and the Winsock library (ws2_32.dll).
It works only for MSVC and clang-cl; the stack-walking code requires the program’s
PDB symbol-file to be present. Hence MinGW and CygWin support has been dropped.

An example output from c:\> ahost msdn.com showing all the addresses of msdn.com

(ahost is part of the DNS library C-ares):

screenshot

Features

  • Colourised trace of the Winsock calls with function parameters and return
    values. The colours are configurable.

  • Runtime caller information: Using Microsoft’s dbghelp (or psapi) APIs
    together with the programs PDB-file, the filename, line-number of the calling
    function-name is shown. In the above example, WSAStartup().aspx)
    is called from ahost.c, line 68. Which should be 53 bytes into the main() function.
    This should be here.

  • Precise Timestamps: All trace-lines starts with a precise timestamp obtained
    from QueryPerformanceCounter().aspx).

    The timestamp is controlled by trace_time in the
    wsock_trace
    config-file.

  • Extension functions: Winsock has several Microsoft-specific extension functions
    (like AcceptEx()
    and ConnectEx()).
    Wsock-trace is able to trace these too.

  • IP-Country information thanks to the MaxMind
    Lite databases. Thanks to the Tor-project
    for a simplified CSV version of these MaxMind GeoIP-databases.
    (using the CSV files GeoIP.csv
    and GeoIP6.csv
    are always enabled).

  • IP-Location information (City and Region) from IP2Location.
    The above Mountain View/California is Google’s well-known location. Many thanks to IP2Location
    [3] for their data-bases.

  • ASN information (Autonomous System Number) from IPFire.

    The screen-shot above shows Google has ASN 15169 (for their DNS server-address 8.8.8.8).

    More details for that ASN is at DNSlytics
    and even more details at PeerDB.
    Many thanks to the IPFire developers [4] for their data-bases.

  • Domain Name System-based Blackhole List
    (DNSBL) support: with the help of
    DROP-files from the Spamhaus project,
    it can detect IPv4 / IPv6-addresses uses by spammers and cyber-criminals.
    The more potent Spamhaus BGPf / BCL is on the to-do list.

  • Slowdown; For testing too fast programs, all receive, transmit, select() and WSAPoll()
    calls can be delayed a number of milli-seconds. E.g. slowing down a recv() call is
    controlled by recv_delay = 0 in wsock_trace
    config-file.

  • Firewall activity; report activity causing events from the Window Filtering Platform (the Internet Connection Firewall; ICF).
    See below.

  • LuaJIT script support is very
    preliminary at the moment. The idea is that .lua scripts could change the
    behaviour of Wsock-trace at runtime without rebuilding it. Only the absolute minimum
    of the needed files are in ./LuaJIT.

Installation

The following assumes you will install this package in c:\prog\wsock_trace.
To clone this repository, do this in an empty c:\prog\wsock_trace directory:

  • c:\prog\wsock_trace> git clone https://github.com/gvanem/wsock-trace.git .

To be able to get more precise Geo-IP information for addresses (city and region), Wsock-trace
will use a IP2Location LITE database. To make best use of it,
do this:

  • Sign-up for an account and download a free
    IP2Location LITE database.
    Or in case you have an account, go here.
  • Download and use a file named like IP2LOCATION-LITE-DBx.IPV6.BIN.

    Such a file contains both IPv4 and IPv6 records. A download-ip2loc.bat like this could do
    it automatically:
    1. @echo off
    2. setlocal
    3. ::
    4. :: Fill in this from the login-page
    5. ::
    6. if %IP2LOCATION_TOKEN. == . set IP2LOCATION_TOKEN=xxxx
    7. curl --output IP2LOCATION-LITE-DB11.IPV6.BIN.zip ^
    8. "https://www.ip2location.com/download/?token=%IP2LOCATION_TOKEN%&file=DB11LITEBINIPV6"
    9. unzip IP2LOCATION-LITE-DB11.IPV6.BIN.zip
  • Copy IP2LOCATION-LITE-DBx.IPV6.BIN into your %APPDATA% directory and edit the keyword in
    the [geoip] section to read:

    ip2location_bin_file = %APPDATA%\IP2LOCATION-LITE-DBx.IPV6.BIN

Note: IP2Location-C-Library
is no longer used as a submodule (since I’ve made several local changes to it). It has been
merged into src/ip2loc.c and simplified.

Building

Enter the src sub-directory and do:
nmake -f makefile.vc6

Notes:

  • For a WIN32 build, the above files will have an -x86 suffix.
  • For a WIN64 build, the above files will have an -x64 suffix.
  • And for a USE_CRT_DEBUG = 1 build, the above files will have an extra _d suffix.

Usage

Link with one of these libraries (instead of the default ws2_32.lib):

  • wsock_trace-x86.lib for x86
  • wsock_trace-x86.lib for x64

Thus most normal Winsock calls are traced on entry and exit.

Example screen-shot above or details in Running samples below.

MSVC: Remember to compile using -Zi
to produce debug-symbols. For MSVC-2015 (or newer) it is recomended to use option
-Zo
too (which will eases the debug of optimised code. And remember to use -debug when linking your program.
See src/Makefile.vc6 for an example.
It is not adviced to use option -Oy
(enable frame pointer omission) since that will make it difficult for StackWalk64()
to figure out the filename and line of the calling function.

Configuration

The trace-level and other settings are controlled by a config-file
wsock_trace. This file is searched along these places until found:

  • The file pointed to by %WSOCK_TRACE.
  • The current directory.
  • Then finally the %APPDATA% directory.

wsock_trace is read in init.c
at startup. Read it’s contents; the comments therein should be self-explanatory.

If wsock_trace is not found in one of the above directories, the default
trace_level is set to 1.

There is currently no install.bat file for Wsock-trace. So you should copy the following files (here at GitHub)

to your %APPDATA% directory:

  1. wsock_trace
  2. GeoIP.csv
  3. GeoIP6.csv
  4. GeoIPASNum.csv
  5. IPv4-address-space.csv
  6. IPv6-unicast-address-assignments.csv
  7. DROP.txt
  8. DROPv6.txt
  9. IPFire-database.db

These environment variables are on the form:

  • <drive>:\Documents and Settings\<User Name>\ProgramData. (Win-XP)
  • <drive>:\Users\<User Name>\AppData\Roaming. (Win-Vista+)

Running samples

All the below samples uses these %APPDATA%/wsock_trace settings:

  • compact = 1
  • trace_time = none and
  • use_short_path = 1.

Example output from src/ws_tool.exe test (built with MSVC):

  1. * ws_trace/test.c(45) (main+50): WSAStartup (2.2) --> No error.
  2. * ws_trace/test.c(24) (do_wsock_tests+125): gethostbyaddr (127.0.0.1, 4, AF_INET) --> 0x003C8780.
  3. * ws_trace/test.c(27) (do_wsock_tests+150): gethostbyaddr (0.0.0.0, 4, AF_INET) --> 0x003C8780.
  4. * ws_trace/test.c(29) (do_wsock_tests+164): gethostbyaddr (::1, 16, AF_INET6) --> 0x003C8780.
  5. * ws_trace/test.c(31) (do_wsock_tests+175): gethostbyname (localhost) --> 0x003C8780.
  6. * ws_trace/test.c(31) (do_wsock_tests+187): socket (AF_INET, SOCK_STREAM, 0) --> 1724.
  7. * ws_trace/test.c(33) (do_wsock_tests+196): WSAGetLastError() --> No error.
  8. * ws_trace/test.c(36) (do_wsock_tests+343): select (n=0-1724, rd, NULL, NULL, {tv=1.000001s}) --> No error.
  9. * ws_trace/test.c(37) (do_wsock_tests+358): FD_ISSET (1724, fd) --> 0.
  10. * ws_trace/test.c(47) (main+61): WSACleanup() --> No error.
  11. ^ ^ ^ ^
  12. | | | |___ The traced Winsock function and the result.
  13. | | |
  14. | | |____ The calling function with displacement (i.e. offset from
  15. | | (nearest public symbol).
  16. | |_____ Line number in src-file.
  17. |
  18. |____ Source-file relative of the application.

Here is a more realistic and useful example with wsock_trace.lib linked to
Nmap [1]:

  1. c:\> nmap -sT -P0 -p23,80 10.0.0.1
  2. * mswin32/winfix.cc(134) (win_pre_init+68): WSAStartup (2.2) --> No error.
  3. Starting Nmap 6.02 ( http://nmap.org ) at 2012-07-24 12:48 CET
  4. * g:/vc_2010/sdk/include/wspiapi.h(1011) (WspiapiGetAddrInfo+79): WSASetLastError (0).
  5. * g:/vc_2010/sdk/include/wspiapi.h(1011) (WspiapiGetAddrInfo+79): WSASetLastError (0).
  6. * g:/vc_2010/sdk/include/wspiapi.h(1011) (WspiapiGetAddrInfo+79): WSASetLastError (0).
  7. * g:/vc_2010/sdk/include/wspiapi.h(1011) (WspiapiGetAddrInfo+79): WSASetLastError (0).
  8. * g:/vc_2010/sdk/include/wspiapi.h(1011) (WspiapiGetAddrInfo+79): WSASetLastError (0).
  9. * g:/vc_2010/sdk/include/wspiapi.h(1011) (WspiapiGetAddrInfo+79): WSASetLastError (0).
  10. * scan_engine.cc(3002) (sendConnectScanProbe+266): socket (AF_INET, SOCK_STREAM, 6) --> 1780.
  11. * nbase/nbase_misc.c(261) (unblock_socket+65): ioctlsocket (1780, FIONBIO, 1) --> No error.
  12. * scan_engine.cc(2964) (init_socket+82): setsockopt (1780, SOL_SOCKET, SO_LINGER, 1, 4) --> No error.
  13. * libnetutil/netutil.cc(856) (set_ttl+34): setsockopt (1780, IPPROTO_IP, IP_TTL, ULONG_MAX, 4) --> WSAEINVAL: Invalid arguments (10022).
  14. * scan_engine.cc(3021) (sendConnectScanProbe+599): connect (1780, 10.0.0.1:23) --> WSAEWOULDBLOCK: Call would block (10035).
  15. * nbase/nbase_misc.c(133) (socket_errno+12): WSAGetLastError() --> WSAEWOULDBLOCK: Call would block (10035).
  16. * scan_engine.cc(922) (ConnectScanInfo::watchSD+82): FD_ISSET (1780, fd) --> 0.
  17. * scan_engine.cc(3002) (sendConnectScanProbe+266): socket (AF_INET, SOCK_STREAM, 6) --> 1720.
  18. * nbase/nbase_misc.c(261) (unblock_socket+65): ioctlsocket (1720, FIONBIO, 1) --> No error.
  19. * scan_engine.cc(2964) (init_socket+82): setsockopt (1720, SOL_SOCKET, SO_LINGER, 1, 4) --> No error.
  20. * libnetutil/netutil.cc(856) (set_ttl+34): setsockopt (1720, IPPROTO_IP, IP_TTL, ULONG_MAX, 4) --> WSAEINVAL: Invalid arguments (10022).
  21. * scan_engine.cc(3021) (sendConnectScanProbe+599): connect (1720, 10.0.0.1:80) --> WSAEWOULDBLOCK: Call would block (10035).
  22. * nbase/nbase_misc.c(133) (socket_errno+12): WSAGetLastError() --> WSAEWOULDBLOCK: Call would block (10035).
  23. * scan_engine.cc(922) (ConnectScanInfo::watchSD+82): FD_ISSET (1720, fd) --> 0.
  24. * scan_engine.cc(3964) (do_one_select_round+473): select (n=0-1780, rd, wr, ex, {tv=0.985000s}) --> 3.
  25. * nbase/nbase_misc.c(133) (socket_errno+12): WSAGetLastError() --> WSAEWOULDBLOCK: Call would block (10035).
  26. * scan_engine.cc(4015) (do_one_select_round+1894): FD_ISSET (1720, fd) --> 0.
  27. * scan_engine.cc(4015) (do_one_select_round+1917): FD_ISSET (1720, fd) --> 1.
  28. * scan_engine.cc(4019) (do_one_select_round+2012): getsockopt (1720, SOL_SOCKET, SO_ERROR, 0, 4) --> No error.
  29. * scan_engine.cc(938) (ConnectScanInfo::clearSD+82): FD_ISSET (1720, fd) --> 1.
  30. * scan_engine.cc(789) (ConnectProbe::~ConnectProbe+37): closesocket (1720) --> No error.
  31. * scan_engine.cc(4015) (do_one_select_round+1894): FD_ISSET (1780, fd) --> 1.
  32. * scan_engine.cc(4019) (do_one_select_round+2012): getsockopt (1780, SOL_SOCKET, SO_ERROR, 0, 4) --> No error.
  33. * scan_engine.cc(938) (ConnectScanInfo::clearSD+82): FD_ISSET (1780, fd) --> 1.
  34. * scan_engine.cc(789) (ConnectProbe::~ConnectProbe+37): closesocket (1780) --> No error.
  35. Nmap scan report for router (10.0.0.1)
  36. Host is up (0.0019s latency).
  37. PORT STATE SERVICE
  38. 23/tcp open telnet
  39. 80/tcp open http
  40. Nmap done: 1 IP address (1 host up) scanned in 7.61 seconds
  41. * mswin32/winfix.cc(290) (win_cleanup+12): WSACleanup() --> No error.

Notes:

  • Nmap uses wrong arguments to setsockopt().aspx);
    a TTL of ULONG_MAX.
  • Nmap also calls WSAStartup().aspx)
    before the startup message.
  • Notice how Wsock-trace handles (demangles) C++ symbols just
    fine thanks to dbghelp.dll and UnDecorateSymbolName().aspx).
    I.e. the destructor ConnectProbe::~ConnectProbe above is calling closesocket().aspx)
    at offset 37. (you can turn off C++ demangling by cpp_demangle = 0 in the wsock_trace config-file).
  • Even symbols from a Rust library can be demangled. E.g. from rustls-ffi as used in
    libcurl:
    1. * 1.807833 sec: f:/MingW32/src/inet/Crypto/Rustls/src/io.rs(44) (rustls_ffi::io::impl$0::read+32)
    2. WSAGetLastError() --> WSAEWOULDBLOCK (10035).
    This Rust function rustls_ffi::io::impl$0::read should be here.

Another example from C-ares‘s
adig.c with the same settings as above:

  1. c:\> adig -t PTR 89.42.216.144
  2. * adig.c(216) (main+105): WSAStartup (2.2) --> No error.
  3. * ares_process.c(1065) (open_udp_socket+248): socket (AF_INET, SOCK_DGRAM, 0) --> 1604.
  4. * ares_process.c(857) (setsocknonblock+61): ioctlsocket (1604, FIONBIO, 1) --> No error.
  5. * ares_process.c(1077) (open_udp_socket+345): connect (1604, 8.8.8.8:53) --> No error.
  6. * ares_process.c(791) (ares__send_query+484): send (1604, 0x00034BDA, 31, 0) --> 31 bytes tx.
  7. * adig.c(397) (main+1780): select (n=0-1604, rd, wr, NULL, {tv=3.109000s}) --> 1.
  8. * ares_process.c(456) (read_udp_packets+146): FD_ISSET (1604, fd) --> 1.
  9. * ares_process.c(485) (read_udp_packets+413): recvfrom (1604, 0x0013F894, 513, 0, 8.8.8.8:53) --> 106 bytes rx.
  10. Domain name not found
  11. id: 58187
  12. flags: qr rd ra
  13. opcode: QUERY
  14. rcode: NXDOMAIN
  15. Questions:
  16. 89.42.216.144 . PTR
  17. Answers:
  18. NS records:
  19. . 1413 SOA a.root-servers.net.
  20. nstld.verisign-grs.com.
  21. ( 2012072400 1800 900 604800 86400 )
  22. Additional records:
  23. * ares__close_sockets.c(63) (ares__close_sockets+408): closesocket (1604) --> No error.
  24. * adig.c(411) (main+1894): WSACleanup() --> No error.

By default, the tracing of htons(),htonl(), ntohs() and ntohl() are
excluded from the trace.

You can edit the %APPDATA%/wsock_trace config-file and exclude whatever calls you like.
And the 2 traces above is showing the effect of the config-value compact = 1.

A more eleborated example from 2 OpenVPN programs; a client and a
server running a simple test (in OpenVPN’s root-dir). Started with the vpn.bat snippet:

  1. cd sample
  2. start /pos=200,50,1000,800 ..\openvpn.exe --config sample-config-files/loopback-server
  3. start /pos=800,150,1000,1000 ..\openvpn.exe --config sample-config-files/loopback-client

screenshot:

A Larger version.

Firewall Monitor

The ws_tool.exe firewall program show a screen like:
screenshot

Together with [DNSBL], enable = 1 it shows remote addresses in SpamHaus DROP-lists.
In this case the address 176.119.4.56
in Ukraine / Donetsk is very active giving a Firewall event approximately every 5 minutes.

A good test of the firewall.c features is to open up your router (create a DMZ) and start a remote
port-scan while ws_tool.exe firewall
is running. You’ll see a lot of DROP-events like:

  1. 6.700 sec: FWPM_NET_EVENT_TYPE_CLASSIFY_DROP, IN, IPPROTO_TCP
  2. layer: (13) Inbound Transport v4 Discard-layer
  3. filter: (277599) Filter to prevent port-scanning
  4. addr: 204.11.35.98 -> 10.0.0.10, ports: 21 (ftp) / 52115
  5. country: United States, Troy/Michigan

Implementation notes

The names of the import libraries and the names of the .DLLs are:

  • For 32-bit: wsock_trace.lib and wsock_trace-x86.dll.
  • For 64-bit: wsock_trace_x64.lib and wsock_trace-x64.dll.

These DLLs off-course needs to be in current directory or on %PATH. The reason
I’ve chosen to make it a DLL and not a static-lib is that applications
using wsock_trace*.lib needs not to be re-linked when I do change the inner
workings of the Wsock-trace source code.
As long as the ABI is stable (e.g. not adding new functions to the
wsock_trace-x86.def
file), the application using wsock_trace*.dll should work the same.

Note that some virus scanners may find the behaviour of programs linked to
wsock_trace.lib suspicious.

Future plans:

  1. LuaJIT-script integration; use a *.lua file to exclude/include processes and/or
    functions to trace.

  2. Injecting wsock_trace-*.dll into a remote process. Ref:
    https://www.viksoe.dk/code/wepmetering.htm.

  3. Optionally load Wireshark’s libwireshark.dll to dissect
    transport and application protocols.

    Do it for selected processes only.

  4. Deny certain applications to use AF_INET6 protocols (return -1 on
    socket(AF_INET6,...)).

  5. Make it possible to switch network stacks at run-time:
    select amongst Winsock2, lwIP and/or

    Cyclone TCP.

  6. Make a GUI trace viewer for it. Ref:
    https://www.viksoe.dk/code/windowless1.htm

  7. Add a Json type config feature to support the above features. E.g.:

    1. wireshark_dissect {
    2. wget.exe : 1 # Wireshark dissection in wget and curl only.
    3. curl.exe : 1
    4. }
    5. exclude_trace {
    6. select: [curl.exe, wget.exe] # Exclude trace of `select()` and `inet_ntoa()` in curl/wget.
    7. inet_ntoa: [curl.exe, wget.exe]
    8. htons: [ * ] # Exclude trace of `htons` globally.
    9. }
    10. deny_ipv6 {
    11. pycurl.pyd : 1 # Deny AF_INET6 sockets in scripts using the PyCurl module.
    12. python27.dll : 1 # And in other Python scripts too.
    13. }
    14. stack_mux {
    15. use_lwip: [wget2.exe, curl.exe] # Force wget2.exe and curl.exe to use lwIP.dll
    16. }

G. Vanem <gvanem@yahoo.no> 2013 - 2025.

Footnotes:

  • [1] Nmap; “Network Mapper“ is a free and open source (license) utility for

    1. network discovery and security auditing. <br>
    2. Ref. [**https://nmap.org/download.html**](https://nmap.org/download.html)
  • [2] A C library for asynchronous DNS requests (including name resolves)

    1. Ref. [**https://c-ares.haxx.se/**](https://c-ares.haxx.se/)
  • [3] This product includes IP2Location LITE data available from

    1. [**https://lite.ip2location.com**](https://lite.ip2location.com).
  • [4] This product includes IPFire location and ASN data available from

    1. [**https://location.ipfire.org/databases/1/**](https://location.ipfire.org/databases/1/).

PS. This file is written with the aid of the Atom
editor and it’s Markdown-Preview.
A real time-saver.