• Welcome to Valhalla Legends Archive.
 

pwcb

Started by squeegee, July 04, 2007, 09:01 PM

Previous topic - Next topic

squeegee

I can't log into Warrior's FTP right now, so here it is:

pwcb.py
import pbuffer
import winamp
import pcap
import dpkt

"""(Python) Winamp Controller for Battle.net"""

__version__ = "1.0.0"
__author__ = "topaz"
__copyright__ = "modified BSD license"

class pwcb:
    def __init__(self, port=6112, verbose=True):
        self.port = port
        self.verbose = verbose
        self.pcap = pcap.pcap()
        self.pcap.setfilter("tcp")
        self.ip = ""
        self.winamp = winamp.winamp()
        self.buffer_data = ""
        self.buffer_length = 0

    def begin_capture(self):
        for t, pkt in self.pcap:
            stream = dpkt.ethernet.Ethernet(pkt)
            data = stream.data.data
            self.ip = "%d.%d.%d.%d" %tuple(map(ord, list(stream.data.dst)))

            if data.dport == self.port:
                self.process_stream(data)

    def process_stream(self, data):
        if data.data != "":
            recv_buffer = pbuffer.recv_buffer(data.data)

            while recv_buffer.position < len(data.data):
   
                if recv_buffer.next_byte() <> 0xFF: return

                packet_id = recv_buffer.next_byte()
                packet_length = recv_buffer.next_word()

                if packet_id == 0x0E:
                    s = recv_buffer.next_string()
                    self.process_cmd(s)

                recv_buffer.position = recv_buffer.position + packet_length

    def process_cmd(self, data):
        if data[0] == "/":
            data = data[1:]
            cmd = data.split(" ")[0]

            if cmd == "play":
                if len(data.split(" ")) == 1:
                    self.winamp.play()
                    self.notify("Winamp has begun playing.")
                else:
                    song_title = " ".join(data.split(" ")[1:])
                    self.winamp.play(song_title)
                   
            elif cmd == "execute":
                self.winamp.execute()
                self.notify("Winamp has been opened.")
               
            elif cmd == "setvol":
                vol = int(data.split(" ")[1])
                self.winamp.set_vol(vol)
                self.notify("Winamp's volume has been set to %d." %vol)
               
            elif cmd == "next":
                self.winamp.next()
                self.notify("Winamp has skipped to the next song.")
               
            elif cmd == "previous":
                self.winamp.previous()
                self.notify("Winamp is skipping to the previous song.")
               
            elif cmd == "close":
                self.winamp.close()
                self.notify("Winamp has been closed.")
               
            elif cmd == "stop":
                self.winamp.stop()
                self.notify("Winamp has been stopped.")
               
            elif cmd == "pause":
                self.winamp.pause()
                self.notify("Winamp has been paused/unpaused.")

    def notify(self, text):
        if self.verbose == True:
            print text

    def about(self):
        print "(Python) Winamp Controller for Battle.net\n"
        print "-- You will require the following items if this program was not included as an executable;"
        print "--     Python 2.5 or above installed on your machine,"
        print "--     the WinPcap port for Windows installed,"
        print "--     the pypcap package (written by Dug Song) installed,"
        print "--     and the dpkt package (also written by Dug Song) installed.\n"
        print "-- PWCB was begun on 11 April of 2007."

print "Welcome to the (Python) Winamp Controller for Battle.net!\n"
p = pwcb()
p.notify("Beginning packet capture for port 6112.")
p.begin_capture()


winamp.py
__version__ = '1.1.0'
__author__ = 'topaz'
__copyright__ = 'modified BSD License'

import win32api
import win32gui
import time
import os

WM_COMMAND = 0x400
WM_MSG = 273

class winamp:
    def __init__(self):
        try:
            self.get_handle()
        except Exception, error:
            print "Winamp does not appear to be open; executing now.\n"
            self.execute()
            time.sleep(1.5)
            self.get_handle()

    def get_handle(self):
        return win32gui.FindWindow('Winamp v1.x', None)

    def execute(self):
        os.startfile('C:\Program Files\Winamp\winamp.exe')

    def play(self, song_title=""):
        if song_title == "":
            win32api.SendMessage(self.get_handle(), WM_MSG, 40045, 0)
        else:
            win32api.PostMessage(self.get_handle(), WM_MSG, 40194, 0)

            while True:
                win32gui.PumpWaitingMessages()

                jumpto = win32gui.FindWindow('#32770', "Jump to file")
                edit = win32gui.FindWindowEx(jumpto, 0, 'Edit', None)
                listbox = win32gui.FindWindowEx(jumpto, 0, 'ListBox', None)

                if listbox != 0: break

            win32gui.SendMessage(edit, 0x0C, 0, song_title)

            if win32api.SendMessage(listbox, 0x18B, 0, 0) == 0:
                win32api.PostMessage(jumpto, 0x10, 0, 0)
            else:
                win32api.SendMessage(listbox, 0x203, 0, 0)

    def set_vol(self, volume):
        win32api.SendMessage(self.get_handle(), WM_COMMAND, int(volume * 2.55), 122)

    def next(self):
        win32api.SendMessage(self.get_handle(), WM_MSG, 40048, 0)

    def previous(self):
        win32api.SendMessage(self.get_handle(), WM_MSG, 40044, 0)

    def close(self):
        win32api.SendMessage(self.get_handle(), WM_MSG, 40001, 0)

    def stop(self):
        win32api.SendMessage(self.get_handle(), WM_MSG, 40047, 0)

    def pause(self):
        #used for both pausing and unpausing
        win32api.SendMessage(self.get_handle(), WM_MSG, 40046, 0)

    def song(self):
        return win32gui.GetWindowText(self.get_handle())[:-9]

    def bitrate(self):
        return win32api.SendMessage(self.get_handle(), WM_COMMAND, 1, 126)

    def play_status(self):
        """0 = stopped, 1 = playing, 3 = paused"""
        return win32api.SendMessage(self.get_handle(), WM_COMMAND, 0, 104)


pbuffer.py
import struct

def unpack_dword(data):
    return struct.unpack('I', data)[0]

def unpack_word(data):
    return struct.unpack('H', data)[0]

def unpack_byte(data):
    return struct.unpack('<B', data)[0]

class recv_buffer:
    def __init__(self, raw_buffer):
        self.raw_buffer = raw_buffer
        self.position = 0

    def jump(self, bytes):
        self.position += bytes

    def back(self, bytes):
        self.position -= bytes

    def set_position(self, position):
        self.position = position

    def next_string(self):
        pos = self.raw_buffer.find(chr(0), self.position)
        string = self.raw_buffer[self.position:pos]

        self.set_position(pos + 1)
        return string

    def next_byte(self):
        param = self.raw_buffer[self.position:self.position + 1]
        byte = unpack_byte(param)

        self.jump(1)
        return byte

    def next_dword(self):
        param = self.raw_buffer[self.position:self.position + 4]
        dword = unpack_dword(param)

        self.jump(4)
        return dword

    def next_word(self):
        param = self.raw_buffer[self.position:self.position + 2]
        word = unpack_word(param)

        self.jump(2)
        return word

    def next_dword_list(self, size):
        dword_list = []

        for i in xrange(size):
            dword_list.append(self.next_dword())

        return dword_list

    def dump_data(self):
        del self.raw_buffer


Listens on port 6112 and reads streams, looking for commands to manipulate Winamp. Only works with Winamp, but itunes/fb2k/etc support could be added if you cared. Only tested on wc3 and w2bn, idk about utf-8 junk on starcraft that could mess with how data is processed. Run pwcb.py in console or in a shell and it'll do the rest.

Requires pypcap, dpkt, WinPcap, and Python to be installed.

raylu

You should have mentioned that this simply hooked onto an existing connection. Essentially, a packet sniffer.

If you're only listening for certain commands, UTF-8 will not affect those commands (they are in English and use only standard alphanumeric characters).
Pie?

squeegee

"Listens on port 6112" kind of says that right off the bat, and the use of WinPcap also tells you that


Good work captain

MyndFyre

Quote from: squeegee on July 04, 2007, 09:42 PM
"Listens on port 6112" kind of says that right off the bat
Actually no, "listens on port 6112" means that it opens a socket on that port and waits until it receives an incoming connection....
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

raylu

I skimmed over the requirements, like most people. I just wanted to see what it did and found no information about this.

Usage of 6112 says either that or shows that the person who made it chose to use the same port as B.net. Stupid, but not totally unreasonable.
Pie?

squeegee

You're not going to cry about it, are you?

Sorc.Polgara

The creator of this topic sure knows how to ask for help.

squeegee

Does it look like I asked for help?

warz

Just another completely useless program, written by mr. topaz.

squeegee

K, gimme a sec to spend eight months reversing something only to write a trivial non-fix



Oh wait


sry.

squeegee

This script is cool, okay? Don't be jealous