clamav/sigtool/vba.c
Micah Snyder 621381e0cd Allmatch-mode overhaul, part 1: append_virus
Rework the append_virus mechanism to store evidence (strong indicators,
pua indicators, and eventually weak indicators) in vectors. When
appending a "virus", we will return CLEAN when in allmatch-mode, and
simply add the indicator to the appropriate vector.
Later we can check if there were any alerts to return a vector by
summing the lengths of the strong and pua indicator vectors.

This does away with storing the latest "virname" in the scan context.
Instead, we can query for the last indicator in the evidence, giving
priority to strong indicators.

When heuristic-precendence is enabled, add PUA as Strong instead of
as PotentiallyUnwanted. This way, they will be treated equally and
reported in order in allmatch mode.

Also document reason for disabling cache with metadata JSON enabled
2022-10-19 13:13:57 -07:00

1362 lines
42 KiB
C

/*
* Copyright (C) 2004 Trog <trog@uncon.org>
*
* 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., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
// libclamav
#include "clamav.h"
#include "vba_extract.h"
#include "ole2_extract.h"
#include "readdb.h"
#include "clamav_rust.h"
// common
#include "output.h"
#include "vba.h"
typedef struct mac_token_tag {
unsigned char token;
const char *str;
} mac_token_t;
typedef struct mac_token2_tag {
uint16_t token;
const char *str;
} mac_token2_t;
cli_ctx *convenience_ctx(int fd)
{
cl_error_t status = CL_EMEM;
cli_ctx *ctx = NULL;
struct cl_engine *engine = NULL;
cl_fmap_t *new_map = NULL;
/* build engine */
engine = cl_engine_new();
if (NULL == engine) {
printf("convenience_ctx: engine initialization failed\n");
goto done;
}
cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
if (cli_initroots(engine, 0) != CL_SUCCESS) {
printf("convenience_ctx: cli_initroots() failed\n");
goto done;
}
if (cli_add_content_match_pattern(engine->root[0], "test", "deadbeef", 0, 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
printf("convenience_ctx: Can't parse signature\n");
goto done;
}
if (CL_SUCCESS != cl_engine_compile(engine)) {
printf("convenience_ctx: failed to compile engine.");
goto done;
}
/* fake input fmap */
new_map = fmap(fd, 0, 0, NULL);
if (NULL == new_map) {
printf("convenience_ctx: fmap failed\n");
goto done;
}
/* prepare context */
ctx = cli_calloc(1, sizeof(cli_ctx));
if (!ctx) {
printf("convenience_ctx: ctx allocation failed\n");
goto done;
}
ctx->engine = (const struct cl_engine *)engine;
ctx->evidence = evidence_new();
ctx->dconf = (struct cli_dconf *)engine->dconf;
ctx->recursion_stack_size = ctx->engine->max_recursion_level;
ctx->recursion_stack = cli_calloc(sizeof(recursion_level_t), ctx->recursion_stack_size);
if (!ctx->recursion_stack) {
status = CL_EMEM;
goto done;
}
// ctx was calloc'd, so recursion_level starts at 0.
ctx->recursion_stack[ctx->recursion_level].fmap = new_map;
ctx->recursion_stack[ctx->recursion_level].type = CL_TYPE_ANY; // ANY for the top level, because we don't yet know the type.
ctx->recursion_stack[ctx->recursion_level].size = new_map->len;
ctx->fmap = ctx->recursion_stack[ctx->recursion_level].fmap;
ctx->options = cli_calloc(1, sizeof(struct cl_scan_options));
if (!ctx->options) {
printf("convenience_ctx: scan options allocation failed\n");
goto done;
}
ctx->options->general |= CL_SCAN_GENERAL_HEURISTICS;
ctx->options->parse = ~(0);
status = CL_SUCCESS;
done:
if (CL_SUCCESS != status) {
if (NULL != new_map) {
funmap(new_map);
}
if (NULL != ctx) {
if (NULL != ctx->options) {
free(ctx->options);
}
if (NULL != ctx->recursion_stack) {
free(ctx->recursion_stack);
}
free(ctx);
ctx = NULL;
}
if (NULL != engine) {
cl_engine_free(engine);
}
}
return ctx;
}
void destroy_ctx(cli_ctx *ctx)
{
if (NULL != ctx) {
if (NULL != ctx->recursion_stack) {
/* Clean up any fmaps */
while (ctx->recursion_level > 0) {
if (NULL != ctx->recursion_stack[ctx->recursion_level].fmap) {
funmap(ctx->recursion_stack[ctx->recursion_level].fmap);
ctx->recursion_stack[ctx->recursion_level].fmap = NULL;
}
ctx->recursion_level -= 1;
}
if (NULL != ctx->recursion_stack[0].fmap) {
funmap(ctx->recursion_stack[0].fmap);
ctx->recursion_stack[0].fmap = NULL;
}
free(ctx->recursion_stack);
ctx->recursion_stack = NULL;
}
if (NULL != ctx->engine) {
cl_engine_free((struct cl_engine *)ctx->engine);
ctx->engine = NULL;
}
if (NULL != ctx->options) {
free(ctx->options);
ctx->options = NULL;
}
if (NULL != ctx->evidence) {
evidence_free(ctx->evidence);
}
free(ctx);
}
}
int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U);
static char *get_unicode_name(char *name, int size)
{
int i, j;
char *newname;
if (*name == 0 || size <= 0) {
return NULL;
}
newname = (char *)malloc(size * 2);
if (!newname) {
return NULL;
}
j = 0;
for (i = 0; i < size; i = i + 2) {
if (isprint(name[i])) {
newname[j++] = name[i];
} else {
if (name[i] < 10 && name[i] >= 0) {
newname[j++] = '_';
newname[j++] = name[i] + '0';
}
newname[j++] = '_';
}
}
newname[j] = '\0';
return newname;
}
static void output_token(unsigned char token)
{
int i;
mac_token_t mac_token[] = {
{0x01, "-"},
{0x02, "Not"},
{0x03, "And"},
{0x04, "Or"},
{0x05, "("},
{0x06, ")"},
{0x07, "+"},
{0x08, "-"},
{0x09, "/"},
{0x0a, "*"},
{0x0b, "Mod"},
{0x0c, "="},
{0x0d, "<>"},
{0x0e, "<"},
{0x0f, ">"},
{0x10, "<="},
{0x11, ">="},
{0x12, ","},
{0x18, "Resume"},
{0x19, ":"},
{0x1a, "End"},
{0x1b, "Sub"},
{0x1c, "Function"},
{0x1d, "If"},
{0x1e, "Then"},
{0x1f, "ElseIf"},
{0x20, "Else"},
{0x21, "While"},
{0x22, "Wend"},
{0x23, "For"},
{0x24, "To"},
{0x25, "Step"},
{0x26, "Next"},
{0x28, ";"},
{0x29, "Call"},
{0x2a, "Goto"},
{0x2c, "On"},
{0x2d, "Error"},
{0x2e, "Let"},
{0x2f, "Dim"},
{0x30, "Shared"},
{0x31, "Select"},
{0x32, "Is"},
{0x33, "Case"},
{0x34, "As"},
{0x35, "Redim"},
{0x36, "Print"},
{0x37, "Input"},
{0x38, "Line"},
{0x39, "Write"},
{0x3a, "Name"},
{0x3b, "Output"},
{0x3c, "Append"},
{0x3d, "Open"},
{0x3e, "GetCurValues"},
{0x3f, "Dialog"},
{0x40, "Super"},
{0x41, "Declare"},
{0x42, "Double"},
{0x43, "Integer"},
{0x44, "Long"},
{0x45, "Single"},
{0x46, "String"},
{0x47, "Cdecl"},
{0x48, "Alias"},
{0x49, "Any"},
{0x4a, "ToolsGetSpelling"},
{0x4b, "ToolsGetSynonyms"},
{0x4c, "Close"},
{0x4d, "Begin"},
{0x4e, "Lib"},
{0x4f, "Read"},
{0x50, "CheckDialog"},
{0x51, " "}, /* not sure about this one - some white space */
{0x52, "\t"},
{0x54, "EndIf"},
{0x64, "\n"},
{0x71, "#"},
{0x72, "\\"},
{0x00, NULL},
};
for (i = 0; mac_token[i].token != 0x00; i++) {
if (token == mac_token[i].token) {
printf(" %s ", mac_token[i].str);
return;
}
}
printf("[#0x%x]", token);
return;
}
static void output_token67(uint16_t token)
{
int i;
mac_token2_t mac_token[] = {
{0x0004, "HelpActivateWindow"},
{0x0009, "HelpAbout"},
{0x000c, "ShrinkFont"},
{0x0016, "NextWindow"},
{0x0017, "PrevWindow"},
{0x001c, "DeleteWord"},
{0x001e, "EditClear"},
{0x0045, "GoBack"},
{0x0046, "SaveTemplate"},
{0x0048, "Cancel"},
{0x004e, "DocumentStatistics"},
{0x004f, "FileNew"},
{0x0050, "FileOpen"},
{0x0053, "FileSave"},
{0x0054, "FileSaveAs"},
{0x0056, "FileSummaryInfo"},
{0x0057, "FileTemplates"},
{0x0058, "FilePrint"},
{0x0061, "FilePrintSetup"},
{0x0063, "FileFind"},
{0x006c, "EditCut"},
{0x006d, "EditCopy"},
{0x006e, "EditPaste"},
{0x0070, "EditFind"},
{0x0074, "EditFindClearFormatting"},
{0x0075, "EditReplace"},
{0x0079, "EditReplaceClearFormatting"},
{0x007a, "EditGoTo"},
{0x007b, "EditAutoText"},
{0x0093, "ViewPage"},
{0x0098, "ToolsCustomize"},
{0x009b, "NormalViewHeaderArea"},
{0x009f, "InsertBreak"},
{0x00a2, "InsertSymbol"},
{0x00a4, "InsertFile"},
{0x00a8, "EditBookmark"},
{0x00ac, "InsertObject"},
{0x00ae, "FormatFont"},
{0x00af, "FormatParagraph"},
{0x00b2, "FilePageSetup"},
{0x00bf, "ToolsSpelling"},
{0x00ca, "ToolsOptions"},
{0x00cc, "ToolsOptionsView"},
{0x00cb, "ToolsOptionsGeneral"},
{0x00d1, "ToolsOptionsSave"},
{0x00d3, "ToolsOptionsSpelling"},
{0x00d5, "ToolsOptionsUserInfo"},
{0x00d7, "ToolsMacro"},
{0x00de, "Organizer"},
{0x00e1, "ToolsOptionsFileLocations"},
{0x00e4, "ToolsWordCount"},
{0x00e9, "DocRestore"},
{0x00ed, "EditSelectAll"},
{0x00f3, "ClosePane"},
{0x0129, "UserDialog"},
{0x012c, "CopyFile"},
{0x012d, "FileNewDefault"},
{0x012e, "FilePrintDefault"},
{0x0143, "ViewToolbars"},
{0x015d, "TextFormField"},
{0x0161, "FormFieldOptions"},
{0x0172, "InsertFootnote"},
{0x0179, "DrawRectangle"},
{0x017a, "ToolsAutoCorrect"},
{0x01a4, "Connect"},
{0x01a5, "WW2_EditFind"},
{0x01a6, "WW2_EditReplace"},
{0x01b0, "ToolsCustomizeKeyboard"},
{0x01b1, "ToolsCustomizeMenus"},
{0x01d2, "DrawBringToFront"},
{0x01d3, "DrawSendToBack"},
{0x01e3, "InsertFormField"},
{0x01f7, "ToolsProtectDocument"},
{0x0202, "ShrinkFontOnePoint"},
{0x0209, "ToolsUnprotectDocument"},
{0x022f, "DrawFlipHorizontal"},
{0x0235, "FormatDrawingObject"},
{0x0241, "ViewZoom"},
{0x0246, "ToogleFull"},
{0x024a, "NewToolbar"},
{0x0265, "FileSendMail"},
{0x0267, "ToolsCustomizeMenuBar"},
{0x0270, "FileRoutingSlip"},
{0x0273, "ChooseButtonImage"},
{0x027b, "HelpTipOfTheDay"},
{0x0280, "Int"},
{0x0290, "MicrosoftMail"},
{0x0299, "ScreenRefresh"},
{0x02b0, "HelpContents"},
{0x0780, "Str$"},
{0x0e80, "Rnd"},
{0x2580, "FileName$"},
{0x2b80, "MsgBox"},
{0x2c80, "Beep"},
{0x5400, "FileSaveAs"},
{0x5600, "FileSummaryInfo"},
{0x8000, "Abs"},
{0x8001, "Sgn"},
{0x8002, "Int"},
{0x8003, "Len"},
{0x8004, "Asc"},
{0x8005, "Chr$"},
{0x8006, "Val"},
{0x8007, "Str$"},
{0x8008, "Left$"},
{0x8009, "Right$"},
{0x800a, "Mid$"},
{0x800b, "String$"},
{0x800c, "Date$"},
{0x800d, "Time$"},
{0x800e, "Rnd"},
{0x800f, "InStr"},
{0x8012, "Insert"},
{0x8013, "InsertPara"},
{0x8015, "Selection$"},
{0x801b, "ExistingBookMark"},
{0x8023, "IsDocumentDirty"},
{0x8024, "SetDocumentDirty"},
{0x8025, "FileName$"},
{0x8026, "CountFiles"},
{0x8027, "GetAutoText$"},
{0x8028, "CountAutoTextEntries"},
{0x802a, "SetAutoText"},
{0x802b, "MsgBox"},
{0x802c, "Beep"},
{0x802d, "Shell"},
{0x802f, "ResetPara"},
{0x8032, "DocMove"},
{0x8033, "DocSize"},
{0x8034, "VLine"},
{0x803a, "CountWindows"},
{0x803b, "WindowName$"},
{0x803e, "Window"},
{0x8041, "AppMinimize"},
{0x8042, "AppMaximize"},
{0x8043, "AppRestore"},
{0x8044, "DocMaximize"},
{0x8045, "GetProfileString$"},
{0x8046, "SetProfileString"},
{0x8047, "CharColor"},
{0x8048, "Bold"},
{0x8049, "Italic"},
{0x804e, "UnderLine"},
{0x8053, "CenterPara"},
{0x8054, "LeftPara"},
{0x8055, "RightPara"},
{0x8056, "JustifyPara"},
{0x805c, "DDEInitiate"},
{0x805d, "DDETerminate"},
{0x8053, "DDETerminateAll"},
{0x805f, "DDEExecute"},
{0x8060, "DDEPoke"},
{0x8061, "DDERequest$"},
{0x8062, "Activate"},
{0x8063, "AppActivate"},
{0x8064, "SendKeys"},
{0x806f, "ViewStatusBar"},
{0x8071, "ViewRibbon"},
{0x8073, "ViewPage"},
{0x8075, "ViewNormal"},
{0x8079, "Overtype"},
{0x807a, "Font$"},
{0x807b, "CountOfFonts"},
{0x807c, "Font"},
{0x807d, "FontSize"},
{0x8081, "WW6_EditClear"},
{0x8082, "FileList"},
{0x8083, "File1"},
{0x8098, "ExtendSelection"},
{0x809e, "DisableInput"},
{0x809f, "DocClose"},
{0x80a0, "FileClose"},
{0x80a1, "File$"},
{0x80a2, "FileExit"},
{0x80a3, "FileSaveAll"},
{0x80a7, "Input$"},
{0x80a8, "Seek"},
{0x80a9, "Eof"},
{0x80aa, "Lof"},
{0x80ab, "Kill"},
{0x80ac, "ChDir"},
{0x80ad, "MkDir"},
{0x80ae, "RmDir"},
{0x80af, "UCase$"},
{0x80b0, "LCase$"},
{0x80b1, "InoutBox$"},
{0x80b3, "OnTime"},
{0x80b5, "AppInfo$"},
{0x80b6, "SelInfo"},
{0x80b7, "CountMacros"},
{0x80b8, "MacroName"},
{0x80b9, "CountFoundFiles"},
{0x80ba, "FoundFileName$"},
{0x80be, "MacroDesc$"},
{0x80bf, "CountKeys"},
{0x80c1, "KeyMacro$"},
{0x80c2, "MacroCopy"},
{0x80c3, "IsExecuteOnly"},
{0x80c7, "OKButton"},
{0x80c8, "CancelButton"},
{0x80c9, "Text"},
{0x80ca, "GroupBox"},
{0x80cb, "OptionButton"},
{0x80cc, "PushButton"},
{0x80d5, "ExitWindows"},
{0x80d6, "DisableAutoMacros"},
{0x80d7, "EditFindFound"},
{0x80d8, "CheckBox"},
{0x80d9, "TextBox"},
{0x80da, "ListBox"},
{0x80db, "OptionGroup"},
{0x80dc, "ComboBox"},
{0x80de, "WindowList"},
{0x80e8, "CountDirectories"},
{0x80e9, "GetDirectory$"},
{0x80ea, "LTrim$"},
{0x80eb, "RTrim$"},
{0x80ee, "Environ$"},
{0x80ef, "WaitCursor"},
{0x80f0, "DateSerial"},
{0x80f1, "DateValue"},
{0x80f2, "Day"},
{0x80f4, "Hour"},
{0x80f5, "Minute"},
{0x80f6, "Month"},
{0x80f7, "Now"},
{0x80f8, "WeekdayNow"},
{0x80f9, "Year"},
{0x80fa, "DocWindowHeight"},
{0x80fb, "DocWindowWidth"},
{0x80fc, "DOSToWIN$"},
{0x80fd, "WinToDOS$"},
{0x80ff, "Second"},
{0x8100, "TimeValue"},
{0x8101, "Today"},
{0x8103, "SetAttr"},
{0x8105, "DocMinimize"},
{0x8107, "AppActivate"},
{0x8108, "AppCount"},
{0x8109, "AppGetNames"},
{0x810a, "AppHide"},
{0x810b, "AppIsRunning"},
{0x810c, "GetSystemInfo$"},
{0x810d, "GetPrivateProfileString$"},
{0x810e, "SetPrivateProfileString"},
{0x810f, "GetAttr"},
{0x8111, "ScreenUpdating"},
{0x8116, "SelectCurWord"},
{0x8118, "IsTemplateDirty"},
{0x8119, "SetTemplateDirty"},
{0x811b, "DlgEnable"},
{0x811d, "DlgVisible"},
{0x811f, "DlgText$"},
{0x8121, "AppShow"},
{0x8122, "DlgListBoxArray"},
{0x8125, "Picture"},
{0x8126, "DlgSetPicture"},
{0x8131, "WW2_Files$"},
{0x8138, "DlgFocus"},
{0x813b, "BorderLineStyle"},
{0x813d, "MenuItemText$"},
{0x813e, "MenuItemMacro$"},
{0x813f, "CountMenus"},
{0x8140, "MenuText$"},
{0x8141, "CountMenuItems"},
{0x8145, "DocWindowPosTop"},
{0x8146, "DocWindowPosLeft"},
{0x8147, "Stop"},
{0x8148, "DropListBox"},
{0x8149, "RenameMenu"},
{0x814a, "FileCloseAll"},
{0x814b, "SortArray"},
{0x814c, "SetDocumentVar"},
{0x814d, "GetDocumentVar$"},
{0x8152, "IsMacro"},
{0x8153, "FileNameFromWindow$"},
{0x815b, "MoveToolbar"},
{0x816e, "MacID$"},
{0x8170, "GetSelEndPos"},
{0x8171, "SetSelRange"},
{0x8172, "GetText$"},
{0x8174, "DeleteButton"},
{0x8175, "AddButton"},
{0x8177, "DeleteAddIn"},
{0x8178, "AddAddIn"},
{0x8179, "GetAddInName$"},
{0x817c, "ResetButtonImage"},
{0x8180, "GetAddInId"},
{0x8181, "CountAddIns"},
{0x8182, "ClearAddIns"},
{0x8183, "AddInState"},
{0x818c, "DefaultDir$"},
{0x818d, "FileNameInfo$"},
{0x818e, "MacroFileName$"},
{0x818f, "ViewHeader"},
{0x8190, "ViewFooter"},
{0x8192, "CopyButtonImage"},
{0x8195, "CountToolbars"},
{0x8196, "ToolbarName$"},
{0x8198, "ChDefaultDir"},
{0x8199, "EditUndo"},
{0x81a0, "GetAutoCorrect$"},
{0x81a2, "FileQuit"},
{0x81a4, "FileConfirmConversions"},
{0x81d3, "SelectionFileName$"},
{0x81d9, "CountToolbarButtons"},
{0x81da, "ToolbarButtonMacro$"},
{0x81db, "WW2_Insert"},
{0x81dc, "AtEndOfDocument"},
{0x81fc, "GetDocumentProperty$"},
{0x81fd, "GetDocumentProperty"},
{0x8201, "DocumentPropertyName$"},
{0x820e, "SpellChecked"},
{0xb780, "CountMacros"},
{0xb880, "MacroName$"},
{0xc000, "CharLeft"},
{0xc001, "CharRight"},
{0xc002, "WordLeft"},
{0xc003, "WordRight"},
{0xc004, "EndOfLine"},
{0xc007, "ParaDown"},
{0xc008, "LineUp"},
{0xc009, "LineDown"},
{0xc00a, "PageUp"},
{0xc00c, "StartOfLine"},
{0xc00d, "EndOfLine"},
{0xc010, "StartOfDocument"},
{0xc011, "EndOfDocument"},
{0xc012, "EditClear"},
{0xc024, "BorderTop"},
{0xc025, "BorderLeft"},
{0xc026, "BorderBottom"},
{0xc027, "BorderRight"},
{0xc280, "MacroCopy"},
{0x0000, NULL},
};
for (i = 0; mac_token[i].token != 0x0000; i++) {
if (token == mac_token[i].token) {
printf("%s", mac_token[i].str);
return;
}
}
printf("[#67(0x%x)]", token);
return;
}
static void output_token73(uint16_t token)
{
int i;
mac_token2_t mac_token[] = {
{0x0001, ".Name"},
{0x0002, ".KeyCode"},
{0x0003, ".Context"},
{0x0004, ".ResetAll"},
{0x0007, ".Menu"},
{0x0008, ".MenuText"},
{0x0009, ".APPUSERNAME"},
{0x000b, ".Delete"},
{0x000c, ".Sort"},
{0x0012, ".SavedBy"},
{0x0014, ".DateCreatedFrom"},
{0x0015, ".DateCreatedTo"},
{0x0016, ".DateSavedFrom"},
{0x0017, ".DateSavedTo"},
{0x0020, ".ButtonFieldClicks"},
{0x0021, ".Font"},
{0x0022, ".Points"},
{0x0023, ".Color"},
{0x0024, ".Bold"},
{0x0025, ".Italic"},
{0x0027, ".Hidden"},
{0x0028, ".Underline"},
{0x0029, ".Outline"},
{0x002b, ".Position"},
{0x002d, ".Spacing"},
{0x002f, ".Printer"},
{0x0034, ".AutoSave"},
{0x0035, ".Units"},
{0x0036, ".Pagination"},
{0x0037, ".SummaryPrompt"},
{0x0039, ".Initials"},
{0x003a, ".Tabs"},
{0x003b, ".Spaces"},
{0x003c, ".Paras"},
{0x003d, ".Hyphens"},
{0x003e, ".ShowAll"},
{0x0041, ".TextBoundaries"},
{0x0043, ".VScroll"},
{0x0046, ".PageWidth"},
{0x0047, ".PageHeight"},
{0x0049, ".TopMargin"},
{0x004a, ".BottomMargin"},
{0x004b, ".LeftMargin"},
{0x004c, ".RightMargin"},
{0x0052, ".Template"},
{0x0059, ".RecentFileCount"},
{0x005d, ".SmallCaps"},
{0x0060, ".Password"},
{0x0061, ".RecentFiles"},
{0x0062, ".Title"},
{0x0063, ".Subject"},
{0x0064, ".Author"},
{0x0065, ".Keywords"},
{0x0066, ".Comments"},
{0x0067, ".FileName"},
{0x0068, ".Directory"},
{0x0069, ".CreateDate"},
{0x006a, ".LastSavedDate"},
{0x006b, ".LastSavedBy"},
{0x006c, ".RevisionNumber"},
{0x006f, ".NumPages"},
{0x0070, ".NumWords"},
{0x0071, ".NumChars"},
{0x0074, ".Rename"},
{0x0075, ".NewName"},
{0x0078, ".SmartQuotes"},
{0x007f, ".Source"},
{0x0080, ".Reference"},
{0x0085, ".Insert"},
{0x0086, ".Destination"},
{0x0087, ".Type"},
{0x0089, ".HeaderDistance"},
{0x008a, ".FooterDistance"},
{0x008b, ".FirstPage"},
{0x008c, ".OddAndEvenPages"},
{0x0091, ".Entry"},
{0x0092, ".Range"},
{0x0095, ".Link"},
{0x0098, ".Add"},
{0x009b, ".NewTemplate"},
{0x009f, ".ReadOnly"},
{0x00a1, ".LeftIndent"},
{0x00a2, ".RightIndent"},
{0x00a3, ".FirstIndent"},
{0x00a5, ".After"},
{0x00b9, ".NumCopies"},
{0x00ba, ".From"},
{0x00bb, ".To"},
{0x00cb, ".Format"},
{0x00cd, ".Replace"},
{0x00ce, ".WholeWord"},
{0x00cf, ".MatchCase"},
{0x00d7, ".CreateBackup"},
{0x00d8, ".LockAnnot"},
{0x00d9, ".Direction"},
{0x00ff, ".SuggestFromMainDictOnly"},
{0x012b, ".UpdateLinks"},
{0x012e, ".Update"},
{0x0131, ".Text"},
{0x0136, ".Description"},
{0x0139, ".Setting"},
{0x013b, ".AllCaps"},
{0x0148, ".Category"},
{0x0149, ".ConfirmConversions"},
{0x014c, ".StatusBar"},
{0x014d, ".PicturePlaceHolders"},
{0x014e, ".FieldCodes"},
{0x0150, ".Show"},
{0x0156, ".FastSaves"},
{0x0157, ".SaveInterval"},
{0x0161, ".LineColor"},
{0x017d, ".Wrap"},
{0x0183, ".AutoFit"},
{0x0184, ".CharNum"},
{0x018b, ".View"},
{0x0190, ".Options"},
{0x0194, ".Find"},
{0x0196, ".Path"},
{0x01a8, ".Background"},
{0x01a9, ".SearchPath"},
{0x01ab, ".CustomDict1"},
{0x01ac, ".CustomDict2"},
{0x01ad, ".CustomDict3"},
{0x01ae, ".CustomDict4"},
{0x01b1, ".Collate"},
{0x01b2, ".Shadow"},
{0x01b4, ".Button"},
{0x01b9, ".Remove"},
{0x01ba, ".Protect"},
{0x01d7, ".Store"},
{0x01da, ".Class"},
{0x01de, ".Hide"},
{0x01df, ".Toolbar"},
{0x01e0, ".ReplaceAll"},
{0x01eb, ".Address"},
{0x01f4, ".SelectedFile"},
{0x01f5, ".Run"},
{0x01f6, ".Edit"},
{0x0218, ".LastSaved"},
{0x0219, ".Revision"},
{0x021c, ".Pages"},
{0x021d, ".Words"},
{0x0232, ".WPHelp"},
{0x0233, ".WPDocNavKeys"},
{0x0234, ".SetDesc"},
{0x023d, ".CountFootNodes"},
{0x0255, ".AddToMru"},
{0x0262, ".NoteTypes"},
{0x0272, ".With"},
{0x0275, ".CustoDict5"},
{0x0276, ".CustoDict6"},
{0x0277, ".CustoDict7"},
{0x0278, ".CustoDict8"},
{0x0279, ".CustoDict9"},
{0x027a, ".CustoDict10"},
{0x027e, ".ErrorBeeps"},
{0x0285, ".Goto"},
{0x0287, ".Copy"},
{0x028e, ".Caption"},
{0x0299, ".AddBelow"},
{0x02a4, ".Effects3d"},
{0x02ac, ".MenuType"},
{0x02ad, ".DraftFont"},
{0x02af, ".WrapToWindow"},
{0x02b0, ".Drawings"},
{0x02c0, ".NumLines"},
{0x02c6, ".SuperScript"},
{0x02c7, ".Subscript"},
{0x02c8, ".WritePassword"},
{0x02c9, ".RecommendReadOnly"},
{0x02ca, ".DocumentPassword"},
{0x02d5, ".HelpText"},
{0x02d6, ".InsertAs"},
{0x02dc, ".Formatting"},
{0x02de, ".InitialCaps"},
{0x02df, ".SentenceCaps"},
{0x02e0, ".Days"},
{0x02e1, ".ReplaceText"},
{0x02e4, ".Product"},
{0x02f1, ".SoundsLike"},
{0x02f2, ".KerningMin"},
{0x02f3, ".PatternMatch"},
{0x0308, ".EmbedFonts"},
{0x030a, ".Width"},
{0x030b, ".Height"},
{0x0316, ".SendMailAttach"},
{0x0318, ".Kerning"},
{0x0319, ".Exit"},
{0x031a, ".Enable"},
{0x031b, ".OwnHelp"},
{0x031c, ".OwnStat"},
{0x031d, ".StatText"},
{0x031e, ".FormsData"},
{0x0320, ".BookMarks"},
{0x0327, ".LinkStyles"},
{0x032a, ".Message"},
{0x032d, ".AllAtOnce"},
{0x032f, ".TrackStatus"},
{0x0330, ".FillColor"},
{0x0332, ".FillPatternColor"},
{0x033a, ".RoundCorners"},
{0x0349, ".TextType"},
{0x0353, ".TextWidth"},
{0x0354, ".TextDefault"},
{0x0355, ".TextFormat"},
{0x0366, ".SearchName"},
{0x0370, ".BlueScreen"},
{0x0377, ".ListBy"},
{0x0378, ".SubDir"},
{0x0388, ".HorizontalPos"},
{0x0389, ".HorizontalFrom"},
{0x038a, ".VerticalPos"},
{0x038b, ".VerticalFrom"},
{0x038f, ".Tab"},
{0x039a, ".Strikethrough"},
{0x039b, ".Face"},
{0x039d, ".NativePictureFormat"},
{0x039e, ".FileSize"},
{0x03a2, ".LineType"},
{0x03a4, ".DisplayIcon"},
{0x03a8, ".IconFilename"},
{0x03a9, ".IconNumber"},
{0x03ac, ".GlobalDotPrompt"},
{0x03b2, ".NoReset"},
{0x03db, ".SaveAsAOCELetter"},
{0x041b, ".CapsLock"},
{0x0422, ".FindAllWordForms"},
{0x045e, ".VirusProtection"},
{0x6200, ".Title"},
{0x6300, ".Subject"},
{0x6400, ".Author"},
{0x6500, ".Keywords"},
{0x6600, ".Comments"},
{0xcb00, ".Format"},
{0x0000, NULL},
};
for (i = 0; mac_token[i].token != 0x0000; i++) {
if (token == mac_token[i].token) {
printf("%s", mac_token[i].str);
return;
}
}
printf("[#73(0x%x)]", token);
return;
}
static void print_hex_buff(unsigned char *start, unsigned char *end, int hex_output)
{
if (!hex_output) {
return;
}
printf("[clam hex:");
while (start < end) {
printf(" %.2x", *start);
start++;
}
printf("]\n");
}
#ifdef __GNUC__
static void wm_decode_macro(unsigned char *buff, uint32_t len, int hex_output) __attribute__((unused));
#endif
static void wm_decode_macro(unsigned char *buff, uint32_t len, int hex_output)
{
uint32_t i;
uint8_t s_length, j;
uint16_t w_length, int_val;
unsigned char *tmp_buff, *tmp_name, *line_start;
i = 2;
line_start = buff;
while (i < len) {
switch (buff[i]) {
case 0x65:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
print_hex_buff(line_start, buff + i + 2 + s_length, hex_output);
printf("\n%s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
line_start = buff + i;
break;
case 0x69:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf(" %s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x6a:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf(" \"%s\"", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x6b:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf(" '%s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x6d:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf(" %s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x70:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf("REM%s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x76:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf(" .%s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x77:
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc(s_length + 1);
strncpy((char *)tmp_buff, (char *)(buff + i + 2), s_length);
tmp_buff[s_length] = '\0';
printf("%s", tmp_buff);
free(tmp_buff);
i += 2 + s_length;
break;
case 0x79: /* unicode "string" */
w_length = (uint16_t)(buff[i + 2] << 8) + buff[i + 1];
tmp_buff = (unsigned char *)malloc((w_length * 2) + 1);
memcpy(tmp_buff, buff + i + 3, w_length * 2);
tmp_name = (unsigned char *)get_unicode_name((char *)tmp_buff, w_length * 2);
free(tmp_buff);
printf("\"%s\"", tmp_name);
free(tmp_name);
i += 3 + (w_length * 2);
break;
case 0x7c: /* unicode 'string */
s_length = (uint8_t)buff[i + 1];
tmp_buff = (unsigned char *)malloc((s_length * 2) + 1);
memcpy(tmp_buff, buff + i + 2, s_length * 2);
tmp_name = (unsigned char *)get_unicode_name((char *)tmp_buff, s_length * 2);
free(tmp_buff);
printf("'%s", tmp_name);
free(tmp_name);
i += 2 + (s_length * 2);
break;
case 0x66:
int_val = (uint8_t)(buff[i + 2] << 8) + buff[i + 1];
print_hex_buff(line_start, buff + i + 3, hex_output);
printf("\n%d", int_val);
i += 3;
line_start = buff + i;
break;
case 0x67:
w_length = (uint16_t)(buff[i + 2] << 8) + buff[i + 1];
output_token67(w_length);
i += 3;
break;
case 0x68:
/* 8-byte float */
printf("(float)");
i += 9;
break;
case 0x6c:
int_val = (uint16_t)(buff[i + 2] << 8) + buff[i + 1];
printf(" %d", int_val);
i += 3;
break;
case 0x6e:
s_length = (uint8_t)buff[i + 1];
for (j = 0; j < s_length; j++) {
printf(" ");
}
i += 2;
break;
case 0x6f:
s_length = (uint8_t)buff[i + 1];
for (j = 0; j < s_length; j++) {
printf("\t");
}
i += 2;
break;
case 0x73:
w_length = (uint16_t)(buff[i + 2] << 8) + buff[i + 1];
output_token73(w_length);
i += 3;
break;
case 0x64:
print_hex_buff(line_start, buff + i + 1, hex_output);
printf("\n");
i++;
line_start = buff + i;
break;
default:
output_token(buff[i]);
i++;
break;
}
}
print_hex_buff(line_start, buff + i, hex_output);
}
static int sigtool_scandir(const char *dirname, int hex_output)
{
int status = -1;
DIR *dd = NULL;
struct dirent *dent;
STATBUF statbuf;
const char *tmpdir;
char *fname = NULL;
char *dir = NULL;
cl_error_t ret = CL_CLEAN;
int desc = -1;
cli_ctx *ctx = NULL;
int has_vba = 0, has_xlm = 0;
if ((dd = opendir(dirname)) != NULL) {
while ((dent = readdir(dd))) {
if (dent->d_ino) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
/* build the full name */
fname = (char *)cli_calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
if (!fname) {
status = -1;
goto done;
}
sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name);
/* stat the file */
if (LSTAT(fname, &statbuf) != -1) {
if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode)) {
if (sigtool_scandir(fname, hex_output)) {
status = CL_VIRUS;
goto done;
}
} else {
if (S_ISREG(statbuf.st_mode)) {
struct uniq *files = NULL;
tmpdir = cli_gettmpdir();
/* generate the temporary directory */
dir = cli_gentemp(tmpdir);
if (!dir) {
printf("cli_gentemp() failed\n");
status = -1;
goto done;
}
if (mkdir(dir, 0700)) {
printf("Can't create temporary directory %s\n", dir);
status = CL_ETMPDIR;
goto done;
}
if ((desc = open(fname, O_RDONLY | O_BINARY)) == -1) {
printf("Can't open file %s\n", fname);
status = 1;
goto done;
}
if (!(ctx = convenience_ctx(desc))) {
status = 1;
goto done;
}
if ((ret = cli_ole2_extract(dir, ctx, &files, &has_vba, &has_xlm, NULL))) {
printf("ERROR %s\n", cl_strerror(ret));
status = ret;
goto done;
}
if (has_vba && files)
sigtool_vba_scandir(dir, hex_output, files);
// Cleanup
if (desc >= 0) {
close(desc);
desc = -1;
}
destroy_ctx(ctx);
ctx = NULL;
cli_rmdirs(dir);
free(dir);
dir = NULL;
}
}
}
// Cleanup
free(fname);
fname = NULL;
}
}
}
} else {
logg(LOGG_ERROR, "Can't open directory %s.\n", dirname);
return CL_EOPEN;
}
status = 0;
done:
if (desc >= 0) {
close(desc);
}
if (NULL != dd) {
closedir(dd);
}
if (NULL != ctx) {
destroy_ctx(ctx);
}
if (NULL != dir) {
cli_rmdirs(dir);
free(dir);
}
if (NULL != fname) {
free(fname);
}
return status;
}
int sigtool_vba_scandir(const char *dirname, int hex_output, struct uniq *U)
{
cl_error_t status = CL_CLEAN;
cl_error_t ret;
int i, fd;
size_t data_len;
vba_project_t *vba_project = NULL;
DIR *dd;
struct dirent *dent;
STATBUF statbuf;
char *fullname, vbaname[1024], *hash;
unsigned char *data;
uint32_t hashcnt;
unsigned int j;
if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) {
logg(LOGG_ERROR, "ScanDir -> uniq_get('_vba_project') failed.\n");
return ret;
}
while (hashcnt) {
if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) {
hashcnt--;
continue;
}
for (i = 0; i < vba_project->count; i++) {
for (j = 0; j < vba_project->colls[i]; j++) {
snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", vba_project->dir, vba_project->name[i], j);
vbaname[sizeof(vbaname) - 1] = '\0';
fd = open(vbaname, O_RDONLY | O_BINARY);
if (fd == -1) continue;
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
close(fd);
if (data) {
data = (unsigned char *)realloc(data, data_len + 1);
data[data_len] = '\0';
printf("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data);
free(data);
}
}
}
cli_free_vba_project(vba_project);
vba_project = NULL;
hashcnt--;
}
if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) {
logg(LOGG_ERROR, "ScanDir -> uniq_get('powerpoint document') failed.\n");
return ret;
}
while (hashcnt) {
snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
fd = open(vbaname, O_RDONLY | O_BINARY);
if (fd == -1) {
hashcnt--;
continue;
}
if ((fullname = cli_ppt_vba_read(fd, NULL))) {
sigtool_scandir(fullname, hex_output);
cli_rmdirs(fullname);
free(fullname);
}
close(fd);
hashcnt--;
}
if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) {
logg(LOGG_ERROR, "ScanDir -> uniq_get('worddocument') failed.\n");
return ret;
}
while (hashcnt) {
snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
fd = open(vbaname, O_RDONLY | O_BINARY);
if (fd == -1) {
hashcnt--;
continue;
}
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
close(fd);
hashcnt--;
continue;
}
for (i = 0; i < vba_project->count; i++) {
data_len = vba_project->length[i];
data = (unsigned char *)cli_wm_decrypt_macro(fd, vba_project->offset[i], (uint32_t)data_len, vba_project->key[i]);
if (data) {
data = (unsigned char *)realloc(data, data_len + 1);
data[data_len] = '\0';
printf("-------------- start of code ------------------\n%s\n-------------- end of code ------------------\n", data);
free(data);
}
}
close(fd);
cli_free_vba_project(vba_project);
vba_project = NULL;
hashcnt--;
}
if ((dd = opendir(dirname)) != NULL) {
while ((dent = readdir(dd))) {
if (dent->d_ino) {
if (strcmp(dent->d_name, ".") && strcmp(dent->d_name, "..")) {
/* build the full name */
fullname = calloc(strlen(dirname) + strlen(dent->d_name) + 2, sizeof(char));
sprintf(fullname, "%s" PATHSEP "%s", dirname, dent->d_name);
/* stat the file */
if (LSTAT(fullname, &statbuf) != -1) {
if (S_ISDIR(statbuf.st_mode) && !S_ISLNK(statbuf.st_mode))
sigtool_vba_scandir(fullname, hex_output, U);
}
free(fullname);
}
}
}
} else {
logg(LOGG_ERROR, "ScanDir -> Can't open directory %s.\n", dirname);
return CL_EOPEN;
}
closedir(dd);
return status;
}