import sys, os
from xml.parsers import expat
def ShowHelp():
print """
Psi IM passwords recoverer 1.0
Copyright (C) 2007 Artamoshin Alexander
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Usage: psipass.py - automated finding passwords
or: psipass.py <filename> - view decoded passwords in config
or: psipass.py <command> <password> <key> - encode/decode password
<Commands>
-d, --decode Decode password with key
-e, --encode Encode password with key
-h, --help Show this help
"""
def Encode(password, key):
if len(key)==0:
return password
n1 = 0; n2 = 0; result = ''
while n1 < len(password):
x = ord(password[n1]) ^ ord(key[n2])
n2 += 1
result += '%04X' % x
if n2 >= len(key):
n2 = 0
n1 += 1
return result
def Decode(password, key):
if len(key)==0:
return password
n1 = 0; n2 = 0; result = ''
while n1 < len(password):
x = 0
if n1 + 4 > len(password):
break
x += int(password[n1], 16)*4096
x += int(password[n1+1], 16)*256
x += int(password[n1+2], 16)*16
x += int(password[n1+3], 16)
result += chr(x ^ ord(key[n2]))
n2 += 1;
if n2 >= len(key):
n2 = 0
n1 += 4
return result
def ParseXML(filename):
global accOpen, jidOpen, passOpen
accOpen = 0; jidOpen = 0; passOpen = 0
def start_element(name, attrs):
global accOpen, jidOpen, passOpen, jid, password
if name == 'account':
accOpen = 1
jid = ''; password = ''
if (accOpen == 1) & (name == 'jid'):
jidOpen = 1
if (accOpen == 1) & (name == 'password'):
passOpen = 1
def end_element(name):
global accOpen, jidOpen, passOpen
if name == 'account':
accOpen = 0
print jid.ljust(30), password
if name == 'jid':
jidOpen = 0
if name == 'password':
passOpen = 0
def char_data(data):
global jid, password
if (accOpen == 1) & (jidOpen == 1):
jid = data
if (accOpen == 1) & (passOpen == 1):
password = Decode(data, jid)
xml_file = open(filename, 'r').read()
p = expat.ParserCreate('UTF-8');
p.returns_unicode = 0
p.StartElementHandler = start_element
p.CharacterDataHandler = char_data
p.EndElementHandler = end_element
p.Parse(xml_file)
def Auto():
def rootDirPath():
if sys.platform == 'win32': # Windows
if os.environ.get('SystemDrive'):
result = os.environ.get('SystemDrive')
else: # if cannot get
result = 'C:\\'
else: # UNIX & MacOS
result = '/'
return result
def homeDirPath():
if os.environ.get('HOME'):
result = os.environ.get('HOME')
else:
if sys.platform == 'win32': # Windows
if os.environ.get('USERPROFILE'):
result = os.environ.get('USERPROFILE')
elif os.environ.get('HOMEDRIVE') & os.environ.get('HOMEPATH'):
result = os.environ.get('HOMEDRIVE') + os.environ.get('HOMEPATH')
else:
result = rootDirPath
else: # UNIX & MacOS
result = rootDirPath()
return result
if os.environ.get('PSIDATADIR'):
profDir = os.environ.get('PSIDATADIR') + os.sep + 'profiles' + os.sep
else:
if sys.platform == 'win32': # Windows
if homeDirPath == rootDirPath(): # Windows 9x
profDir = '.'
else:
profDir = homeDirPath()
profDir += '\\PsiData\\profiles\\'
else: # UNIX & MacOS
profDir = homeDirPath() + '/.psi/profiles/'
if os.path.exists(profDir) & os.path.isdir(profDir):
names = os.listdir(profDir)
if len(names) > 0:
for name in names:
if os.path.isdir(profDir + name) & os.path.exists(profDir + name + os.sep + 'config.xml'):
print 'Profile: ' + name
ParseXML(profDir + name + os.sep + 'config.xml')
print
else:
print 'Profiles not found'
else:
print 'Psi IM data not found'
agrv = sys.argv[1:]
agrs = len(agrv)
if agrs == 0:
Auto()
elif agrs == 1:
if agrv[0] in ('h', '-h', '--help', '/h'):
ShowHelp()
else:
ParseXML(agrv[0])
elif agrs == 3:
if agrv[0] in ('e', '-e', '--encode', '/e'):
print Encode(agrv[1], agrv[2])
elif agrv[0] in ('d', '-d', '--decode', '/d'):
print Decode(agrv[1], agrv[2])
else:
ShowHelp()
else:
ShowHelp()