-
-
Save dfirfpi/113ff71274a97b489dfd to your computer and use it in GitHub Desktop.
| #!/usr/bin/python | |
| # -*- coding: utf-8 -*- | |
| # | |
| # Copyright 2015, Francesco "dfirfpi" Picasso <[email protected]> | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # | |
| """Python Windows-only utility to decompress MAM compressed files.""" | |
| import binascii | |
| import ctypes | |
| import struct | |
| import sys | |
| def tohex(val, nbits): | |
| """Utility to convert (signed) integer to hex.""" | |
| return hex((val + (1 << nbits)) % (1 << nbits)) | |
| def main(): | |
| """Utility core.""" | |
| if len(sys.argv) != 3: | |
| sys.exit('Missing params [win10compressed.pf] [win10decompressed.pf]') | |
| NULL = ctypes.POINTER(ctypes.c_uint)() | |
| SIZE_T = ctypes.c_uint | |
| DWORD = ctypes.c_uint32 | |
| USHORT = ctypes.c_uint16 | |
| UCHAR = ctypes.c_ubyte | |
| ULONG = ctypes.c_uint32 | |
| # You must have at least Windows 8, or it should fail. | |
| try: | |
| RtlDecompressBufferEx = ctypes.windll.ntdll.RtlDecompressBufferEx | |
| except AttributeError: | |
| sys.exit('You must have Windows with version >=8.') | |
| RtlGetCompressionWorkSpaceSize = \ | |
| ctypes.windll.ntdll.RtlGetCompressionWorkSpaceSize | |
| with open(sys.argv[1], 'rb') as fin: | |
| header = fin.read(8) | |
| compressed = fin.read() | |
| signature, decompressed_size = struct.unpack('<LL', header) | |
| calgo = (signature & 0x0F000000) >> 24 | |
| crcck = (signature & 0xF0000000) >> 28 | |
| magic = signature & 0x00FFFFFF | |
| if magic != 0x004d414d : | |
| sys.exit('Wrong signature... wrong file?') | |
| if crcck: | |
| # I could have used RtlComputeCrc32. | |
| file_crc = struct.unpack('<L', compressed[:4])[0] | |
| crc = binascii.crc32(header) | |
| crc = binascii.crc32(struct.pack('<L',0), crc) | |
| compressed = compressed[4:] | |
| crc = binascii.crc32(compressed, crc) | |
| if crc != file_crc: | |
| sys.exit('Wrong file CRC {0:x} - {1:x}!'.format(crc, file_crc)) | |
| compressed_size = len(compressed) | |
| ntCompressBufferWorkSpaceSize = ULONG() | |
| ntCompressFragmentWorkSpaceSize = ULONG() | |
| ntstatus = RtlGetCompressionWorkSpaceSize(USHORT(calgo), | |
| ctypes.byref(ntCompressBufferWorkSpaceSize), | |
| ctypes.byref(ntCompressFragmentWorkSpaceSize)) | |
| if ntstatus: | |
| sys.exit('Cannot get workspace size, err: {}'.format( | |
| tohex(ntstatus, 32))) | |
| ntCompressed = (UCHAR * compressed_size).from_buffer_copy(compressed) | |
| ntDecompressed = (UCHAR * decompressed_size)() | |
| ntFinalUncompressedSize = ULONG() | |
| ntWorkspace = (UCHAR * ntCompressFragmentWorkSpaceSize.value)() | |
| ntstatus = RtlDecompressBufferEx( | |
| USHORT(calgo), | |
| ctypes.byref(ntDecompressed), | |
| ULONG(decompressed_size), | |
| ctypes.byref(ntCompressed), | |
| ULONG(compressed_size), | |
| ctypes.byref(ntFinalUncompressedSize), | |
| ctypes.byref(ntWorkspace)) | |
| if ntstatus: | |
| sys.exit('Decompression failed, err: {}'.format( | |
| tohex(ntstatus, 32))) | |
| if ntFinalUncompressedSize.value != decompressed_size: | |
| print 'Decompressed with a different size than original!' | |
| with open(sys.argv[2], 'wb') as fout: | |
| fout.write(bytearray(ntDecompressed)) | |
| print 'Lucky man, you have your prefetch file ready to be parsed!' | |
| if __name__ == "__main__": | |
| main() |
no logro descomprimirlo
no logro descomprimirlo
Ahem, that's not that useful... what are you trying to decompress, on which system, which Python version etc etc.
Hi Fransesco,
Great Work, man !! I am trying to decompress prefetch file on Win10 machine with Python Version 2 using your script. I tried following command
w10pfdecomp.py CMD.EXE-6D6290C5.pf c:\temp\cmd.pf
w10pfdecomp.py [CMD.EXE-6D6290C5.pf] [c:\temp\cmd.pf]
did not work for me. A new command window flickers and then nothing happens. Can you please help?
Thanks and once gain appreciate your good work.
Regards
Hi @Kirtar22,
ahum, are you able to execute the script without any param? You should receive the output
'Missing params [win10compressed.pf] [win10decompressed.pf]'
Note that you don't need '[]' when specifying parameters.
Hi Fransesco,
Great Work, man !! I am trying to decompress prefetch file on Win10 machine with Python Version 2 using your script. I tried following command
w10pfdecomp.py CMD.EXE-6D6290C5.pf c:\temp\cmd.pf
w10pfdecomp.py [CMD.EXE-6D6290C5.pf] [c:\temp\cmd.pf]
did not work for me. A new command window flickers and then nothing happens. Can you please help?
Thanks and once gain appreciate your good work.
Regards
Hi @Kirtar22,
ahum, are you able to execute the script without any param? You should receive the output
'Missing params [win10compressed.pf] [win10decompressed.pf]'Note that you don't need '[]' when specifying parameters.
Hi Fransesco,
Great Work, man !! I am trying to decompress prefetch file on Win10 machine with Python Version 2 using your script. I tried following command
w10pfdecomp.py CMD.EXE-6D6290C5.pf c:\temp\cmd.pf
w10pfdecomp.py [CMD.EXE-6D6290C5.pf] [c:\temp\cmd.pf]
did not work for me. A new command window flickers and then nothing happens. Can you please help?
Thanks and once gain appreciate your good work.
Regards
Hi @dfirfpi,
Thanks a lot for your answer. I have tried to run it with Python2 with a bash installed on my Windows10 box.
python2 w10pfdecomp.py /mnt/c/Windows/Prefetch/CMD.EXE-6D6290C5.pf /mnt/c/temp/cmd.pf
You must have Windows with version >=8.
The output says that I need to have windows version >8 however I am running this coed on Win10.
Regards,
Kirtar
and yes, I get the message as you mentioned if I run the program without any parameters. Please see below
python2 w10pfdecomp.py
Missing params [win10compressed.pf] [win10decompressed.pf]
Did you solve the issue @Kirtar22?
So Im trying to decompress a .png that for some reason has MAM encoding, or appears to. I keep getting errors with the script, but did a sanity check with a file from c:\windows\prefetch and that worked. The specific error code is: 0xc0000242L
@DJP89 don't know about the PNG, most likely you will need to adjust the script.
Hi @dfirfpi, I'm doing some prefetch research as part of some postgrad study and found your super helpful tool. Thank you!
I had a minor issue getting it running on Python 3.10.4. To get it working I just modified the code to enclose the print commands at row 104 and 109 with parenthesis as per below.
if ntFinalUncompressedSize.value != decompressed_size:
print ('Decompressed with a different size than original!')
with open(sys.argv[2], 'wb') as fout:
fout.write(bytearray(ntDecompressed))
print ('Lucky man, you have your prefetch file ready to be parsed!')
Running Python 3.9.16 on Cygwin 3.4.6 on Win10.0.19045.2965 x64.
To accommodate the possibility of running non-Windows-native Python and load the ntdll.dll library. I modified the try ... RtlDecompressBufferEx block as follows:
try:
RtlDecompressBufferEx = ctypes.windll.ntdll.RtlDecompressBufferEx
RtlGetCompressionWorkSpaceSize = \
ctypes.windll.ntdll.RtlGetCompressionWorkSpaceSize
except AttributeError:
#sys.exit('You must have Windows with version >=8.')
# Handle running non-Windows-native Python.
try:
ntdll = ctypes.CDLL("ntdll.dll")
except Exception as e:
print(type(e).__name__ + ": " + str(e), file=sys.stderr)
exit(1)
else:
RtlDecompressBufferEx = ntdll.RtlDecompressBufferEx
RtlGetCompressionWorkSpaceSize = ntdll.RtlGetCompressionWorkSpaceSize
But when I get to the actual RtlDecompressBufferEx call:
ntstatus = RtlDecompressBufferEx(
USHORT(calgo),
ctypes.byref(ntDecompressed),
ULONG(decompressed_size),
ctypes.byref(ntCompressed),
ULONG(compressed_size),
ctypes.byref(ntFinalUncompressedSize),
ctypes.byref(ntWorkspace))
if ntstatus:
raise ValueError('Decompression failed, err: {}'.\
format(tohex(ntstatus, 32)))
I get ValueError: Decompression failed, err: 0xc0000242 which is STATUS_BAD_COMPRESSION_BUFFER.
I tried different ctype calls & type modifications with no luck.
I also tried running it via native-Windpws Python 3.11 from the MS Store.
Exactly same error code.
I recon either the input or ouput buffer is incorrectly cast / passed to RtlDecompressBufferEx but I lack skill / knowledge to debug WinNT API + Python ctypes...
Any ideas?
Added checksum code. Now it's able to decompress files that uses MAM format, as Windows 10 Prefetch and SuperFetch files, together with Windows 8.1 SuperFetch files.