mirror of https://github.com/hak5/ToorChat.git
497 lines
15 KiB
Python
497 lines
15 KiB
Python
import struct
|
|
|
|
fmtsLSB = [None, "B", "<H", "<I", "<I", "<Q", "<Q", "<Q", "<Q"]
|
|
fmtsMSB = [None, "B", ">H", ">I", ">I", ">Q", ">Q", ">Q", ">Q"]
|
|
sizes = [ 0, 1, 2, 4, 4, 8, 8, 8, 8]
|
|
masks = [ (1<<(8*i))-1 for i in xrange(9) ]
|
|
|
|
def wtfo(string):
|
|
outstr = []
|
|
bitlen = len(outstr) * 8
|
|
for x in range(8):
|
|
outstr.append(shiftString(string, x))
|
|
|
|
string = strBitReverse(string)
|
|
for x in range(8):
|
|
outstr.append(shiftString(string, x))
|
|
|
|
return outstr
|
|
|
|
def strBitReverse(string):
|
|
# FIXME: this is really dependent upon python's number system. large strings will not convert well.
|
|
# FIXME: break up array of 8-bit numbers and bit-swap in the array
|
|
num = 0
|
|
bits = len(string)*8
|
|
# convert to MSB number
|
|
for x in range(len(string)):
|
|
ch = string[x]
|
|
#num |= (ord(ch)<<(8*x)) # this is LSB
|
|
num <<= 8
|
|
num |= ord(ch)
|
|
|
|
print (hex(num))
|
|
rnum = bitReverse(num, bits)
|
|
print (hex(rnum))
|
|
|
|
# convert back from MSB number to string
|
|
out = []
|
|
for x in range(len(string)):
|
|
out.append(chr(rnum&0xff))
|
|
rnum >>= 8
|
|
out.reverse()
|
|
print(''.join(out).encode('hex'))
|
|
return ''.join(out)
|
|
|
|
def strXorMSB(string, xorval, size):
|
|
'''
|
|
lsb
|
|
pads end of string with 00
|
|
'''
|
|
out = []
|
|
strlen = len(string)
|
|
string += "\x00" * sizes[size]
|
|
|
|
for idx in range(0, strlen, size):
|
|
tempstr = string[idx:idx+sizes[size]]
|
|
temp, = struct.unpack( fmtsMSB[size], tempstr )
|
|
temp ^= xorval
|
|
temp &= masks[size]
|
|
tempstr = struct.pack( fmtsMSB[size], temp )[-size:]
|
|
out.append(tempstr)
|
|
return ''.join(out)
|
|
|
|
|
|
|
|
|
|
def bitReverse(num, bitcnt):
|
|
newnum = 0
|
|
for idx in range(bitcnt):
|
|
newnum <<= 1
|
|
newnum |= num&1
|
|
num >>= 1
|
|
return newnum
|
|
|
|
def shiftString(string, bits):
|
|
carry = 0
|
|
news = []
|
|
for x in xrange(len(string)-1):
|
|
newc = ((ord(string[x]) << bits) + (ord(string[x+1]) >> (8-bits))) & 0xff
|
|
news.append("%c"%newc)
|
|
newc = (ord(string[-1])<<bits) & 0xff
|
|
news.append("%c"%newc)
|
|
return "".join(news)
|
|
|
|
def getNextByte_feedbackRegister7bitsMSB():
|
|
'''
|
|
this returns a byte of a 7-bit feedback register stemming off bits 4 and 7
|
|
the register is 7 bits long, but we return a more usable 8bits (ie.
|
|
'''
|
|
global fbRegister
|
|
|
|
retval = 0
|
|
for x in range(8): #MSB,
|
|
retval <<= 1
|
|
retval |= (fbRegister >> 6) # start with bit 7
|
|
nb = ( ( fbRegister>>3) ^ (fbRegister>>6)) &1
|
|
fbRegister = ( ( fbRegister << 1 ) | nb ) & 0x7f # do shifting
|
|
#print "retval: %x fbRegister: %x bit7: %x nb: %x" % (retval, fbRegister, (fbRegister>>6), nb)
|
|
|
|
return retval
|
|
|
|
def getNextByte_feedbackRegister7bitsLSB():
|
|
'''
|
|
this returns a byte of a 7-bit feedback register stemming off bits 4 and 7
|
|
the register is 7 bits long, but we return a more usable 8bits (ie.
|
|
'''
|
|
global fbRegister
|
|
|
|
retval = 0
|
|
for x in range(8): #MSB,
|
|
retval >>= 1
|
|
retval |= ((fbRegister << 1)&0x80) # start with bit 7
|
|
|
|
nb = ( ( fbRegister>>3) ^ (fbRegister>>6)) &1
|
|
fbRegister = ( ( fbRegister << 1 ) | nb ) & 0x7f # do shifting
|
|
#print "retval: %x fbRegister: %x bit7: %x nb: %x" % (retval, fbRegister, (fbRegister>>6), nb)
|
|
|
|
return retval
|
|
|
|
|
|
def whitenData(data, seed=0xffff, getNextByte=getNextByte_feedbackRegister7bitsMSB):
|
|
global fbRegister
|
|
fbRegister = seed
|
|
|
|
carry = 0
|
|
news = []
|
|
for x in xrange(len(data)-1):
|
|
newc = ((ord(data[x]) ^ getNextByte() ) & 0xff)
|
|
news.append("%c"%newc)
|
|
return "".join(news)
|
|
|
|
def findSyncWord(byts, sensitivity=4, minpreamble=2):
|
|
'''
|
|
seek SyncWords from a raw bitstream.
|
|
assumes we capture at least two (more likely 3 or more) preamble bytes
|
|
'''
|
|
possDwords = []
|
|
# find the preamble (if any)
|
|
while True: # keep searching through string until we don't find any more preamble bits to pick on
|
|
sbyts = byts
|
|
pidx = byts.find("\xaa"*minpreamble)
|
|
if pidx == -1:
|
|
pidx = byts.find("\x55"*minpreamble)
|
|
byts = shiftString(byts, 1)
|
|
|
|
if pidx == -1:
|
|
return possDwords
|
|
|
|
# chop off the nonsense before the preamble
|
|
sbyts = byts[pidx:]
|
|
#print "sbyts: %s" % repr(sbyts)
|
|
|
|
# find the definite end of the preamble (ie. it may be sooner, but we know this is the end)
|
|
while (sbyts[0] == '\xaa' and len(sbyts)>2):
|
|
sbyts = sbyts[1:]
|
|
|
|
#print "sbyts: %s" % repr(sbyts)
|
|
# now we look at the next 16 bits to narrow the possibilities to 8
|
|
# at this point we have no hints at bit-alignment aside from 0xaa vs 0x55
|
|
dwbits, = struct.unpack(">H", sbyts[:2])
|
|
#print "sbyts: %s" % repr(sbyts)
|
|
#print "dwbits: %s" % repr(dwbits)
|
|
if len(sbyts)>=3:
|
|
bitcnt = 0
|
|
# bits1 = aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb
|
|
# bits2 = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
|
bits1, = struct.unpack(">H", sbyts[:2])
|
|
bits1 = bits1 | (ord('\xaa') << 16)
|
|
bits1 = bits1 | (ord('\xaa') << 24)
|
|
bits1 <<= 8
|
|
bits1 |= (ord(sbyts[2]) )
|
|
#print "bits: %x" % (bits1)
|
|
|
|
bit = (5 * 8) - 2 # bytes times bits/byte #FIXME: MAGIC NUMBERS!?
|
|
while (bits1 & (3<<bit) == (2<<bit)):
|
|
bit -= 2
|
|
#print "bit = %d" % bit
|
|
bits1 >>= (bit-16)
|
|
#while (bits1 & 0x30000 != 0x20000): # now we align the end of the 101010 pattern with the beginning of the dword
|
|
# bits1 >>= 2
|
|
#print "bits: %x" % (bits1)
|
|
|
|
bitcount = min( 2 * sensitivity, 17 )
|
|
for frontbits in xrange( bitcount ): # with so many bit-inverted systems, let's not assume we know anything about the bit-arrangement. \x55\x55 could be a perfectly reasonable preamble.
|
|
poss = (bits1 >> frontbits) & 0xffff
|
|
if not poss in possDwords:
|
|
possDwords.append(poss)
|
|
byts = byts[pidx+1:]
|
|
|
|
return possDwords
|
|
|
|
def findSyncWordDoubled(byts):
|
|
possDwords = []
|
|
# find the preamble (if any)
|
|
bitoff = 0
|
|
pidx = byts.find("\xaa\xaa")
|
|
if pidx == -1:
|
|
pidx = byts.find("\55\x55")
|
|
bitoff = 1
|
|
if pidx == -1:
|
|
return []
|
|
|
|
# chop off the nonsense before the preamble
|
|
byts = byts[pidx:]
|
|
|
|
# find the definite end of the preamble (ie. it may be sooner, but we know this is the end)
|
|
while (byts[0] == ('\xaa', '\x55')[bitoff] and len(byts)>2):
|
|
byts = byts[1:]
|
|
|
|
# now we look at the next 16 bits to narrow the possibilities to 8
|
|
# at this point we have no hints at bit-alignment
|
|
dwbits, = struct.unpack(">H", byts[:2])
|
|
if len(byts)>=5:
|
|
bitcnt = 0
|
|
# bits1 = aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb
|
|
# bits2 = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
|
bits1, = struct.unpack(">H", byts[:2])
|
|
bits1 = bits1 | (ord(('\xaa','\x55')[bitoff]) << 16)
|
|
bits1 = bits1 | (ord(('\xaa','\x55')[bitoff]) << 24)
|
|
bits1 <<= 8
|
|
bits1 |= (ord(byts[2]) )
|
|
bits1 >>= bitoff
|
|
|
|
bits2, = struct.unpack(">L", byts[:4])
|
|
bits2 <<= 8
|
|
bits2 |= (ord(byts[4]) )
|
|
bits2 >>= bitoff
|
|
|
|
|
|
frontbits = 0
|
|
for frontbits in xrange(16, 40, 2): #FIXME: if this doesn't work, try 16, then 18+frontbits
|
|
dwb1 = (bits1 >> (frontbits)) & 3
|
|
dwb2 = (bits2 >> (frontbits)) & 3
|
|
print "\tfrontbits: %d \t\t dwb1: %s dwb2: %s" % (frontbits, bin(bits1 >> (frontbits)), bin(bits2 >> (frontbits)))
|
|
if dwb2 != dwb1:
|
|
break
|
|
|
|
# frontbits now represents our unknowns... let's go from the other side now
|
|
for tailbits in xrange(16, -1, -2):
|
|
dwb1 = (bits1 >> (tailbits)) & 3
|
|
dwb2 = (bits2 >> (tailbits)) & 3
|
|
print "\ttailbits: %d\t\t dwb1: %s dwb2: %s" % (tailbits, bin(bits1 >> (tailbits)), bin(bits2 >> (tailbits)))
|
|
if dwb2 != dwb1:
|
|
tailbits += 2
|
|
break
|
|
|
|
# now, if we have a double syncword, iinm, tailbits + frontbits >= 16
|
|
print "frontbits: %d\t\t tailbits: %d, bits: %s " % (frontbits, tailbits, bin((bits2>>tailbits & 0xffffffff)))
|
|
if (frontbits + tailbits >= 16):
|
|
tbits = bits2 >> (tailbits&0xffff)
|
|
tbits &= (0xffffffff)
|
|
print "tbits: %x" % tbits
|
|
|
|
poss = tbits&0xffffffff
|
|
if poss not in possDwords:
|
|
possDwords.append(poss)
|
|
else:
|
|
pass
|
|
# FIXME: what if we *don't* have a double-sync word? then we stop at AAblah or 55blah and take the next word?
|
|
|
|
possDwords.reverse()
|
|
return possDwords
|
|
|
|
#def test():
|
|
|
|
def visBits(data):
|
|
pass
|
|
|
|
|
|
|
|
def getBit(data, bit):
|
|
idx = bit / 8
|
|
bidx = bit % 8
|
|
char = data[idx]
|
|
return (ord(char)>>(7-bidx)) & 1
|
|
|
|
|
|
|
|
def detectRepeatPatterns(data, size=64, minEntropy=.07):
|
|
#FIXME: convert strings to bit arrays before comparing.
|
|
c1 = 0
|
|
c2 = 0
|
|
d1 = 0
|
|
p1 = 0
|
|
mask = (1<<size) - 1
|
|
bitlen = 8*len(data)
|
|
|
|
while p1 < (bitlen-size-8):
|
|
d1 <<= 1
|
|
d1 |= getBit(data, p1)
|
|
d1 &= mask
|
|
#print bin(d1)
|
|
|
|
if c1 < (size):
|
|
p1 += 1
|
|
c1 += 1
|
|
continue
|
|
|
|
d2 = 0
|
|
p2 = p1+size
|
|
while p2 < (bitlen):
|
|
d2 <<= 1
|
|
d2 |= getBit(data, p2)
|
|
d2 &= mask
|
|
#print bin(d2)
|
|
|
|
if c2 < (size):
|
|
p2 += 1
|
|
c2 += 1
|
|
continue
|
|
|
|
if d1 == d2 and d1 > 0:
|
|
s1 = p1 - size
|
|
s2 = p2 - size
|
|
print "s1: %d\t p1: %d\t " % (s1, p1)
|
|
print "s2: %d\t p2: %d\t " % (s2, p2)
|
|
# complete the pattern until the numbers differ or meet
|
|
while True:
|
|
p1 += 1
|
|
p2 += 1
|
|
#print "s1: %d\t p1: %d\t " % (s1, p1)
|
|
#print "s2: %d\t p2: %d\t " % (s2, p2)
|
|
if p2 >= bitlen:
|
|
break
|
|
|
|
b1 = getBit(data,p1)
|
|
b2 = getBit(data,p2)
|
|
|
|
if p1 == s2 or b1 != b2:
|
|
break
|
|
|
|
length = p1 - s1
|
|
c2 = 0
|
|
p2 -= size
|
|
|
|
bitSection, ent = bitSectString(data, s1, s1+length)
|
|
if ent > minEntropy:
|
|
print "success:"
|
|
print " * bit idx1: %4d (%4d bits) - '%s' %s" % (s1, length, bin(d1), bitSection.encode("hex"))
|
|
print " * bit idx2: %4d (%4d bits) - '%s'" % (s2, length, bin(d2))
|
|
#else:
|
|
# print " * idx1: %d - '%s' * idx2: %d - '%s'" % (p1, d1, p2, d2)
|
|
p2 += 1
|
|
p1 += 1
|
|
|
|
|
|
def bitSectString(string, startbit, endbit):
|
|
'''
|
|
bitsects a string... ie. chops out the bits from the middle of the string
|
|
returns the new string and the entropy (ratio of 0:1)
|
|
'''
|
|
ones = 0
|
|
zeros = 0
|
|
entropy = [zeros, ones]
|
|
|
|
s = ''
|
|
bit = startbit
|
|
|
|
Bidx = bit / 8
|
|
bidx = (bit % 8)
|
|
|
|
while bit < endbit:
|
|
|
|
byte1 = ord( string[Bidx] )
|
|
try:
|
|
byte2 = ord( string[Bidx+1] )
|
|
except IndexError:
|
|
byte2 = 0
|
|
|
|
byte = (byte1 << bidx) & 0xff
|
|
byte |= (byte2 >> (8-bidx))
|
|
#calculate entropy over the byte
|
|
for bi in range(8):
|
|
b = (byte>>bi) & 1
|
|
entropy[b] += 1
|
|
|
|
bit += 8
|
|
Bidx += 1
|
|
|
|
if bit > endbit:
|
|
diff = bit-endbit
|
|
mask = ~ ( (1<<diff) - 1 )
|
|
byte &= mask
|
|
|
|
s += chr(byte)
|
|
|
|
ent = (min(entropy)+1.0) / (max(entropy)+1)
|
|
#print "entropy: %f" % ent
|
|
return (s, ent)
|
|
|
|
|
|
|
|
def genBitArray(string, startbit, endbit):
|
|
'''
|
|
bitsects a string... ie. chops out the bits from the middle of the string
|
|
returns the new string and the entropy (ratio of 0:1)
|
|
'''
|
|
binStr, ent = bitSectString(string, startbit, endbit)
|
|
|
|
s = []
|
|
for byte in binStr:
|
|
byte = ord(byte)
|
|
for bitx in range(7, -1, -1):
|
|
bit = (byte>>bitx) & 1
|
|
s.append(bit)
|
|
|
|
return (s, ent)
|
|
|
|
|
|
chars_top = [
|
|
" ", #000
|
|
" ", #001
|
|
"^", #010
|
|
"/", #011
|
|
" ", #100
|
|
" ", #101
|
|
"\\",#110
|
|
"-", #111
|
|
]
|
|
|
|
chars_mid = [
|
|
" ", #000
|
|
"|", #001
|
|
"#", #010
|
|
" ", #011
|
|
"|", #100
|
|
"#", #101
|
|
" ", #110
|
|
" ", #110
|
|
]
|
|
|
|
chars_bot = [
|
|
"-", #000
|
|
"/", #001
|
|
" ", #010
|
|
" ", #011
|
|
"\\",#100
|
|
"V", #101
|
|
" ", #110
|
|
" ", #110
|
|
]
|
|
|
|
|
|
def reprBitArray(bitAry, width=194):
|
|
top = []
|
|
mid = []
|
|
bot = []
|
|
|
|
arylen = len(bitAry)
|
|
# top line
|
|
#FIXME: UGGGGLY and kinda broken.
|
|
fraction = 1.0 * arylen/width
|
|
expand = [bitAry[int(x*fraction)] for x in xrange(width)]
|
|
|
|
for bindex in xrange(width):
|
|
bits = 0
|
|
if bindex>0:
|
|
bits += (expand[bindex-1]) << (2)
|
|
bits += (expand[bindex]) << (1)
|
|
if bindex < width-1:
|
|
bits += (expand[bindex+1])
|
|
|
|
top.append( chars_top[ bits ] )
|
|
mid.append( chars_mid[ bits ] )
|
|
bot.append( chars_bot[ bits ] )
|
|
|
|
tops = "".join(top)
|
|
mids = "".join(mid)
|
|
bots = "".join(bot)
|
|
return "\n".join([tops, mids, bots])
|
|
|
|
def invertBits(data):
|
|
output = []
|
|
ldata = len(data)
|
|
off = 0
|
|
|
|
if ldata&1:
|
|
output.append( chr( ord( data[0] ) ^ 0xff) )
|
|
off = 1
|
|
|
|
if ldata&2:
|
|
output.append( struct.pack( "<H", struct.unpack( "<H", data[off:off+2] )[0] ^ 0xffff) )
|
|
off += 2
|
|
|
|
#method 1
|
|
#for idx in xrange( off, ldata, 4):
|
|
# output.append( struct.pack( "<I", struct.unpack( "<I", data[idx:idx+4] )[0] & 0xffff) )
|
|
|
|
#method2
|
|
count = ldata / 4
|
|
#print ldata, count
|
|
numlist = struct.unpack( "<%dI" % count, data[off:] )
|
|
modlist = [ struct.pack("<L", (x^0xffffffff) ) for x in numlist ]
|
|
output.extend(modlist)
|
|
|
|
return ''.join(output)
|
|
|