Q:

How should i decode this data/these strings

I am currently trying to work through an OLD python CTF challenge, the script of the server is provided, and the idea is to send the correct data to this server,
#!/usr/bin/env python3
# from dis import dis
import socketserver
import types

class RequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        self.request.sendall(b'PyDRM Proof of Concept version 0.7\n')
        self.request.sendall(
            b'Submit the secret password to retrieve the flag:\n')
        user_input_bytes = self.request.recv(4096).strip()
        user_input = user_input_bytes.decode('utf-8', 'ignore')
        if validate_password(user_input):
            self.request.sendall(read_flag())
        else:
            self.request.sendall(b'Invalid password\n')

class RequestServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def read_flag():
    with open('flag.txt', 'rb') as fh:
        return fh.read()

def generate_validation_function():
    code_obj = types.CodeType(
        1,
        0,
        5,
        32,
        67,
        b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        ('append', 'chr', 'ord', 'join'),
        ('a', 'b', 'c', 'd', 'e'),
        'drm.py',
        'validate_password',
        5,
        b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        (),
        ()
    )
    func_obj = types.FunctionType(code_obj, globals())
    return func_obj

def main():
    setattr(__import__(__name__), 'validate_password',
            generate_validation_function())
    server = RequestServer(('0.0.0.0', 8765), RequestHandler)
    try:
        server.serve_forever()
    except (SystemExit, KeyboardInterrupt):
        server.shutdown()
        server.server_close()

if __name__ == '__main__':
    main()

EDIT
I understand, what is going on to the point that a validate_password function is created by using a CodeType and FunctionType objects. I also understand that if validate_password(user_input) evaluates as True, the flag will be sent. meaning that the return type must be boolean. The documentation for CodeType along with the server script also reveals that validate_password has only one argument.
My Actual Question
The source contains compiled python bytecode. b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'for example. I have tried numerous ways to decode/encode these strings to get some meaningful data, the only data i have managed to extract is hexadecimal. 
How do i convert this data into actual code, therefore being able to reconstruct the validate_password function.
What I have Tried
SO - Python: convert string to packed hex ( '01020304' -> '\x01\x02\x03\x04' ) - I have attempted to basically do what this answer suggests but in reverse, i have either not understood it correctly, or this doesn't work
binascii.b2a_hex() - This is how I managed to convert the strings into hex, like i stated earlier however, i cannot yield utf-8 data from this hex.
struct.unpack() - Had some success with this method, yet am at a loss of what the data would mean in the context of the validate_password function, I can only get integers with this method. (Unless i have misunderstood)

A:

Start an interactive Python 3 session. If you use the plain python interpreter, type
import types
help(types.CodeType)

If you're using IPython, you might instead write
import types
types.CodeType?

You'll learn that types.CodeType is there to

Create a code object.  Not for the faint of heart.

Uh hu. What are code objects? Let's have a look at the Python documentation.

The type for code objects such as returned by compile().

So the bytestring arguments might, at least partially be binary data (or binary instructions), rather than (text) string encoded somehow.
The help or ? invocation also told us the signature of this type's initializer:

code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,
      constants, names, varnames, filename, name, firstlineno,
      lnotab[, freevars[, cellvars]])

With that, we can write the construction more self-descriptively:
    code_obj = types.CodeType(
        argcount=1,
        kwonlyargcount=0,
        nlocals=5,
        stacksize=32,
        flags=67,
        codestring=b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        constants=(None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        names=('append', 'chr', 'ord', 'join'),
        varnames=('a', 'b', 'c', 'd', 'e'),
        filename='drm.py',
        name='validate_password',
        firstlineno=5,
        lnotab=b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        freevars=(),
        cellvars=()
    )

(This is just for illustration. It isn't actually executable like this, because types.CodeType() expects all arguments to be passed positionally rather than as keyword arguments.)
Now what does all that mean?
You can disassemble the code object to get closer to that question:
import dis
dis.dis(code_obj)

(output:)
  6           0 LOAD_CONST               1 ('\x87') 
              3 LOAD_CONST               2 ('\x9a') 
              6 LOAD_CONST               3 ('\x92') 
              9 LOAD_CONST               4 ('\x8e') 
             12 LOAD_CONST               5 ('\x8b') 
             15 LOAD_CONST               6 ('\x85') 
             18 LOAD_CONST               5 ('\x8b') 
             21 LOAD_CONST               7 ('\x96') 
             24 LOAD_CONST               8 ('\x81') 
             27 LOAD_CONST               5 ('\x8b') 
             30 LOAD_CONST               9 ('\x95') 
             33 LOAD_CONST               8 ('\x81') 

  7          36 LOAD_CONST              10 ('\x84') 
             39 LOAD_CONST               1 ('\x87') 
             42 LOAD_CONST               7 ('\x96') 
             45 LOAD_CONST               7 ('\x96') 
             48 LOAD_CONST               1 ('\x87') 
             51 LOAD_CONST              11 ('\x94') 
             54 LOAD_CONST               8 ('\x81') 
             57 LOAD_CONST               7 ('\x96') 
             60 LOAD_CONST              12 ('\x8a') 
             63 LOAD_CONST              13 ('\x83') 
             66 LOAD_CONST              14 ('\x90') 
             69 LOAD_CONST               8 ('\x81') 

  8          72 LOAD_CONST               5 ('\x8b') 
             75 LOAD_CONST              15 ('\x8f') 
             78 LOAD_CONST               3 ('\x92') 
             81 LOAD_CONST               4 ('\x8e') 
             84 LOAD_CONST               5 ('\x8b') 
             87 LOAD_CONST               6 ('\x85') 
             90 LOAD_CONST               5 ('\x8b') 
             93 LOAD_CONST               7 ('\x96') 
             96 BUILD_LIST              32 
             99 STORE_FAST               1 (b) 

  9         102 BUILD_LIST               0 
            105 STORE_FAST               2 (c) 

 10         108 SETUP_LOOP              43 (to 154) 
            111 LOAD_FAST                1 (b) 
            114 GET_ITER             
        >>  115 FOR_ITER                35 (to 153) 
            118 STORE_FAST               3 (d) 

 11         121 LOAD_FAST                2 (c) 
            124 LOAD_ATTR                0 (append) 
            127 LOAD_GLOBAL              1 (chr) 
            130 LOAD_GLOBAL              2 (ord) 
            133 LOAD_FAST                3 (d) 
            136 CALL_FUNCTION            1 
            139 LOAD_CONST              16 (34) 
            142 BINARY_SUBTRACT      
            143 CALL_FUNCTION            1 
            146 CALL_FUNCTION            1 
            149 POP_TOP              
            150 JUMP_ABSOLUTE          115 
        >>  153 POP_BLOCK            

 12     >>  154 LOAD_CONST              17 ('') 
            157 LOAD_ATTR                3 (join) 
            160 LOAD_FAST                2 (c) 
            163 CALL_FUNCTION            1 
            166 STORE_FAST               4 (e) 

 13         169 LOAD_FAST                0 (a) 
            172 LOAD_FAST                4 (e) 
            175 COMPARE_OP               2 (==) 
            178 POP_JUMP_IF_FALSE      185 

 14         181 LOAD_CONST              18 (True) 
            184 RETURN_VALUE         

 15     >>  185 LOAD_CONST              19 (False) 
            188 RETURN_VALUE         

See the dis documentation for the meaning of the bytecode operations (LOAD_CONST, BUILD_LIST, etc.).
To get an even better grasp of what the function is doing, one would then try to decompile it back to Python code. I didn't manage to do that, though. (Tried with uncompyle6.)

A:

Riffing off of das-g's answer, this code works. Sorta. 
import uncompyle6
import types
code_obj = types.CodeType(
        1, 0, 5, 32, 67, b'd\x01\x00d\x02\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05\x00d\x07'
        b'\x00d\x08\x00d\x05\x00d\t\x00d\x08\x00d\n\x00d\x01\x00d\x07\x00d\x07'
        b'\x00d\x01\x00d\x0b\x00d\x08\x00d\x07\x00d\x0c\x00d\r\x00d\x0e\x00d'
        b'\x08\x00d\x05\x00d\x0f\x00d\x03\x00d\x04\x00d\x05\x00d\x06\x00d\x05'
        b'\x00d\x07\x00g \x00}\x01\x00g\x00\x00}\x02\x00x+\x00|\x01\x00D]#\x00'
        b'}\x03\x00|\x02\x00j\x00\x00t\x01\x00t\x02\x00|\x03\x00\x83\x01\x00d'
        b'\x10\x00\x18\x83\x01\x00\x83\x01\x00\x01qs\x00Wd\x11\x00j\x03\x00|'
        b'\x02\x00\x83\x01\x00}\x04\x00|\x00\x00|\x04\x00k\x02\x00r\xb9\x00d'
        b'\x12\x00Sd\x13\x00S',
        (None, '\x87', '\x9a', '\x92', '\x8e', '\x8b', '\x85', '\x96', '\x81',
         '\x95', '\x84', '\x94', '\x8a', '\x83', '\x90', '\x8f', 34, '', True,
         False),
        ('append', 'chr', 'ord', 'join'),
        ('a', 'b', 'c', 'd', 'e'),
        'drm.py',
        'validate_password',
        5,
        b'\x00\x01$\x01$\x01\x1e\x01\x06\x01\r\x01!\x01\x0f\x01\x0c\x01\x04'
        b'\x01',
        freevars=(),
        cellvars=()
    )

import sys
uncompyle6.main.uncompyle(3.5, code_obj, sys.stdout)

What's missing here is that this code is really wrapped inside a function that takes an "a" parameter. 
I won't spoil the fun giving the answer. Instead:

Run the above program.
Wrap the output in something like:

def drm(a): 
   # Output from run above.

