diff --git a/DLL/README.md b/DLL/README.md new file mode 100644 index 0000000..d2d068b --- /dev/null +++ b/DLL/README.md @@ -0,0 +1,179 @@ +# EicarSpam + +## How to use + +### Python + +```python +# Windows +from ctypes import windll as sysdll +filename = "EicarSpam.dll" + +# Linux +from ctypes import cdll as sysdll +filename = "EicarSpam.so" + +from os.path import abspath +eicarspam = sysdll.LoadLibrary(abspath("EicarSpam.dll")) +eicarspam.eicar(300) +``` + +### Ruby + +```rb +# Windows +FILENAME = "EicarSpam.dll" + +# Linux +FILENAME = "EicarSpam.so" + +require 'fiddle/import' +require 'fiddle/types' + +module EicarSpam + extend Fiddle::Importer + dlload File.join(Dir.pwd, FILENAME) + include Fiddle::Win32Types + extern 'int eicar(int)' +end + +EicarSpam.eicar(5) +``` + +### Perl + +```perl +# Windows +use Cwd qw(abs_path); +use File::Spec; +use Win32::API; + +Win32::API->Import(abs_path(File::Spec->canonpath('EicarSpam.dll')),'int eicar(int x)'); +eicar(5); +``` + +### JScript + +```bash +# download dynwrapx.dll (https://dynwrapx.script-coding.com/dwx/pages/download.php?ver=2.2.0.0&lang=en) +regsvr32.exe /i \dynwrapx.dll +cscript EicarSpam.js +``` + +```js +var oDynaWrap = new ActiveXObject( "DynamicWrapper" ) +oDynaWrap.Register( "EicarSpam.dll", "eicar", "I=l", "R=l" ) // I(input)=l(int), R(return)=l(int) +oDynaWrap.eicar(5) +``` + +### VBScript + +```bash +# download dynwrapx.dll (https://dynwrapx.script-coding.com/dwx/pages/download.php?ver=2.2.0.0&lang=en) +regsvr32.exe /i \dynwrapx.dll +cscript EicarSpam.vbs +``` + +```vbs +Set DX = CreateObject("DynamicWrapperX") +DX.Register "EicarSpam.dll", "eicar", "i=l", "r=l" +DX.eicar(5) +``` + +## Sources + +### Rust + +```rs +use std::fs; + +#[no_mangle] +pub extern fn eicar(x: i32) -> i32 { + let eicar = format!( + "{}EICAR-STANDARD-ANTIVIRUS-TEST-FILE{end}", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + end="!$H+H*" + ); + + for x in 0..x { + fs::write( + format!("test{}.txt", x), eicar.clone() + ); + } + + return 0; +} +``` + +### C + +```c +#include + +__declspec( dllexport ) int eicar(int x) { + FILE *file; + char filename[12]; + + for(int i = 0; i < x; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file can't be opened\n"); + return 1; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + } + + fclose(file); + + return 0; +} +``` + +### Go + +```go +package main + +import ( + "log" + "os" + "fmt" + "C" +) + +//export eicar +func eicar(x C.uint) C.uint { + var datas [3]string + datas[0] = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$" + datas[1] = "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" + datas[2] = "!$H+H*" + + var i C.uint + + for i = 0; i < x; i++ { + file, err := os.Create(fmt.Sprintf("./test%d.txt", i)) + + if err != nil { + log.Fatal(err) + } + + defer file.Close() + + for _, data := range datas { + file.WriteString(data) + } + } + + return C.uint(0) +} + +func main () {} +``` \ No newline at end of file diff --git a/DLL/lib.c b/DLL/lib.c new file mode 100644 index 0000000..c7814b4 --- /dev/null +++ b/DLL/lib.c @@ -0,0 +1,29 @@ +#include + +// Linux: +// __attribute__((visibility("default"))) int eicar(int x) { +__declspec( dllexport ) int eicar(int x) { + FILE *file; + char filename[12]; + + for(int i = 0; i < x; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file \"test%d.txt\" can't be opened\n", i); + return 1; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + return 0; +} \ No newline at end of file diff --git a/DLL/lib.go b/DLL/lib.go new file mode 100644 index 0000000..f025c0e --- /dev/null +++ b/DLL/lib.go @@ -0,0 +1,36 @@ +package main + +import ( + "log" + "os" + "fmt" + "C" +) + +//export eicar +func eicar(x C.uint) C.uint { + var datas [3]string + datas[0] = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$" + datas[1] = "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" + datas[2] = "!$H+H*" + + var i C.uint + + for i = 0; i < x; i++ { + file, err := os.Create(fmt.Sprintf("./test%d.txt", i)) + + if err != nil { + log.Fatal(err) + } + + defer file.Close() + + for _, data := range datas { + file.WriteString(data) + } + } + + return C.uint(0) +} + +func main () {} \ No newline at end of file diff --git a/DLL/lib.rs b/DLL/lib.rs new file mode 100644 index 0000000..6e9f3b2 --- /dev/null +++ b/DLL/lib.rs @@ -0,0 +1,18 @@ +use std::fs; + +#[no_mangle] +pub extern fn eicar(x: i32) -> i32 { + let eicar = format!( + "{}EICAR-STANDARD-ANTIVIRUS-TEST-FILE{end}", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + end="!$H+H*" + ); + + for x in 0..x { + fs::write( + format!("test{}.txt", x), eicar.clone() + ); + } + + return 0; +} \ No newline at end of file diff --git a/Executable/EicarSpam.c b/Executable/EicarSpam.c new file mode 100644 index 0000000..a38cbdb --- /dev/null +++ b/Executable/EicarSpam.c @@ -0,0 +1,27 @@ +#include + +int main() { + FILE *file; + char filename[12]; + + for(int i = 0; i < 300; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file \"test%d.txt\" can't be opened\n", i); + return 1; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + return 0; +} \ No newline at end of file diff --git a/Executable/EicarSpam.fsx b/Executable/EicarSpam.fsx new file mode 100644 index 0000000..7b8c4e0 --- /dev/null +++ b/Executable/EicarSpam.fsx @@ -0,0 +1,11 @@ +open System.IO +let start = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$" +let end_ = "!$H+H*" +let eicar = ( + sprintf + $"{start}EICAR-STANDARD-ANTIVIRUS-TEST-FILE{end_}" +) +for i = 1 to 300 do + File.WriteAllText( + (sprintf "test%i.txt" i), eicar + ) \ No newline at end of file diff --git a/Executable/EicarSpam.go b/Executable/EicarSpam.go new file mode 100644 index 0000000..f5924d7 --- /dev/null +++ b/Executable/EicarSpam.go @@ -0,0 +1,29 @@ +package main + +import ( + "log" + "os" + "fmt" +) + + +func main() { + var datas [3]string + datas[0] = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$" + datas[1] = "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" + datas[2] = "!$H+H*" + + for i := 0; i < 300; i++ { + file, err := os.Create(fmt.Sprintf("./test%d.txt", i)) + + if err != nil { + log.Fatal(err) + } + + defer file.Close() + + for _, data := range datas { + file.WriteString(data) + } + } +} \ No newline at end of file diff --git a/Executable/EicarSpam.ps1 b/Executable/EicarSpam.ps1 new file mode 100644 index 0000000..144fb4b --- /dev/null +++ b/Executable/EicarSpam.ps1 @@ -0,0 +1,5 @@ +$string = 'X5O!P%@AP[4\PZX54(P^)7CC)7}$_!$H+H*'.replace('_', 'EICAR-STANDARD-ANTIVIRUS-TEST-FILE') + +for($i = 0; $i -lt 300; $i++){ + Set-Content "test$i.txt" $string +} \ No newline at end of file diff --git a/Executable/EicarSpam.rs b/Executable/EicarSpam.rs new file mode 100644 index 0000000..bca43ff --- /dev/null +++ b/Executable/EicarSpam.rs @@ -0,0 +1,17 @@ +use std::fs; + +fn main() -> std::io::Result<()> { + let eicar = format!( + "{}EICAR-STANDARD-ANTIVIRUS-TEST-FILE{end}", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + end="!$H+H*" + ); + + for x in 0..301 { + fs::write( + format!("test{}.txt", x), eicar.clone() + )?; + } + + Ok(()) +} \ No newline at end of file diff --git a/Executable/README.md b/Executable/README.md new file mode 100644 index 0000000..e292af2 --- /dev/null +++ b/Executable/README.md @@ -0,0 +1,207 @@ +# Tests antivirus + +Small programs to test your antivirus with eicar strings (create 300 eicar strings in 300 files). + +Sources are available here and executables are available [here](https://github.com/mauricelambert/EicarSpam/releases/latest/) + + - Go + - Rust + - F# + - C + +## Go + +### Linux + +#### Start execution with command line + +```bash +curl -o EicarSpam_go "https://objects.githubusercontent.com/github-production-release-asset-2e65be/470340204/d14fa6c1-7685-4c75-992d-d840d2726209?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220316%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220316T103304Z&X-Amz-Expires=300&X-Amz-Signature=dc572c25a04a593f666fe1556130f552ad93f631a91698ba40230dbf9c7e519d&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=470340204&response-content-disposition=attachment%3B%20filename%3DEicarSpam_go_Linux&response-content-type=application%2Foctet-stream" +chmod +x EicarSpam_go +./EicarSpam_go +``` + +### Compile + +```bash +go build EicarSpam.go +./EicarSpam +``` + +### Code + +```go +package main + +import ( + "log" + "os" + "fmt" +) + + +func main() { + var datas [3]string + datas[0] = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$" + datas[1] = "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" + datas[2] = "!$H+H*" + + for i := 0; i < 300; i++ { + file, err := os.Create(fmt.Sprintf("./test%d.txt", i)) + + if err != nil { + log.Fatal(err) + } + + defer file.Close() + + for _, data := range datas { + file.WriteString(data) + } + } +} +``` + +## C + +### Linux + +#### Start execution with command line + +```bash +curl -o EicarSpam_c "https://objects.githubusercontent.com/github-production-release-asset-2e65be/470340204/1ec8cbc3-64bd-40f8-b403-839b11002280?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220316%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220316T101859Z&X-Amz-Expires=300&X-Amz-Signature=0201848ead42c88ee07095a2b056891ea0dcd1fcb0ba7c74b849049b0c4d100a&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=470340204&response-content-disposition=attachment%3B%20filename%3DEicarSpam_c_Linux&response-content-type=application%2Foctet-stream" +chmod +x EicarSpam_c +./EicarSpam_c +``` + +### Compile + +```bash +gcc -o EicarSpam_c -O3 EicarSpam.c # Debian sid / Windows 10 (MinGW) +gcc --std=c99 -o EicarSpam_c -O3 EicarSpam.c # CentOS 7 +./EicarSpam_c +``` + +### Code + +```c +#include + +int main() { + FILE *file; + char filename[12]; + + for(int i = 0; i < 300; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file can't be opened\n"); + return 1; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + return 0; +} +``` + +## F# + +### Linux + +#### Start execution with command line + +```bash +curl -o EicarSpam_fsharp_Linux.zip "https://objects.githubusercontent.com/github-production-release-asset-2e65be/470340204/bb93d9b2-e6a8-41fa-a489-16ffe71ffb27?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220319%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220319T160736Z&X-Amz-Expires=300&X-Amz-Signature=aff09d23f04c7f76b1a471c4b10ca829ce80b2c01f7fe8890a389fe21837eebf&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=470340204&response-content-disposition=attachment%3B%20filename%3DEicarSpam_fsharp_Linux.zip&response-content-type=application%2Foctet-stream" +unzip EicarSpam_fsharp_Linux.zip +cd EicarSpam_fsharp_Linux +chmod +x EicarSpam +./EicarSpam +``` + +### Compile + +```bash +dotnet new console -lang F# --author MauriceLambert -o EicarSpam -n EicarSpam +mv EicarSpam.fsx EicarSpam/Program.fs + +# Windows +dotnet build -o EicarSpamWindows --os win --self-contained +./EicarSpamWindows/EicarSpam.exe + +# Linux +dotnet build -o EicarSpamLinux --os linux --self-contained +chmod +x ./EicarSpamLinux/EicarSpam.exe +./EicarSpamLinux/EicarSpam.exe +``` + +### Run + +```bash +dotnet fsi EicarSpam.fsx +``` + +### Code + +```fs +open System.IO +let start = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$" +let end_ = "!$H+H*" +let eicar = ( + sprintf + $"{start}EICAR-STANDARD-ANTIVIRUS-TEST-FILE{end_}" +) +for i = 1 to 300 do + File.WriteAllText( + (sprintf "test%i.txt" i), eicar + ) +``` + +## Rust + +### Linux + +#### Start execution with command line + +```bash +curl -o EicarSpam_rust_Linux "https://objects.githubusercontent.com/github-production-release-asset-2e65be/470340204/70c67674-6cff-4e71-86ea-73dba509468d?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20220319%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20220319T161424Z&X-Amz-Expires=300&X-Amz-Signature=f049be0260737dbe0ba2e9de3beb2c7abf7b4a8df81fa87e16ff24fe1f46f5c3&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=470340204&response-content-disposition=attachment%3B%20filename%3DEicarSpam_rust_Linux&response-content-type=application%2Foctet-stream" +chmod +x EicarSpam_rust_Linux +./EicarSpam_rust_Linux +``` + +### Compile + +```bash +rustc EicarSpam.rs +``` + +### Code + +```rs +use std::fs; + +fn main() -> std::io::Result<()> { + let eicar = format!( + "{}EICAR-STANDARD-ANTIVIRUS-TEST-FILE{end}", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + end="!$H+H*" + ); + + for x in 0..301 { + fs::write( + format!("test{}.txt", x), eicar.clone() + )?; + } + + Ok(()) +} +``` \ No newline at end of file diff --git a/Module/CGo.go b/Module/CGo.go new file mode 100644 index 0000000..cf326ce --- /dev/null +++ b/Module/CGo.go @@ -0,0 +1,32 @@ +package main + +// #include +// +// static void eicar(int x) { +// FILE *file; +// char filename[12]; +// +// for(int i = 0; i < x; i++) { +// snprintf(filename, 12, "test%d.txt", i); +// file = fopen(filename, "w"); +// +// if(file == NULL) { +// printf("file \"test%d.txt\" can't be opened\n", i); +// return; +// } +// +// fprintf( +// file, +// "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", +// "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", +// "!$H+H*" +// ); +// +// fclose(file); +// } +// } // no blank line after this line ! +import "C" + +func main() { + C.eicar(C.int(300)) +} diff --git a/Module/Python/CPython.c b/Module/Python/CPython.c new file mode 100644 index 0000000..314e893 --- /dev/null +++ b/Module/Python/CPython.c @@ -0,0 +1,51 @@ +#include + +static PyObject *method_eicar(PyObject *self, PyObject *args) { + int x = NULL; + + if(!PyArg_ParseTuple(args, "i", &x)) { + return NULL; + } + + FILE *file; + char filename[12]; + + for(int i = 0; i < x; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file \"test%d.txt\" can't be opened\n", i); + Py_RETURN_NONE; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + Py_RETURN_NONE; +} + +static PyMethodDef EicarMethods[] = { + {"eicar", method_eicar, METH_VARARGS, "Generate eicar test files."}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef eicarspammodule = { + PyModuleDef_HEAD_INIT, + "EicarSpam", + "Generate eicar test files.", + -1, + EicarMethods +}; + +PyMODINIT_FUNC PyInit_EicarSpam(void) { + PyObject *module = PyModule_Create(&eicarspammodule); + return module; +} \ No newline at end of file diff --git a/Module/Python/setup.py b/Module/Python/setup.py new file mode 100644 index 0000000..62c8159 --- /dev/null +++ b/Module/Python/setup.py @@ -0,0 +1,14 @@ +from setuptools import setup, Extension + +def main(): + setup( + name="EicarSpam", + version="1.0.0", + description="Generate eicar test files.", + author="Maurice Lambert", + author_email="mauricelambert434@gmail.com", + ext_modules=[Extension("EicarSpam", ["CPython.c"])], + ) + +if __name__ == "__main__": + main() diff --git a/Module/README.md b/Module/README.md new file mode 100644 index 0000000..1504fa5 --- /dev/null +++ b/Module/README.md @@ -0,0 +1,152 @@ +# EicarSpam + +## Go + +```go +package main + +// #include +// +// static void eicar(int x) { +// FILE *file; +// char filename[12]; +// +// for(int i = 0; i < x; i++) { +// snprintf(filename, 12, "test%d.txt", i); +// file = fopen(filename, "w"); +// +// if(file == NULL) { +// printf("file can't be opened\n"); +// return; +// } +// +// fprintf( +// file, +// "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", +// "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", +// "!$H+H*" +// ); +// +// fclose(file); +// } +// } // no blank line after this line ! +import "C" + +func main() { + C.eicar(C.int(300)) +} +``` + +## Python + +```c +#include + +static PyObject *method_eicar(PyObject *self, PyObject *args) { + int x = NULL; + + if(!PyArg_ParseTuple(args, "i", &x)) { + return NULL; + } + + FILE *file; + char filename[12]; + + for(int i = 0; i < x; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file \"test%d.txt\" can't be opened\n", i); + Py_RETURN_NONE; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + Py_RETURN_NONE; +} + +static PyMethodDef EicarMethods[] = { + {"eicar", method_eicar, METH_VARARGS, "Generate eicar test files."}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef eicarspammodule = { + PyModuleDef_HEAD_INIT, + "EicarSpam", + "Generate eicar test files.", + -1, + EicarMethods +}; + +PyMODINIT_FUNC PyInit_EicarSpam(void) { + PyObject *module = PyModule_Create(&eicarspammodule); + return module; +} +``` + +```python +from setuptools import setup, Extension + +def main(): + setup( + name="EicarSpam", + version="1.0.0", + description="Generate eicar test files.", + author="Maurice Lambert", + author_email="mauricelambert434@gmail.com", + ext_modules=[Extension("EicarSpam", ["CPython.c"])], + ) + +if __name__ == "__main__": + main() +``` + +```bash +python3 setup.py build_ext --inplace +``` + +### Ruby + +```c +#include "ruby.h" +#include +#include "extconf.h" + +VALUE rb_eicar(VALUE self, VALUE num) { + FILE *file; + char filename[12]; + + int number = NUM2INT(num); + + for(int i = 0; i < number; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + return Qnil; +} + +void Init_EicarSpam() +{ + VALUE mod = rb_define_module("Eicar"); + rb_define_method(mod, "eicar", rb_eicar, 1); +} +``` \ No newline at end of file diff --git a/Module/RubyLinux.c b/Module/RubyLinux.c new file mode 100644 index 0000000..ec0e15f --- /dev/null +++ b/Module/RubyLinux.c @@ -0,0 +1,32 @@ +#include "ruby.h" +#include +#include "extconf.h" + +VALUE rb_eicar(VALUE self, VALUE num) { + FILE *file; + char filename[12]; + + int number = NUM2INT(num); + + for(int i = 0; i < number; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + fclose(file); + } + + return Qnil; +} + +void Init_EicarSpam() +{ + VALUE mod = rb_define_module("Eicar"); + rb_define_method(mod, "eicar", rb_eicar, 1); +} \ No newline at end of file diff --git a/Module/RubyWindows/EicarSpam.c b/Module/RubyWindows/EicarSpam.c new file mode 100644 index 0000000..ba53fb7 --- /dev/null +++ b/Module/RubyWindows/EicarSpam.c @@ -0,0 +1,40 @@ +#include "cfunc.h" +#include + +#include "ruby.h" +#include "extconf.h" + +VALUE rb_eicar(VALUE self, VALUE num) { + FILE *file; + char filename[12]; + + int number = NUM2INT(num); + printf("%d", number); + + for(int i = 0; i < number; i++) { + snprintf(filename, 12, "test%d.txt", i); + file = fopen(filename, "w"); + + if(file == NULL) { + printf("file \"test%d.txt\" can't be opened\n", i); + return Qnil; + } + + fprintf( + file, + "%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s", + "X5O!P%@AP[4\\PZX54(P^)7CC)7}$", + "!$H+H*" + ); + + cfclose(file); + } + + return Qnil; +} + +void Init_EicarSpam() +{ + VALUE mod = rb_define_module("Eicar"); + rb_define_method(mod, "eicar", rb_eicar, 1); +} diff --git a/Module/RubyWindows/Makefile b/Module/RubyWindows/Makefile new file mode 100644 index 0000000..59333ec --- /dev/null +++ b/Module/RubyWindows/Makefile @@ -0,0 +1,271 @@ + +SHELL = /bin/sh + +# V=0 quiet, V=1 verbose. other values don't work. +V = 0 +V0 = $(V:0=) +Q1 = $(V:1=) +Q = $(Q1:0=@) +ECHO1 = $(V:1=@ :) +ECHO = $(ECHO1:0=@ echo) +NULLCMD = : + +#### Start of system configuration section. #### + +srcdir = C:\path\to\EicarSpam\sources +topdir = C:\Ruby31-x64\include\ruby-3.1.0 +hdrdir = $(topdir) +arch_hdrdir = C:\Ruby31-x64\include\ruby-3.1.0\x64-mingw-ucrt +PATH_SEPARATOR = : +VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby +prefix = C:\Ruby31-x64 +rubysitearchprefix = $(rubylibprefix)/$(sitearch) +rubyarchprefix = $(rubylibprefix)/$(arch) +rubylibprefix = $(libdir)/$(RUBY_BASE_NAME) +exec_prefix = $(prefix) +vendorarchhdrdir = $(vendorhdrdir)/$(sitearch) +sitearchhdrdir = $(sitehdrdir)/$(sitearch) +rubyarchhdrdir = $(rubyhdrdir)/$(arch) +vendorhdrdir = $(rubyhdrdir)/vendor_ruby +sitehdrdir = $(rubyhdrdir)/site_ruby +rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME) +vendorarchdir = $(vendorlibdir)/$(sitearch) +vendorlibdir = $(vendordir)/$(ruby_version) +vendordir = $(rubylibprefix)/vendor_ruby +sitearchdir = $(sitelibdir)/$(sitearch) +sitelibdir = $(sitedir)/$(ruby_version) +sitedir = $(rubylibprefix)/site_ruby +rubyarchdir = $(rubylibdir)/$(arch) +rubylibdir = $(rubylibprefix)/$(ruby_version) +sitearchincludedir = $(includedir)/$(sitearch) +archincludedir = $(includedir)/$(arch) +sitearchlibdir = $(libdir)/$(sitearch) +archlibdir = $(libdir)/$(arch) +ridir = $(datarootdir)/$(RI_BASE_NAME) +mandir = $(datarootdir)/man +localedir = $(datarootdir)/locale +libdir = $(exec_prefix)/lib +psdir = $(docdir) +pdfdir = $(docdir) +dvidir = $(docdir) +htmldir = $(docdir) +infodir = $(datarootdir)/info +docdir = $(datarootdir)/doc/$(PACKAGE) +oldincludedir = $(DESTDIR)/usr/include +includedir = $(prefix)/include +runstatedir = $(localstatedir)/run +localstatedir = $(prefix)/var +sharedstatedir = $(prefix)/com +sysconfdir = $(DESTDIR) +datadir = $(datarootdir) +datarootdir = $(prefix)/share +libexecdir = $(exec_prefix)/libexec +sbindir = $(exec_prefix)/sbin +bindir = $(exec_prefix)/bin +archdir = $(rubyarchdir) + + +CC_WRAPPER = +CC = gcc +CXX = g++ +LIBRUBY = lib$(RUBY_SO_NAME).dll.a +LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a +LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME) +LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static $(MAINLIBS) +empty = +OUTFLAG = -o $(empty) +COUTFLAG = -o $(empty) +CSRCFLAG = $(empty) + +RUBY_EXTCONF_H = extconf.h +cflags = $(optflags) $(debugflags) $(warnflags) +cxxflags = +optflags = -O3 -fno-omit-frame-pointer -fno-fast-math +debugflags = -ggdb3 +warnflags = -Wall -Wextra -Wdeprecated-declarations -Wduplicated-cond -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wwrite-strings -Wimplicit-fallthrough=0 -Wmissing-noreturn -Wno-cast-function-type -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-packed-bitfield-compat -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wsuggest-attribute=format -Wsuggest-attribute=noreturn -Wunused-variable -Wundef +cppflags = +CCDLFLAGS = +CFLAGS = $(CCDLFLAGS) -O3 -fno-fast-math -fstack-protector-strong $(ARCH_FLAG) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) +DEFS = -D_FILE_OFFSET_BITS=64 +CPPFLAGS = -DRUBY_EXTCONF_H=\"$(RUBY_EXTCONF_H)\" -D__USE_MINGW_ANSI_STDIO=1 -DFD_SETSIZE=2048 -D_WIN32_WINNT=0x0600 -D__MINGW_USE_VC2005_COMPAT $(DEFS) $(cppflags) +CXXFLAGS = $(CCDLFLAGS) -march=x86-64 -mtune=generic -O2 -pipe $(ARCH_FLAG) +ldflags = -L. -pipe -s -fstack-protector-strong -Wl,--no-as-needed +dldflags = -pipe -s -fstack-protector-strong -Wl,--enable-auto-image-base,--enable-auto-import $(DEFFILE) +ARCH_FLAG = -m64 +DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG) +LDSHARED = $(CC) -shared +LDSHAREDXX = $(CXX) -shared +AR = x86_64-w64-mingw32-gcc-ar +EXEEXT = .exe + +RUBY_INSTALL_NAME = $(RUBY_BASE_NAME) +RUBY_SO_NAME = x64-ucrt-ruby310 +RUBYW_INSTALL_NAME = $(RUBYW_BASE_NAME) +RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version) +RUBYW_BASE_NAME = rubyw +RUBY_BASE_NAME = ruby + +arch = x64-mingw-ucrt +sitearch = x64-ucrt +ruby_version = 3.1.0 +ruby = $(bindir)/$(RUBY_BASE_NAME) +RUBY = $(ruby) +ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h $(RUBY_EXTCONF_H) + +RM = rm.py -f +RM_RF = rm.py -fr +RMDIRS = rmdir --ignore-fail-on-non-empty -p +MAKEDIRS = /usr/bin/mkdir -p +INSTALL = /usr/bin/install -c +INSTALL_PROG = $(INSTALL) -m 0755 +INSTALL_DATA = $(INSTALL) -m 644 +COPY = cp +TOUCH = exit > + +#### End of system configuration section. #### + +preload = +libpath = . $(libdir) +LIBPATH = -L. -L $(libdir) -L C:\Ruby31-x64\bin +DEFFILE = $(TARGET)-$(arch).def + +CLEANFILES = mkmf.log $(DEFFILE) +DISTCLEANFILES = +DISTCLEANDIRS = + +extout = +extout_prefix = +target_prefix = +LOCAL_LIBS = +LIBS = $(LIBRUBYARG_SHARED) -lshell32 -lws2_32 -liphlpapi -limagehlp -lshlwapi -lbcrypt +ORIG_SRCS = EicarSpam.c +SRCS = $(ORIG_SRCS) +OBJS = EicarSpam.o +HDRS = $(srcdir)/extconf.h +LOCAL_HDRS = +TARGET = EicarSpam +TARGET_NAME = EicarSpam +TARGET_ENTRY = Init_$(TARGET_NAME) +DLLIB = $(TARGET).so +EXTSTATIC = +STATIC_LIB = + +TIMESTAMP_DIR = . +BINDIR = $(bindir) +RUBYCOMMONDIR = $(sitedir)$(target_prefix) +RUBYLIBDIR = $(sitelibdir)$(target_prefix) +RUBYARCHDIR = $(sitearchdir)$(target_prefix) +HDRDIR = $(sitehdrdir)$(target_prefix) +ARCHHDRDIR = $(sitearchhdrdir)$(target_prefix) +TARGET_SO_DIR = +TARGET_SO = $(TARGET_SO_DIR)$(DLLIB) +CLEANLIBS = $(TARGET_SO) false +CLEANOBJS = *.o *.bak + +all: $(DLLIB) +static: $(STATIC_LIB) +.PHONY: all install static install-so install-rb +.PHONY: clean clean-so clean-static clean-rb + +clean-static:: +clean-rb-default:: +clean-rb:: +clean-so:: +clean: clean-so clean-static clean-rb-default clean-rb + python3 $(RM_RF) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time + +distclean-rb-default:: +distclean-rb:: +distclean-so:: +distclean-static:: +distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb + python3 $(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log + python3 $(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES) + python3 $(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true + +realclean: distclean +install: install-so install-rb + +install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time + $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR) +clean-static:: + python3 $(RM) $(STATIC_LIB) +install-rb: pre-install-rb do-install-rb install-rb-default +install-rb-default: pre-install-rb-default do-install-rb-default +pre-install-rb: Makefile +pre-install-rb-default: Makefile +do-install-rb: +do-install-rb-default: +pre-install-rb-default: + @$(NULLCMD) +$(TIMESTAMP_DIR)/.sitearchdir.time: + $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR) + $(Q) $(TOUCH) $@ + +site-install: site-install-so site-install-rb +site-install-so: install-so +site-install-rb: install-rb + +.SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S + +.cc.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cc.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.mm.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.mm.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cxx.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cxx.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.cpp.o: + $(ECHO) compiling $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.cpp.S: + $(ECHO) translating $(<) + $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.c.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.c.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +.m.o: + $(ECHO) compiling $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$< + +.m.S: + $(ECHO) translating $(<) + $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$< + +$(TARGET_SO): $(DEFFILE) $(OBJS) Makefile + $(ECHO) linking shared-object $(DLLIB) + python3 $(RM) $(@) + $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS) cfunc.c + + + +$(DEFFILE): + $(ECHO) generating $(@) + $(Q) (echo EXPORTS && echo $(TARGET_ENTRY)) > $@ + +$(OBJS): $(HDRS) $(ruby_headers) diff --git a/Module/RubyWindows/cfunc.c b/Module/RubyWindows/cfunc.c new file mode 100644 index 0000000..a934b09 --- /dev/null +++ b/Module/RubyWindows/cfunc.c @@ -0,0 +1,6 @@ +#include +#include "cfunc.h" + +int myclose(FILE * file) { + return fclose(file); +} diff --git a/Module/RubyWindows/cfunc.h b/Module/RubyWindows/cfunc.h new file mode 100644 index 0000000..2777a4f --- /dev/null +++ b/Module/RubyWindows/cfunc.h @@ -0,0 +1,8 @@ +#include +#define cfclose(f) myclose(f) +#define cfclose_ptr cfclose_ptr + +int myclose(FILE *file); + +// int (*cfclose_ptr)(FILE *) = &fclose; +// (*cfclose_ptr)(file); \ No newline at end of file diff --git a/Module/RubyWindows/extconf.h b/Module/RubyWindows/extconf.h new file mode 100644 index 0000000..cda0cc8 --- /dev/null +++ b/Module/RubyWindows/extconf.h @@ -0,0 +1,3 @@ +#ifndef EXTCONF_H +#define EXTCONF_H +#endif diff --git a/Module/RubyWindows/extconf.rb b/Module/RubyWindows/extconf.rb new file mode 100644 index 0000000..0957603 --- /dev/null +++ b/Module/RubyWindows/extconf.rb @@ -0,0 +1,5 @@ +require 'mkmf' + +create_header +# dir_config('EicarSpam') +create_makefile 'EicarSpam' \ No newline at end of file diff --git a/Scripts/EicarSpam.bat b/Scripts/EicarSpam.bat new file mode 100644 index 0000000..3c62006 --- /dev/null +++ b/Scripts/EicarSpam.bat @@ -0,0 +1,6 @@ +@echo off +SET a=X5O!P%@AP[4\PZX54(P^)7CC)7}$ +SET c=!$H+H* +SET b=EICAR-STANDARD-ANTIVIRUS-TEST-FILE + +for /L %D in (1,1,300) do echo %a%%b%%c% > test%D.txt \ No newline at end of file diff --git a/Scripts/EicarSpam.js b/Scripts/EicarSpam.js new file mode 100644 index 0000000..2e87e8f --- /dev/null +++ b/Scripts/EicarSpam.js @@ -0,0 +1,15 @@ +var part1; +var part3; +var file; +var FSO; +var i; + +part1 = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$"; +part3 = "!$H+H*"; + +for (i = 0; i < 300; i++) { + FSO = new ActiveXObject("Scripting.FileSystemObject"); + file = FSO.CreateTextFile("test" + i.toString() + ".text", true); + file.WriteLine(part1 + "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" + part3); + file.Close() +} diff --git a/Scripts/EicarSpam.pl b/Scripts/EicarSpam.pl new file mode 100644 index 0000000..a0ac91a --- /dev/null +++ b/Scripts/EicarSpam.pl @@ -0,0 +1,6 @@ +foreach my $i ((1..300)) { + # open a filehandle for your file + open my $file, '>', "test$i.txt" or die "test$i.txt: $!"; + printf $file '%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s', 'X5O!P%@AP[4\PZX54(P^)7CC)7}$', '!$H+H*'; + close $file; +} \ No newline at end of file diff --git a/Scripts/EicarSpam.py b/Scripts/EicarSpam.py new file mode 100644 index 0000000..fb34c0a --- /dev/null +++ b/Scripts/EicarSpam.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 + +for a in range(300): + with open(f"test{a}","w") as f: + _ = f.write("X5O!P%@AP[4\\PZX54(P^)7CC)7}$_!$H+H*".replace("_", "EICAR-STANDARD-ANTIVIRUS-TEST-FILE")) \ No newline at end of file diff --git a/Scripts/EicarSpam.rb b/Scripts/EicarSpam.rb new file mode 100644 index 0000000..9bba461 --- /dev/null +++ b/Scripts/EicarSpam.rb @@ -0,0 +1,7 @@ +300.times { + |i| File.open("tmp#{i}.txt", 'w') do |f| + f.write('X5O!P%@AP[4\PZX54(P^)7CC)7}$') + f.write('EICAR-STANDARD-ANTIVIRUS-TEST-FILE') + f.write('!$H+H*') + end +} \ No newline at end of file diff --git a/Scripts/EicarSpam.sh b/Scripts/EicarSpam.sh new file mode 100644 index 0000000..41cee91 --- /dev/null +++ b/Scripts/EicarSpam.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +a='X5O!P%@AP[4\PZX54(P^)7CC)7}$_!$H+H*' +for i in {0..300}; do + echo "${a/_/EICAR-STANDARD-ANTIVIRUS-TEST-FILE}" > "test${i}.txt" +done \ No newline at end of file diff --git a/Scripts/EicarSpam.vbs b/Scripts/EicarSpam.vbs new file mode 100644 index 0000000..3560667 --- /dev/null +++ b/Scripts/EicarSpam.vbs @@ -0,0 +1,9 @@ +part1 = "X5O!P%@AP[4\PZX54(P^)7CC)7}$" +part3 = "!$H+H*" + +For i = 1 To 300 + Set FSO = CreateObject("Scripting.FileSystemObject") + Set file = FSO.CreateTextFile("test" & CStr(i) & ".text", True) + file.WriteLine(part1 & "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" & part3) + file.Close +Next diff --git a/Scripts/README.md b/Scripts/README.md new file mode 100644 index 0000000..19d061d --- /dev/null +++ b/Scripts/README.md @@ -0,0 +1,149 @@ +# Tests antivirus + +Small scripts and programs to test your antivirus with eicar strings (create 300 eicar strings in 300 files). + +1) Windows (without any installation) + - Batch script: Windows XP - Windows 11/2022 + - VBScript script: Windows XP - Windows 11/2022 + - JScript script: Windows XP - Windows 11/2022 + - Powershell script: Windows 7 - Windows11/2022 +2) Linux (without any installation) + - Bash +3) Linux (probably no installation) + - Perl + - Python +4) Others + - Ruby + +All these scripts work on Windows 10, Debian sid and CentOS 7, some requirements might be required. + +## Python + +```bash +python3 EicarSpam.py +``` + +```python +for a in range(300): + with open(f"test{a}","w") as f: + _ = f.write("X5O!P%@AP[4\\PZX54(P^)7CC)7}$_!$H+H*".replace("_", "EICAR-STANDARD-ANTIVIRUS-TEST-FILE")) +``` + +## Powershell + +```bash +powershell ./EicarSpam.ps1 +``` + +```powershell +$string = 'X5O!P%@AP[4\PZX54(P^)7CC)7}$_!$H+H*'.replace('_', 'EICAR-STANDARD-ANTIVIRUS-TEST-FILE') + +for($i = 0; $i -lt 300; $i++){ + Set-Content "test$i.txt" $string +} +``` + +## Bash + +```bash +bash EicarSpam.sh +``` + +```bash +a='X5O!P%@AP[4\PZX54(P^)7CC)7}$_!$H+H*' +for i in {0..300}; do + echo "${a/_/EICAR-STANDARD-ANTIVIRUS-TEST-FILE}" > "test${i}.txt" +done +``` + +```bash +echo 'X5O!P%@AP[4\PZX54(P^)7CC)7}$'"EICAR-STANDARD-ANTIVIRUS-TEST-FILE"'!$H+H*' > "test.txt" +``` + +## VBScript + +```bash +EicarSpam.vbs +``` + +```vbscript +part1 = "X5O!P%@AP[4\PZX54(P^)7CC)7}$" +part3 = "!$H+H*" + +For i = 1 To 300 + Set FSO = CreateObject("Scripting.FileSystemObject") + Set file = FSO.CreateTextFile("test" & CStr(i) & ".text", True) + file.WriteLine(part1 & "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" & part3) + file.Close +Next +``` + +## JScript + +```bash +EicarSpam.js +``` + +```js +var part1; +var part3; +var file; +var FSO; +var i; + +part1 = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$"; +part3 = "!$H+H*"; + +for (i = 0; i < 300; i++) { + FSO = new ActiveXObject("Scripting.FileSystemObject"); + file = FSO.CreateTextFile("test" + i.toString() + ".text", true); + file.WriteLine(part1 + "EICAR-STANDARD-ANTIVIRUS-TEST-FILE" + part3); + file.Close() +} +``` + +## Batch + +```bash +EicarSpam.bat +``` + +```bash +@echo off +SET a=X5O!P%@AP[4\PZX54(P^)7CC)7}$ +SET c=!$H+H* +SET b=EICAR-STANDARD-ANTIVIRUS-TEST-FILE + +for /L %D in (1,1,300) do echo %a%%b%%c% > test%D.txt +``` + +## Ruby + +```bash +ruby EicarSpam.rb +``` + +```rb +300.times { + |i| File.open("tmp#{i}.txt", 'w') do |f| + f.write('X5O!P%@AP[4\PZX54(P^)7CC)7}$') + f.write('EICAR-STANDARD-ANTIVIRUS-TEST-FILE') + f.write('!$H+H*') + end +} +``` + +## Perl + +```bash +perl EicarSpam.pl +``` + +```perl +foreach my $i ((1..300)) { + # open a filehandle for your file + open my $file, '>', "test$i.txt" or die "test$i.txt: $!"; + printf $file '%sEICAR-STANDARD-ANTIVIRUS-TEST-FILE%s', 'X5O!P%@AP[4\PZX54(P^)7CC)7}$', '!$H+H*'; + close $file; +} +```