X-Tensions API Documentation
XT_* functions that you may export

For “ordinary” X-Tensions

LONG XT_Init(
   DWORD nVersion,
   DWORD nFlags,
   HANDLE hMainWnd,
   struct LicenseInfo* LicInfo
);

#pragma pack(2)
struct LicenseInfo {
   DWORD nSize,
   DWORD nLicFlags,
   DWORD nUsers,
   FILETIME nExpDate,
   BYTE nLicID[16]
};

Mandatory to export. Will be called before anything else happens, before the X-Tension does its actual job, just to inform the DLL of the version of X-Ways Forensics that is loading the DLL, already when the X-Tension is selected by the user in X-Ways Forensics. You may return -1 to prevent further use of the DLL, for example if certain functions that you require are not present (i.e. exported by a certain version of X-Ways Forensics). Otherwise you must return either 1 or (if you consider your X-Tension to be thread-safe) 2. If your X-Tension does not identifies itself as thread-safe, that may result in suboptimal performance of X-Ways Forensics during volume snapshot refinement operations which invoke your X-Tension. At least disk I/O X-Tension should be made thread-safe.

nVersion: The higher word specifies the version number. For example 1640 means v16.4. The third highest byte specified the service release number. The lowest byte specifies the current language of the user interface of the calling program.

nFlags:
#define XT_INIT_XWF 0x00000001 // X-Ways Forensics (flag used reliably in releases from 2015)
#define XT_INIT_WHX 0x00000002 // WinHex  (flag used reliably in releases from 2015)
#define XT_INIT_XWI 0x00000004 // X-Ways Investigator
#define XT_INIT_BETA 0x00000008 // pre-release version
#define XT_INIT_QUICKCHECK 0x00000020 // called just to check whether the X-Tension accepts the calling application (used by v16.5 and later)
#define XT_INIT_ABOUTONLY 0x00000040 // called just to prepare for XT_About or XT_PrepareSearch (used by v16.5 and later)

hMainWnd: Handle of the main window in case you need it.

LicInfo: Points to a structure that contains information about the license. Provided by v18.1 and later. NULL in older releases. nSize is the size of the structure provided.

nLicFlags:
0x01: running unlocked/licensed
0x02: expiration date field is populated
0x04: non-perpetual license (not only the update maintenance, but the license itself will expire on the expiration date)
0x10: the software uses a hardware-based copy protection method (dongle or BYOD)
0x20: the hardware device is a dongle (if 0x10 is set and 0x20 is not, then it's BYOD)
0x40: the dongle is a network dongle that is accessed remotely
0x80: the BYOD device is a remote web server (i.e. BYOD+), flag supported by v19.3 SR-7 and later

nUsers: Specifies how many different users may use the same license file/dongle simultaneously. For BYOD this is currently always 1. 0 means unknown.

nLicID: Uniquely identifies the license file/dongle/BYOD license. You could license your X-Tension based on that ID and only allow users to run your X-Tension if the ID matches your expectations (if the ID is in your unlock list). Please note that the actual dongle ID or BYOD license ID cannot be derived from nLicID.

LONG XT_Done(
   PVOID lpReserved
);

If exported (optional), will be called just before the DLL is unloaded to give you a chance to dispose any allocated memory, save certain data permanently etc. You should return 0.

nReserved: Currently always NULL.

LONG XT_About(
   HANDLE hParentWnd
   PVOID lpReserved
);

If exported (optional), will be called when the user requests to see information about the DLL. You can display copyright notices, a version number, a brief description of the exported functionality, extensive help on how to use it, from where in X-Ways Forensics to call it with what settings etc. etc. You could even display a dialog window where the user can change settings for this X-Tension, which you store in the Windows registry or in a permanent file. You should return 0.

nReserved: Currently always NULL.

LONG XT_Prepare(
   HANDLE hVolume,
   HANDLE hEvidence,
   DWORD nOpType,
   PVOID lpReserved
);

If exported (optional), will be called immediately for a volume when volume snapshot refinement or some other action starts, before items or search hits in that volume are processed individually, or simply when the user runs your X-Tension from the main menu or applies it to selected files directly. Your X-Tension can do its actual job when responding to a call of this function or any of the other below functions. The nOpType parameter tells you in which context exactly your X-Tension is running.

Possible negative return values:
-4 if you want X-Ways Forensics to stop the whole operation (e.g. volume snapshot refinement) altogether
-3 if you want to prevent further use of the X-Tension for the remainder of the whole operation, for example because your X-Tension is not supposed to do anything for that kind of operation as indicated by nOpType or because your X-Tension expects to be applied to a particular data window (requiring hVolume to be unequal to 0)
-2 if you want this particular volume excluded from the operation
-1 if you don't want other functions of this X-Tension to be called for this particular volume, not even XT_Finalize
Full negative return value evaluation only for XT_ACTION_RVS.

0 is the default return value, if you just want XT_Finalize to be called. Will also be assumed if you do not export XT_Prepare.

Positive return values are a combination of these flags:
#define XT_PREPARE_CALLPI 0x01
#define XT_PREPARE_CALLPILATE 0x02
#define XT_PREPARE_EXPECTMOREITEMS 0x04
#define XT_PREPARE_DONTOMIT 0x08
#define XT_PREPARE_TARGETDIRS 0x10
#define XT_PREPARE_TARGETZEROBYTEFILES 0x20

XT_PREPARE_CALLPI: if you want X-Ways Forensics to call your implementation of XT_ProcessItem[Ex] (whichever is exported) for each item this volume snapshot (not if the volume snapshot is not targeted, e.g. in case of XT_ACTION_RUN)
XT_PREPARE_CALLPILATE: for XT_ACTION_RVS specify this flag in addition to XT_PREPARE_CALLPI if you wish to receive calls of XT_ProcessItem (not Ex), if actually exported, after all other individual item refinement operations instead of before (preferable for example so that you do not get called for ignorable files that were recognized as such by hash database matching during the same volume snapshot refinement run)
XT_PREPARE_EXPECTMOREITEMS: in case of XT_ACTION_RVS, to signal XWF that you may create more items in the volume snapshot, so that for example the user will definitely be informed of how many item were added (v16.5 and later only)
XT_PREPARE_DONTOMIT: in case of XT_ACTION_RVS, to signal XWF that you wish to receive calls for XT_ProcessItem[Ex] even for files that the user wants to omit for any of the possible three reasons (v18.5 and later only)
XT_PREPARE_TARGETDIRS: in case of XT_ACTION_RVS, to signal XWF that you wish to receive calls for XT_ProcessItem[Ex] even for directories, not only files, for example because you wish to parse the file system data structures in those directories (v18.5 and later only)
XT_PREPARE_TARGETZEROBYTEFILES: in case of XT_ACTION_RVS, to signal XWF that you wish to receive calls for XT_ProcessItem[Ex] even for files that have a size of 0 bytes, which are otherwise skipped for performance reasons (v18.9 SR-7 and later only)

hVolume: Typically a handle to the volume that the X-Tension is applied to. 0 (i.e. not a valid handle) if run from the main menu with no data window open, i.e. when not applied to anything. A handle to a file if run from the main window if the active data window represents a single file opened via File | Open. To make sure that a non-zero handle is a handle to a volume, you can call XWF_GetVolumeInformation and check that lpBytesPerSector retrieves a value unequal to zero. Or, if your X-Tension is intended to be applied to a file opened that way, verify that lpBytesPerSector retrieves zero.

hEvidence: From v17.5 SR-2, a handle to an evidence object if hVolume represents an evidence object, otherwise 0.

nOpType: How the X-Tension is executed within X-Ways Forensics.
#define XT_ACTION_RUN 0 // simply run directly from the main menu, since v16.63
#define XT_ACTION_RVS 1 // volume snapshot refinement starting2
#define XT_ACTION_LSS 2 // logical simultaneous search starting
#define XT_ACTION_PSS 3 // physical simultaneous search starting
#define XT_ACTION_DBC 4 // directory browser context menu command invoked1
#define XT_ACTION_SHC 5 // search hit context menu command invoked

1 Run from the directory browser context menu, an X-Tension is applied to selected files. This may occur in the case root window, not for just one particular volume! XT_ProcessItem is not necessarily called for the selected items in the order in which they are listed in the directory browser.
2 Run from Specialist | Refine Volume Snapshot, the X-Tension is applied to a volume snapshot (all files if you want).
3 Run from Tools | Run X-Tension, the X-Tension is applied to the data window as a whole (the file or disk or image represented by the active data window), but not to the volume snapshot. The data window could be one with no volume snapshot at all (e.g. an ordinary binary file opened with File | Open). So there are no "items" in that sense that need to be processed (XT_ProcessItem[Ex] is not called!) because no volume snapshot is targeted in the first place.

nReserved: Currently always NULL.

LONG XT_Finalize(
   HANDLE hVolume,
   HANDLE hEvidence,
   DWORD nOpType,
   PVOID lpReserved
);

If exported (optional), will be called when volume snapshot refinement or another operation has completed. Return 1 if the current directory listing in the directory browser of the active data window has to be refreshed after XT_ACTION_DBC (usually not necessary, perhaps when adding new files to the directory, has an effect in v17.6 and later only), or otherwise 0.

hEvidence: From v17.6, a handle to an evidence object if the hVolume represents an evidence object, otherwise 0.

nOpType: see above

nReserved: Currently always NULL.

LONG XT_ProcessItem(
   LONG nItemID,
   PVOID lpReserved
);

If exported (optional) and if wanted by XT_Prepare, will be called for each file in the volume snapshot that is targeted for refinement or selected and targeted with the directory browser context menu. Implement and export this function if you merely need to retrieve information about the file and don't need to read its data. There is a slight performance benefit if the user does not select other refinement operations that do need to open the item and read its data, i.e. you save a little bit time if a file does not need to opened for reading. By calling XWF_OpenItem, you can still open the file to read its data if needed.

Return -1 if you want X-Ways Forensics to stop the current operation (e.g. volume snapshot refinement), -2 if you want have X-Ways Forensics skip all other volume snapshot refinement operations for this file, otherwise 0.

nReserved: Currently always NULL.

LONG XT_ProcessItemEx(
   LONG nItemID,
   HANDLE hItem,
   PVOID lpReserved
);

If exported (optional) and if wanted by XT_Prepare, will be called for each item (file or directory) in the volume snapshot that is targeted for refinement or selected and targeted with the directory browser context menu. The item will be opened for reading prior to the function call. Implement and export this function if you need to read the item's data, which you can do using the hItem parameter. Return -1 if you want X-Ways Forensics to stop the current operation (e.g. volume snapshot refinement), otherwise 0.

nReserved: Currently always NULL. 

LONG XT_PrepareSearch(
   struct PrepareSearchInfo* PSInfo
   struct CodePages* CPages
);

#pragma pack(2)
struct PrepareSearchInfo {
   DWORD nSize,
   LPWSTR lpSearchTerms,
   DWORD nBufLen,
   DWORD nFlags
};

#pragma pack(2)
struct CodePages {
   DWORD nSize,
   WORD nCodePage1,
   WORD nCodePage2,
   WORD nCodePage3,
   WORD nCodePage4,
   WORD nCodePage5
};

If exported (optional), will be called by v16.9 and later if an X-Tension is loaded for use with a simultaneous search, so that the X-Tension can enter predefined search terms into the dialog window for use with the search. The X-Tension can also learn about the current search settings (the active code pages and some other settings through the flags field) and could inform the user of necessary adjustments for the search to work as intended by the X-Tension. Return 1 if you have made adjustments to the search terms, or 0 if not, or -1 if you are not happy with the current settings at all and want the X-Tension to be unselected. Adjustments to the flags or the code pages are ignored.

lpSearchTerms: Null-terminated. Delimited by line breaks. Specifies the currently entered search terms, which you can freely manipulate, replace or complete.

nBufLen: Size of the buffer that lpSearchTerms points to in Unicode characters.

nFlags:
#define XWF_SEARCH_MATCHCASE 0x00000010 // match case
#define XWF_SEARCH_WHOLEWORDS 0x00000020 // whole words only
#define XWF_SEARCH_GREP 0x00000040 // GREP syntax
#define XWF_SEARCH_WHOLEWORDS2 0x00004000 // whole words only for search terms that are specially marked
#define XWF_SEARCH_GREP2 0x00008000 // GREP syntax only search terms that start with "grep:"

CPages: Indicates code pages currently selected for the search. See this web page for possible code page identifiers. 0 means unused code page.

LONG XT_ProcessSearchHit(
   struct SearchHitInfo* Info
);

#pragma pack(2)
struct SearchHitInfo {
   DWORD nSize;
   LONG nItemID;
   INT64 nRelOfs;
   INT64 nAbsOfs;
   PVOID lpOptionalHitPtr;
   WORD nSearchTermID;
   WORD nLength;
   WORD nCodePage;
   WORD nFlags;
   HANDLE hOptionalItemOrVolume
};

If exported (optional), will be called for each search hit, either when it is found or, in a future version of X-Ways Forensics, later if selected by the user in a search hit list. Return 0, except if you want X-Ways Forensics to abort the search (return -1) or if you want X-Ways Forensics to stop calling you (return -2). This function is not called if the search was initiated by the X-Tension itself (via XWF_Search).

nSize: Size of the record. The record is packed. Currently In future versions of the API the record may be larger if more fields are provided.
nRelOfs
: Relative offset of the search hit in its respective file, if any, otherwise -1.
nAbsOfs: Absolute offset of the search hit from the point of the volume, if available, otherwise -1. You may change the offset, if that helps to improve the quality of the search hit.
lpFlags: you may change the flags, for example to mark a hit as notable or to discard it
0x0001: resides in the text that was extracted from the file, nRelOfs is not an offset in the file
0x0002: notable
0x0008: deleted, set to discard the search hit
0x0040: index search hit
0x0080: in slack space etc.
lpOptionalHitPtr: Pointer to the search hit in memory. Provided only if XT_ProcessSearchHit is called during a search, not when later applied to an existing search hit, and only for search hits of the simultaneous search, not for index searches. Do not make any assumption about how many bytes before or after the search hit can be read in memory.
nSearchTermID: you may assign a search hit to a different search term by changing this ID
nLength
: Size of the search hit in bytes. You may change that size, if that helps to improve the quality of the search hit.
hItemOrVolume: Part of the structure in v16.5 and later. Specifies the item (for a logical search) or volume (for a physical search) in which a search hit was found. Useful if you wish to read more data from this item. Provided only if XT_ProcessSearchHit is called during a search, only for search hits of simultaneous search. 0 for index searches, 0 when later applied to an existing search hit. 

If you call XWF_SelectVolumeSnapshot while responding to a call to XT_ProcessSearchHit, you need to change call it again to change it back before returning control.

For Viewer X-Tensions (only supported by X-Ways Forensics, not WinHex)

PVOID XT_View(
   HANDLE hItem,
   LONG nItemID,
   HANDLE hVolume,
   HANDLE hEvidence,
   PVOID lpReserved,
   PINT64 nResSize
);

If an X-Tension exports this function (optional), the X-Tension may be used by v17.6 and later as a "Viewer X-Tension". The function is called for each file that is to be viewed in a separate window or in Preview mode or that is included in a case report. The X-Tension can provide a human-readable representation of a binary file for example as plain text or HTML, or by converting special graphics file formats to BMP/JPEG/PNG etc., or using any other file format understood by the viewer component. This representation should be written into a buffer that is allocated by the X-Tension itself using a function of its own choice (e.g. VirtualAlloc, GlobalAlloc, HeapAlloc, malloc, GetMem, ...). Return the address of that buffer, or NULL to signal failure. X-Ways Forensics will call XT_ReleaseMem at a later point in time to make the X-Tension free up the allocated memory when the buffer no longer needed.

nResSize should be set to -1 if you just do not want to be responsible for providing a representation of this file (in most instances because your X-Tension supports very specific file types only), -2 if you want to indicate that an error occurred that needs to be reported, 0 to signal that the file should be represented as no data, or a positive value to signal success and indicate the size of the data in the buffer that you supply.

You may use the hItem handle to query the size of the file (via XWF_GetSize) and to read from it (using XWF_Read, for example first to merely check the signature of the file, to see whether you support that particular file type). You may use nItemID for the volume snapshot item property functions for example if you require more file system level metadata about the file such as the filename, or if you require more data from the volume snapshot such as the detected type of the file. You may use the hVolume handle if you require more information about the volume that the file resides in, and the hEvidence handle if you require more information about the evidence object that the volume represents (if any). 

You should ignore the lpReserved parameter.

Note that if the user loads your X-Tension in X-Ways Forensics for viewing purposes, XT_Prepare, XT_Finalize, XT_ProcessItem, XT_ProcessItemEx, XT_PrepareSearch, and XT_ProcessSearchHit will not be called even if exported. XT_View will not be called in your X-Tension even if loaded and selected by the user if a Viewer X-Tension higher in the list signals that it does provide a view of that particular file already.

In v18.2 and later, a button labelled "XT" is shown in the user interface when viewer X-Tensions are available (loaded), next to the "Raw" button. That button allows the user to conveniently change the preview to the representation provided by the first viewer X-Tension that feels responsible for the type of the selected file. Or back to the regular preview if not helpful, in both directions with a single mouse click. The user may also combine Raw and XT submodes of Preview mode, for example for debugging purposes, if you are programming a viewer X-Tension of your own and have it return HTML code that you wish to conveniently check right within X-Ways Forensics.

BOOL XT_ReleaseMem(
   PVOID lpBuffer
);

If an X-Tension exports this function (mandatory if XT_View is exported), it will be called by X-Ways Forensics v17.6 and later to free up memory allocated by a previous call of XT_View. The return value is currently ignored, but you should signal success or failure of the release of the memory buffer.

For Disk I/O X-Tensions

DWORD XT_SectorIOInit(
   struct DriveInfo* DInfo
);

#pragma pack(2)
struct DriveInfo {
   DWORD nSize,
   LONG nDrive,
   LONG nParentDrive,
   DWord nBytesPerSector,
   INT64 nSectorCount,
   INT64 nParentSectorCount,
   INT64 nStartSectorOnParent,
   LPVOID lpPrivate
};

If an X-Tension exports this function (optional), it will be called by X-Ways Forensics 18.4 and later when opening a disk or image or partition or volume or reconstructed RAID to see whether the X-Tension wishes to act as an additional abstraction layer for disk I/O. In particular that allows the X-Tension to decrypt data on encrypted disks/partitions/... (FDE, full disk encryption) on the fly when needed by X-Ways Forensics, so that X-Ways Forensics will only get to see the decrypted data. Such an X-Tension will likely check first whether the disk/partition/... contains any supported kind of encryption and may have to prompt the user for a decryption key or a key file (using a dialog window of its own) and/or read some sectors by calling the XWF_DiskIO function to make the final decision.

The X-Tension should return flags: 0x01 if it wishes to be responsible for read access to the disk/partition/... and receive XT_SectorIO calls, 0x02 if it wishes to be responsible for write access (not currently supported), 0x04 to enforce read-only mode otherwise if direct writing (not through the X-Tension) must be prevented to avoid corruption. 0x10 should be returned if the X-Tension wishes to be responsible for reading data at the file level by getting its XT_FileIO function called. The function should return 0 if the X-Tension does not feel responsible for handling that particular disk/partition/... at all, for example because it found an unknown or unsupported type of encryption.

nSize is the size of the structure. The structure might grow in future versions of X-Ways Forensics, but the elements at the beginning of the structure remain the same.

nDrive may be a negative number (in case of a physical, partitioned disk or image or hardware RAID) or a positive number (in case of a partition or volume on a disk or in an image or RAID). This parameter identifies the data source and must be used for any calls to XWF_DriveIO.

lpPrivate is initially a pointer to an initialized Unicode buffer that you may fill with an error message in case your function returns 0. The buffer may hold up to 255 characters. If however you signal success, then you may change this pointer to any private value or other pointer for your own use. You will be provided with the same value/pointer again when responding to calls for XT_SectorIO and XT_SectorIODone. The value/pointer may help you to reference your own dynamically allocated data about the encryption or to identify the disk.

nSectorCount is not only provided to you, but you may also change that value. For example if you provide access to an encrypted volume that is contained in the designated partition, but does not occupy the entire space of that partition because of a reserved header area, you reduce the sector count accordingly to prevent X-Ways Forensics from accessing sectors that do not exist in your volume. In such a case of a reserved header area of n sectors, that also means that when you respond to calls for XT_SectorIO to read sector x, you will actually read sector x+n using XWF_SectorIO and then (probably after decrypting it) return that data.

nParentDrive, nParentSectorCount, and nStartSectorOnParent are provided in case you need metadata from outside of the partition to properly interpret the data in the partition. You may read data from the parent disk using XWF_SectorIO, specifying nParentDrive as the drive to read from. If nParentDrive is zero, there is no parent.

DWORD XT_SectorIO(
   LPVOID lpPrivate,
   LONG nDrive,
   INT64 nSector,
   DWORD nCount,
   LPVOID lpBuffer,
   DWORD nFlags
);

An X-Tension must export this function if its XT_SectorIOInit function ever returns the flag 0x01. If the flag is returned, X-Ways Forensics 18.4 and later will call XT_SectorIO for any internally triggered I/O sector-wise operations on storage media or partitions/volumes.

It is your resonsibility to fill the buffer and return the number of transferred sectors. You can retrieve the original sector contents by calling XWF_SectorIO, alter the data as necessary (e.g. decrypt), and then pass it back to the caller. You may read from the same sector number or translate the external sector number to a different internal sector number and read from that sector instead, for example to skip a header with encryption metadata.

nFlags has the same meanings as in XWF_SectorIO and may be simply passed on to that function.

INT64 XT_FileIO(
   LPVOID lpPrivate,
   LONG nDrive,
   HANDLE hVolume,
   HANDLE hItem,
   LONG nItemID,
   INT64 nOffset,
   LPVOID lpBuffer,
  
INT64 nNumberOfBytes,
   DWORD nFlags
);

An X-Tension must export this function if its XT_SectorIOInit function ever returns the flag 0x10. If the flag is returned, X-Ways Forensics 19.2 and later will call XT_FileIO for any internally triggered file read operations on the same volume, but only for files that are defined in the file system (e.g. not carved files, files embedded in other files, files in archives, e-mails extracted from e-mail archives, stills extracted from videos, etc.). 

It is your responsibility to fill the buffer. You can, for example, retrieve the original file contents by calling XWF_Read for that file (item) using hItem, alter the data as necessary (e.g. decrypt), and then pass it back to the caller. Or, you can locate the storage location of the file contents on the volume yourself and read from the volume sector-wise by calling XWF_SectorIO using the nDrive parameter, or you can read from the volume with random access by calling XWF_Read for that volume using hVolume.

This function is also used to signal when a file is opened (access to it is initialized) or when it is closed (access to it has ended and allocated resources need to be freed), i.e. before the first actual I/O happens and after the last I/O happens. nNumberOfBytesToRead will be 0 in those cases, lpBuffer will be NULL, and nOffset will be -1 to signal that initialization is required and -2 to signal that clean-up is due. Whether these calls actually need any action at all depends on the inner working of the X-Tension. In these special situations you return 0 unless during initialization you decide that you do not wish to be responsible for I/O for that file, in which case you return -1. Calls with negative values of nOffset other than -1 and -2 must be ignored.

nFlags may be one of these values:
0x01: write instead of read (not currently supported for XT_FileIO)
0x40: check for and signal sparse file contents if possible

If nOffset is greater than or equal to 0, return the number of bytes filled into the buffer / that were successfully read. 0 mean nothing was read, for example because the requested read offset is past the end of the available date. -1 means complete failure, for example if it was not even possible any more to access the unterlying volume. -2 may be returned if (and only if) the 0x40 flag was set, in order to signal that the entire requested portion of the file is considered sparse, so that the caller will know it can ignore the data and doesn't have to do anything with it. Useful for performance reasons. You don't need to fill the buffer in that case. Observing the 0x40 flag and specially treating and signaling sparse areas is optional.

DWORD XT_SectorIODone(
   LPVOID lpPrivate,
   LPVOID lpReserved
);

If an X-Tension exports this function (mandatory if XT_SectorIOInit is exported), it will be called by X-Ways Forensics 18.4 and later, only if an X-Tension returned 0x01 or 0x10 for a previous call for XT_SectorIOInit. Gives the X-Tension the opportunity to free any resources when the disk/partition/... is about to be closed, in particular memory on the heap that you may have allocated before and this is pointed to by lpPrivate. Return 0.