📄 oledecod.c
字号:
/* OLEdecode - Decode Microsoft OLE files into its components. Copyright (C) 1998, 1999 Andrew Scriven This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* Released under GPL, written by Andrew Scriven <andy.scriven@research.natpower.co.uk> Copyright (C) 1998, 1999 Andrew Scriven *//* ----------------------------------------------------------------------- Andrew Scriven Research and Engineering Electron Building, Windmill Hill, Whitehill Way, Swindon, SN5 6PB, UK Phone (44) 1793 896206, Fax (44) 1793 896251 ----------------------------------------------------------------------- *//* *Extremely* modified by Arturo Tena <arturo@directmail.org> */#include <stdio.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <sys/types.h>#include <assert.h>#if !(defined( __BORLANDC__ ) || defined( __WIN32__ ))#include "cole.h"#include "config.h"#include <unistd.h> /* for unlink() */#else#include "cole.h.in"#endif/* FIXME: replace all VERBOSE with COLE_VERBOSE */#ifdef COLE_VERBOSE#define VERBOSE#else#undef VERBOSE#endif#include "support.h"#include "internal.h"#define ENTRYCHUNK 20 /* number of entries in root_list and sbd_list will be added each time. must be at least 1 */#define MIN(a,b) ((a)<(b) ? (a) : (b)) /* reorder pps tree, from tree structure to a linear one, and write the level numbers, returns zero if OLE format fails, returns no zero if success */static int reorder_pps_tree (pps_entry * root_pps, U16 level); /* free memory used (except the pps tree) */static void ends (void); /* close and remove files in the tree *//* closeOLEtreefiles --- outdated because not to generate the real files by now --- cole 2.0.0 *//* static void closeOLEtreefiles (pps_entry * tree, U32 root); *//* Verbose pps tree. Input: pps_list: stream list. root_pps: root pps. level: how much levels will be extracted. Output: none. */static void verbosePPSTree (pps_entry * pps_list, U32 root_pps, int level);static FILE *input;static U8 *Block;static U8 *Blockx;static U8 *BDepot, *SDepot, *Root;static pps_entry *pps_list;static U32 num_of_pps;static FILE *sbfile;/* sbfilename is stored in *_sbfilename instead -- cole 2.0.0 *//* static char sbfilename[L_tmpnam]; */static U32 *sbd_list;static U32 *root_list;int __OLEdecode (char *OLEfilename, pps_entry ** stream_list, U32 * root, U8 **_BDepot, U8 **_SDepot, FILE **_sbfile, char **_sbfilename, FILE **_input, U16 max_level){ int c; U32 num_bbd_blocks; U32 num_xbbd_blocks; U32 bl; U32 i, j, len; U8 *s, *p, *t; long FilePos; /* FilePos is long, not U32, because second argument of fseek is long */ /* initialize static variables */ input = sbfile = NULL; Block = Blockx = BDepot = SDepot = Root = NULL; pps_list = NULL; num_of_pps = 0;/* sbfilename is stored in *_sbfilename instead -- cole 2.0.0 *//* sbfilename[0] = 0; */ root_list = sbd_list = NULL; /* initalize return parameters */ *stream_list = NULL; /* open input file */ verbose ("open input file"); input = fopen (OLEfilename, "rb"); test_exitf (input != NULL, 4, ends ()); *_input = input; /* fast check type of file */ verbose ("fast testing type of file"); test_exitf ((c = getc (input)) != EOF, 5, ends ()); test_exitf (ungetc (c, input) != EOF, 5, ends ());/* test_exitf (!isprint (c), 8, ends ()); OpenBSD suggestion to comment this out */ test_exitf (c == 0xd0, 9, ends ()); /* read header block */ verbose ("read header block"); Block = (U8 *) malloc (0x0200); test_exitf (Block != NULL, 10, ends ()); fread (Block, 0x0200, 1, input); test_exitf (!ferror (input), 5, ends ()); /* really check type of file */ rewind (input); verbose ("testing type of file"); test_exitf (fil_sreadU32 (Block) != 0xd0cf11e0UL, 9, ends ()); test_exitf (fil_sreadU32 (Block + 0x04) != 0xa1b11ae1UL, 9, ends ()); /* read big block depot */ verbose ("read big block depot (bbd)"); num_bbd_blocks = fil_sreadU32 (Block + 0x2c); num_xbbd_blocks = fil_sreadU32 (Block + 0x48); verboseU32 (num_bbd_blocks); verboseU32 (num_xbbd_blocks); BDepot = (U8 *) malloc (0x0200 * (num_bbd_blocks + num_xbbd_blocks)); test_exitf (BDepot != NULL, 10, ends ()); *_BDepot = BDepot; s = BDepot; assert (num_bbd_blocks <= (0x0200 / 4 - 1) * num_xbbd_blocks + (0x0200 / 4) - 19); /* the first 19 U32 in header does not belong to bbd_list */ for (i = 0; i < MIN (num_bbd_blocks, 0x0200 / 4 - 19); i++) { /* note: next line may be needed to be cast to long in right side */ FilePos = 0x0200 * (1 + fil_sreadU32 (Block + 0x4c + (i * 4))); assert (FilePos >= 0); test_exitf (!fseek (input, FilePos, SEEK_SET), 5, ends ()); fread (s, 0x0200, 1, input); test_exitf (!ferror (input), 5, ends ()); s += 0x0200; } Blockx = (U8 *) malloc (0x0200); test_exitf (Blockx != NULL, 10, ends ()); bl = fil_sreadU32 (Block + 0x44); for (i = 0; i < num_xbbd_blocks; i++) { FilePos = 0x0200 * (1 + bl); assert (FilePos >= 0); test_exitf (!fseek (input, FilePos, SEEK_SET), 5, ends ()); fread (Blockx, 0x0200, 1, input); test_exitf (!ferror (input), 5, ends ()); for (j=0; j < 0x0200 / 4 - 1;j++) /* last U32 is for the next bl */ { if (fil_sreadU32 (Blockx + (j * 4)) == 0xfffffffeUL || fil_sreadU32 (Blockx + (j * 4)) == 0xfffffffdUL || fil_sreadU32 (Blockx + (j * 4)) == 0xffffffffUL) break; /* note: next line may be needed to be cast to long in right side */ FilePos = 0x0200 * (1 + fil_sreadU32 (Blockx + (j * 4))); assert (FilePos >= 0); test_exitf (!fseek (input, FilePos, SEEK_SET), 5, ends ()); fread (s, 0x0200, 1, input); test_exitf (!ferror (input), 5, ends ()); s += 0x0200; } bl = fil_sreadU32 (Blockx + 0x0200 - 4); } verboseU8Array (BDepot, (num_bbd_blocks+num_xbbd_blocks), 0x0200); /* extract the sbd block list */ verbose ("extract small block depot (sbd) block list"); sbd_list = (U32 *) malloc (ENTRYCHUNK * 4); test_exitf (sbd_list != NULL, 10, ends ()); sbd_list[0] = fil_sreadU32 (Block + 0x3c); /* -2 signed long int == 0xfffffffe unsinged long int */ for (len = 1; sbd_list[len - 1] != 0xfffffffeUL; len++) { test_exitf (len != 0, 5, ends ()); /* means file is too big */ /* if memory allocated in sbd_list is all used, allocate more memory */ if (!(len % ENTRYCHUNK)) { U32 *newspace; newspace = realloc (sbd_list, (1 + len / ENTRYCHUNK) * ENTRYCHUNK * 4); test_exitf (newspace != NULL, 10, ends ()); sbd_list = newspace; } sbd_list[len] = fil_sreadU32 (BDepot + (sbd_list[len - 1] * 4)); /*verboseU32 (len);*/ /*verboseU32 (sbd_list[0]);*/ /*verboseU32 (sbd_list[1]);*/ if (sbd_list[len] != 0xfffffffeUL) test_exitf (sbd_list[len] <= num_bbd_blocks * 0x0200 - 4, 5, ends ()); test_exitf (sbd_list[len] != 0xfffffffdUL && sbd_list[len] != 0xffffffffUL, 5, ends ()); } len--; verboseU32Array (sbd_list, len+1); /* read in small block depot, if there's any small block */ if (len == 0) { SDepot = NULL; verbose ("not read small block depot (sbd): there's no small blocks"); } else { verbose ("read small block depot (sbd)"); SDepot = (U8 *) malloc (0x0200 * len); test_exitf (SDepot != NULL, 10, ends ()); s = SDepot; for (i = 0; i < len; i++) { FilePos = 0x0200 * (1 + sbd_list[i]); assert (FilePos >= 0); test_exitf (!fseek (input, FilePos, SEEK_SET), 5, ends ()); fread (s, 0x0200, 1, input); test_exitf (!ferror (input), 5, ends ()); s += 0x200; } verboseU8Array (SDepot, len, 0x0200); } *_SDepot = SDepot; /* extract the root block list */ verbose ("extract root block depot (root) block list"); root_list = (U32 *) malloc (ENTRYCHUNK * 4); test_exitf (root_list != NULL, 10, ends ()); root_list[0] = fil_sreadU32 (Block + 0x30); for (len = 1; root_list[len - 1] != 0xfffffffeUL; len++) { test_exitf (len != 0, 5, ends ()); /* means file is too long */ /* if memory allocated in root_list is all used, allocate more memory */ if (!(len % ENTRYCHUNK)) { U32 *newspace; newspace = realloc (root_list, (1 + len / ENTRYCHUNK) * ENTRYCHUNK * 4); test_exitf (newspace != NULL, 10, ends ()); root_list = newspace; } root_list[len] = fil_sreadU32 (BDepot + (root_list[len - 1] * 4)); test_exitf (root_list[len] != 0xfffffffdUL && root_list[len] != 0xffffffffUL, 5, ends ()); } len--; verboseU32Array (root_list, len+1); /* read in root block depot */ verbose ("read in root block depot (Root)"); Root = (U8 *) malloc (0x0200 * len); test_exitf (Root != NULL, 10, ends ()); s = Root; for (i = 0; i < len; i++) { FilePos = 0x0200 * (root_list[i] + 1); assert (FilePos >= 0); test_exitf (!fseek (input, FilePos, SEEK_SET), 5, ends ()); fread (s, 0x0200, 1, input); test_exitf (!ferror (input), 5, ends ()); s += 0x200; } verboseU8Array (Root, len, 0x0200); /* assign space for pps list */ verbose ("read pps list"); num_of_pps = len * 4; /* each sbd block have 4 pps */ *stream_list = pps_list = (pps_entry *)malloc(num_of_pps*sizeof(pps_entry)); test_exitf (pps_list != NULL, 10, ends ()); /* read pss entry details and look out for "Root Entry" */ verbose ("read pps entry details"); for (i = 0; i < num_of_pps; i++) { U16 size_of_name; s = Root + (i * 0x80); /* read the number */ pps_list[i].ppsnumber = i; /* read the name */ size_of_name = (U16)MIN (0x40, fil_sreadU16 (s + 0x40)); pps_list[i].name[0] = 0; if (size_of_name == 0) continue; for (p = (U8 *) pps_list[i].name, t = s; t < s + size_of_name; t++) *p++ = *t++; /* makes visible the non printable first character */ /* if (!isprint (pps_list[i].name[0]) && pps_list[i].name[0]) pps_list[i].name[0] += 'a'; */ /* read the pps type */ pps_list[i].type = *(s + 0x42); if (pps_list[i].type == 5) { assert (i == 0); *root = i; /* this pps is the root */ } /* read the others fields */ pps_list[i].previous = fil_sreadU32 (s + 0x44); pps_list[i].next = fil_sreadU32 (s + 0x48); pps_list[i].dir = fil_sreadU32 (s + 0x4c); pps_list[i].start = fil_sreadU32 (s + 0x74); pps_list[i].size = fil_sreadU32 (s + 0x78); pps_list[i].seconds1 = fil_sreadU32 (s + 0x64); pps_list[i].seconds2 = fil_sreadU32 (s + 0x6c); pps_list[i].days1 = fil_sreadU32 (s + 0x68); pps_list[i].days2 = fil_sreadU32 (s + 0x70); } /* NEXT IS VERBOSE verbose */#ifdef VERBOSE { U32 i; printf ("before reorder pps tree\n"); printf ("pps type prev next dir start level size name\n"); for (i = 0; i < num_of_pps; i++) { if (!pps_list[i].name[0]) { printf (" -\n"); continue; } printf ("%08lx ", pps_list[i].ppsnumber); printf ("%d ", pps_list[i].type); printf ("%08lx ", pps_list[i].previous); printf ("%08lx ", pps_list[i].next); printf ("%08lx ", pps_list[i].dir); printf ("%08lx ", pps_list[i].start); printf ("%04x ", pps_list[i].level); printf ("%08lx ", pps_list[i].size); printf ("'%c", !isprint (pps_list[i].name[0]) ? ' ' : pps_list[i].name[0]); printf ("%s'\n", pps_list[i].name+1); } }#endif /* go through the tree made with pps entries, and reorder it so only the next link is used (move the previous-link-children to the last visited next-link-children) */ test_exitf (reorder_pps_tree (&pps_list[*root], 0), 9, ends ()); /* NEXT IS VERBOSE verbose */#ifdef VERBOSE { U32 i; printf ("after reorder pps tree\n"); printf ("pps type prev next dir start level size name\n"); for (i = 0; i < num_of_pps; i++) { if (!pps_list[i].name[0]) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -