NetLimiter 1.3

haxorcize on Jun 6th 2008

Today we’ll figure out how NetLimiter (version 1.3) works!

Here’s a short description:

“NetLimiter is an ultimate internet traffic control and monitoring tool designed for Windows. You can use NetLimiter to set download/upload transfer rate limits for applications or even single connection and monitor their internet traffic.”

NetLimiter offers numerous useful features, but the one I was interested in particular was the Transfer Rate Limiting feature. Given this particular feature, one is able to control transfer rates for his currently running processes, giving one process the temporary benefit of bandwidth it so desperately requires while his other time-slice sharing buddies manage with the remains.

I was really interested in finding out the methods available to implement a “system-wide per-process bandwidth limiter” under windows and NetLimiter’s method in particular. At first, it didn’t seem too inconceivable to think that NetLimiter may be using Kernel-Mode code to achieve its goals. Browsing through the web, searching for other methods, I have stumbled upon some nice articles (1, 2) discussing the deprecated Microsoft Traffic Control APIs which can very well be a solution on its own (might not be a per-process one, but still close).

After I packed small bits of knowledge about several traffic limiting methods, I began looking at the NetLimiter application. The version I chose to analyze was 1.3 (2.0 is out aswell, but for a while now I’ve found no real reason to upgrade).

Starting at the installation root, you notice the NetLimiter.exe program executable and two interesting DLLs: sporder.exe and nl_lsp.dll. After checking the main executable’s implicit dependencies (Dependency Walker), I saw it is using nl_msgs.dll (residing at %windir%\system32) and sporder.exe (residing at the installation root).

NetLimiter.exe is using one of sporder.dll’s exported functions, called WSCWriteProviderOrder. A quick google check lead me to MSDN, which in turn explains that this function is meant to “reorder the available winsock 2 transport providers” and that belongs to the “Winsock Transport SPI” (Transport Service Provider Interface).

Hold on a minute I said. SPI? Winsock Transport Providers? What are all of those? Sounds interesting due to its relevancy to Winsock and Network Manipulation (after all, thats what we’re looking for). I then recalled reading about Winsock Extensions as part of the “Windows Networking APIs” chapter inside the amazing Microsoft Windows Internals book, so I’ve decided to take another look, and I was surprisingly correct. The book does mention “Winsock Extensions”, and discusses winsock SPI.

SPI enables third parties to extend the Winsock API by providing additional layers on top of existing protocols to provide all kinds of functionalities (ehm… even more interesting). When such TSPs (transport service providers) are registered with Winsock, Winsock uses the TSPs to implement socket functions such as connect and accept, enabling it to communicate with its own transport driver in kernel mode. When a program creates a socket, Winsock searches through its catalog for potential TSPs and loads them according to the order currently defined in the system which is the same order manipulated by the NetLimiter.exe through the WSCWriteProviderOrder function.

The platform SDK includes a utility called sporder.exe that allows the user to change the order the TSPs are enumerated by Winsock. Running sporder.exe on my system showed the following interesting things:

Doesn’t take a genius to figure that NL stands for NetLimiter and that those additional entries belong to the program itself. Pushing the “More” button showed me the TSP in question is the nl_lsp.dll we found earlier in the installation root! Unfortunately, after looking at the other fields of newly opened dialog, I had a feeling I am not familiar enough with the SPI internals, so I’ve googled some more and I came up with this article which cleared a few things up.

Looking at the NetLimiter.exe file through IDA, you can pretty easily see it installs the TSP nl_lsp.dll using the WSCInstallProvider function (those of you who are interested, it takes the dll path from the registry), and then arranges the order with the WSCWriteProviderOrder function. (There are a few more actions performed, such as grouping the protocols in a ProtocolChain, you can read up on it in the article I linked to on the last paragraph).

Given the fact that NetLimiter installs a TSP on our system, it is easy to speculate on the method used to manipulate the bandwidth. According to the documentation, the TSP will be loaded into each process that uses the Winsock API, and inside it will intercept each API call on its way down the chain to the Base Protocol Providers (TCP/UDP), thus enabling it to pace any recv/recvfrom and send/sendto API function calls.

In order to verify this speculation, I’ve created a random 100mb test file on my webserver, and I am going to consume it with a small Python script that I’ve NetLimited to 1kb/s. I start off by attaching my newly created Python process into a capable debugger, such as WinDBG (kobyk have showed me just how invaluable this debugger is during out work together):

[windbg]
0:001> lm m nl* // cannot find the nl_lsp module at first
start    end        module name

0:001> sxe ld nl_lsp // capture nl_lsp.dll load
0:001> g

1
2
>>> from socket import *
>>> s = socket(AF_INET, SOCK_DGRAM)
[windbg]
// The dll has just been loaded after calling socket()
ModLoad: 00e40000 00e55000   C:\Program Files\NetLimiter\nl_lsp.dll
eax=00000003 ebx=00000000 ecx=00e51004 edx=f0e40000 esi=00333150 edi=00000000
eip=7c90eb94 esp=0021edfc ebp=0021eef0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246

0:000> !uniqstack
…
0021f4f0 71ab74f1 kernel32!LoadLibraryA+0×94 // nl_lsp.dll being loaded
0021f874 71ab494d WS2_32!DPROVIDER::Initialize+0×112
0021f894 71ab49ac WS2_32!DCATALOG::LoadProvider+0×6d // load relevant TSPs
0021f8b0 71ab3a20 WS2_32!DCATALOG::GetCountedCatalogItemFromAttributes+0xf5
0021f908 71ab3be1 WS2_32!WSASocketW+0×89
0021f930 00aa3c50 WS2_32!socket+0×73
…
00000000 00000000 python25!PyEval_EvalCodeEx+0×62d

0:000> g
ModLoad: 00e60000 00e71000   C:\WINDOWS\system32\nl_msgc.dll (RPC client)
ModLoad: 71a50000 71a8f000   C:\WINDOWS\system32\mswsock.dll
ModLoad: 662b0000 66308000   C:\WINDOWS\system32\hnetcfg.dll
ModLoad: 71a90000 71a98000   C:\WINDOWS\System32\wshtcpip.dll

At the above debugging session we can notice that the TSP is being loaded during the socket creation operation. Next I’m going to let the python script consume the big file:

1
2
>>> import urllib
>>> urllib.urlretrieve("http://www.haxorcize.com/test/big", r"c:\\big")

@note: Some of the following IDA screen-caps have functions and symbols I have renamed to ease the reversing process and maintain readability to the viewer. Your reverse outputs may not seem as friendly.

At this point nl_lsp!WSPRecv intercepts every recv performed by the process (python in our case). Careful studying of the nl_lsp!WSPRecv function shows us that checks for a certain context value associated with each SOCKET it messes with:

Later on we meet some branching as to whether the socket is overlapped or not, and then a big function call with many of the main parameters being passed to it. My assumption was that this function carries on the pacing logics, so I’ve decided to analyze it aswell.

I found out the big\interesting function calls mswsock!WSPRecv (which in turn calls the next TSP in the chain):

And also performs Sleeps in a loop with variable sleep durations which perfectly conforms to our assumption:

The following WinDBG breakpoint will enable you to examine the dynamic sleep duration algorithm and how it behaves in situations where the throttling is On/Off:

0:000> bp nl_lsp+3C8C "?edi; g" // this is the address where Sleep is being called
                                // edi holds the sleep duration

Thats all for now, see you next time.

(Half of this post has mysteriously disappeared when I came back home tonight, so I recovered it from memory at 04:31am. I hope I’ve done as good as the original post :))

Filed in Dissected Programs

2 Responses to “NetLimiter 1.3”

  1. Yakiron 09 Jun 2008 at 1:48 pm

    Hey G…

    I stumbled upon your blog while on facebook… The article is very interesting and is extremely well written.. Keep up the good work!

  2. MushArereon 10 Aug 2008 at 3:58 pm

    Thank you

Trackback URI | Comments RSS

Leave a Reply