mirror of https://github.com/Cisco-Talos/clamav
Merge f06e72ed02 into c73755d3fc
commit
cd4b957f54
@ -1,275 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2020-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
||||||
* |
|
||||||
* 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. |
|
||||||
*/ |
|
||||||
|
|
||||||
/*
|
|
||||||
* This example demonstrates using callbacks to record information about each |
|
||||||
* file found during a recursive scan. |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <stdbool.h> |
|
||||||
#include <string.h> |
|
||||||
#ifndef _WIN32 |
|
||||||
#include <unistd.h> |
|
||||||
#endif |
|
||||||
#include <sys/types.h> |
|
||||||
#include <sys/stat.h> |
|
||||||
#include <fcntl.h> |
|
||||||
|
|
||||||
#include <clamav.h> |
|
||||||
|
|
||||||
#ifndef MIN |
|
||||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
|
||||||
#endif |
|
||||||
#ifndef MAX |
|
||||||
#define MAX(a, b) (((a) > (b)) ? (a) : (b)) |
|
||||||
#endif |
|
||||||
|
|
||||||
/** Max # of bytes to show for archive inspection preview */ |
|
||||||
#define MAX_PREVIEW 10 |
|
||||||
|
|
||||||
cl_error_t inspection_callback( |
|
||||||
int fd, |
|
||||||
const char *type, |
|
||||||
const char **ancestors, // array of null-terminated strings, array size == recursion_level
|
|
||||||
size_t parent_file_size, |
|
||||||
const char *file_name, |
|
||||||
size_t file_size, |
|
||||||
const char *file_buffer, |
|
||||||
uint32_t recursion_level, |
|
||||||
uint32_t attributes, // E.g.: was normalized, decrypted, etc. See LAYER_ATTRIBUTES_* flags in clamav.h
|
|
||||||
void *context) // Could be used to retrieve / store contextual information for app
|
|
||||||
{ |
|
||||||
size_t i = 0; |
|
||||||
|
|
||||||
// printf("Message: %s\n", (char *)context.blah);
|
|
||||||
UNUSEDPARAM(context); |
|
||||||
|
|
||||||
printf("ancestors: "); |
|
||||||
for (i = 0; i < recursion_level; i++) { |
|
||||||
printf("%s", ancestors[i]); |
|
||||||
if (i + 1 < recursion_level) { |
|
||||||
printf(" > "); |
|
||||||
} |
|
||||||
} |
|
||||||
printf("\n"); |
|
||||||
printf("parent size: %zu\n", parent_file_size); |
|
||||||
printf("file name: %s\n", file_name); |
|
||||||
printf("file desc: %d\n", fd); |
|
||||||
printf("file size: %zu\n", file_size); |
|
||||||
printf("file type: %s\n", type); |
|
||||||
printf("recursion level: %u\n", recursion_level); |
|
||||||
printf("decrypted: %s\n", attributes & LAYER_ATTRIBUTES_DECRYPTED ? "yes" : "no"); |
|
||||||
printf("normalized: %s\n", attributes & LAYER_ATTRIBUTES_NORMALIZED ? "yes" : "no"); |
|
||||||
printf("file preview: "); |
|
||||||
for (i = 0; i < MIN(file_size, MAX_PREVIEW); i++) { |
|
||||||
uint8_t byte = file_buffer[i]; |
|
||||||
printf("%02x ", byte); |
|
||||||
} |
|
||||||
printf("\n\n"); |
|
||||||
|
|
||||||
return CL_CLEAN; /* keep scanning */ |
|
||||||
} |
|
||||||
|
|
||||||
cl_error_t post_callback( |
|
||||||
int fd, |
|
||||||
int result, |
|
||||||
const char *virname, |
|
||||||
void *context) // Could be used to retrieve / store contextual information for app
|
|
||||||
{ |
|
||||||
(void)fd; |
|
||||||
(void)context; |
|
||||||
|
|
||||||
printf("result: %d\n", result); |
|
||||||
printf("virname: %s\n", virname); |
|
||||||
printf("\n\n"); |
|
||||||
|
|
||||||
return CL_CLEAN; // respect the original result
|
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* Exit codes: |
|
||||||
* 0: clean |
|
||||||
* 1: infected |
|
||||||
* 2: error |
|
||||||
*/ |
|
||||||
|
|
||||||
int main(int argc, char **argv) |
|
||||||
{ |
|
||||||
int status = 2; |
|
||||||
cl_error_t ret = CL_ERROR; |
|
||||||
|
|
||||||
int db_fd = -1; |
|
||||||
int target_fd = -1; |
|
||||||
|
|
||||||
unsigned long int size = 0; |
|
||||||
long double mb; |
|
||||||
const char *virname; |
|
||||||
const char *filename; |
|
||||||
struct cl_engine *engine = NULL; |
|
||||||
struct cl_scan_options options; |
|
||||||
char database_filepath[256]; |
|
||||||
bool created_database = false; |
|
||||||
|
|
||||||
STATBUF st; |
|
||||||
char *mem = NULL; |
|
||||||
ssize_t bytes_read; |
|
||||||
cl_fmap_t *map = NULL; |
|
||||||
|
|
||||||
if (argc != 2) { |
|
||||||
printf("Usage: %s file\n", argv[0]); |
|
||||||
return 2; |
|
||||||
} |
|
||||||
|
|
||||||
filename = argv[1]; |
|
||||||
|
|
||||||
if ((target_fd = open(argv[1], O_RDONLY)) == -1) { |
|
||||||
printf("Can't open file %s\n", argv[1]); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
if (FSTAT(target_fd, &st)) { |
|
||||||
printf("fmap: fstat failed\n"); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
if (NULL == (mem = malloc((size_t)st.st_size))) { |
|
||||||
printf("malloc failed, buffer size: %zu\n", (size_t)st.st_size); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
bytes_read = read(target_fd, mem, (size_t)st.st_size); |
|
||||||
if (bytes_read != (ssize_t)st.st_size) { |
|
||||||
printf("read failed, buffer size: %zu\n", (size_t)st.st_size); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
map = cl_fmap_open_memory(mem, (size_t)st.st_size); |
|
||||||
|
|
||||||
if (CL_SUCCESS != (ret = cl_init(CL_INIT_DEFAULT))) { |
|
||||||
printf("Can't initialize libclamav: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
if (!(engine = cl_engine_new())) { |
|
||||||
printf("Can't create new engine\n"); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
/* Example version macro usage to determine if new feature is available */ |
|
||||||
#if defined(LIBCLAMAV_VERSION_NUM) && (LIBCLAMAV_VERSION_NUM >= 0x090400) |
|
||||||
/* Example feature usage lowering max scan time to 15 seconds. */ |
|
||||||
cl_engine_set_num(engine, CL_ENGINE_MAX_SCANTIME, 15000); |
|
||||||
#endif |
|
||||||
cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); |
|
||||||
cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); |
|
||||||
|
|
||||||
/* load a pwdb signature, to demonstrate the "was decrypted" feature */ |
|
||||||
#define PWDB_FILENAME "./ex3.pwdb" |
|
||||||
unsigned int signo = 0; |
|
||||||
if (-1 == (db_fd = open(PWDB_FILENAME, O_CREAT | O_RDWR, 0600))) { |
|
||||||
printf("Failed to create ex3.pwdb database\n"); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
#define PWDB_SIGNATURE "SignatureName;Engine:80-1000;0;virus" |
|
||||||
if (-1 == write(db_fd, PWDB_SIGNATURE, strlen(PWDB_SIGNATURE))) { |
|
||||||
printf("Failed write to ex3.pwdb database\n"); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
if (CL_SUCCESS != (ret = cl_load(PWDB_FILENAME, engine, &signo, CL_DB_STDOPT))) { |
|
||||||
printf("Database load error: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
close(db_fd); |
|
||||||
|
|
||||||
/* build engine */ |
|
||||||
if (CL_SUCCESS != (ret = cl_engine_compile(engine))) { |
|
||||||
printf("Database initialization error: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
/* scan file descriptor */ |
|
||||||
memset(&options, 0, sizeof(struct cl_scan_options)); |
|
||||||
options.parse |= ~0; /* enable all parsers */ |
|
||||||
options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */ |
|
||||||
options.general |= CL_SCAN_GENERAL_ALLMATCHES; /* run in all-match mode, so it keeps looking for alerts after the first one */ |
|
||||||
|
|
||||||
options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED_ARCHIVE; |
|
||||||
options.heuristic |= CL_SCAN_HEURISTIC_ENCRYPTED_DOC; |
|
||||||
|
|
||||||
/*
|
|
||||||
* Set our callbacks for inspecting embedded files during the scan. |
|
||||||
*/ |
|
||||||
cl_engine_set_clcb_file_inspection(engine, &inspection_callback); |
|
||||||
/*
|
|
||||||
* Set our callbacks for inspecting embedded files during the scan. |
|
||||||
*/ |
|
||||||
cl_engine_set_clcb_post_scan(engine, &post_callback); |
|
||||||
|
|
||||||
printf("Testing file inspection on FD %d - %s\n", target_fd, filename); |
|
||||||
|
|
||||||
if (CL_VIRUS == (ret = cl_scanmap_callback( |
|
||||||
map, |
|
||||||
filename, |
|
||||||
&virname, |
|
||||||
&size, |
|
||||||
engine, |
|
||||||
&options, |
|
||||||
(void *)"Hello, World!"))) { |
|
||||||
printf("Virus detected: %s\n", virname); |
|
||||||
} else { |
|
||||||
if (ret != CL_CLEAN) { |
|
||||||
printf("Error: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
} |
|
||||||
/* calculate size of scanned data */ |
|
||||||
mb = size * (CL_COUNT_PRECISION / 1024) / 1024.0; |
|
||||||
printf("Data scanned: %2.2Lf MB\n", mb); |
|
||||||
|
|
||||||
status = ret == CL_VIRUS ? 1 : 0; |
|
||||||
|
|
||||||
done: |
|
||||||
|
|
||||||
if (NULL != map) { |
|
||||||
cl_fmap_close(map); |
|
||||||
} |
|
||||||
if (NULL != mem) { |
|
||||||
free(mem); |
|
||||||
} |
|
||||||
unlink(PWDB_FILENAME); |
|
||||||
if (-1 != db_fd) { |
|
||||||
close(db_fd); |
|
||||||
} |
|
||||||
if (-1 != target_fd) { |
|
||||||
close(target_fd); |
|
||||||
} |
|
||||||
if (NULL != engine) { |
|
||||||
cl_engine_free(engine); |
|
||||||
} |
|
||||||
if (true == created_database) { |
|
||||||
unlink(database_filepath); |
|
||||||
} |
|
||||||
|
|
||||||
return status; |
|
||||||
} |
|
||||||
@ -1,162 +0,0 @@ |
|||||||
/*
|
|
||||||
* Copyright (C) 2020-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
|
||||||
* |
|
||||||
* 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. |
|
||||||
*/ |
|
||||||
|
|
||||||
/*
|
|
||||||
* This example demonstrates using callbacks to record information about each |
|
||||||
* file found during a recursive scan. |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <string.h> |
|
||||||
#ifndef _WIN32 |
|
||||||
#include <unistd.h> |
|
||||||
#endif |
|
||||||
#include <sys/types.h> |
|
||||||
#include <sys/stat.h> |
|
||||||
#include <fcntl.h> |
|
||||||
|
|
||||||
#include <clamav.h> |
|
||||||
|
|
||||||
#ifdef _WIN32 |
|
||||||
typedef int ssize_t; |
|
||||||
#endif |
|
||||||
|
|
||||||
cl_error_t scan_callback(int fd, const char *type, void *context) |
|
||||||
{ |
|
||||||
char buf[10]; |
|
||||||
ssize_t bytes_read = 0; |
|
||||||
(void)context; /* Could be used to retrieve/store info */ |
|
||||||
|
|
||||||
printf("fd: %u, type: %s, initial bytes: ", fd, type); |
|
||||||
if (-1 != (bytes_read = read(fd, &buf, sizeof(buf)))) { |
|
||||||
/* Was able to read a few bytes */ |
|
||||||
ssize_t i = 0; |
|
||||||
for (i = 0; i < bytes_read; i++) { |
|
||||||
printf("%02x", (unsigned int)buf[i]); |
|
||||||
} |
|
||||||
printf("\n"); |
|
||||||
} |
|
||||||
return CL_CLEAN; /* keep scanning */ |
|
||||||
} |
|
||||||
|
|
||||||
/*
|
|
||||||
* Exit codes: |
|
||||||
* 0: clean |
|
||||||
* 1: infected |
|
||||||
* 2: error |
|
||||||
*/ |
|
||||||
|
|
||||||
int main(int argc, char **argv) |
|
||||||
{ |
|
||||||
int status = 2; |
|
||||||
cl_error_t ret = CL_ERROR; |
|
||||||
|
|
||||||
char *db_filepath = NULL; |
|
||||||
int db_fd = -1; |
|
||||||
int target_fd = -1; |
|
||||||
|
|
||||||
unsigned long int size = 0; |
|
||||||
long double mb; |
|
||||||
const char *virname; |
|
||||||
const char *filename; |
|
||||||
struct cl_engine *engine = NULL; |
|
||||||
struct cl_scan_options options; |
|
||||||
|
|
||||||
if (argc != 2) { |
|
||||||
printf("Usage: %s file\n", argv[0]); |
|
||||||
return 2; |
|
||||||
} |
|
||||||
|
|
||||||
filename = argv[1]; |
|
||||||
|
|
||||||
if ((target_fd = open(argv[1], O_RDONLY)) == -1) { |
|
||||||
printf("Can't open file %s\n", argv[1]); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
if (CL_SUCCESS != (ret = cl_init(CL_INIT_DEFAULT))) { |
|
||||||
printf("Can't initialize libclamav: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
if (!(engine = cl_engine_new())) { |
|
||||||
printf("Can't create new engine\n"); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
/* Example version macro usage to determine if new feature is available */ |
|
||||||
#if defined(LIBCLAMAV_VERSION_NUM) && (LIBCLAMAV_VERSION_NUM >= 0x090400) |
|
||||||
/* Example feature usage lowering max scan time to 15 seconds. */ |
|
||||||
cl_engine_set_num(engine, CL_ENGINE_MAX_SCANTIME, 15000); |
|
||||||
#endif |
|
||||||
cl_engine_set_num(engine, CL_ENGINE_MAX_SCANSIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); |
|
||||||
cl_engine_set_num(engine, CL_ENGINE_MAX_FILESIZE, 1024 /*MB*/ * 1024 /*KB*/ * 1024 /*bytes*/); |
|
||||||
|
|
||||||
/* build engine */ |
|
||||||
if (CL_SUCCESS != (ret = cl_engine_compile(engine))) { |
|
||||||
printf("Database initialization error: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
|
|
||||||
/* scan file descriptor */ |
|
||||||
memset(&options, 0, sizeof(struct cl_scan_options)); |
|
||||||
options.parse |= ~0; /* enable all parsers */ |
|
||||||
options.general |= CL_SCAN_GENERAL_HEURISTICS; /* enable heuristic alert options */ |
|
||||||
options.general |= CL_SCAN_GENERAL_ALLMATCHES; /* run in all-match mode, so it keeps looking for alerts after the first one */ |
|
||||||
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA; /* collect metadata may enable collecting additional filenames (like in zip) */ |
|
||||||
|
|
||||||
/*
|
|
||||||
* Set our callbacks for inspecting embedded files during the scan. |
|
||||||
*/ |
|
||||||
cl_engine_set_clcb_pre_scan(engine, &scan_callback); |
|
||||||
|
|
||||||
printf("Testing prescan on FD %d - %s\n", target_fd, filename); |
|
||||||
|
|
||||||
if (CL_VIRUS == (ret = cl_scandesc(target_fd, filename, &virname, &size, engine, &options))) { |
|
||||||
printf("Virus detected: %s\n", virname); |
|
||||||
} else { |
|
||||||
if (ret != CL_CLEAN) { |
|
||||||
printf("Error: %s\n", cl_strerror(ret)); |
|
||||||
goto done; |
|
||||||
} |
|
||||||
} |
|
||||||
/* calculate size of scanned data */ |
|
||||||
mb = size * (CL_COUNT_PRECISION / 1024) / 1024.0; |
|
||||||
printf("Data scanned: %2.2Lf MB\n", mb); |
|
||||||
|
|
||||||
status = ret == CL_VIRUS ? 1 : 0; |
|
||||||
|
|
||||||
done: |
|
||||||
|
|
||||||
if (-1 != db_fd) { |
|
||||||
close(db_fd); |
|
||||||
} |
|
||||||
if (-1 != target_fd) { |
|
||||||
close(target_fd); |
|
||||||
} |
|
||||||
if (NULL != engine) { |
|
||||||
cl_engine_free(engine); |
|
||||||
} |
|
||||||
if (NULL != db_filepath) { |
|
||||||
free(db_filepath); |
|
||||||
} |
|
||||||
|
|
||||||
return status; |
|
||||||
} |
|
||||||
Loading…
Reference in new issue