Calling an external function

Hi,

I’m trying to write a script to decode compressed windows prefetch files (MAM\04).To achieve this you have to decompress the data section using two function calls in NTDLL.DLL:

RtlGetCompressionWorkSpaceSize(…) and RtlDecompressBufferEx(…)

The function protoypes (see below) use pointers to the buffers. Does anyone know if there is a way to pass pointers to these external functions?

Code example:

const ushort COMPRESSION_FORMAT_XPRESSHUFF = 4;

/*
long RtlGetCompressionWorkSpaceSize(
USHORT CompressionFormatAndEngine,
PULONG CompressBufferWorkSpaceSize,
PULONG CompressFragmentWorkSpaceSize
);

long RtlDecompressBufferEx(
USHORT CompressionFormat,
PVOID UncompressedBuffer,
ULONG UncompressedBufferSize,
PVOID CompressedBuffer,
ULONG CompressedBufferSize,
PULONG FinalUncompressedSize,
PVOID WorkSpace
);

*/

#link “c:\windows\system32\ntdll.dll”
long RtlGetCompressionWorkSpaceSize(ushort compressionFormat, ulong &compressBufferWorkSpaceSize, ulong &compressFragmentWorkSpaceSize);
long RtlDecompressBufferEx(ushort compressionFormat, byte uncompressedBuffer, uint32 uncompressedBufferSize, byte compressedBuffer, uint32 compressedBufferSize, uint32 &finalUncompressedSize, byte workSpace);
#endlink

typedef struct CompressedPF {
uint32 Signature <format=hex>;
uint32 UnCompressedSz;
byte CompressedBuffer[FileSize()-FTell()];
};

// -------------------- Main --------------------
LittleEndian();

// Read in raw file
CompressedPF Header;

// Decode
local byte UnCompressedBuffer[Header.UnCompressedSz];
local ulong compressBufferWorkSpaceSize = 0;
local ulong compressFragmentWorkSpaceSize = 0;
local ushort ret;
local uint32 finalUncompressedSize;

//get the size of what our workspace needs to be
ret = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_XPRESSHUFF, &compressBufferWorkSpaceSize, &compressFragmentWorkSpaceSize);
if (ret != 0) {
Printf(“Error: RtlGetCompressionWorkSpaceSize() failed\n”);
} else {
byte workSpace[compressFragmentWorkSpaceSize];
ulong dstSize = 0;

ret = RtlDecompressBufferEx(COMPRESSION_FORMAT_XPRESSHUFF, UnCompressedBuffer, Header.UnCompressedSz, CompressedBuffer, sizeof(Header.Compressedbuffer), &dstSize, workSpace);
if (ret == 0) {
Printf(“Error: RtlGetCompressionWorkSpaceSize() failed\n”);
};

};

One of the limitations of the 010 Editor language is that it does not currently support pointers. However, I believe you can work around this for DLL arguments by using an array of size 1 instead of a pointer. For example, if you define your functions as:

#link "c:\windows\system32\ntdll.dll"
long RtlGetCompressionWorkSpaceSize(ushort compressionFormat, ulong compressBufferWorkSpaceSize[1], ulong compressFragmentWorkSpaceSize[1]);
long RtlDecompressBufferEx(ushort compressionFormat, byte uncompressedBuffer, uint32 uncompressedBufferSize, byte compressedBuffer, uint32 compressedBufferSize, uint32 finalUncompressedSize[1], byte workSpace);
#endlink

Then you should be able to call the function using:

local ulong compressBufferWorkSpaceSize[1];
local ulong compressFragmentWorkSpaceSize[1];
ret = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_XPRESSHUFF, compressBufferWorkSpaceSize, compressFragmentWorkSpaceSize);

Let us know if you have any trouble getting this to work.

Graeme
SweetScape Software

Hi Graham,

Thanks for your help, excellent advice as usual. The working code block is as follows:

  • decompresses a window prefetch file with the header MAM\04
  • writes the raw SCCM prefech file into a new window
const ushort COMPRESSION_FORMAT_XPRESSHUFF = 4;

#link "c:\windows\system32\ntdll.dll"
    long RtlGetCompressionWorkSpaceSize(ushort CompressionFormat, ulong CompressBufferWorkSpaceSize[0], ulong CompressFragmentWorkSpaceSize[0]);
    long RtlDecompressBufferEx(ushort CompressionFormat, byte UncompressedBuffer[0], ulong UncompressedBufferSize, byte CompressedBuffer[0], ulong CompressedBufferSize, ulong FinalUncompressedSize[0], byte WorkSpace[0]);
#endlink

// Contains the raw PF file
typedef struct CompressedPF {
    byte    Signature[4] <format=hex>;
    ulong   UnCompressedSz;
    byte    CompressedBuffer[FileSize()-FTell()] <format=hex>;
};



// -------------------- Main --------------------
LittleEndian();

// Read in raw file
CompressedPF   Header;
local long     ret;

// Decode
local ulong  CompressBufferWorkSpaceSize[1];
local ulong  CompressFragmentWorkSpaceSize[1];
local ulong  FinalUncompressedSize;
local byte   UnCompressedBuffer[Header.UnCompressedSz] <format=hex>;

//get the size of what our workspace needs to be
ret = RtlGetCompressionWorkSpaceSize(COMPRESSION_FORMAT_XPRESSHUFF, CompressBufferWorkSpaceSize, CompressFragmentWorkSpaceSize);

if (ret != 0) {
    Printf("Error: RtlGetCompressionWorkSpaceSize() failed, return code %08d\n",ret);
} else {
    if (CompressFragmentWorkSpaceSize[0]>0) {

        local byte WorkSpace[CompressFragmentWorkSpaceSize[0]];

        local ulong dstSize[1] = 256;

        ret = RtlDecompressBufferEx(COMPRESSION_FORMAT_XPRESSHUFF, UnCompressedBuffer, Header.UnCompressedSz, Header.CompressedBuffer, Header.UnCompressedSz, dstSize, WorkSpace);
        if (ret == 0) {
            Printf("Error: RtlGetCompressionWorkSpaceSize() failed, return code %08d\n",ret);
        };
        
        // Get curent file working directory and create an output folder
//        local char sSRCDIR[]=FileNameGetPath(GetFileName());
        local char sFileName[]=GetFileName();

        local int hFile,hCurFile;
        local char sfileout[],sfiledir[];
        SPrintf(sfileout,"%s.pf.unpacked.pf",sFileName);

        Printf("%s",sfileout);

        // Save File
        hCurFile=GetFileNum();
        hFile=FileNew("Hex",true);
        FileSelect(hFile);
        WriteBytes(UnCompressedBuffer,0,Header.UnCompressedSz);
        if (DEBUG) {
            Printf("\n\nDEBUG: file write disabled\n");
        } else {
            Printf("\n\nUncompressed PF written to %s\n",sfileout);
            FileSave(sfileout);
//            FileClose();
        }
        FileSelect(hCurFile);
    };
};

I’m planning to roll this into the PF template so it handles uncompressed and compressed prefetch files.

Thanks

Simon