verbose msi file verification errors

This commit is contained in:
olszomal 2022-02-18 15:01:35 +01:00 committed by Michał Trojnara
parent ce196ce147
commit 4eeeec32b4
3 changed files with 109 additions and 108 deletions

173
msi.c
View File

@ -16,19 +16,19 @@
#define MIN(a,b) ((a) < (b) ? a : b) #define MIN(a,b) ((a) < (b) ? a : b)
/* Get absolute address from sector and offset */ /* Get absolute address from sector and offset */
static const u_char *sector_offset_to_address(MSI_FILE *msi, uint32_t sector, uint32_t offset) static const u_char *sector_offset_to_address(MSI_FILE *msi, uint32_t sector, uint32_t offset, int verbose)
{ {
if ((sector >= MAXREGSECT) || (offset >= msi->m_sectorSize) if ((sector >= MAXREGSECT) || (offset >= msi->m_sectorSize)
|| (msi->m_sectorSize == 0x0200 && sector + 1 >= 0x00800000) || (msi->m_sectorSize == 0x0200 && sector + 1 >= 0x00800000)
|| (msi->m_sectorSize == 0x1000 && sector + 1 >= 0x00100000) || (msi->m_sectorSize == 0x1000 && sector + 1 >= 0x00100000)
|| (msi->m_bufferLen <= (sector + 1) * msi->m_sectorSize + offset)) { || (msi->m_bufferLen <= (sector + 1) * msi->m_sectorSize + offset)) {
printf("Corrupted file\n"); if (verbose) printf("Corrupted file\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
return msi->m_buffer + (sector + 1) * msi->m_sectorSize + offset; return msi->m_buffer + (sector + 1) * msi->m_sectorSize + offset;
} }
static uint32_t get_fat_sector_location(MSI_FILE *msi, uint32_t fatSectorNumber) static uint32_t get_fat_sector_location(MSI_FILE *msi, uint32_t fatSectorNumber, int verbose)
{ {
uint32_t entriesPerSector, difatSectorLocation; uint32_t entriesPerSector, difatSectorLocation;
const u_char *address; const u_char *address;
@ -41,16 +41,16 @@ static uint32_t get_fat_sector_location(MSI_FILE *msi, uint32_t fatSectorNumber)
difatSectorLocation = msi->m_hdr->firstDIFATSectorLocation; difatSectorLocation = msi->m_hdr->firstDIFATSectorLocation;
while (fatSectorNumber >= entriesPerSector) { while (fatSectorNumber >= entriesPerSector) {
fatSectorNumber -= entriesPerSector; fatSectorNumber -= entriesPerSector;
address = sector_offset_to_address(msi, difatSectorLocation, msi->m_sectorSize - 4); address = sector_offset_to_address(msi, difatSectorLocation, msi->m_sectorSize - 4, verbose);
if (!address) { if (!address) {
printf("Failed to get a next sector address\n"); if (verbose) printf("Failed to get a next sector address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
difatSectorLocation = GET_UINT32_LE(address); difatSectorLocation = GET_UINT32_LE(address);
} }
address = sector_offset_to_address(msi, difatSectorLocation, fatSectorNumber * 4); address = sector_offset_to_address(msi, difatSectorLocation, fatSectorNumber * 4, verbose);
if (!address) { if (!address) {
printf("Failed to get a next sector address\n"); if (verbose) printf("Failed to get a next sector address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
return GET_UINT32_LE(address); return GET_UINT32_LE(address);
@ -58,33 +58,33 @@ static uint32_t get_fat_sector_location(MSI_FILE *msi, uint32_t fatSectorNumber)
} }
/* Lookup FAT */ /* Lookup FAT */
static uint32_t get_next_sector(MSI_FILE *msi, uint32_t sector) static uint32_t get_next_sector(MSI_FILE *msi, uint32_t sector, int verbose)
{ {
const u_char *address; const u_char *address;
uint32_t entriesPerSector = msi->m_sectorSize / 4; uint32_t entriesPerSector = msi->m_sectorSize / 4;
uint32_t fatSectorNumber = sector / entriesPerSector; uint32_t fatSectorNumber = sector / entriesPerSector;
uint32_t fatSectorLocation = get_fat_sector_location(msi, fatSectorNumber); uint32_t fatSectorLocation = get_fat_sector_location(msi, fatSectorNumber, verbose);
if (fatSectorLocation == 0) { if (fatSectorLocation == 0) {
printf("Failed to get a fat sector location\n"); if (verbose) printf("Failed to get a fat sector location\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
address = sector_offset_to_address(msi, fatSectorLocation, sector % entriesPerSector * 4); address = sector_offset_to_address(msi, fatSectorLocation, sector % entriesPerSector * 4, verbose);
if (!address) { if (!address) {
printf("Failed to get a next sector address\n"); if (verbose) printf("Failed to get a next sector address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
return GET_UINT32_LE(address); return GET_UINT32_LE(address);
} }
/* Locate the final sector/offset when original offset expands multiple sectors */ /* Locate the final sector/offset when original offset expands multiple sectors */
static int locate_final_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset, uint32_t *finalSector, uint32_t *finalOffset) static int locate_final_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset, uint32_t *finalSector, uint32_t *finalOffset, int verbose)
{ {
while (offset >= msi->m_sectorSize) { while (offset >= msi->m_sectorSize) {
offset -= msi->m_sectorSize; offset -= msi->m_sectorSize;
sector = get_next_sector(msi, sector); sector = get_next_sector(msi, sector, verbose);
if (sector == 0) { if (sector == 0) {
printf("Failed to get a next sector\n"); if (verbose) printf("Failed to get a next sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
} }
@ -94,49 +94,49 @@ static int locate_final_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset,
} }
/* Get absolute address from mini sector and offset */ /* Get absolute address from mini sector and offset */
static const u_char *mini_sector_offset_to_address(MSI_FILE *msi, uint32_t sector, uint32_t offset) static const u_char *mini_sector_offset_to_address(MSI_FILE *msi, uint32_t sector, uint32_t offset, int verbose)
{ {
if (sector >= MAXREGSECT || offset >= msi->m_minisectorSize || if (sector >= MAXREGSECT || offset >= msi->m_minisectorSize ||
msi->m_bufferLen <= msi->m_minisectorSize * sector + offset) { msi->m_bufferLen <= msi->m_minisectorSize * sector + offset) {
printf("Corrupted file\n"); if (verbose) printf("Corrupted file\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!locate_final_sector(msi, msi->m_miniStreamStartSector, sector * msi->m_minisectorSize + offset, &sector, &offset)) { if (!locate_final_sector(msi, msi->m_miniStreamStartSector, sector * msi->m_minisectorSize + offset, &sector, &offset, verbose)) {
printf("Failed to locate a final sector\n"); if (verbose) printf("Failed to locate a final sector\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
return sector_offset_to_address(msi, sector, offset); return sector_offset_to_address(msi, sector, offset, verbose);
} }
/* /*
* Copy as many as possible in each step * Copy as many as possible in each step
* copylen typically iterate as: msi->m_sectorSize - offset --> msi->m_sectorSize --> msi->m_sectorSize --> ... --> remaining * copylen typically iterate as: msi->m_sectorSize - offset --> msi->m_sectorSize --> msi->m_sectorSize --> ... --> remaining
*/ */
static int read_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *buffer, uint32_t len) static int read_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *buffer, uint32_t len, int verbose)
{ {
if (!locate_final_sector(msi, sector, offset, &sector, &offset)) { if (!locate_final_sector(msi, sector, offset, &sector, &offset, verbose)) {
printf("Failed to locate a final sector\n"); if (verbose) printf("Failed to locate a final sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
while (len > 0) { while (len > 0) {
const u_char *address; const u_char *address;
uint32_t copylen; uint32_t copylen;
address = sector_offset_to_address(msi, sector, offset); address = sector_offset_to_address(msi, sector, offset, verbose);
if (!address) { if (!address) {
printf("Failed to get a next sector address\n"); if (verbose) printf("Failed to get a next sector address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
copylen = MIN(len, msi->m_sectorSize - offset); copylen = MIN(len, msi->m_sectorSize - offset);
if (msi->m_buffer + msi->m_bufferLen < address + copylen) { if (msi->m_buffer + msi->m_bufferLen < address + copylen) {
printf("Corrupted file\n"); if (verbose) printf("Corrupted stream size\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
memcpy(buffer, address, copylen); memcpy(buffer, address, copylen);
buffer += copylen; buffer += copylen;
len -= copylen; len -= copylen;
sector = get_next_sector(msi, sector); sector = get_next_sector(msi, sector, verbose);
if (sector == 0) { if (sector == 0) {
printf("Failed to get a next sector\n"); if (verbose) printf("Failed to get a next sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
offset = 0; offset = 0;
@ -145,30 +145,30 @@ static int read_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *bu
} }
/* Lookup miniFAT */ /* Lookup miniFAT */
static uint32_t get_next_mini_sector(MSI_FILE *msi, uint32_t miniSector) static uint32_t get_next_mini_sector(MSI_FILE *msi, uint32_t miniSector, int verbose)
{ {
uint32_t sector, offset; uint32_t sector, offset;
const u_char *address; const u_char *address;
if (!locate_final_sector(msi, msi->m_hdr->firstMiniFATSectorLocation, miniSector * 4, &sector, &offset)) { if (!locate_final_sector(msi, msi->m_hdr->firstMiniFATSectorLocation, miniSector * 4, &sector, &offset, verbose)) {
printf("Failed to locate a final sector\n"); if (verbose) printf("Failed to locate a final sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
address = sector_offset_to_address(msi, sector, offset); address = sector_offset_to_address(msi, sector, offset, verbose);
if (!address) { if (!address) {
printf("Failed to get a next mini sector address\n"); if (verbose) printf("Failed to get a next mini sector address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
return GET_UINT32_LE(address); return GET_UINT32_LE(address);
} }
static int locate_final_mini_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset, uint32_t *finalSector, uint32_t *finalOffset) static int locate_final_mini_sector(MSI_FILE *msi, uint32_t sector, uint32_t offset, uint32_t *finalSector, uint32_t *finalOffset, int verbose)
{ {
while (offset >= msi->m_minisectorSize) { while (offset >= msi->m_minisectorSize) {
offset -= msi->m_minisectorSize; offset -= msi->m_minisectorSize;
sector = get_next_mini_sector(msi, sector); sector = get_next_mini_sector(msi, sector, verbose);
if (sector == 0) { if (sector == 0) {
printf("Failed to get a next mini sector\n"); if (verbose) printf("Failed to get a next mini sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
} }
@ -178,31 +178,31 @@ static int locate_final_mini_sector(MSI_FILE *msi, uint32_t sector, uint32_t off
} }
/* Same logic as "read_stream" except that use mini stream functions instead */ /* Same logic as "read_stream" except that use mini stream functions instead */
static int read_mini_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *buffer, uint32_t len) static int read_mini_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, char *buffer, uint32_t len, int verbose)
{ {
if (!locate_final_mini_sector(msi, sector, offset, &sector, &offset)) { if (!locate_final_mini_sector(msi, sector, offset, &sector, &offset, verbose)) {
printf("Failed to locate a final mini sector\n"); if (verbose) printf("Failed to locate a final mini sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
while (len > 0) { while (len > 0) {
const u_char *address; const u_char *address;
uint32_t copylen; uint32_t copylen;
address = mini_sector_offset_to_address(msi, sector, offset); address = mini_sector_offset_to_address(msi, sector, offset, verbose);
if (!address) { if (!address) {
printf("Failed to get a next mini sector address\n"); if (verbose) printf("Failed to get a next mini sector address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
copylen = MIN(len, msi->m_minisectorSize - offset); copylen = MIN(len, msi->m_minisectorSize - offset);
if (msi->m_buffer + msi->m_bufferLen < address + copylen) { if (msi->m_buffer + msi->m_bufferLen < address + copylen) {
printf("Corrupted file\n"); if (verbose) printf("Corrupted stream size\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
memcpy(buffer, address, copylen); memcpy(buffer, address, copylen);
buffer += copylen; buffer += copylen;
len -= copylen; len -= copylen;
sector = get_next_mini_sector(msi, sector); sector = get_next_mini_sector(msi, sector, verbose);
if (sector == 0) { if (sector == 0) {
printf("Failed to get a next mini sector\n"); if (verbose) printf("Failed to get a next mini sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
offset = 0; offset = 0;
@ -214,13 +214,13 @@ static int read_mini_stream(MSI_FILE *msi, uint32_t sector, uint32_t offset, cha
* Get file (stream) data start with "offset". * Get file (stream) data start with "offset".
* The buffer must have enough space to store "len" bytes. Typically "len" is derived by the steam length. * The buffer must have enough space to store "len" bytes. Typically "len" is derived by the steam length.
*/ */
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len) int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len, int verbose)
{ {
if (len < msi->m_hdr->miniStreamCutoffSize) { if (len < msi->m_hdr->miniStreamCutoffSize) {
if (!read_mini_stream(msi, entry->startSectorLocation, offset, buffer, len)) if (!read_mini_stream(msi, entry->startSectorLocation, offset, buffer, len, verbose))
return 0; /* FAILED */ return 0; /* FAILED */
} else { } else {
if (!read_stream(msi, entry->startSectorLocation, offset, buffer, len)) if (!read_stream(msi, entry->startSectorLocation, offset, buffer, len, verbose))
return 0; /* FAILED */ return 0; /* FAILED */
} }
return 1; /* OK */ return 1; /* OK */
@ -255,14 +255,14 @@ static MSI_FILE_HDR *parse_header(char *data)
} }
/* Parse MSI_ENTRY struct */ /* Parse MSI_ENTRY struct */
static MSI_ENTRY *parse_entry(MSI_FILE *msi, const u_char *data) static MSI_ENTRY *parse_entry(MSI_FILE *msi, const u_char *data, int verbose)
{ {
uint32_t inlen; uint32_t inlen;
MSI_ENTRY *entry = (MSI_ENTRY *)OPENSSL_malloc(sizeof(MSI_ENTRY)); MSI_ENTRY *entry = (MSI_ENTRY *)OPENSSL_malloc(sizeof(MSI_ENTRY));
entry->nameLen = GET_UINT16_LE(data + DIRENT_NAME_LEN); entry->nameLen = GET_UINT16_LE(data + DIRENT_NAME_LEN);
/* This length MUST NOT exceed 64, the maximum size of the Directory Entry Name field */ /* This length MUST NOT exceed 64, the maximum size of the Directory Entry Name field */
if (entry->nameLen == 0 || entry->nameLen > 64) { if (entry->nameLen == 0 || entry->nameLen > 64) {
printf("Corrupted Directory Entry Name Length\n"); if (verbose) printf("Corrupted Directory Entry Name Length\n");
OPENSSL_free(entry); OPENSSL_free(entry);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -280,7 +280,7 @@ static MSI_ENTRY *parse_entry(MSI_FILE *msi, const u_char *data)
if ((entry->startSectorLocation >= MAXREGSECT) if ((entry->startSectorLocation >= MAXREGSECT)
|| (msi->m_sectorSize == 0x0200 && entry->startSectorLocation + 1 >= 0x00800000) || (msi->m_sectorSize == 0x0200 && entry->startSectorLocation + 1 >= 0x00800000)
|| (msi->m_sectorSize == 0x1000 && entry->startSectorLocation + 1 >= 0x00100000)) { || (msi->m_sectorSize == 0x1000 && entry->startSectorLocation + 1 >= 0x00100000)) {
printf("Corrupted Starting Sector Location 0x%08X\n", entry->startSectorLocation); if (verbose) printf("Corrupted Starting Sector Location 0x%08X\n", entry->startSectorLocation);
OPENSSL_free(entry); OPENSSL_free(entry);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -290,7 +290,7 @@ static MSI_ENTRY *parse_entry(MSI_FILE *msi, const u_char *data)
inlen = GET_UINT32_LE(entry->size); inlen = GET_UINT32_LE(entry->size);
if ((msi->m_sectorSize == 0x0200 && inlen > 0x80000000) if ((msi->m_sectorSize == 0x0200 && inlen > 0x80000000)
|| (msi->m_bufferLen <= inlen)) { || (msi->m_bufferLen <= inlen)) {
printf("Corrupted Stream Size 0x%08X\n", inlen); if (verbose) printf("Corrupted Stream Size 0x%08X\n", inlen);
OPENSSL_free(entry); OPENSSL_free(entry);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -302,7 +302,7 @@ static MSI_ENTRY *parse_entry(MSI_FILE *msi, const u_char *data)
* Pass "0" to get the root directory entry. -- This is the start point to navigate the compound file. * Pass "0" to get the root directory entry. -- This is the start point to navigate the compound file.
* Use the returned object to access child entries. * Use the returned object to access child entries.
*/ */
static int get_entry(MSI_FILE *msi, uint32_t entryID, int is_root, MSI_ENTRY **entry) static int get_entry(MSI_FILE *msi, uint32_t entryID, int is_root, MSI_ENTRY **entry, int verbose)
{ {
uint32_t sector = 0; uint32_t sector = 0;
uint32_t offset = 0; uint32_t offset = 0;
@ -314,54 +314,55 @@ static int get_entry(MSI_FILE *msi, uint32_t entryID, int is_root, MSI_ENTRY **e
} }
/* Corrupted file */ /* Corrupted file */
if (!is_root && entryID == 0) { if (!is_root && entryID == 0) {
printf("Corrupted file\n"); if (verbose) printf("Corrupted entryID\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (msi->m_bufferLen / sizeof(MSI_ENTRY) <= entryID) { if (msi->m_bufferLen / sizeof(MSI_ENTRY) <= entryID) {
printf("Invalid argument entryID\n"); if (verbose) printf("Invalid argument entryID\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
/* The first entry in the first sector of the directory chain is known as /* The first entry in the first sector of the directory chain is known as
the root directory entry so it can not contain the directory stream */ the root directory entry so it can not contain the directory stream */
if (msi->m_hdr->firstDirectorySectorLocation == 0 && entryID == 0) { if (msi->m_hdr->firstDirectorySectorLocation == 0 && entryID == 0) {
printf("Corrupted First Directory Sector Location\n"); if (verbose) printf("Corrupted First Directory Sector Location\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!locate_final_sector(msi, msi->m_hdr->firstDirectorySectorLocation, entryID * sizeof(MSI_ENTRY), &sector, &offset)) { if (!locate_final_sector(msi, msi->m_hdr->firstDirectorySectorLocation,
printf("Failed to locate a final sector\n"); entryID * sizeof(MSI_ENTRY), &sector, &offset, verbose)) {
if (verbose) printf("Failed to locate a final sector\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
address = sector_offset_to_address(msi, sector, offset); address = sector_offset_to_address(msi, sector, offset, verbose);
if (!address) { if (!address) {
printf("Failed to get a final address\n"); if (verbose) printf("Failed to get a final address\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
*entry = parse_entry(msi, address); *entry = parse_entry(msi, address, verbose);
if (!*entry) { if (!*entry) {
printf("Failed to parse MSI_ENTRY struct\n"); if (verbose) printf("Failed to parse MSI_ENTRY struct\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
return 1; /* OK */ return 1; /* OK */
} }
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi) MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi, int verbose)
{ {
MSI_ENTRY *entry = NULL; MSI_ENTRY *entry = NULL;
if (!get_entry(msi, 0, TRUE, &entry)) { if (!get_entry(msi, 0, TRUE, &entry, verbose)) {
return NULL; return NULL;
} }
return entry; return entry;
} }
/* Parse MSI_FILE struct */ /* Parse MSI_FILE struct */
MSI_FILE *msi_file_new(char *buffer, uint32_t len) MSI_FILE *msi_file_new(char *buffer, uint32_t len, int verbose)
{ {
MSI_FILE *msi; MSI_FILE *msi;
MSI_ENTRY *root; MSI_ENTRY *root;
if (buffer == NULL || len == 0) { if (buffer == NULL || len == 0) {
printf("Invalid argument\n"); if (verbose) printf("Invalid argument\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
msi = (MSI_FILE *)OPENSSL_malloc(sizeof(MSI_FILE)); msi = (MSI_FILE *)OPENSSL_malloc(sizeof(MSI_FILE));
@ -374,7 +375,7 @@ MSI_FILE *msi_file_new(char *buffer, uint32_t len)
if (msi->m_bufferLen < sizeof *(msi->m_hdr) || if (msi->m_bufferLen < sizeof *(msi->m_hdr) ||
memcmp(msi->m_hdr->signature, msi_magic, sizeof msi_magic)) { memcmp(msi->m_hdr->signature, msi_magic, sizeof msi_magic)) {
printf("Wrong file format\n"); if (verbose) printf("Wrong file format\n");
msi_file_free(msi); msi_file_free(msi);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -382,13 +383,13 @@ MSI_FILE *msi_file_new(char *buffer, uint32_t len)
/* The file must contains at least 3 sectors */ /* The file must contains at least 3 sectors */
if (msi->m_bufferLen < msi->m_sectorSize * 3) { if (msi->m_bufferLen < msi->m_sectorSize * 3) {
printf("The file must contains at least 3 sectors\n"); if (verbose) printf("The file must contains at least 3 sectors\n");
msi_file_free(msi); msi_file_free(msi);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
root = msi_root_entry_get(msi); root = msi_root_entry_get(msi, verbose);
if (!root) { if (!root) {
printf("Failed to get msi root entry\n"); if (verbose) printf("Failed to get msi root entry\n");
msi_file_free(msi); msi_file_free(msi);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -403,7 +404,7 @@ MSI_FILE_HDR *msi_header_get(MSI_FILE *msi)
} }
/* Recursively parse MSI_DIRENT struct */ /* Recursively parse MSI_DIRENT struct */
int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret) int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret, int verbose)
{ {
MSI_DIRENT *dirent, *unused = NULL; MSI_DIRENT *dirent, *unused = NULL;
MSI_ENTRY *lnode = NULL, *rnode = NULL, *cnode = NULL; MSI_ENTRY *lnode = NULL, *rnode = NULL, *cnode = NULL;
@ -412,7 +413,7 @@ int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRE
return 1; /* OK */ return 1; /* OK */
} }
if (entry->nameLen == 0 || entry->nameLen > 64) { if (entry->nameLen == 0 || entry->nameLen > 64) {
printf("Corrupted file\n"); if (verbose) printf("Corrupted Directory Entry Name Length\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
dirent = (MSI_DIRENT *)OPENSSL_malloc(sizeof(MSI_DIRENT)); dirent = (MSI_DIRENT *)OPENSSL_malloc(sizeof(MSI_DIRENT));
@ -423,44 +424,44 @@ int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRE
dirent->children = sk_MSI_DIRENT_new_null(); dirent->children = sk_MSI_DIRENT_new_null();
if (parent && !sk_MSI_DIRENT_push(parent->children, dirent)) { if (parent && !sk_MSI_DIRENT_push(parent->children, dirent)) {
printf("Failed to insert MSI_DIRENT\n"); if (verbose) printf("Failed to insert MSI_DIRENT\n");
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
return 0; /* FAILED */ return 0; /* FAILED */
} }
/* NOTE : These links are a tree, not a linked list */ /* NOTE : These links are a tree, not a linked list */
if (!get_entry(msi, entry->leftSiblingID, FALSE, &lnode)) { if (!get_entry(msi, entry->leftSiblingID, FALSE, &lnode, verbose)) {
printf("Corrupted leftSiblingID: 0x%08X\n", entry->leftSiblingID); if (verbose) printf("Corrupted Left Sibling ID: 0x%08X\n", entry->leftSiblingID);
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!msi_dirent_new(msi, lnode, parent, &unused)) { if (!msi_dirent_new(msi, lnode, parent, &unused, verbose)) {
OPENSSL_free(lnode); OPENSSL_free(lnode);
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!get_entry(msi, entry->rightSiblingID, FALSE, &rnode)) { if (!get_entry(msi, entry->rightSiblingID, FALSE, &rnode, verbose)) {
printf("Corrupted rightSiblingID: 0x%08X\n", entry->rightSiblingID); if (verbose) printf("Corrupted Right Sibling ID: 0x%08X\n", entry->rightSiblingID);
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!msi_dirent_new(msi, rnode, parent, &unused)) { if (!msi_dirent_new(msi, rnode, parent, &unused, verbose)) {
OPENSSL_free(rnode); OPENSSL_free(rnode);
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (entry->type != DIR_STREAM) { if (entry->type != DIR_STREAM) {
if (!get_entry(msi, entry->childID, FALSE, &cnode)) { if (!get_entry(msi, entry->childID, FALSE, &cnode, verbose)) {
printf("Corrupted childID: 0x%08X\n", entry->childID); if (verbose) printf("Corrupted Child ID: 0x%08X\n", entry->childID);
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!msi_dirent_new(msi, cnode, dirent, &unused)) { if (!msi_dirent_new(msi, cnode, dirent, &unused, verbose)) {
OPENSSL_free(cnode); OPENSSL_free(cnode);
sk_MSI_DIRENT_free(dirent->children); sk_MSI_DIRENT_free(dirent->children);
OPENSSL_free(dirent); OPENSSL_free(dirent);
@ -604,7 +605,7 @@ out:
} }
/* Recursively hash a MSI directory (storage) */ /* Recursively hash a MSI directory (storage) */
int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root) int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root, int verbose)
{ {
int i, ret = 0; int i, ret = 0;
@ -625,8 +626,8 @@ int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root)
continue; continue;
} }
indata = (char *)OPENSSL_malloc(inlen); indata = (char *)OPENSSL_malloc(inlen);
if (!msi_file_read(msi, child->entry, 0, indata, inlen)) { if (!msi_file_read(msi, child->entry, 0, indata, inlen, verbose)) {
printf("Failed to read stream data\n"); if (verbose) printf("Failed to read stream data\n");
OPENSSL_free(indata); OPENSSL_free(indata);
goto out; goto out;
} }
@ -634,7 +635,7 @@ int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root)
OPENSSL_free(indata); OPENSSL_free(indata);
} }
if (child->type == DIR_STORAGE) { if (child->type == DIR_STORAGE) {
if (!msi_hash_dir(msi, child, hash, 0)) { if (!msi_hash_dir(msi, child, hash, 0, verbose)) {
printf("Failed to hash a MSI storage\n"); printf("Failed to hash a MSI storage\n");
goto out; goto out;
} }
@ -804,7 +805,7 @@ static int stream_read(MSI_FILE *msi, MSI_ENTRY *entry, u_char *p_msi, int len_m
*indata = (char *)p_msiex; *indata = (char *)p_msiex;
inlen = len_msiex; inlen = len_msiex;
} else { } else {
if (!msi_file_read(msi, entry, 0, *indata, inlen)) { if (!msi_file_read(msi, entry, 0, *indata, inlen, 1)) {
printf("Failed to read stream data\n"); printf("Failed to read stream data\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }

10
msi.h
View File

@ -199,16 +199,16 @@ static const u_char digital_signature_ex[] = {
0x45, 0x00, 0x78, 0x00, 0x00, 0x00 0x45, 0x00, 0x78, 0x00, 0x00, 0x00
}; };
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len); int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len, int verbose);
MSI_FILE *msi_file_new(char *buffer, uint32_t len); MSI_FILE *msi_file_new(char *buffer, uint32_t len, int verbose);
void msi_file_free(MSI_FILE *msi); void msi_file_free(MSI_FILE *msi);
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi); MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi, int verbose);
int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret); int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret, int verbose);
MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse); MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
void msi_dirent_free(MSI_DIRENT *dirent); void msi_dirent_free(MSI_DIRENT *dirent);
MSI_FILE_HDR *msi_header_get(MSI_FILE *msi); MSI_FILE_HDR *msi_header_get(MSI_FILE *msi);
int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root); int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root);
int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root); int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root, int verbose);
int msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, uint32_t fileend); int msi_calc_digest(char *indata, const EVP_MD *md, u_char *mdbuf, uint32_t fileend);
int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen); int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p, int len, u_char *p_msiex, int len_msiex, BIO *outdata); int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p, int len, u_char *p_msiex, int len_msiex, BIO *outdata);

View File

@ -2903,23 +2903,23 @@ static int verify_signature(SIGNATURE *signature, GLOBAL_OPTIONS *options)
* https://msdn.microsoft.com/en-us/library/dd942138.aspx * https://msdn.microsoft.com/en-us/library/dd942138.aspx
*/ */
static int msi_verify_header(char *indata, uint32_t filesize, MSI_PARAMS *msiparams) static int msi_verify_header(char *indata, uint32_t filesize, MSI_PARAMS *msiparams, int verbose)
{ {
int ret = 1; int ret = 1;
MSI_ENTRY *root; MSI_ENTRY *root;
MSI_FILE_HDR *hdr; MSI_FILE_HDR *hdr;
MSI_DIRENT *root_dir = NULL; MSI_DIRENT *root_dir = NULL;
msiparams->msi = msi_file_new(indata, filesize); msiparams->msi = msi_file_new(indata, filesize, verbose);
if (!msiparams->msi) { if (!msiparams->msi) {
return 0; /* FAILED */ return 0; /* FAILED */
} }
root = msi_root_entry_get(msiparams->msi); root = msi_root_entry_get(msiparams->msi, verbose);
if (!root) { if (!root) {
printf("Failed to get file entry\n"); printf("Failed to get file entry\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!msi_dirent_new(msiparams->msi, root, NULL, &root_dir)) { if (!msi_dirent_new(msiparams->msi, root, NULL, &root_dir, verbose)) {
printf("Failed to parse MSI_DIRENT struct\n"); printf("Failed to parse MSI_DIRENT struct\n");
OPENSSL_free(root); OPENSSL_free(root);
return 0; /* FAILED */ return 0; /* FAILED */
@ -3039,7 +3039,7 @@ static int msi_verify_pkcs7(SIGNATURE *signature, MSI_FILE *msi, MSI_DIRENT *dir
printf("Calculated MsiDigitalSignatureEx : %s\n", hexbuf); printf("Calculated MsiDigitalSignatureEx : %s\n", hexbuf);
} }
if (!msi_hash_dir(msi, dirent, hash, 1)) { if (!msi_hash_dir(msi, dirent, hash, 1, options->verbose)) {
printf("Failed to calculate DigitalSignature\n\n"); printf("Failed to calculate DigitalSignature\n\n");
BIO_free_all(hash); BIO_free_all(hash);
goto out; goto out;
@ -3081,7 +3081,7 @@ static int msi_verify_file(MSI_PARAMS *msiparams, GLOBAL_OPTIONS *options)
} }
inlen = GET_UINT32_LE(ds->size); inlen = GET_UINT32_LE(ds->size);
indata = OPENSSL_malloc(inlen); indata = OPENSSL_malloc(inlen);
if (!msi_file_read(msiparams->msi, ds, 0, indata, inlen)) { if (!msi_file_read(msiparams->msi, ds, 0, indata, inlen, options->verbose)) {
printf("DigitalSignature stream data error\n\n"); printf("DigitalSignature stream data error\n\n");
goto out; goto out;
} }
@ -3090,7 +3090,7 @@ static int msi_verify_file(MSI_PARAMS *msiparams, GLOBAL_OPTIONS *options)
} else { } else {
exlen = GET_UINT32_LE(dse->size); exlen = GET_UINT32_LE(dse->size);
exdata = OPENSSL_malloc(exlen); exdata = OPENSSL_malloc(exlen);
if (!msi_file_read(msiparams->msi, dse, 0, exdata, exlen)) { if (!msi_file_read(msiparams->msi, dse, 0, exdata, exlen, options->verbose)) {
printf("MsiDigitalSignatureEx stream data error\n\n"); printf("MsiDigitalSignatureEx stream data error\n\n");
goto out; goto out;
} }
@ -3119,12 +3119,12 @@ out:
return ret; return ret;
} }
static PKCS7 *msi_extract_existing_pkcs7(MSI_PARAMS *msiparams, MSI_ENTRY *ds, char **data, uint32_t len) static PKCS7 *msi_extract_existing_pkcs7(MSI_PARAMS *msiparams, MSI_ENTRY *ds, char **data, uint32_t len, int verbose)
{ {
PKCS7 *p7 = NULL; PKCS7 *p7 = NULL;
const u_char *blob; const u_char *blob;
if (!msi_file_read(msiparams->msi, ds, 0, *data, len)) { if (!msi_file_read(msiparams->msi, ds, 0, *data, len, verbose)) {
printf("DigitalSignature stream data error\n"); printf("DigitalSignature stream data error\n");
return NULL; return NULL;
} }
@ -3137,7 +3137,7 @@ static PKCS7 *msi_extract_existing_pkcs7(MSI_PARAMS *msiparams, MSI_ENTRY *ds, c
return p7; return p7;
} }
static int msi_extract_file(MSI_PARAMS *msiparams, BIO *outdata, int output_pkcs7) static int msi_extract_file(MSI_PARAMS *msiparams, BIO *outdata, GLOBAL_OPTIONS *options)
{ {
int ret; int ret;
PKCS7 *sig; PKCS7 *sig;
@ -3152,12 +3152,12 @@ static int msi_extract_file(MSI_PARAMS *msiparams, BIO *outdata, int output_pkcs
len = GET_UINT32_LE(ds->size); len = GET_UINT32_LE(ds->size);
data = OPENSSL_malloc(len); data = OPENSSL_malloc(len);
(void)BIO_reset(outdata); (void)BIO_reset(outdata);
sig = msi_extract_existing_pkcs7(msiparams, ds, &data, len); sig = msi_extract_existing_pkcs7(msiparams, ds, &data, len, options->verbose);
if (!sig) { if (!sig) {
printf("Unable to extract existing signature\n"); printf("Unable to extract existing signature\n");
return 1; /* FAILED */ return 1; /* FAILED */
} }
if (output_pkcs7) { if (options->output_pkcs7) {
ret = !PEM_write_bio_PKCS7(outdata, sig); ret = !PEM_write_bio_PKCS7(outdata, sig);
} else { } else {
ret = !BIO_write(outdata, data, len); ret = !BIO_write(outdata, data, len);
@ -4773,7 +4773,7 @@ static int input_validation(file_type_t type, GLOBAL_OPTIONS *options, FILE_HEAD
printf("Warning: -ph option is only valid for PE files\n"); printf("Warning: -ph option is only valid for PE files\n");
if (options->jp >= 0) if (options->jp >= 0)
printf("Warning: -jp option is only valid for CAB files\n"); printf("Warning: -jp option is only valid for CAB files\n");
if (!msi_verify_header(indata, filesize, msiparams)) { if (!msi_verify_header(indata, filesize, msiparams, options->verbose)) {
printf("Corrupt MSI file: %s\n", options->infile); printf("Corrupt MSI file: %s\n", options->infile);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -4836,7 +4836,7 @@ static int check_attached_data(file_type_t type, FILE_HEADER *header, GLOBAL_OPT
printf("Error verifying result\n"); printf("Error verifying result\n");
return 1; /* FAILED */ return 1; /* FAILED */
} }
if (!msi_verify_header(outdata, filesize, msiparams)) { if (!msi_verify_header(outdata, filesize, msiparams, options->verbose)) {
printf("Corrupt MSI file: %s\n", options->outfile); printf("Corrupt MSI file: %s\n", options->outfile);
return 1; /* FAILED */ return 1; /* FAILED */
} }
@ -5466,7 +5466,7 @@ static PKCS7 *msi_presign_file(file_type_t type, cmd_type_t cmd, FILE_HEADER *he
printf("Unable to calc MsiDigitalSignatureEx\n"); printf("Unable to calc MsiDigitalSignatureEx\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!msi_hash_dir(msiparams->msi, msiparams->dirent, hash, 1)) { if (!msi_hash_dir(msiparams->msi, msiparams->dirent, hash, 1, options->verbose)) {
printf("Unable to msi_handle_dir()\n"); printf("Unable to msi_handle_dir()\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -5485,7 +5485,7 @@ static PKCS7 *msi_presign_file(file_type_t type, cmd_type_t cmd, FILE_HEADER *he
} }
len = GET_UINT32_LE(ds->size); len = GET_UINT32_LE(ds->size);
data = OPENSSL_malloc(len); data = OPENSSL_malloc(len);
*cursig = msi_extract_existing_pkcs7(msiparams, ds, &data, len); *cursig = msi_extract_existing_pkcs7(msiparams, ds, &data, len, options->verbose);
OPENSSL_free(data); OPENSSL_free(data);
if (!*cursig) { if (!*cursig) {
printf("Unable to extract existing signature\n"); printf("Unable to extract existing signature\n");
@ -6042,7 +6042,7 @@ int main(int argc, char **argv)
if (type == FILE_TYPE_MSI) { if (type == FILE_TYPE_MSI) {
if (cmd == CMD_EXTRACT) { if (cmd == CMD_EXTRACT) {
ret = msi_extract_file(&msiparams, outdata, options.output_pkcs7); ret = msi_extract_file(&msiparams, outdata, &options);
goto skip_signing; goto skip_signing;
} else if (cmd == CMD_VERIFY) { } else if (cmd == CMD_VERIFY) {
ret = msi_verify_file(&msiparams, &options); ret = msi_verify_file(&msiparams, &options);