Monthly Archives: June 2009

py2exe and pyOpenGL 3.x with no manual tinkering!

If you have ever had to py2exe a Python program using pyOpenGL, you know that it’s a painful, tedious, but above all unclean process. (Even back with 2.x, that “version” file was so troublesome, but here we have one of py2exe’s worst enemies: funky import hooks.)

I actually figured this out some time ago and have been using it in many of my projects; I first did it for Frets on Fire X (FoFiX), and now, upon finding a certain lack of this information elsewhere on the Internet, I’m bringing it to you here.

Other documents advocate excluding the OpenGL package from your distribution and manually adding it back in after you actually run py2exe.  However, it’s actually quite trivial to work around the weird import hooks.  The hooks don’t care whether import (well, really, __import__…) is operating the standard CPython way (loading modules and packages directly from the filesystem) or through zipimport, just as long as it returns something useful and doesn’t raise ImportError.  So we can just force the stuff that gets indirectly imported to be included when py2exe does its thing.

It’s a case of passing the necessary module names to py2exe via the py2exe includes option.  To do that, pass a dictionary as a keyword argument named options to setup. In that dictionary, assign the key py2exe to another dictionary. In that sub-dictionary, set includes to a list that contains (at least) the following strings:

OpenGL.platform.win32
OpenGL.arrays.ctypesarrays
OpenGL.arrays.numpymodule
OpenGL.arrays.lists
OpenGL.arrays.numbers
OpenGL.arrays.strings

(Note that you probably won’t need all of those array converters, and you may in fact need extra ones. Those should cover practically all use cases, though. FoFiX, which is a quite involved codebase, only needs those.)

If all goes well, everything that pyOpenGL 3.x needs to run should end up actually in the distribution (cleanly!) once py2exe is invoked with the new includes.

If you need to see an example of this in action, see FoFiX’s setup.py script, and all will become clear to you.

Happy py2exeing with pyOpenGL 3.x!

No, the sky is not falling…

That’s right… as of some arbitrary time not too long before you read this, I have a Facebook account.

If you know me, you will know that I have generally shied away from social networking in the past.  But I finally realized that there’s no sense in doing so any longer.  (Being able to much more reliably stay in contact with my friends as I jump from high school to college is a very good thing.)

Don’t expect me to be glued to my account the way I know some people are.  I will check it regularly but not (always) constantly.

Every time I have not used of some sort of social technology and then started using it, I wondered why I did not start sooner.  Hopefully this is what will happen as I open this new chapter in my Internet life.

Blog revival: Adventures with Win32/Rustock.M

Wow, I just let this blog sit unused all year.  I’ll have to remember to use it more often.

Today I got to experience dealing with a nasty rootkit on my brother’s Windows machine.  I was successful, but the full story behind discovering and destroying the infection has a lot of interesting little twists and turns to it.

I first noticed that DNS lookups had suddenly become rather slow on my network.  This is not out of the ordinary due to my very buggy, flimsy router, but this time it was a fair deal worse than usual.

More weirdly, the router was quite happily handling tons of packets.  And the blinking lights were Internet, wireless (where my brother’s computer is), and my testbed Windows Server 2003 box that acts as my internal DNS and DHCP server when I’m not doing anything else with it.

Suspecting to find something a small bit out of the ordinary, I popped open Wireshark on my brother’s computer and was horrified to find that it was attempting to send out spam at an alarming rate.  (All those parallel DNS MX and A queries had brought some intermediate DNS server, most likely that of my router, to its knees.)  I immediately used the netstat command to locate the guilty process.

The process at fault was services.exe.  Immediately I knew that I wasn’t just dealing with a typical spambot – it had probably injected a thread into there to do its bidding.  And yet services.exe is a core system process…

I watched the spam flow for a short time to try to catch the spambot grab addresses from whatever entity is controlling it, when I noticed a binary blob get HTTP POSTed to a PHP script on grizimvozim.name, with another binary blob sent in reply.

I then filtered my Wireshark capture to HTTP requests so as to wait and see whether any other servers were being contacted.  No others were, so I made the domain in question resolve to 0.0.0.0 in the hosts file to see what would happen.  The spam stopped almost immediately upon the next request (which I knew happened due to the machine starting to broadcast for the name via NetBIOS upon it failing to resolve through DNS), and I started investigating in earnest.

Firing up Process Explorer, I looked in services.exe for any unknown DLLs.  There were none.  There were no services out of the ordinary running out of services.exe itself either.  Somewhat perplexed, I updated AVG’s definitions and carried out a full system scan, which turned up nothing.

Suspecting that whatever malware I was dealing with had entered via an exploit in some piece of software in the system (and was covering its tracks unbelievably well), I decided to update critical network-facing system components to try to prevent it from happening again in the future after I got to the bottom of this one.  It was when I attempted to perform a Windows update that I was led down the path of discovery of the true extent of the infection.

I could access Windows Update, but it errored out very early.  Microsoft’s recommendation for the specific error code I received was to stop the Automatic Updates service, clean out the temporary folder the AU service uses, and start the service again.

The service was already stopped, though it was set to automatic start.  I suspected that AU was one of those services that would just stop when it had nothing to do (in my case, since I have the AU functionality turned off, as I prefer to update the machine manually).  I cleaned the AU temporary folder, right-clicked the service, and chose Start.

“The system cannot find the file specified.”

I went into the service properties to verify the filename it was trying to execute.  It turns out that the AU service runs through svchost.exe, but the command line it was trying to use was “%fystemroot%\system32\svchost.exe -k netsvcs”.  Almost reflexively I started regedit and dug through to try to fix the spelling of the SystemRoot environment variable.

“Access is denied.”

Sure enough, whatever had perturbed the spelling of the command line had also revoked access to that Registry key.  I restored it to default permissions (inherit and pass through inheritable parent ACEs without modification), and tried to fix it again.  Same thing.

I opened Process Explorer again and combed for open handles to anywhere in the service area of the Registry.  I found nothing.

By this point I was sure I was dealing with a full-blown rootkit.  It would have to be kernel-based to do some of the things that it was doing.  I looked through the list of loaded kernel modules in Process Explorer and saw a .sys file named with eight random hexadecimal characters.

“net stop [those characters]”: no such service.  I figured as much.

The service key named with those characters came up existent but empty.  Suspecting that the rootkit was playing with the permissions on that key just like it did with the AU service key, I found that I could not even get to the permissions dialog for it without getting an error.

I found the .sys file in \windows\system32\drivers and tried to scan it with AVG via shell extension.  File not found.

I tried to open it in a hex editor for a quick look around.  File not found.

I tried to copy it into another folder.  File not found.

I refreshed the drivers folder.  File still very much there.

At this point, I rebooted into my rarely-used reserve installation of Windows on that computer to have a look around not (hopefully) under the influence of the rootkit.

I mounted the SYSTEM registry hive from the main Windows installation and went down to the service key for that driver.  One of the values was a base64-encoded string which I duly pasted into the base64.b64decode() function in an interactive Python prompt.  “grizimvozim.name” !

I duly changed the start type of the service from 1 (system – during the pulsating progress bar phase of bootup) to 4 (disabled) and renamed the driver for good measure.  I also looked for more information on “fystemroot” and found that malware that does that to AU also tends to do that to BITS (which Windows Update relies on), and sure enough the BITS command line was misspelled too.  I fixed the permissions and spelling on both and rebooted into the main installation.

Sure enough, no more references to grizimvozim in an extended Wireshark session, Windows Update worked once again, and AVG nuked the driver for being Win32/Rustock.M as soon as I tried to open it in a hex editor.

Upon looking for information about Rustock, I was only able to get information for earlier generations of it, but their injection of spambot threads into critical system processes (winlogon.exe rather than services.exe, though) is well documented.  I saw that some forms would gain access to the kernel by unloading a rarely-used driver (such as null.sys or beep.sys), overwriting it, and reloading it, but all the rest of the drivers checked out free of infection.

Moral of the story: I may not use Windows all that much, but I certainly know my way around it, enough to find a kernel-based rootkit and stop it in its tracks.  Stump 1, Rustock zip.