Skip to content

Instantly share code, notes, and snippets.

@herrcore
Created October 2, 2017 03:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save herrcore/b935bd64d0af4e5761ba39c29a16b3f0 to your computer and use it in GitHub Desktop.
Save herrcore/b935bd64d0af4e5761ba39c29a16b3f0 to your computer and use it in GitHub Desktop.
UCL NRV2B Decompression Library - Full Python (compression used by Zeus variants)
#!/usr/bin/env python
################################################################################################
## UCL NRV2B Decompression Library
##
## Code from "Clash of the Titans: ZeuS v SpyEye":
## https://www.sans.org/reading-room/whitepapers/malicious/clash-titans-zeus-spyeye-33393
## Author: Harshit Nayyar, harshit.nayyar@telus.com
##
## NOTE: This is the compression algorithm used in the Zeus trojan and subsequent variants
##
## Lipstick, rouge, and bugfixes from: @herrcore
################################################################################################
import struct
class DecompressError(Exception):
pass
def getBit(pos, recordDataEncoded, fourBytes, count):
#Get the bit at position count. If count == 0, reinitialize count and move to #next decompression.
if count == 0:
count = 31
fourBytes = struct.unpack('<L', recordDataEncoded[pos:pos+4])[0]
pos += 4
else:
count -= 1
bit = ((fourBytes >> count ) & 1)
return (bit, pos, fourBytes, count)
def decompress(recordDataEncoded):
recordDataDecoded = ''
sPos = 0
dPos = 0
lastMOff = 1
shift = 0
fourBytes = 0
#Main Loop
while True:
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
while(gb != 0):
recordDataDecoded += recordDataEncoded[sPos]
sPos += 1
if sPos > len(recordDataEncoded):
raise DecompressError('Record Data Len Exceeded 1')
return recordDataDecoded
dPos += 1
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
#mOff calculation
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
mOff = 2+gb
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
while(gb == 0):
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
mOff = 2*mOff + gb
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
if mOff == 2:
mOff = lastMOff
else:
mOff = (mOff - 3) * 256 + ord(recordDataEncoded[sPos])
sPos += 1
if sPos > len(recordDataEncoded):
raise DecompressError('Record Data Len Exceeded 2')
return recordDataDecoded
if int(mOff) == -1:
break;
else:
mOff += 1
lastMOff = mOff
#mLen calculation
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(mLen, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
mLen = mLen*2 + gb
if mLen == 0:
mLen += 1
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
mLen = 2*mLen + gb
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
while (gb == 0):
if sPos >= len(recordDataEncoded):
return recordDataDecoded
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
mLen = 2*mLen + gb
(gb, sPos, fourBytes, shift) = getBit(sPos, recordDataEncoded, fourBytes, shift)
mLen += 2
if mOff > 0xd00:
mLen += 1
mPos = dPos - mOff
if mPos < 0:
raise DecompressError('mPos is negative')
return recordDataDecoded
if mPos > dPos:
raise DecompressError('Oops mPos exceeds dPos')
return recordDataDecoded
#Copy uncompressed data
recordDataDecoded += recordDataDecoded[mPos]
mPos += 1
dPos += 1
while mLen > 0:
mLen -= 1
recordDataDecoded += recordDataDecoded[mPos]
dPos += 1
mPos += 1
return recordDataDecoded
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment