This is how you should proceed in such cases.
Step 1 : Load the executable in a debugger like Ollydbg.
Step 2 : In the memory dump window, navigate to PyImport_FrozenModules
by pressing Ctrl + G
Step 3 : PyImport_FrozenModules
is a pointer which is initialized to point to an array of struct _frozen
records. Follow this pointer in dump
.
Step 4 : Now you are at the position where there is an array of _frozen
structures. This structure is defined as
struct _frozen {
char *name;
unsigned char *code;
int size;
};
The above array is terminated by a structure whose all of its members are null.
Step 5 : In the above structure, the first member is the pointer to the name of the frozen module, the second member is a pointer to the bytecode of the module. (This is the thing which you are looking for). The last member will give you the size in bytes of the bytecode. Using the size, dump out the bytecode to a file.
Step 6 : The bytecode which you have just dumped out does not contain the magic header value for pyc files (for python 2.7 this is 03 F3 0D 0A, followed by a 4 byte timestamp)
Add the header and now the file should be decompile-able.
To automate the above process, you could also write a script.
UPDATE
Here is a PyCommand ( a immunity debugger script) to dump the frozen modules. You need to run the script after all frozen modules are loaded. For this you may set a breakpoint on
the function PyImport_ImportFrozenModule()
so that you can track each frozen module as they are loaded. If you are new to Immunity Debugger see this and this
import immlib
DESC = 'PyCommand to dump frozen python modules'
PYTHONMAGIC = '\x03\xF3\x0D\x0A\x00\x00\x00\x00' # Change this value according to the version of python used. The value given here is for Python 2.7
'''
Run this pycommand when all frozen modules are loaded.
This will dump each frozen module in a .pyc file in
immunity debugger installation directory
'''
def main(args):
imm = immlib.Debugger()
addr = imm.getAddress('PyImport_FrozenModules')
structAddr = imm.readLong(addr)
while True:
ptrToName = imm.readLong(structAddr)
ptrToCode = imm.readLong(structAddr + 4)
sizeOfCode = imm.readLong(structAddr + 8)
structAddr += 12
# The array is terminated by a structure whose members are null
if ptrToName == 0 and ptrToCode == 0 and sizeOfCode == 0:
break
if sizeOfCode > 0 and sizeOfCode < 2147483647:
moduleName = imm.readString(ptrToName)
moduleCode = imm.readMemory(ptrToCode, sizeOfCode)
# You can change the output path here
open(moduleName + '.pyc', 'wb').write(PYTHONMAGIC + moduleCode)
return '[*] Frozen modules dumped'
After the frozen modules are dumped, use a decompiler on the resultant pyc files. You may use Easy Python Decompiler for that.