src/file_lnk.c: fix parser
This commit is contained in:
parent
2346e44dfd
commit
29dfb071f5
1 changed files with 85 additions and 87 deletions
172
src/file_lnk.c
172
src/file_lnk.c
|
@ -36,8 +36,8 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*@ requires \valid(file_stat); */
|
||||||
static void register_header_check_lnk(file_stat_t *file_stat);
|
static void register_header_check_lnk(file_stat_t *file_stat);
|
||||||
static int header_check_lnk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new);
|
|
||||||
|
|
||||||
const file_hint_t file_hint_lnk= {
|
const file_hint_t file_hint_lnk= {
|
||||||
.extension="lnk",
|
.extension="lnk",
|
||||||
|
@ -67,28 +67,34 @@ struct lnk_header_s {
|
||||||
} __attribute__ ((gcc_struct, __packed__));
|
} __attribute__ ((gcc_struct, __packed__));
|
||||||
|
|
||||||
/* These constants comes from winedump/lnk.c */
|
/* These constants comes from winedump/lnk.c */
|
||||||
#define SCF_PIDL 1
|
#define SLDF_HAS_ID_LIST 1
|
||||||
#define SCF_LOCATION 2
|
#define SLDF_HAS_LINK_INFO 2
|
||||||
#define SCF_DESCRIPTION 4
|
#define SLDF_HAS_NAME 4
|
||||||
#define SCF_RELATIVE 8
|
#define SLDF_HAS_RELPATH 8
|
||||||
#define SCF_WORKDIR 0x10
|
#define SLDF_HAS_WORKINGDIR 0x10
|
||||||
#define SCF_ARGS 0x20
|
#define SLDF_HAS_ARGS 0x20
|
||||||
#define SCF_CUSTOMICON 0x40
|
#define SLDF_HAS_ICONLOCATION 0x40
|
||||||
#define SCF_UNICODE 0x80
|
#define SLDF_UNICODE 0x80
|
||||||
#define SCF_PRODUCT 0x800
|
#define SLDF_HAS_LOGO3ID 0x800
|
||||||
#define SCF_COMPONENT 0x1000
|
#define SLDF_HAS_DARWINID 0x1000
|
||||||
/* */
|
|
||||||
|
|
||||||
|
/*@
|
||||||
|
@ requires buffer_size > 0x4c;
|
||||||
|
@ requires \valid_read(buffer + (0 .. buffer_size-1));
|
||||||
|
@ assigns \nothing;
|
||||||
|
@*/
|
||||||
static unsigned int lnk_get_size(const unsigned char *buffer, const unsigned int buffer_size)
|
static unsigned int lnk_get_size(const unsigned char *buffer, const unsigned int buffer_size)
|
||||||
{
|
{
|
||||||
const struct lnk_header_s* lnk_head=(const struct lnk_header_s*)buffer;
|
const struct lnk_header_s* lnk_head=(const struct lnk_header_s*)buffer;
|
||||||
const uint32_t flags=le32(lnk_head->flags);
|
const uint32_t flags=le32(lnk_head->flags);
|
||||||
unsigned int i=0x4c; /* .LNK File Header */
|
unsigned int i=0x4c; /* .LNK File Header */
|
||||||
unsigned int len;
|
/* avoid out of bound read access */
|
||||||
if((flags&SCF_PIDL)!=0)
|
if(i >= buffer_size - 4)
|
||||||
|
return 0;
|
||||||
|
if((flags&SLDF_HAS_ID_LIST)!=0)
|
||||||
{ /* The Shell Item Id List */
|
{ /* The Shell Item Id List */
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
||||||
len=le16(*ptr);
|
const unsigned int len=le16(*ptr);
|
||||||
#ifdef DEBUG_LNK
|
#ifdef DEBUG_LNK
|
||||||
log_debug("LNK Shell Item Id List at 0x%04x=%04x\n",
|
log_debug("LNK Shell Item Id List at 0x%04x=%04x\n",
|
||||||
i, len);
|
i, len);
|
||||||
|
@ -99,142 +105,134 @@ static unsigned int lnk_get_size(const unsigned char *buffer, const unsigned int
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 4)
|
if(i >= buffer_size - 4)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_LOCATION)!=0)
|
if((flags&SLDF_HAS_LINK_INFO)!=0)
|
||||||
{ /* File location info */
|
{ /* File location info */
|
||||||
const uint32_t *ptr=(const uint32_t *)&buffer[i];
|
const uint32_t *ptr=(const uint32_t *)&buffer[i];
|
||||||
len=le32(*ptr);
|
const unsigned int len=le32(*ptr);
|
||||||
#ifdef DEBUG_LNK
|
#ifdef DEBUG_LNK
|
||||||
log_debug("LNK File location info at 0x%04x=%04x\n", i, len);
|
log_debug("LNK File location info at 0x%04x %u bytes\n", i, len);
|
||||||
#endif
|
#endif
|
||||||
/* Discard too big files, avoid overflow */
|
/* Discard too big files, avoid overflow */
|
||||||
if(len >= 0x10000000)
|
if(len >= 0x10000000)
|
||||||
return 0;
|
return 0;
|
||||||
i+=2;
|
|
||||||
i+=len;
|
i+=len;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 2)
|
if(i >= buffer_size - 2)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_DESCRIPTION)!=0)
|
if((flags&SLDF_HAS_NAME)!=0)
|
||||||
{ /* Description string */
|
{ /* Description string */
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
||||||
len=le16(*ptr);
|
unsigned int len=le16(*ptr);
|
||||||
#ifdef DEBUG_LNK
|
if((flags& SLDF_UNICODE)!=0)
|
||||||
log_debug("LNK description string at 0x%04x=%04x\n", i, len);
|
|
||||||
#endif
|
|
||||||
i+=2;
|
|
||||||
if((flags& SCF_UNICODE)!=0)
|
|
||||||
len*=2;
|
len*=2;
|
||||||
|
i+=2;
|
||||||
|
#ifdef DEBUG_LNK
|
||||||
|
log_debug("LNK description string at 0x%04x %u bytes\n", i, len);
|
||||||
|
#endif
|
||||||
i+=len;
|
i+=len;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 2)
|
if(i >= buffer_size - 2)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_RELATIVE)!=0)
|
if((flags&SLDF_HAS_RELPATH)!=0)
|
||||||
{ /* Relative path */
|
{ /* Relative path */
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
||||||
len=le16(*ptr);
|
unsigned int len=le16(*ptr);
|
||||||
|
if((flags& SLDF_UNICODE)!=0)
|
||||||
|
len*=2;
|
||||||
|
i+=2;
|
||||||
#ifdef DEBUG_LNK
|
#ifdef DEBUG_LNK
|
||||||
log_debug("LNK relative path at 0x%04x=%04x\n", i, len);
|
log_debug("LNK relative path at 0x%04x=%04x\n", i, len);
|
||||||
#endif
|
#endif
|
||||||
i+=2;
|
|
||||||
if((flags& SCF_UNICODE)!=0)
|
|
||||||
len*=2;
|
|
||||||
i+=len;
|
i+=len;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 2)
|
if(i >= buffer_size - 2)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_WORKDIR)!=0)
|
if((flags&SLDF_HAS_WORKINGDIR)!=0)
|
||||||
{ /* Working directory */
|
{ /* Working directory */
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
||||||
len=le16(*ptr);
|
unsigned int len=le16(*ptr);
|
||||||
#ifdef DEBUG_LNK
|
if((flags& SLDF_UNICODE)!=0)
|
||||||
log_debug("LNK Working directory at 0x%04x=%04x\n", i, len);
|
|
||||||
#endif
|
|
||||||
i+=2;
|
|
||||||
if((flags& SCF_UNICODE)!=0)
|
|
||||||
len*=2;
|
len*=2;
|
||||||
|
i+=2;
|
||||||
|
#ifdef DEBUG_LNK
|
||||||
|
log_debug("LNK Working directory at 0x%04x %u bytes\n", i, len);
|
||||||
|
#endif
|
||||||
i+=len;
|
i+=len;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 2)
|
if(i >= buffer_size - 2)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_ARGS)!=0)
|
if((flags&SLDF_HAS_ARGS)!=0)
|
||||||
{ /* Command line string */
|
{ /* Command line string */
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
||||||
len=le16(*ptr);
|
unsigned int len=le16(*ptr);
|
||||||
#ifdef DEBUG_LNK
|
if((flags& SLDF_UNICODE)!=0)
|
||||||
log_debug("LNK Command line string at 0x%04x=%04x\n", i, len);
|
|
||||||
#endif
|
|
||||||
i+=2;
|
|
||||||
if((flags& SCF_UNICODE)!=0)
|
|
||||||
len*=2;
|
len*=2;
|
||||||
|
i+=2;
|
||||||
|
#ifdef DEBUG_LNK
|
||||||
|
log_debug("LNK Command line string at 0x%04x %u bytes\n", i, len);
|
||||||
|
#endif
|
||||||
i+=len;
|
i+=len;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 2)
|
if(i >= buffer_size - 2)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_CUSTOMICON)!=0)
|
if((flags&SLDF_HAS_ICONLOCATION)!=0)
|
||||||
{ /* Icon filename string */
|
{ /* Icon filename string */
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
||||||
len=le16(*ptr);
|
unsigned int len=le16(*ptr);
|
||||||
|
if((flags& SLDF_UNICODE)!=0)
|
||||||
|
len*=2;
|
||||||
|
i+=2;
|
||||||
#ifdef DEBUG_LNK
|
#ifdef DEBUG_LNK
|
||||||
log_debug("LNK Icon filename string at 0x%04x=%04x\n", i, len);
|
log_debug("LNK Icon filename string at 0x%04x=%04x\n", i, len);
|
||||||
#endif
|
#endif
|
||||||
i+=2;
|
|
||||||
if((flags& SCF_UNICODE)!=0)
|
|
||||||
len*=2;
|
|
||||||
i+=len;
|
i+=len;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
/* avoid out of bound read access */
|
||||||
if(i >= buffer_size - 2)
|
if(i >= buffer_size - 2)
|
||||||
return 0;
|
return 0;
|
||||||
if((flags&SCF_PRODUCT)!=0)
|
/*@
|
||||||
|
@ loop invariant i < buffer_size-2;
|
||||||
|
@ loop assigns i;
|
||||||
|
@*/
|
||||||
|
while(1)
|
||||||
{
|
{
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
/* avoid out of bound read access */
|
||||||
|
const uint16_t *ptr;
|
||||||
|
unsigned int len;
|
||||||
|
ptr=(const uint16_t *)&buffer[i];
|
||||||
|
/*@ assert \valid_read(ptr); */
|
||||||
len=le16(*ptr);
|
len=le16(*ptr);
|
||||||
#ifdef DEBUG_LNK
|
#ifdef DEBUG_LNK
|
||||||
log_debug("LNK Icon product at 0x%04x=%04x\n", i, len);
|
log_debug("LNK 0x%04x - %u bytes\n", i, len);
|
||||||
#endif
|
#endif
|
||||||
|
if(len == 0)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_LNK
|
||||||
|
log_debug("LNK size %u (0x%04x)\n", i, i);
|
||||||
|
#endif
|
||||||
|
return i;
|
||||||
|
}
|
||||||
i+=2;
|
i+=2;
|
||||||
i+=len;
|
if(i >= buffer_size - 2)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
/* avoid out of bound read access */
|
|
||||||
if(i >= buffer_size - 2)
|
|
||||||
return 0;
|
|
||||||
if((flags&SCF_COMPONENT)!=0)
|
|
||||||
{
|
|
||||||
const uint16_t *ptr=(const uint16_t *)&buffer[i];
|
|
||||||
len=le16(*ptr);
|
|
||||||
#ifdef DEBUG_LNK
|
|
||||||
log_debug("LNK Icon component at 0x%04x=%04x\n", i, len);
|
|
||||||
#endif
|
|
||||||
i+=2;
|
|
||||||
i+=len;
|
|
||||||
}
|
|
||||||
/* avoid out of bound read access */
|
|
||||||
if(i >= buffer_size - 4)
|
|
||||||
return 0;
|
|
||||||
/* Extra stuff */
|
|
||||||
{
|
|
||||||
const uint32_t *ptr=(const uint32_t *)&buffer[i];
|
|
||||||
len=le32(*ptr);
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_LNK
|
|
||||||
log_debug("LNK extra stuff at 0x%04x=%04x\n", i, len);
|
|
||||||
#endif
|
|
||||||
/* Discard too big files */
|
|
||||||
if(len >= 0x10000000)
|
|
||||||
return 0;
|
|
||||||
i+=4;
|
|
||||||
i+=len;
|
|
||||||
#ifdef DEBUG_LNK
|
|
||||||
log_debug("LNK size %u (0x%04x)\n", i, i);
|
|
||||||
#endif
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*@
|
||||||
|
@ requires buffer_size >= 10;
|
||||||
|
@ requires \valid_read(buffer+(0..buffer_size-1));
|
||||||
|
@ requires valid_file_recovery(file_recovery);
|
||||||
|
@ requires \valid(file_recovery_new);
|
||||||
|
@ requires file_recovery_new->blocksize > 0;
|
||||||
|
@ requires separation: \separated(&file_hint_lnk, buffer+(..), file_recovery, file_recovery_new);
|
||||||
|
@ assigns *file_recovery_new;
|
||||||
|
@ ensures \result!=0 ==> valid_file_recovery(file_recovery_new);
|
||||||
|
@*/
|
||||||
static int header_check_lnk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
|
static int header_check_lnk(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
|
||||||
{
|
{
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
Loading…
Reference in a new issue