某的机器,前几日意外染毒,由于这几日在试用ZoneAlarm,对机器表现把握不准,连什么时候中毒都不知道。。。(在此先深切怀念一下我用了七年多的PFW,可怜了我抠抠索索出钱买的正版序列号:( 现在搞得有正版序列号还得用试用版T_T)。
直到突然发现机器表现有一些异常了,一刷autoruns,Image Hijacks一大堆!果然中毒了!
我对中毒过敏,立刻还原系统。还原后,新装个驱动,再刷autoruns,啊!又来了!
分区根目录下并没有autoruns.inf之类的触发。难道是感染型病毒?!
我在每个分区下都放了一个小EXE,当蜜罐使。结果一看,原本4.5K的变30.5K了,果然是感染了。可是我的驱动是压缩包里的啊,这*毒,连压缩包也不放过!!
完蛋完蛋,我长时间来收集一些软件啊程序啊啥的,看来要废了,我要撞墙了!!
不甘心啊不甘心。
那就看看有没有专杀吧,给个样本让别人用杀软看看是什么毒,结果查出来叫Win32.Agent.??(后面叫什么,忘记了),上网查有没有专杀工具,结果都没有。全是要装杀软。俺与杀软有不共戴天之仇
,如何也不会装。而且杀软那些技俩俺也领教过,但凡感染的文件,一律做删除处理,根本不会恢复它。
看来,得自己动手试试。
看看这个感染复不复杂吧?原PE与感染PE一对比,加之早早分析了一下,发现如下几点:
1.新加一个节区,名字是.tc。
2.PE入口被修改,指向新加节区头。
3.区段数目+1,映像大小修改,代码块大小修改
仅这些特征,看来有恢复的希望。
于是有了之后的修复代码。其实修复手段很简单了,就是把感染过程反着做就行了嘛。
不过代码里有加了压缩包的处理(加解压我并不熟悉,全是临时学习WinRAR命令行的处理。测试的过程中,可能是系统设置问题,发现解压恢复后,空文件夹无法删除。不过无伤大雅了)
这里先给一下被感染PE的入口情况:
00408000 hget.<ModuleEntryPoint> 64:8B3D 30000000 mov edi, dword ptr fs:[30]
00408007 8B7F 0C mov edi, dword ptr [edi+C]
0040800A 8B7F 1C mov edi, dword ptr [edi+1C]
0040800D 8B3F mov edi, dword ptr [edi]
0040800F 8B7F 08 mov edi, dword ptr [edi+8]
00408012 E8 00000000 call hget.00408017
00408017 5B pop ebx
00408018 81EB 17104000 sub ebx, hget.00401017
0040801E 89BB DC114000 mov dword ptr [ebx+4011DC], edi
00408024 8BF7 mov esi, edi
00408026 0376 3C add esi, dword ptr [esi+3C]
00408029 8B76 78 mov esi, dword ptr [esi+78]
0040802C 03F7 add esi, edi
0040802E 56 push esi
0040802F 8B6E 18 mov ebp, dword ptr [esi+18]
00408032 8B76 20 mov esi, dword ptr [esi+20]
00408035 03F7 add esi, edi
00408037 33D2 xor edx, edx
00408039 56 push esi
0040803A 8B3E mov edi, dword ptr [esi]
0040803C 03BB DC114000 add edi, dword ptr [ebx+4011DC]
00408042 8DB3 9E114000 lea esi, dword ptr [ebx+40119E]
00408048 B9 0F000000 mov ecx, 0F
0040804D F3:A6 repe cmps byte ptr es:[edi], byte ptr [es>
0040804F 75 06 jnz short hget.00408057
00408051 5E pop esi
00408052 8BD6 mov edx, esi
00408054 5E pop esi
00408055 EB 12 jmp short hget.00408069
00408057 5E pop esi
00408058 83C6 04 add esi, 4
0040805B 42 inc edx
0040805C 90 nop
0040805D 3BD5 cmp edx, ebp
0040805F ^ 72 D8 jb short hget.00408039
00408061 83EC 04 sub esp, 4
00408064 E9 18010000 jmp hget.00408181 ;这里有一个跳转,硬编码
00408181 - E9 0AE5FFFF jmp hget.00406690 ;这里跳向原OEP
新加节区情况:
4. item:
Name: .tc
VirtualSize: 0x00007000
VirtualAddress: 0x00008000
SizeOfRawData: 0x00006800
PointerToRawData: 0x00001200
PointerToRelocations: 0x00000000
PointerToLinenumbers: 0x0000006B
NumberOfRelocations: 0x0000
NumberOfLinenumbers: 0x006B
Characteristics: 0xE0000020
(CODE, EXECUTE, READ, WRITE)
以下是修复代码,有兴趣或者有需要的兄弟可以拿去参考参考。其它就不多放了。
// Fuck_Win32Agent.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
#include <ShellAPI.h>
#pragma comment(lib, "Shell32.lib ")
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib ")
#define _DBGOUT
#include "E:\\work\\封装头文件\\dbgout.h"
#include "E:\\work\\封装头文件\\mkValue.h"
unsigned long GetRAbyRVA(HANDLE hMapView,unsigned long RVA)
{
IMAGE_DOS_HEADER* doshead = (IMAGE_DOS_HEADER*)hMapView;
IMAGE_NT_HEADERS* PEhead = (IMAGE_NT_HEADERS*)((unsigned long)doshead + (unsigned long)doshead->e_lfanew);
IMAGE_SECTION_HEADER* ISH = (IMAGE_SECTION_HEADER*)((unsigned long)PEhead + sizeof(IMAGE_NT_HEADERS));
IMAGE_EXPORT_DIRECTORY* lpExpF = 0;
for(int i=0;i<PEhead->FileHeader.NumberOfSections;++i)
{
if(RVA>=ISH->VirtualAddress && RVA<(ISH->VirtualAddress+ISH->Misc.VirtualSize))
{
return( (unsigned long)hMapView + ISH->PointerToRawData + RVA - ISH->VirtualAddress );
}
++ISH;
}
return 0;
}
bool dealPE(const TCHAR* ps)
{
HANDLE hMapView = 0;
bool rets = false;
try
{
HANDLE hFile = CreateFile(ps,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hFile == INVALID_HANDLE_VALUE) return false;
HANDLE hFileMapping = CreateFileMapping(hFile,0,PAGE_READWRITE,0,0,0);
CloseHandle(hFile);
hMapView = MapViewOfFile(hFileMapping,FILE_MAP_READ|FILE_MAP_WRITE,0,0,0);
CloseHandle(hFileMapping);
if(!hMapView) throw runtime_error("MapViewOfFile失败!");
IMAGE_DOS_HEADER* doshead = (IMAGE_DOS_HEADER*)hMapView;
if(doshead->e_magic != 'ZM') throw runtime_error("检测MZ标志失败!");
IMAGE_NT_HEADERS* PEhead = (IMAGE_NT_HEADERS*)((unsigned long)doshead + (unsigned long)doshead->e_lfanew);
if(PEhead->Signature != 'EP') throw runtime_error("检测PE标志失败!");
unsigned long Entry = PEhead->OptionalHeader.AddressOfEntryPoint;
Entry = GetRAbyRVA(hMapView,Entry);
bool befuckentry = false;
bool befucksection = false;
if(mkL(Entry)==0x303D8B64)
{
befuckentry = true;
errs<<"●●●"<<errTchar((TCHAR*)ps)<<"有感染的特征!"<<endd;
}
IMAGE_SECTION_HEADER* ISH = (IMAGE_SECTION_HEADER*)((unsigned long)PEhead + sizeof(IMAGE_NT_HEADERS));
ISH+=(PEhead->FileHeader.NumberOfSections - 1);
if(mkL(ISH->Name)=='\0ct.')
{
befucksection = true;
errs<<"●●●"<<errTchar((TCHAR*)ps)<<"有感染的节区!"<<endd;
}
if(befucksection&&befuckentry)
{
// cout<<"※已经确定:"<<errTchar((TCHAR*)ps)<<"被Win32.Agent感染,是否修复(Y/N):";
// char oks;
// cin>>oks;
// if((oks!='Y') && (oks!='y'))
// {
// errs<<"修复已经被跳过!"<<endd;
// throw 0;
// }
errs<<"正在修复"<<errTchar((TCHAR*)ps)<<"..."<<endd;
int IP = Entry + 0x64 + 1;
int offsets = mkL(IP); //0x118
IP += sizeUL + offsets + 1;
offsets = mkL(IP);
int realEntry = IP + sizeUL + offsets - (int)hMapView - ISH->PointerToRawData + ISH->VirtualAddress;
PEhead->OptionalHeader.AddressOfEntryPoint = realEntry; //修复入口
size_t realfilelen = ISH->PointerToRawData;
PEhead->OptionalHeader.SizeOfCode -= ISH->Misc.VirtualSize; //修复代码块大小
--(PEhead->FileHeader.NumberOfSections); //修复区段个数
PEhead->OptionalHeader.SizeOfImage -= ISH->Misc.VirtualSize; //修复映像大小
UnmapViewOfFile(hMapView);
hMapView = 0;
HANDLE hFile = CreateFile(ps,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hFile == INVALID_HANDLE_VALUE) return false;
SetFilePointer(hFile,realfilelen,0,FILE_BEGIN);
SetEndOfFile(hFile);
CloseHandle(hFile);
errs<<"========修复成功!========"<<endd;
rets = true;
}
}
catch(...)
{
;
}
if(hMapView)UnmapViewOfFile(hMapView);
return rets;
}
enum fileflag {flag_no,PE_EXE,RAR};
fileflag iswant(const TCHAR* ps)
{
size_t len = _tcslen(ps);
if(len<=4)return flag_no;
if(_tcsicmp(TEXT(".exe"),&ps[len-4])==0)
{
return PE_EXE;
}
if(_tcsicmp(TEXT(".dll"),&ps[len-4])==0)
{
return PE_EXE;
}
if(_tcsicmp(TEXT(".sys"),&ps[len-4])==0)
{
return PE_EXE;
}
if(_tcsicmp(TEXT(".rar"),&ps[len-4])==0)
{
return RAR;
}
if(_tcsicmp(TEXT(".zip"),&ps[len-4])==0)
{
return RAR;
}
return flag_no;
}
void domain(const TCHAR* ps);
void doit(const TCHAR* ps)
{
fileflag ff = iswant(ps);
if(ff==flag_no)return;
if(ff==PE_EXE)
{
dealPE(ps);
return;
}
if(ff==RAR)
{
wstring path = ps;
path += TEXT("$$");
wstring cmdline = TEXT("D:\\Program Files\\WinRAR\\WinRAR.exe x -O+ \"");
cmdline += ps;
cmdline += TEXT("\" *.* \"");
cmdline += path;
cmdline += TEXT("\\\"");
STARTUPINFO info;
PROCESS_INFORMATION pi;
ZeroMemory(&info,sizeof(info));
if(!CreateProcess(0,(TCHAR*)cmdline.c_str(),0,0,0,0,0,0,&info,&pi))
{
errs<<"释放:"<<errTchar(ps)<<"失败!"<<endd;
return;
}
WaitForSingleObject(pi.hProcess,INFINITE);
domain(path.c_str());
cmdline = TEXT("D:\\Program Files\\WinRAR\\WinRAR.exe m -r -ep1 -y \"");
cmdline += ps;
cmdline += TEXT("\" ");
cmdline += path;
cmdline += TEXT("\\*\"");
ZeroMemory(&info,sizeof(info));
if(!CreateProcess(0,(TCHAR*)cmdline.c_str(),0,0,0,0,0,0,&info,&pi))
{
errs<<"更新:"<<errTchar(ps)<<"失败!"<<endd;
return;
}
WaitForSingleObject(pi.hProcess,INFINITE);
errs<<"〓〓〓〓已经处理完:"<<errTchar(ps)<<endd;
}
}
void domain(const TCHAR* ps)
{
if(*ps==TEXT('.'))return;
//PathIsDirectory
if(PathIsDirectory(ps))
{
//errs<<"★★★"<<errTchar((TCHAR*)ps)<<":是一个目录,向下枚举..."<<endd;
wstring oo = ps;
if(*(oo.rbegin())==TEXT('\\'))
{
oo.erase(oo.end()-1);
}
oo+=TEXT("\\*.*");
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(oo.c_str(),&wfd);
if(INVALID_HANDLE_VALUE == hFind)return;
for(;FindNextFile(hFind,&wfd);)
{
if(*wfd.cFileName==TEXT('.'))continue;
wstring fn;
fn = ps;
if(*(fn.rbegin())==TEXT('\\'))
{
fn.erase(fn.end()-1);
}
fn+=TEXT('\\');
fn+=wfd.cFileName;
domain(fn.c_str());
}
CloseHandle(hFind);
return;
}
doit(ps);
}
//函数:显示开始时间
void showSYSTEMTIME(void)
{
SYSTEMTIME systime;
GetLocalTime(&systime);
errs<<"************ ";
errs<<setw(4)<<systime.wYear<<'-';
errs<<setw(2)<<systime.wMonth<<'-';
errs<<setw(2)<<systime.wDay<<" ";
errs<<setw(2)<<systime.wHour<<':';
errs<<setw(2)<<systime.wMinute<<':';
errs<<setw(2)<<systime.wSecond<<" ************"<<endd;
}
void usage()
{
cout<<"\n Fuck_Win32Agent [路径] [PE文件] ..."<<endl;
cout<<"\n 如果参数为“路径”时,枚举其下所有文件。"<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
unsigned long times = GetTickCount();
//更改全局输出格式
errs<<setfill('0');
errs<<"****************************************************************"<<endd;
showSYSTEMTIME(); //输出时间
if(argc<=1)
{
usage();
return 0;
}
for(int i = 1;i < argc;++i)
{
domain(argv[i]);
}
unsigned long usetime = GetTickCount() - times;
errs<<"************ 共计用时:"<<setw(3)<<usetime/1000;
errs<<'.'<<setw(3)<<usetime%1000;
errs<<"秒 ************"<<endd;
errs<<"****************************************************************"<<endd;
Beep(2300,50);
return 0;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课