doc/ppt: moved information stream parsing from vba source to ole2 source

pull/6/head
Kevin Lin 11 years ago
parent 09dddc5be3
commit 4c37996842
  1. 948
      libclamav/ole2_extract.c
  2. 21
      libclamav/ole2_extract.h
  3. 4
      libclamav/scanners.c
  4. 991
      libclamav/vba_extract.c
  5. 3
      libclamav/vba_extract.h

@ -127,6 +127,20 @@ typedef struct property_tag {
unsigned char reserved[4];
} property_t;
struct ole2_list_node;
typedef struct ole2_list_node
{
uint32_t Val;
struct ole2_list_node *Next;
} ole2_list_node_t;
typedef struct ole2_list
{
uint32_t Size;
ole2_list_node_t *Head;
} ole2_list_t;
int
ole2_list_init(ole2_list_t * list)
{
@ -1188,3 +1202,937 @@ abort:
return ret == CL_BREAK ? CL_CLEAN : ret;
}
/* Summary and Document Information Parsing to JSON */
#ifdef HAVE_JSON
#define cli_jsonnull(o,n) \
{ \
json_object *fpobj = json_object_new_string("null"); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json string object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#define cli_jsonstr(o,n,s) \
{ \
json_object *fpobj = json_object_new_string(s); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json string object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#define cli_jsonint(o,n,i) \
{ \
json_object *fpobj = json_object_new_int(i); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
/*
#define cli_jsonint64(o,n,i) \
{ \
json_object *fpobj = json_object_new_int64(i); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
*/
#define cli_jsonint64(o,n,i) cli_dbgmsg("%s: %lld [%llx]\n", n, i, i)
#define cli_jsonbool(o,n,b) \
{ \
json_object *fpobj = json_object_new_boolean(b); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#define cli_jsondouble(o,n,d) \
{ \
json_object *fpobj = json_object_new_double(d); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#else
#define cli_jsonnull(o,n) cli_dbgmsg("%s: null\n", n)
#define cli_jsonstr(o,n,s) cli_dbgmsg("%s: \"%s\"\n", n, s)
#define cli_jsonint(o,n,i) cli_dbgmsg("%s: %d [%x]\n", n, i, i)
#define cli_jsonint64(o,n,i) cli_dbgmsg("%s: %lld [%llx]\n", n, i, i)
#define cli_jsonbool(o,n,b) cli_dbgmsg("%s: %s\n", n, b ? "true":"false")
#define cli_jsondouble(o,n,d) cli_dbgmsg("%s: %f\n", n, d)
#endif
#define WINUNICODE 0x04B0
#define PROPCNTLIMIT 25
#define PROPSTRLIMIT 100
#define sum16_endian_convert(v) le16_to_host((uint16_t)(v))
#define sum32_endian_convert(v) le32_to_host((uint32_t)(v))
#define sum64_endian_convert(v) le64_to_host((uint32_t)(v))
enum summary_pidsi {
SPID_CODEPAGE = 0x00000001,
SPID_TITLE = 0x00000002,
SPID_SUBJECT = 0x00000003,
SPID_AUTHOR = 0x00000004,
SPID_KEYWORDS = 0x00000005,
SPID_COMMENTS = 0x00000006,
SPID_TEMPLATE = 0x00000007,
SPID_LASTAUTHOR = 0x00000008,
SPID_REVNUMBER = 0x00000009,
SPID_EDITTIME = 0x0000000A,
SPID_LASTPRINTED = 0x0000000B,
SPID_CREATEDTIME = 0x0000000C,
SPID_MODIFIEDTIME = 0x0000000D,
SPID_PAGECOUNT = 0x0000000E,
SPID_WORDCOUNT = 0x0000000F,
SPID_CHARCOUNT = 0x00000010,
SPID_THUMBNAIL = 0x00000011,
SPID_APPNAME = 0x00000012,
SPID_SECURITY = 0x00000013
};
enum docsum_pidsi {
DSPID_CODEPAGE = 0x00000001,
DSPID_CATEGORY = 0x00000002,
DSPID_PRESFORMAT = 0x00000003,
DSPID_BYTECOUNT = 0x00000004,
DSPID_LINECOUNT = 0x00000005,
DSPID_PARCOUNT = 0x00000006,
DSPID_SLIDECOUNT = 0x00000007,
DSPID_NOTECOUNT = 0x00000008,
DSPID_HIDDENCOUNT = 0x00000009,
DSPID_MMCLIPCOUNT = 0x0000000A,
DSPID_SCALE = 0x0000000B,
DSPID_HEADINGPAIR = 0x0000000C, /* VT_VARIANT | VT_VECTOR */
DSPID_DOCPARTS = 0x0000000D, /* VT_VECTOR | VT_LPSTR */
DSPID_MANAGER = 0x0000000E,
DSPID_COMPANY = 0x0000000F,
DSPID_LINKSDIRTY = 0x00000010,
DSPID_CCHWITHSPACES = 0x00000011,
DSPID_SHAREDDOC = 0x00000013, /* must be false */
DSPID_LINKBASE = 0x00000014, /* moved to user-defined */
DSPID_HLINKS = 0x00000015, /* moved to user-defined */
DSPID_HYPERLINKSCHANGED = 0x00000016,
DSPID_VERSION = 0x00000017,
DSPID_DIGSIG = 0x00000018,
DSPID_CONTENTTYPE = 0x0000001A,
DSPID_CONTENTSTATUS = 0x0000001B,
DSPID_LANGUAGE = 0x0000001C,
DSPID_DOCVERSION = 0x0000001D
};
enum property_type {
PT_EMPTY = 0x0000,
PT_NULL = 0x0001,
PT_INT16 = 0x0002,
PT_INT32 = 0x0003,
PT_FLOAT32 = 0x0004,
PT_DOUBLE64 = 0x0005,
PT_DATE = 0x0007,
PT_BSTR = 0x0008,
PT_BOOL = 0x000B,
PT_INT8v1 = 0x0010,
PT_UINT8 = 0x0011,
PT_UINT16 = 0x0012,
PT_UINT32 = 0x0013,
PT_INT64 = 0x0014,
PT_UINT64 = 0x0015,
PT_INT32v1 = 0x0016,
PT_UINT32v1 = 0x0017,
PT_LPSTR = 0x001E,
PT_LPWSTR = 0x001F,
PT_FILETIME = 0x0040,
/* More Types not currently handled */
};
typedef struct summary_stub {
uint16_t byte_order;
uint16_t version;
uint32_t system; /* implementation-specific */
uint8_t CLSID[16];
uint32_t num_propsets; /* 1 or 2 */
} summary_stub_t;
typedef struct propset_summary_entry {
uint8_t FMTID[16];
uint32_t offset;
} propset_entry_t;
typedef struct summary_ctx {
cli_ctx *ctx;
#ifdef HAVE_JSON
json_object *summary;
#else
char *summary;
#endif
uint16_t byte_order;
uint16_t version;
int16_t codepage;
const char *propname;
int writecp; /* used to trigger writing the codepage value */
} summary_ctx_t;
static int
ole2_process_property(summary_ctx_t *sctx, unsigned char *databuf, size_t buflen, uint32_t offset)
{
uint16_t proptype, padding;
if (offset+4 > buflen) {
return CL_EFORMAT;
}
memcpy(&proptype, databuf+offset, sizeof(proptype));
offset+=sizeof(proptype);
memcpy(&padding, databuf+offset, sizeof(padding));
offset+=sizeof(padding);
/* endian conversion */
proptype = sum16_endian_convert(proptype);
//cli_dbgmsg("proptype: 0x%04x\n", proptype);
if (padding != 0) {
return CL_EFORMAT;
}
switch (proptype) {
case PT_EMPTY:
cli_jsonnull(sctx->summary, sctx->propname);
break;
case PT_NULL:
cli_jsonnull(sctx->summary, sctx->propname);
break;
case PT_INT16:
{
int16_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum16_endian_convert(dout);
if (sctx->writecp) sctx->codepage = dout;
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_INT32:
case PT_INT32v1:
{
int32_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum32_endian_convert(dout);
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_FLOAT32: /* review this please */
{
float dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* TODO - endian conversion */
cli_jsondouble(sctx->summary, sctx->propname, dout);
break;
}
case PT_DATE:
case PT_DOUBLE64: /* review this please */
{
double dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* TODO - endian conversion */
cli_jsondouble(sctx->summary, sctx->propname, dout);
break;
}
case PT_BOOL:
{
uint16_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* no need for endian conversion */
cli_jsonbool(sctx->summary, sctx->propname, dout);
break;
}
case PT_INT8v1:
{
int8_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* no need for endian conversion */
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT8:
{
uint8_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* no need for endian conversion */
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT16:
{
uint16_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum16_endian_convert(dout);
if (sctx->writecp) sctx->codepage = dout;
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT32:
case PT_UINT32v1:
{
uint32_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum32_endian_convert(dout);
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_INT64:
{
int64_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum64_endian_convert(dout);
cli_jsonint64(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT64:
{
uint64_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum64_endian_convert(dout);
cli_jsonint64(sctx->summary, sctx->propname, dout);
break;
}
case PT_BSTR:
case PT_LPSTR:
if (sctx->codepage == 0) {
cli_dbgmsg("ole2_propset_json: current codepage is unknown, cannot parse char stream\n");
break;
}
else if (sctx->codepage != WINUNICODE) {
uint32_t strsize;
char *outstr;
if (offset+sizeof(strsize) > buflen) {
return CL_EFORMAT;
}
memcpy(&strsize, databuf+offset, sizeof(strsize));
offset+=sizeof(strsize);
/* no need for endian conversion */
if (offset+strsize > buflen) {
return CL_EFORMAT;
}
/* limitation on string length */
if (strsize > PROPSTRLIMIT) {
cli_dbgmsg("ole2_process_property: property string sized %lu truncated to size %lu\n",
(unsigned long)strsize, (unsigned long)PROPSTRLIMIT);
strsize = PROPSTRLIMIT;
}
outstr = cli_malloc(strsize+1);
if (!outstr) {
return CL_EMEM;
}
strncpy(outstr, databuf+offset, strsize);
outstr[strsize] = '\0'; /* guarentee a NULL-termination */
cli_jsonstr(sctx->summary, sctx->propname, outstr);
free(outstr);
break;
}
/* fall-through for unicode strings */
case PT_LPWSTR:
{
uint32_t strsize;
char *outstr, *outstr2;
if (offset+sizeof(strsize) > buflen) {
return CL_EFORMAT;
}
memcpy(&strsize, databuf+offset, sizeof(strsize));
offset+=sizeof(strsize);
/* no need for endian conversion */
if (proptype == PT_LPSTR) { /* fall-through specifics */
if (strsize % 2) {
return CL_EFORMAT;
}
}
else {
strsize*=2; /* Unicode strings are by length, not size */
}
if (offset+strsize > buflen) {
return CL_EFORMAT;
}
outstr = cli_malloc(strsize+2);
if (!outstr) {
return CL_EMEM;
}
strncpy(outstr, databuf+offset, strsize);
outstr[strsize-1] = '\0'; /* guarentee a UTF-16 NULL-termination */
outstr[strsize] = '\0';
outstr2 = (char*)get_property_name2(outstr, strsize);
cli_jsonstr(sctx->summary, sctx->propname, outstr);
free(outstr);
free(outstr2);
break;
}
case PT_FILETIME:
{
uint32_t ltime, htime;
#ifdef HAVE_JSON
#else
uint64_t wtime = 0, utime =0;
#endif
if (offset+sizeof(ltime)+sizeof(htime) > buflen) {
return CL_EFORMAT;
}
memcpy(&ltime, databuf+offset, sizeof(ltime));
offset+=sizeof(ltime);
memcpy(&htime, databuf+offset, sizeof(htime));
offset+=sizeof(ltime);
ltime = sum32_endian_convert(ltime);
htime = sum32_endian_convert(htime);
#ifdef HAVE_JSON
/* Raw Output */
{
json_object *fpobj0, *fpobj1;
json_object *fparr = json_object_new_array();
if (NULL == fparr) {
cli_errmsg("ole2_process_property: no memory for json array object.\n");
return CL_EMEM;
}
fpobj0 = json_object_new_int(ltime);
if (NULL == fpobj0) {
cli_errmsg("ole2_process_property: no memory for json int object.\n");
return CL_EMEM;
}
fpobj1 = json_object_new_int(htime);
if (NULL == fpobj1) {
cli_errmsg("ole2_process_property: no memory for json int object.\n");
return CL_EMEM;
}
json_object_array_add(fparr, fpobj0);
json_object_array_add(fparr, fpobj1);
json_object_object_add(sctx->summary, sctx->propname, fparr);
}
#else
/* human-readable formatting */
wtime = htime;
wtime <<= 32;
wtime |= ltime;
utime = wtime / 10000000;
utime -= 11644473600LL;
cli_jsonstr(sctx->summary, sctx->propname, ctime((timer_t*)&utime));
#endif
break;
}
default:
cli_dbgmsg("ole2_process_property: unhandled property type 0x%04x for %s property\n",
proptype, sctx->propname);
}
return CL_SUCCESS;
}
static int
ole2_docsum_propset_json(summary_ctx_t *sctx, fmap_t *sumfmap, propset_entry_t *entry)
{
uint32_t size, numprops, limitprops;
uint32_t propid, poffset;
unsigned char *databuf, *ptr = NULL;
unsigned i;
int ret;
sctx->codepage = 0;
sctx->writecp = 0;
sctx->propname = NULL;
/* examine property set metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, 8);
if (!databuf) {
return CL_EREAD;
}
memcpy(&size, databuf, sizeof(size));
memcpy(&numprops, databuf+sizeof(size), sizeof(numprops));
/* endian conversion */
size = sum32_endian_convert(size);
numprops = sum32_endian_convert(numprops);
cli_dbgmsg("ole2_docsum_propset_json: size: %u, numprops: %u\n", size, numprops);
/* extract the property packet and advance past metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, size);
if (!databuf) {
return CL_EREAD;
}
ptr = databuf+sizeof(size)+sizeof(numprops);
if (numprops > PROPCNTLIMIT) {
limitprops = PROPCNTLIMIT;
}
else {
limitprops = numprops;
}
cli_dbgmsg("ole2_docsum_propset_json: processing %u of %u (%u max) propeties\n",
limitprops, numprops, PROPCNTLIMIT);
for (i = 0; i < limitprops; ++i) {
memcpy(&propid, ptr, sizeof(propid));
ptr+=4;
memcpy(&poffset, ptr, sizeof(poffset));
ptr+=4;
/* endian conversion */
propid = sum32_endian_convert(propid);
poffset = sum32_endian_convert(poffset);
cli_dbgmsg("ole2_docsum_propset_json: propid: 0x%08x, poffset: %u\n", propid, poffset);
sctx->propname = NULL; sctx->writecp = 0;
switch(propid) {
case DSPID_CODEPAGE:
sctx->writecp = 1; /* must be set ONLY for codepage */
if (!sctx->propname) sctx->propname = "CodePage";
case DSPID_CATEGORY:
if (!sctx->propname) sctx->propname = "Category";
case DSPID_PRESFORMAT:
if (!sctx->propname) sctx->propname = "PresentationTarget";
case DSPID_BYTECOUNT:
if (!sctx->propname) sctx->propname = "Bytes";
case DSPID_LINECOUNT:
if (!sctx->propname) sctx->propname = "Lines";
case DSPID_PARCOUNT:
if (!sctx->propname) sctx->propname = "Paragraphs";
case DSPID_SLIDECOUNT:
if (!sctx->propname) sctx->propname = "Slides";
case DSPID_NOTECOUNT:
if (!sctx->propname) sctx->propname = "Notes";
case DSPID_HIDDENCOUNT:
if (!sctx->propname) sctx->propname = "HiddenSlides";
case DSPID_MMCLIPCOUNT:
if (!sctx->propname) sctx->propname = "MMClips";
case DSPID_SCALE:
if (!sctx->propname) sctx->propname = "Scale";
case DSPID_HEADINGPAIR: /* VT_VARIANT | VT_VECTOR */
if (!sctx->propname) sctx->propname = "HeadingPairs";
case DSPID_DOCPARTS: /* VT_VECTOR | VT_LPSTR */
if (!sctx->propname) sctx->propname = "DocPartTitles";
case DSPID_MANAGER:
if (!sctx->propname) sctx->propname = "Manager";
case DSPID_COMPANY:
if (!sctx->propname) sctx->propname = "Company";
case DSPID_LINKSDIRTY:
if (!sctx->propname) sctx->propname = "LinksDirty";
case DSPID_CCHWITHSPACES:
if (!sctx->propname) sctx->propname = "Char&WSCount";
case DSPID_SHAREDDOC: /* SHOULD BE FALSE! */
if (!sctx->propname) sctx->propname = "SharedDoc";
case DSPID_LINKBASE: /* moved to user-defined */
if (!sctx->propname) sctx->propname = "LinkBase";
case DSPID_HLINKS: /* moved to user-defined */
if (!sctx->propname) sctx->propname = "HyperLinks";
case DSPID_HYPERLINKSCHANGED:
if (!sctx->propname) sctx->propname = "HyperLinksChanged";
case DSPID_VERSION:
if (!sctx->propname) sctx->propname = "Version";
case DSPID_DIGSIG:
if (!sctx->propname) sctx->propname = "DigitalSig";
case DSPID_CONTENTTYPE:
if (!sctx->propname) sctx->propname = "ContentType";
case DSPID_CONTENTSTATUS:
if (!sctx->propname) sctx->propname = "ContentStatus";
case DSPID_LANGUAGE:
if (!sctx->propname) sctx->propname = "Language";
case DSPID_DOCVERSION:
if (!sctx->propname) sctx->propname = "DocVersion";
ret = ole2_process_property(sctx, databuf, size, poffset);
break;
default:
cli_dbgmsg("ole2_docsum_propset_json: unrecognized propid!\n");
}
}
return CL_SUCCESS;
}
static int
ole2_summary_propset_json(summary_ctx_t *sctx, fmap_t *sumfmap, propset_entry_t *entry)
{
uint32_t size, numprops, limitprops;
uint32_t propid, poffset;
unsigned char *databuf, *ptr = NULL;
unsigned i;
int ret;
sctx->codepage = 0;
sctx->writecp = 0;
sctx->propname = NULL;
/* examine property set metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, 8);
if (!databuf) {
return CL_EREAD;
}
memcpy(&size, databuf, sizeof(size));
memcpy(&numprops, databuf+sizeof(size), sizeof(numprops));
/* endian conversion */
size = sum32_endian_convert(size);
numprops = sum32_endian_convert(numprops);
cli_dbgmsg("ole2_summary_propset_json: size: %u, numprops: %u\n", size, numprops);
/* extract the property packet and advance past metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, size);
if (!databuf) {
return CL_EREAD;
}
ptr = databuf+sizeof(size)+sizeof(numprops);
if (numprops > PROPCNTLIMIT) {
limitprops = PROPCNTLIMIT;
}
else {
limitprops = numprops;
}
cli_dbgmsg("ole2_summary_propset_json: processing %u of %u (%u max) propeties\n",
limitprops, numprops, PROPCNTLIMIT);
for (i = 0; i < limitprops; ++i) {
memcpy(&propid, ptr, sizeof(propid));
ptr+=4;
memcpy(&poffset, ptr, sizeof(poffset));
ptr+=4;
/* endian conversion */
propid = sum32_endian_convert(propid);
poffset = sum32_endian_convert(poffset);
cli_dbgmsg("ole2_summary_propset_json: propid: 0x%08x, poffset: %u\n", propid, poffset);
sctx->propname = NULL; sctx->writecp = 0;
switch(propid) {
case SPID_CODEPAGE:
sctx->writecp = 1; /* must be set ONLY for codepage */
if (!sctx->propname) sctx->propname = "CodePage";
case SPID_TITLE:
if (!sctx->propname) sctx->propname = "Title";
case SPID_SUBJECT:
if (!sctx->propname) sctx->propname = "Subject";
case SPID_AUTHOR:
if (!sctx->propname) sctx->propname = "Author";
case SPID_KEYWORDS:
if (!sctx->propname) sctx->propname = "Keywords";
case SPID_COMMENTS:
if (!sctx->propname) sctx->propname = "Comments";
case SPID_TEMPLATE:
if (!sctx->propname) sctx->propname = "Template";
case SPID_LASTAUTHOR:
if (!sctx->propname) sctx->propname = "LastAuthor";
case SPID_REVNUMBER:
if (!sctx->propname) sctx->propname = "RevNumber";
case SPID_EDITTIME:
if (!sctx->propname) sctx->propname = "EditTime";
case SPID_LASTPRINTED:
if (!sctx->propname) sctx->propname = "LastPrinted";
case SPID_CREATEDTIME:
if (!sctx->propname) sctx->propname = "CreatedTime";
case SPID_MODIFIEDTIME:
if (!sctx->propname) sctx->propname = "ModifiedTime";
case SPID_PAGECOUNT:
if (!sctx->propname) sctx->propname = "PageCount";
case SPID_WORDCOUNT:
if (!sctx->propname) sctx->propname = "WordCount";
case SPID_CHARCOUNT:
if (!sctx->propname) sctx->propname = "CharCount";
case SPID_THUMBNAIL:
if (!sctx->propname) sctx->propname = "Thumbnail";
case SPID_APPNAME:
if (!sctx->propname) sctx->propname = "AppName";
case SPID_SECURITY:
if (!sctx->propname) sctx->propname = "Security";
ret = ole2_process_property(sctx, databuf, size, poffset);
break;
default:
cli_dbgmsg("ole2_summary_propset_json: unrecognized propid!\n");
}
}
return CL_SUCCESS;
}
int
cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
{
summary_ctx_t sctx;
fmap_t *sumfmap;
summary_stub_t sumstub;
propset_entry_t pentry[2];
STATBUF statbuf;
unsigned char *databuf;
size_t maplen;
int ret = CL_SUCCESS;
if (ctx == NULL) {
return -42;
}
sctx.ctx = ctx;
if (fd < 0) {
cli_dbgmsg("ole2_summary_json: invalid file descriptor\n");
return -42; /* placeholder */
}
if (FSTAT(fd, &statbuf) == -1) {
cli_dbgmsg("ole2_summary_json: cannot stat file descriptor\n");
return CL_ESTAT;
}
sumfmap = fmap(fd, 0, statbuf.st_size);
if (!sumfmap) {
cli_dbgmsg("ole2_summary_json: failed to get fmap\n");
return CL_EMAP;
}
maplen = sumfmap->len;
cli_dbgmsg("ole2_summary_json: streamsize: %u\n", maplen);
if (maplen < sizeof(summary_stub_t)) {
cli_dbgmsg("ole2_summary_json: stream is too small to contain summary stub!");
return CL_EFORMAT;
}
databuf = (unsigned char*)fmap_need_off_once(sumfmap, 0, sizeof(summary_stub_t));
if (!databuf) {
return CL_EREAD;
}
/* Process the Summary Stream */
memcpy(&sumstub, databuf, sizeof(summary_stub_t));
/* endian conversion */
sumstub.byte_order = le16_to_host(sumstub.byte_order);
if (sumstub.byte_order != 0xfffe) {
cli_dbgmsg("ole2_summary_json: byteorder 0x%x is invalid\n", sumstub.byte_order);
return CL_EFORMAT;
}
sumstub.version = sum16_endian_convert(sumstub.version);
sumstub.system = sum32_endian_convert(sumstub.system);
sumstub.num_propsets = sum32_endian_convert(sumstub.num_propsets);
cli_dbgmsg("ole2_summary_json: byteorder 0x%x\n", sumstub.byte_order);
/* summary context setup */
sctx.byte_order = sumstub.byte_order;
sctx.version = sumstub.version;
#ifdef HAVE_JSON
sctx.summary = json_object_new_object();
if (!sctx.summary) {
cli_errmsg("ole2_summary_json: no memory for json object.\n");
return CL_EMEM;
}
#else
sctx.summary = NULL;
#endif
sctx.codepage = 0;
sctx.writecp = 0;
cli_dbgmsg("ole2_summary_json: %u property set(s) detected\n", sumstub.num_propsets);
if (sumstub.num_propsets == 1) {
databuf = (unsigned char*)fmap_need_off_once(sumfmap, sizeof(summary_stub_t),
sizeof(propset_entry_t));
if (!databuf) {
return CL_EREAD;
}
memcpy(pentry, databuf, sizeof(summary_stub_t));
/* endian conversion */
pentry[0].offset = sum32_endian_convert(pentry[0].offset);
/* TODO - check return and mode */
if (!mode) {
ret = ole2_summary_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "SummaryInfo", sctx.summary);
#endif
}
else {
ret = ole2_docsum_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "DocSummaryInfo", sctx.summary);
#endif
}
}
else if (sumstub.num_propsets == 2) {
databuf = (unsigned char*)fmap_need_off_once(sumfmap, sizeof(summary_stub_t),
2*sizeof(propset_entry_t));
if (!databuf) {
return CL_EREAD;
}
memcpy(pentry, databuf, 2*sizeof(summary_stub_t));
/* endian conversion */
pentry[0].offset = sum32_endian_convert(pentry[0].offset);
pentry[1].offset = sum32_endian_convert(pentry[1].offset);
/* multi-propset handling */
/* first propset is user-defined, ignored for now */
/* TODO - check return and mode */
if (!mode) {
ret = ole2_summary_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "SummaryInfo", sctx.summary);
#endif
}
else {
ret = ole2_docsum_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "DocSummaryInfo", sctx.summary);
#endif
}
}
else {
cli_dbgmsg("ole2_summary_json: invalid number of property sets\n");
return CL_EFORMAT;
}
/*------DEBUG------
int i;
cli_dbgmsg("byte_order: %x\n", sumstub.byte_order);
cli_dbgmsg("version: %x\n", sumstub.version);
cli_dbgmsg("system: %x\n", sumstub.system);
cli_dbgmsg("CLSID: ");
for (i = 0; i < 16; ++i) {
if (i == 3 || i == 5 || i == 7) {
fprintf(stderr, "-");
}
fprintf(stderr, "%02x", sumstub.CLSID[i]);
}
fprintf(stderr, "\n");
cli_dbgmsg("num_propsets: %u\n", sumstub.num_propsets);
cli_dbgmsg("FMTID0: ");
for (i = 0; i < 16; ++i) {
if (i == 3 || i == 5 || i == 7) {
fprintf(stderr, "-");
}
fprintf(stderr, "%02x", pentry[0].FMTID[i]);
}
fprintf(stderr, "\n");
cli_dbgmsg("offset0: %u\n", pentry[0].offset);
if (sumstub.num_propsets == 2) {
cli_dbgmsg("FMTID1: ");
for (i = 0; i < 16; ++i) {
if (i == 3 || i == 5 || i == 7) {
fprintf(stderr, "-");
}
fprintf(stderr, "%02x", pentry[1].FMTID[i]);
}
fprintf(stderr, "\n");
cli_dbgmsg("offset1: %u\n", pentry[1].offset);
}
json_object* newobj = json_object_new_object();
json_object* obj0 = json_object_new_boolean(1);
json_object* obj1 = json_object_new_boolean(0);
json_object* obj2 = json_object_new_int(-1);
//json_object* obj3 = json_object_new_int64(-64);
json_object* obj4 = json_object_new_string("hello world!");
json_object* obj5 = json_object_new_string_len("hello world!", 5);
json_object_object_add(newobj, "bool", obj0);
json_object_object_add(newobj, "bool", obj1);
json_object_object_add(newobj, "int", obj2);
//json_object_object_add(newobj, "int64", obj3);
json_object_object_add(newobj, "string", obj4);
json_object_object_add(newobj, "string_len", obj5);
json_object_object_add(ctx->properties, "summary2", newobj);
-----------------*/
funmap(sumfmap);
return ret;
}

@ -26,26 +26,7 @@
#include "others.h"
#include "uniq.h"
struct ole2_list_node;
typedef struct ole2_list_node
{
uint32_t Val;
struct ole2_list_node *Next;
} ole2_list_node_t;
typedef struct ole2_list
{
uint32_t Size;
ole2_list_node_t *Head;
} ole2_list_t;
int ole2_list_init(ole2_list_t*);
int ole2_list_is_empty(ole2_list_t*);
uint32_t ole2_list_size(ole2_list_t*);
int ole2_list_push(ole2_list_t*, uint32_t);
uint32_t ole2_list_pop(ole2_list_t*);
int ole2_list_delete(ole2_list_t*);
int cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **);
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode);
#endif

@ -1111,7 +1111,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
fd = open(vbaname, O_RDONLY|O_BINARY);
if (fd >= 0) {
cli_dbgmsg("VBADir: detected a '_5_summaryinformation' stream\n");
cli_vba_summary_json(ctx, fd, 0);
cli_ole2_summary_json(ctx, fd, 0);
close(fd);
}
}
@ -1124,7 +1124,7 @@ static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
fd = open(vbaname, O_RDONLY|O_BINARY);
if (fd >= 0) {
cli_dbgmsg("VBADir: detected a '_5_documentsummaryinformation' stream\n");
cli_vba_summary_json(ctx, fd, 1);
cli_ole2_summary_json(ctx, fd, 1);
close(fd);
}
}

@ -1337,994 +1337,3 @@ create_vba_project(int record_count, const char *dir, struct uniq *U)
return ret;
}
#ifdef HAVE_JSON
#define cli_jsonnull(o,n)\
{ \
json_object *fpobj = json_object_new_string("null"); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json string object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#define cli_jsonstr(o,n,s) \
{ \
json_object *fpobj = json_object_new_string(s); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json string object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#define cli_jsonint(o,n,i) \
{ \
json_object *fpobj = json_object_new_int(i); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
/*
#define cli_jsonint64(o,n,i) \
{ \
json_object *fpobj = json_object_new_int64(i); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
*/
#define cli_jsonint64(o,n,i) cli_dbgmsg("%s: %lld [%llx]\n", n, i, i)
#define cli_jsonbool(o,n,b) \
{ \
json_object *fpobj = json_object_new_boolean(b); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#define cli_jsondouble(o,n,d) \
{ \
json_object *fpobj = json_object_new_double(d); \
if (NULL == fpobj) { \
cli_errmsg("json: no memory for json int object.\n"); \
return CL_EMEM; \
} \
json_object_object_add(o, n, fpobj); \
}
#else
#define cli_jsonnull(o,n) cli_dbgmsg("%s: null\n", n)
#define cli_jsonstr(o,n,s) cli_dbgmsg("%s: \"%s\"\n", n, s)
#define cli_jsonint(o,n,i) cli_dbgmsg("%s: %d [%x]\n", n, i, i)
#define cli_jsonint64(o,n,i) cli_dbgmsg("%s: %lld [%llx]\n", n, i, i)
#define cli_jsonbool(o,n,b) cli_dbgmsg("%s: %s\n", n, b ? "true":"false")
#define cli_jsondouble(o,n,d) cli_dbgmsg("%s: %f\n", n, d)
#endif
#define WINUNICODE 0x04B0
#define PROPCNTLIMIT 25
#define PROPSTRLIMIT 100
#define sum16_endian_convert(v) le16_to_host((uint16_t)(v))
#define sum32_endian_convert(v) le32_to_host((uint32_t)(v))
#define sum64_endian_convert(v) le64_to_host((uint32_t)(v))
static char *
get_property_name2(char *name, int size)
{
int i, j;
char *newname;
if (*name == 0 || size <= 0 || size > 64) {
return NULL;
}
newname = (char *)cli_malloc(size * 7);
if (!newname) {
cli_errmsg("OLE2 [get_property_name2]: Unable to allocate memory for newname: %u\n", size * 7);
return NULL;
}
j = 0;
/* size-2 to ignore trailing NULL */
for (i = 0; i < size - 2; i += 2) {
if ((!(name[i] & 0x80)) && isprint(name[i])) {
newname[j++] = tolower(name[i]);
} else {
if (name[i] < 10 && name[i] >= 0) {
newname[j++] = '_';
newname[j++] = name[i] + '0';
} else {
const uint16_t x = (((uint16_t) name[i]) << 8) | name[i + 1];
newname[j++] = '_';
newname[j++] = 'a' + ((x & 0xF));
newname[j++] = 'a' + ((x >> 4) & 0xF);
newname[j++] = 'a' + ((x >> 8) & 0xF);
newname[j++] = 'a' + ((x >> 16) & 0xF);
newname[j++] = 'a' + ((x >> 24) & 0xF);
}
newname[j++] = '_';
}
}
newname[j] = '\0';
if (strlen(newname) == 0) {
free(newname);
return NULL;
}
return newname;
}
enum summary_pidsi {
SPID_CODEPAGE = 0x00000001,
SPID_TITLE = 0x00000002,
SPID_SUBJECT = 0x00000003,
SPID_AUTHOR = 0x00000004,
SPID_KEYWORDS = 0x00000005,
SPID_COMMENTS = 0x00000006,
SPID_TEMPLATE = 0x00000007,
SPID_LASTAUTHOR = 0x00000008,
SPID_REVNUMBER = 0x00000009,
SPID_EDITTIME = 0x0000000A,
SPID_LASTPRINTED = 0x0000000B,
SPID_CREATEDTIME = 0x0000000C,
SPID_MODIFIEDTIME = 0x0000000D,
SPID_PAGECOUNT = 0x0000000E,
SPID_WORDCOUNT = 0x0000000F,
SPID_CHARCOUNT = 0x00000010,
SPID_THUMBNAIL = 0x00000011,
SPID_APPNAME = 0x00000012,
SPID_SECURITY = 0x00000013
};
enum docsum_pidsi {
DSPID_CODEPAGE = 0x00000001,
DSPID_CATEGORY = 0x00000002,
DSPID_PRESFORMAT = 0x00000003,
DSPID_BYTECOUNT = 0x00000004,
DSPID_LINECOUNT = 0x00000005,
DSPID_PARCOUNT = 0x00000006,
DSPID_SLIDECOUNT = 0x00000007,
DSPID_NOTECOUNT = 0x00000008,
DSPID_HIDDENCOUNT = 0x00000009,
DSPID_MMCLIPCOUNT = 0x0000000A,
DSPID_SCALE = 0x0000000B,
DSPID_HEADINGPAIR = 0x0000000C, /* VT_VARIANT | VT_VECTOR */
DSPID_DOCPARTS = 0x0000000D, /* VT_VECTOR | VT_LPSTR */
DSPID_MANAGER = 0x0000000E,
DSPID_COMPANY = 0x0000000F,
DSPID_LINKSDIRTY = 0x00000010,
DSPID_CCHWITHSPACES = 0x00000011,
DSPID_SHAREDDOC = 0x00000013, /* must be false */
DSPID_LINKBASE = 0x00000014, /* moved to user-defined */
DSPID_HLINKS = 0x00000015, /* moved to user-defined */
DSPID_HYPERLINKSCHANGED = 0x00000016,
DSPID_VERSION = 0x00000017,
DSPID_DIGSIG = 0x00000018,
DSPID_CONTENTTYPE = 0x0000001A,
DSPID_CONTENTSTATUS = 0x0000001B,
DSPID_LANGUAGE = 0x0000001C,
DSPID_DOCVERSION = 0x0000001D
};
enum property_type {
PT_EMPTY = 0x0000,
PT_NULL = 0x0001,
PT_INT16 = 0x0002,
PT_INT32 = 0x0003,
PT_FLOAT32 = 0x0004,
PT_DOUBLE64 = 0x0005,
PT_CURRENCY = 0x0006,
PT_DATE = 0x0007,
PT_BSTR = 0x0008,
PT_ERROR = 0x000A,
PT_BOOL = 0x000B,
PT_DECIMAL = 0x000E,
PT_INT8v1 = 0x0010,
PT_UINT8 = 0x0011,
PT_UINT16 = 0x0012,
PT_UINT32 = 0x0013,
PT_INT64 = 0x0014,
PT_UINT64 = 0x0015,
PT_INT32v1 = 0x0016,
PT_UINT32v1 = 0x0017,
PT_LPSTR = 0x001E,
PT_LPWSTR = 0x001F,
PT_FILETIME = 0x0040,
PT_BLOB = 0x0041
/* More Types not currently handled */
};
typedef struct summary_stub {
uint16_t byte_order;
uint16_t version;
uint32_t system; /* implementation-specific */
uint8_t CLSID[16];
uint32_t num_propsets; /* 1 or 2 */
} summary_stub_t;
typedef struct propset_summary_entry {
uint8_t FMTID[16];
uint32_t offset;
} propset_entry_t;
typedef struct summary_ctx {
cli_ctx *ctx;
#ifdef HAVE_JSON
json_object *summary;
#else
char *summary;
#endif
uint16_t byte_order;
uint16_t version;
int16_t codepage;
const char *propname;
int writecp; /* used to trigger writing the codepage value */
} summary_ctx_t;
static int
cli_vba_process_prop(summary_ctx_t *sctx, unsigned char *databuf, size_t buflen, uint32_t offset)
{
uint16_t proptype, padding;
if (offset+4 > buflen) {
return CL_EFORMAT;
}
memcpy(&proptype, databuf+offset, sizeof(proptype));
offset+=sizeof(proptype);
memcpy(&padding, databuf+offset, sizeof(padding));
offset+=sizeof(padding);
/* endian conversion */
proptype = sum16_endian_convert(proptype);
//cli_dbgmsg("proptype: 0x%04x\n", proptype);
if (padding != 0) {
return CL_EFORMAT;
}
switch (proptype) {
case PT_EMPTY:
cli_jsonnull(sctx->summary, sctx->propname);
break;
case PT_NULL:
cli_jsonnull(sctx->summary, sctx->propname);
break;
case PT_INT16:
{
int16_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum16_endian_convert(dout);
if (sctx->writecp) sctx->codepage = dout;
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_INT32:
case PT_INT32v1:
{
int32_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum32_endian_convert(dout);
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_FLOAT32: /* review this please */
{
float dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* TODO - endian conversion */
cli_jsondouble(sctx->summary, sctx->propname, dout);
break;
}
case PT_DATE:
case PT_DOUBLE64: /* review this please */
{
double dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* TODO - endian conversion */
cli_jsondouble(sctx->summary, sctx->propname, dout);
break;
}
/*
case PT_CURRENCY:
break;
case PT_ERROR:
break;
*/
case PT_BOOL:
{
uint16_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* no need for endian conversion */
cli_jsonbool(sctx->summary, sctx->propname, dout);
break;
}
/* case PT_DECIMAL:
break;*/
case PT_INT8v1:
{
int8_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* no need for endian conversion */
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT8:
{
uint8_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* no need for endian conversion */
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT16:
{
uint16_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum16_endian_convert(dout);
if (sctx->writecp) sctx->codepage = dout;
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT32:
case PT_UINT32v1:
{
uint32_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum32_endian_convert(dout);
cli_jsonint(sctx->summary, sctx->propname, dout);
break;
}
case PT_INT64:
{
int64_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum64_endian_convert(dout);
cli_jsonint64(sctx->summary, sctx->propname, dout);
break;
}
case PT_UINT64:
{
uint64_t dout;
if (offset+sizeof(dout) > buflen) {
return CL_EFORMAT;
}
memcpy(&dout, databuf+offset, sizeof(dout));
offset+=sizeof(dout);
/* endian conversion */
dout = sum64_endian_convert(dout);
cli_jsonint64(sctx->summary, sctx->propname, dout);
break;
}
case PT_BSTR:
case PT_LPSTR:
if (sctx->codepage == 0) {
cli_dbgmsg("vba_propset_json: current codepage is unknown, cannot parse char stream\n");
break;
}
else if (sctx->codepage != WINUNICODE) {
uint32_t strsize;
char *outstr;
if (offset+sizeof(strsize) > buflen) {
return CL_EFORMAT;
}
memcpy(&strsize, databuf+offset, sizeof(strsize));
offset+=sizeof(strsize);
/* no need for endian conversion */
if (offset+strsize > buflen) {
return CL_EFORMAT;
}
/* limitation on string length */
if (strsize > PROPSTRLIMIT) {
cli_dbgmsg("vba_process_prop: property string sized %lu truncated to size %lu\n",
(unsigned long)strsize, (unsigned long)PROPSTRLIMIT);
strsize = PROPSTRLIMIT;
}
outstr = cli_malloc(strsize+1);
if (!outstr) {
return CL_EMEM;
}
strncpy(outstr, databuf+offset, strsize);
outstr[strsize] = '\0'; /* guarentee a NULL-termination */
cli_jsonstr(sctx->summary, sctx->propname, outstr);
free(outstr);
break;
}
/* fall-through for unicode strings */
case PT_LPWSTR:
{
uint32_t strsize;
char *outstr, *outstr2;
if (offset+sizeof(strsize) > buflen) {
return CL_EFORMAT;
}
memcpy(&strsize, databuf+offset, sizeof(strsize));
offset+=sizeof(strsize);
/* no need for endian conversion */
if (proptype == PT_LPSTR) { /* fall-through specifics */
if (strsize % 2) {
return CL_EFORMAT;
}
}
else {
strsize*=2; /* Unicode strings are by length, not size */
}
if (offset+strsize > buflen) {
return CL_EFORMAT;
}
outstr = cli_malloc(strsize+2);
if (!outstr) {
return CL_EMEM;
}
strncpy(outstr, databuf+offset, strsize);
outstr[strsize-1] = '\0'; /* guarentee a UTF-16 NULL-termination */
outstr[strsize] = '\0';
outstr2 = (char*)get_property_name2(outstr, strsize);
cli_jsonstr(sctx->summary, sctx->propname, outstr);
free(outstr);
free(outstr2);
break;
}
case PT_FILETIME:
{
uint32_t ltime, htime;
#ifdef HAVE_JSON
#else
uint64_t wtime = 0, utime =0;
#endif
if (offset+sizeof(ltime)+sizeof(htime) > buflen) {
return CL_EFORMAT;
}
memcpy(&ltime, databuf+offset, sizeof(ltime));
offset+=sizeof(ltime);
memcpy(&htime, databuf+offset, sizeof(htime));
offset+=sizeof(ltime);
ltime = sum32_endian_convert(ltime);
htime = sum32_endian_convert(htime);
#ifdef HAVE_JSON
/* Raw Output */
{
json_object *fpobj0, *fpobj1;
json_object *fparr = json_object_new_array();
if (NULL == fparr) {
cli_errmsg("vba_process_prop: no memory for json array object.\n");
return CL_EMEM;
}
fpobj0 = json_object_new_int(ltime);
if (NULL == fpobj0) {
cli_errmsg("vba_process_prop: no memory for json int object.\n");
return CL_EMEM;
}
fpobj1 = json_object_new_int(htime);
if (NULL == fpobj1) {
cli_errmsg("vba_process_prop: no memory for json int object.\n");
return CL_EMEM;
}
json_object_array_add(fparr, fpobj0);
json_object_array_add(fparr, fpobj1);
json_object_object_add(sctx->summary, sctx->propname, fparr);
}
#else
/* human-readable formatting */
wtime = htime;
wtime <<= 32;
wtime |= ltime;
utime = wtime / 10000000;
utime -= 11644473600LL;
cli_jsonstr(sctx->summary, sctx->propname, ctime((timer_t*)&utime));
#endif
break;
}
/*
case PT_BLOB:
break;*/
default:
cli_dbgmsg("vba_process_prop: unhandled property type %04x for %s property\n",
proptype, sctx->propname);
}
return CL_SUCCESS;
}
static int
cli_vba_docsum_propset_json(summary_ctx_t *sctx, fmap_t *sumfmap, propset_entry_t *entry)
{
uint32_t size, numprops, limitprops;
uint32_t propid, poffset;
unsigned char *databuf, *ptr = NULL;
unsigned i;
int ret;
sctx->codepage = 0;
sctx->writecp = 0;
sctx->propname = NULL;
/* examine property set metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, 8);
if (!databuf) {
return CL_EREAD;
}
memcpy(&size, databuf, sizeof(size));
memcpy(&numprops, databuf+sizeof(size), sizeof(numprops));
/* endian conversion */
size = sum32_endian_convert(size);
numprops = sum32_endian_convert(numprops);
cli_dbgmsg("vba_docsum_propset_json: size: %u, numprops: %u\n", size, numprops);
/* extract the property packet and advance past metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, size);
if (!databuf) {
return CL_EREAD;
}
ptr = databuf+sizeof(size)+sizeof(numprops);
if (numprops > PROPCNTLIMIT) {
limitprops = PROPCNTLIMIT;
}
else {
limitprops = numprops;
}
cli_dbgmsg("vba_docsum_propset_json: processing %u of %u (%u max) propeties\n",
limitprops, numprops, PROPCNTLIMIT);
for (i = 0; i < limitprops; ++i) {
memcpy(&propid, ptr, sizeof(propid));
ptr+=4;
memcpy(&poffset, ptr, sizeof(poffset));
ptr+=4;
/* endian conversion */
propid = sum32_endian_convert(propid);
poffset = sum32_endian_convert(poffset);
cli_dbgmsg("vba_docsum_propset_json: propid: 0x%08x, poffset: %u\n", propid, poffset);
sctx->propname = NULL; sctx->writecp = 0;
switch(propid) {
case DSPID_CODEPAGE:
sctx->writecp = 1; /* must be set ONLY for codepage */
if (!sctx->propname) sctx->propname = "CodePage";
case DSPID_CATEGORY:
if (!sctx->propname) sctx->propname = "Category";
case DSPID_PRESFORMAT:
if (!sctx->propname) sctx->propname = "PresentationTarget";
case DSPID_BYTECOUNT:
if (!sctx->propname) sctx->propname = "Bytes";
case DSPID_LINECOUNT:
if (!sctx->propname) sctx->propname = "Lines";
case DSPID_PARCOUNT:
if (!sctx->propname) sctx->propname = "Paragraphs";
case DSPID_SLIDECOUNT:
if (!sctx->propname) sctx->propname = "Slides";
case DSPID_NOTECOUNT:
if (!sctx->propname) sctx->propname = "Notes";
case DSPID_HIDDENCOUNT:
if (!sctx->propname) sctx->propname = "HiddenSlides";
case DSPID_MMCLIPCOUNT:
if (!sctx->propname) sctx->propname = "MMClips";
case DSPID_SCALE:
if (!sctx->propname) sctx->propname = "Scale";
case DSPID_HEADINGPAIR: /* VT_VARIANT | VT_VECTOR */
if (!sctx->propname) sctx->propname = "HeadingPairs";
case DSPID_DOCPARTS: /* VT_VECTOR | VT_LPSTR */
if (!sctx->propname) sctx->propname = "DocPartTitles";
case DSPID_MANAGER:
if (!sctx->propname) sctx->propname = "Manager";
case DSPID_COMPANY:
if (!sctx->propname) sctx->propname = "Company";
case DSPID_LINKSDIRTY:
if (!sctx->propname) sctx->propname = "LinksDirty";
case DSPID_CCHWITHSPACES:
if (!sctx->propname) sctx->propname = "Char&WSCount";
case DSPID_SHAREDDOC: /* SHOULD BE FALSE! */
if (!sctx->propname) sctx->propname = "SharedDoc";
case DSPID_LINKBASE: /* moved to user-defined */
if (!sctx->propname) sctx->propname = "LinkBase";
case DSPID_HLINKS: /* moved to user-defined */
if (!sctx->propname) sctx->propname = "HyperLinks";
case DSPID_HYPERLINKSCHANGED:
if (!sctx->propname) sctx->propname = "HyperLinksChanged";
case DSPID_VERSION:
if (!sctx->propname) sctx->propname = "Version";
case DSPID_DIGSIG:
if (!sctx->propname) sctx->propname = "DigitalSig";
case DSPID_CONTENTTYPE:
if (!sctx->propname) sctx->propname = "ContentType";
case DSPID_CONTENTSTATUS:
if (!sctx->propname) sctx->propname = "ContentStatus";
case DSPID_LANGUAGE:
if (!sctx->propname) sctx->propname = "Language";
case DSPID_DOCVERSION:
if (!sctx->propname) sctx->propname = "DocVersion";
ret = cli_vba_process_prop(sctx, databuf, size, poffset);
break;
default:
cli_dbgmsg("vba_docsum_propset_json: unrecognized propid!\n");
}
}
return CL_SUCCESS;
}
static int
cli_vba_summary_propset_json(summary_ctx_t *sctx, fmap_t *sumfmap, propset_entry_t *entry)
{
uint32_t size, numprops, limitprops;
uint32_t propid, poffset;
unsigned char *databuf, *ptr = NULL;
unsigned i;
int ret;
sctx->codepage = 0;
sctx->writecp = 0;
sctx->propname = NULL;
/* examine property set metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, 8);
if (!databuf) {
return CL_EREAD;
}
memcpy(&size, databuf, sizeof(size));
memcpy(&numprops, databuf+sizeof(size), sizeof(numprops));
/* endian conversion */
size = sum32_endian_convert(size);
numprops = sum32_endian_convert(numprops);
cli_dbgmsg("vba_summary_propset_json: size: %u, numprops: %u\n", size, numprops);
/* extract the property packet and advance past metadata */
databuf = (unsigned char*)fmap_need_off_once(sumfmap, entry->offset, size);
if (!databuf) {
return CL_EREAD;
}
ptr = databuf+sizeof(size)+sizeof(numprops);
if (numprops > PROPCNTLIMIT) {
limitprops = PROPCNTLIMIT;
}
else {
limitprops = numprops;
}
cli_dbgmsg("vba_summary_propset_json: processing %u of %u (%u max) propeties\n",
limitprops, numprops, PROPCNTLIMIT);
for (i = 0; i < limitprops; ++i) {
memcpy(&propid, ptr, sizeof(propid));
ptr+=4;
memcpy(&poffset, ptr, sizeof(poffset));
ptr+=4;
/* endian conversion */
propid = sum32_endian_convert(propid);
poffset = sum32_endian_convert(poffset);
cli_dbgmsg("vba_summary_propset_json: propid: 0x%08x, poffset: %u\n", propid, poffset);
sctx->propname = NULL; sctx->writecp = 0;
switch(propid) {
case SPID_CODEPAGE:
sctx->writecp = 1; /* must be set ONLY for codepage */
if (!sctx->propname) sctx->propname = "CodePage";
case SPID_TITLE:
if (!sctx->propname) sctx->propname = "Title";
case SPID_SUBJECT:
if (!sctx->propname) sctx->propname = "Subject";
case SPID_AUTHOR:
if (!sctx->propname) sctx->propname = "Author";
case SPID_KEYWORDS:
if (!sctx->propname) sctx->propname = "Keywords";
case SPID_COMMENTS:
if (!sctx->propname) sctx->propname = "Comments";
case SPID_TEMPLATE:
if (!sctx->propname) sctx->propname = "Template";
case SPID_LASTAUTHOR:
if (!sctx->propname) sctx->propname = "LastAuthor";
case SPID_REVNUMBER:
if (!sctx->propname) sctx->propname = "RevNumber";
case SPID_EDITTIME:
if (!sctx->propname) sctx->propname = "EditTime";
case SPID_LASTPRINTED:
if (!sctx->propname) sctx->propname = "LastPrinted";
case SPID_CREATEDTIME:
if (!sctx->propname) sctx->propname = "CreatedTime";
case SPID_MODIFIEDTIME:
if (!sctx->propname) sctx->propname = "ModifiedTime";
case SPID_PAGECOUNT:
if (!sctx->propname) sctx->propname = "PageCount";
case SPID_WORDCOUNT:
if (!sctx->propname) sctx->propname = "WordCount";
case SPID_CHARCOUNT:
if (!sctx->propname) sctx->propname = "CharCount";
case SPID_THUMBNAIL:
if (!sctx->propname) sctx->propname = "Thumbnail";
case SPID_APPNAME:
if (!sctx->propname) sctx->propname = "AppName";
case SPID_SECURITY:
if (!sctx->propname) sctx->propname = "Security";
ret = cli_vba_process_prop(sctx, databuf, size, poffset);
break;
default:
cli_dbgmsg("vba_summary_propset_json: unrecognized propid!\n");
}
}
return CL_SUCCESS;
}
int
cli_vba_summary_json(cli_ctx *ctx, int fd, int mode)
{
summary_ctx_t sctx;
fmap_t *sumfmap;
summary_stub_t sumstub;
propset_entry_t pentry[2];
STATBUF statbuf;
unsigned char *databuf;
size_t maplen;
int ret = CL_SUCCESS;
if (ctx == NULL) {
return -42;
}
sctx.ctx = ctx;
if (fd < 0) {
cli_dbgmsg("vba_summary_json: invalid file descriptor\n");
return -42; /* placeholder */
}
if (FSTAT(fd, &statbuf) == -1) {
cli_dbgmsg("vba_summary_json: cannot stat file descriptor\n");
return CL_ESTAT;
}
sumfmap = fmap(fd, 0, statbuf.st_size);
if (!sumfmap) {
cli_dbgmsg("vba_summary_json: failed to get fmap\n");
return CL_EMAP;
}
maplen = sumfmap->len;
cli_dbgmsg("vba_summary_json: streamsize: %u\n", maplen);
if (maplen < sizeof(summary_stub_t)) {
cli_dbgmsg("vba_summary_json: stream is too small to contain summary stub!");
return CL_EFORMAT;
}
databuf = (unsigned char*)fmap_need_off_once(sumfmap, 0, sizeof(summary_stub_t));
if (!databuf) {
return CL_EREAD;
}
/* Process the Summary Stream */
memcpy(&sumstub, databuf, sizeof(summary_stub_t));
/* endian conversion */
sumstub.byte_order = le16_to_host(sumstub.byte_order);
if (sumstub.byte_order != 0xfffe) {
cli_dbgmsg("vba_summary_json: byteorder 0x%x is invalid\n", sumstub.byte_order);
return CL_EFORMAT;
}
sumstub.version = sum16_endian_convert(sumstub.version);
sumstub.system = sum32_endian_convert(sumstub.system);
sumstub.num_propsets = sum32_endian_convert(sumstub.num_propsets);
cli_dbgmsg("vba_summary_json: byteorder 0x%x\n", sumstub.byte_order);
/* summary context setup */
sctx.byte_order = sumstub.byte_order;
sctx.version = sumstub.version;
#ifdef HAVE_JSON
sctx.summary = json_object_new_object();
if (!sctx.summary) {
cli_errmsg("vba_summary_json: no memory for json object.\n");
return CL_EMEM;
}
#else
sctx.summary = NULL;
#endif
sctx.codepage = 0;
sctx.writecp = 0;
cli_dbgmsg("vba_summary_json: %u property set(s) detected\n", sumstub.num_propsets);
if (sumstub.num_propsets == 1) {
databuf = (unsigned char*)fmap_need_off_once(sumfmap, sizeof(summary_stub_t),
sizeof(propset_entry_t));
if (!databuf) {
return CL_EREAD;
}
memcpy(pentry, databuf, sizeof(summary_stub_t));
/* endian conversion */
pentry[0].offset = sum32_endian_convert(pentry[0].offset);
/* TODO - check return and mode */
if (!mode) {
ret = cli_vba_summary_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "SummaryInfo", sctx.summary);
#endif
}
else {
ret = cli_vba_docsum_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "DocSummaryInfo", sctx.summary);
#endif
}
}
else if (sumstub.num_propsets == 2) {
databuf = (unsigned char*)fmap_need_off_once(sumfmap, sizeof(summary_stub_t),
2*sizeof(propset_entry_t));
if (!databuf) {
return CL_EREAD;
}
memcpy(pentry, databuf, 2*sizeof(summary_stub_t));
/* endian conversion */
pentry[0].offset = sum32_endian_convert(pentry[0].offset);
pentry[1].offset = sum32_endian_convert(pentry[1].offset);
/* multi-propset handling */
/* first propset is user-defined, ignored for now */
/* TODO - check return and mode */
if (!mode) {
ret = cli_vba_summary_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "SummaryInfo", sctx.summary);
#endif
}
else {
ret = cli_vba_docsum_propset_json(&sctx, sumfmap, &pentry[0]);
#ifdef HAVE_JSON
json_object_object_add(ctx->properties, "DocSummaryInfo", sctx.summary);
#endif
}
}
else {
cli_dbgmsg("vba_summary_json: invalid number of property sets\n");
return CL_EFORMAT;
}
/*------DEBUG------
int i;
cli_dbgmsg("byte_order: %x\n", sumstub.byte_order);
cli_dbgmsg("version: %x\n", sumstub.version);
cli_dbgmsg("system: %x\n", sumstub.system);
cli_dbgmsg("CLSID: ");
for (i = 0; i < 16; ++i) {
if (i == 3 || i == 5 || i == 7) {
fprintf(stderr, "-");
}
fprintf(stderr, "%02x", sumstub.CLSID[i]);
}
fprintf(stderr, "\n");
cli_dbgmsg("num_propsets: %u\n", sumstub.num_propsets);
cli_dbgmsg("FMTID0: ");
for (i = 0; i < 16; ++i) {
if (i == 3 || i == 5 || i == 7) {
fprintf(stderr, "-");
}
fprintf(stderr, "%02x", pentry[0].FMTID[i]);
}
fprintf(stderr, "\n");
cli_dbgmsg("offset0: %u\n", pentry[0].offset);
if (sumstub.num_propsets == 2) {
cli_dbgmsg("FMTID1: ");
for (i = 0; i < 16; ++i) {
if (i == 3 || i == 5 || i == 7) {
fprintf(stderr, "-");
}
fprintf(stderr, "%02x", pentry[1].FMTID[i]);
}
fprintf(stderr, "\n");
cli_dbgmsg("offset1: %u\n", pentry[1].offset);
}
json_object* newobj = json_object_new_object();
json_object* obj0 = json_object_new_boolean(1);
json_object* obj1 = json_object_new_boolean(0);
json_object* obj2 = json_object_new_int(-1);
//json_object* obj3 = json_object_new_int64(-64);
json_object* obj4 = json_object_new_string("hello world!");
json_object* obj5 = json_object_new_string_len("hello world!", 5);
json_object_object_add(newobj, "bool", obj0);
json_object_object_add(newobj, "bool", obj1);
json_object_object_add(newobj, "int", obj2);
//json_object_object_add(newobj, "int64", obj3);
json_object_object_add(newobj, "string", obj4);
json_object_object_add(newobj, "string_len", obj5);
json_object_object_add(ctx->properties, "summary2", newobj);
-----------------*/
funmap(sumfmap);
return ret;
}

@ -45,7 +45,4 @@ int cli_scan_ole10(int fd, cli_ctx *ctx);
char *cli_ppt_vba_read(int fd, cli_ctx *ctx);
unsigned char *cli_wm_decrypt_macro(int fd, off_t offset, uint32_t len,
unsigned char key);
int cli_vba_summary_json(cli_ctx *ctx, int fd, int mode);
#endif

Loading…
Cancel
Save