Revision as of 08:32, 26 July 2007

This document is a reference guide to the Advanced Forensics Format library. It is intended to be read by software developers seeking to use the library in their own programs. It is not intended for end users.

End users will be better off reading the "AFF Users Guide" that comes with the library. This guide gives an introduction to the AFF format and explains the tools included with the library. The default imager, aimage, is covered in this guide.

Introduction

Using the AFF is (hopefully) a rather transparent process. The library can handle plain files, such as those generated by dd, AFF files, and EnCase images. It is not necessary for your program to know which kind of file it is processing, the data is extracted and presented to the program transparently. All you need to do is change the basic file operations to their AFF equivalents. These simple substitutions allow you to use AFF or Encase files just like dd images.

Compiling AFF programs

The library currently supports the following compilers:

gcc

g++

MinGW

Microsoft Visual C++

When compiling an AFF program you must include the AFF header:

#include <afflib.h>

During linking you must include the AFF library itself and the SSL library. Additionally, if you're using a C compiler, you will need the C++ standard library. Some examples using several compilers are shown below:

Using g++

$ g++ file.c -lafflib -lssl

Using gcc

$ gcc file.c -lafflib -lssl -lstdc++

Using MinGW

C:\> gcc file.c -lafflib -lssl -lstdc++

Using Microsoft Visual C++

c:\> LINK file.obj afflib.lib

Testing for the AFF using Automake

If you're using the GNU Automake and other tools to check for the AFF, we recommend the following tests to determine if the AFF is present on the system:

These tests will define two variables in the config.h file for you. First, the value USE_AFF is defined the AFF is found on the development system. Second, the value USE_AFF_STDIN is defined if the function af_open_stdin is supported. That function was not present in early versions of the library.

Your First AFF program

The first program we will examine the command line arguments to determine if they are valid AFF files. If so, it will attempt to open them and display the size of their uncompressed data. The complete source code is below.

This line attempts to open the given file using the af_open command. The O_RDONLY is one of many macros defined in fcntl.h that can be used when opening files. The final parameter specifies whether or not the file must be created. This normally only applies when writing AFF files, so it's safe to leave it as zero here. The function returns a pointer to an AFFILE structure. There are some public data fields in that structure defined in afflib.h.

This line uses one of the miscellaneous functions included with the AFF to display the size of the uncompressed image stored in the file. Compare the value displayed by this line to the size of the AFF image on the disk and you can see how much the library compresses. The example file zeros.aff shows an extreme case!

af_close(af);

This final line closes the file handle and destroys the AFFILE structure.

AFF Concepts

Segments

AFF files can be viewed as a series of name/value pairs.

Pages

AFF Return Values

The following status codes can be returned by AFF functions.

Code

Description

AF_ERROR_EOF

The end of the AFF file has been reached

AF_ERROR_DATASMALL

The buffer provided for the requested AFF segment is not large enough to hold the data that would be returned.

AF_ERROR_TAIL

There is no tail or an error occurred trying to read the tail of an AFF segment. This indicates that the file is corrupt (probably truncated).

AF_ERROR_SEGH

There is no head or an error occurred trying to read the head. This indicates that the AFF file is corrupt.

AF_ERROR_NAME

Invalid segment name

AF_ERROR_INVALID_ARG

The argument was invalid

AF_ERROR_NO_AES

This version of the library was compiled without AES support and the program is attempting to read an AES-encrypted segment.

AF_ERROR_AES_TOO_SMALL

The decrypted AES segment is too small for the amount of data that it was supposed to contain. The segment is probably corrupt.

AF_ERROR_KEY_SET

A key was previously set. (You can only have one AES encryption key per file.)

AFF Function Reference

Stream Functions

af_open

AFFILE * af_open(const char *filename, int flags, int mode);

The flags parameter controls what the program should be allowed to do with the file. There are a set of handy macros defined in fcntl.h that you should use. When reading files, using O_RDONLY is usually sufficient. When writing an AFF file, it is best to use O_CREAT|O_RDWR.

The mode parameter is only used when creating a new file (RBF – and only on *nix?). It controls the

It should be noted here that when writing AFF files, the af_open command does more than just open a file handle. When writing, the af_open command causes the default AFF header to be written to the file on the disk.

RBF – What happens, when opening for write, if the file already exists?RBF – Which parts of the header are written by default?

See open(2)

af_open_stdin

AFFILE * af_open_stdin(void);

A special case of af_open, this function an AFF handle on standard input. Note that this function did not appear until AFF version 2.3. Also note that if you are working on the Windows platform (or plan to support the Windows platform) you need to explicitly tell the compiler to treat standard input as a stream of binary data. For example, using MinGW you can set:

af_popen

This function is currently on supported on UNIX variants, Cygwin and MinGW (which are really both Unix variants).

See popen(2)

af_close

int af_close(AFFILE *af);

Closes an AFF file handle and frees all resources associated with it. You can use this function regardless if you opened the file with af_open or af_popen.

af_read

int af_read(AFFILE *af, unsigned char *buf, size_t count);

Similar to fread, this function reads count bytes from the file and stores them in buf. buf should already be allocated to hold this amount of data. The function returns the number of bytes read or -1 on error. Note the number of bytes read is size_t, not uint64_t, because size_t defines the maximum data segment size on the current platform.

af_seek

uint64_t af_seek(AFFILE *af, int64 pos, int whence);

Similar to fseeko (a 64-bit version of fseek).

Advances the file pointer into the decompressed data to the offset given by pos depending on whence.
SEEK_SET, SEEK_CUR, or SEEK_END.

af_tell

uint64 af_tell(AFFILE *af);

Similar to ftello (a 64-bit version of ftell), this function returns the offset into the decompressed data

af_eof

int af_eof(AFFILE *af);

Returns TRUE if the file pointer into the decompressed data is at the end of the decompressed data. Otherwise, returns FALSE.

af_reopen

Writing AFF Files

af_enable_writing

void af_enable_writing(AFFILE *af, int flag);

This function must be executed before attempting to write data (using af_write) to an AFF file. You do not need to execute this function, however, before calling af_update_seg. If flag is TRUE, enables the user to write to the file AF.

af_set_callback

Sets a callback function that is called during each of the four phases of the segment write operation.

af_enable_compression

void af_enable_compression(AFFILE *af, int type, int level);

Enables compression on the given AFF file. The type of compression must be an AFF compression algorithm as shown in Table 2. The compression level can be any integer between AF_COMPRESSION_MIN and AF_COMPRESSION_MAX. These values are currently these are one and nine, respectively, but could change in future versions.

For example, to enable maximum LZMA compression:

af_enable_compression(af,AF_COMPRESSION_ALG_LZMA,AF_COMPRESSION_MAX);

Flag

Algorithm

AF_COMPRESSION_ALG_NONE

No compression

AF_COMPRESSION_ALG_ZLIB

zlib

AF_COMPRESSION_ALG_LZMA

LZMA. Dramatically slower than zlib, this algorithm can produce image files that are significantly smaller.

af_compression_type

int af_compression_type(AFFILE *af);

Returns the compression algorithm being used by the file in question. The algorithms are given in Table 2.

af_write

int af_write(AFFILE *af, unsigned char *buf, size_t count);

Note that you must call af_enable_writing on af before using this function.

af_badflag

const unsigned char * af_badflag(AFFILE *af);

Returns the pattern used to identify bad sectors in this file.

af_is_badsector

af_is_badsector(AFFILE *af, unsigned char *buf);

Returns TRUE if buf is the pattern used to mark a bad sector, Otherwise, returns FALSE.

af_stats

void af_stats(AFFILE *af, FILE *f);

This function writes statistics about the current usage of the given AFF file. This includes the file's name and the number of pages read, pages written, pages compressed, pages decompressed, cache hits, cache misses, and bytes copied into the cache. This function is generally used only for debugging the AFF.

Proposed new prototype:

This function is used both to set and change the values of segments in a file. The name of the segment to be updated is given in name. If the segment does not exist, it will be created. The value arg is 32-bits of application specific data. If your segment is only going to store 32 bits of data or less, you can easily store the value in the arg parameter. In this case, set data to NULL and datalen to zero.

Programmers do not need to call af_enable_writing before using this fucntion.
af_update_seg returns zero on success and -1 on error. When an error occurs the value errno is set to indicate the problem. Possible values for errno include:
ENOTSUP The operation is not supported by the filesystem. This happens when the programmer attempts to set segments in a file that doesn't support metadata (e.g. AF_IDENTIFY_RAW).