天天看點

Win7 Wininit.exe任意加載/執行

1.背景:

a.Windows關機時,将調用NtShutdownSystem Native API來執行關機動作。

b.在WinXp時代,使用者執行"關機"後,将由winlogon.exe調用NtShutdownSystem API;但是到了Win7時代,winlogon.exe不再司此職,而是交由Wininit.exe調用NtShutdownSystem API。 

c.進入win10後,雖然Wininit.exe中仍保留WinInitShutdown及PerformSystemRestore函數,但關機時不會由WinInitShutdown調用NtShutdownSystem Native API。是以該任意加載/執行不适用于win10。

2.正文:

在Win7上,給nt!NtShutdownSystem下斷點後,當使用者點選"開始"菜單--"關機"後會得到下列函數調用棧:

#搜尋NtShutdownSystem Native API并下斷點
kd> x nt!NtShutdownSystem
8318c3e6 nt!NtShutdownSystem = <no type information>
kd> bp nt!NtShutdownSystem


#關機後,windbg會中斷在WinInitShutdown函數
kd> g
Breakpoint 0 hit
nt!NtShutdownSystem:
8318c3e6 8bff            mov     edi,edi
kd> kb
ChildEBP RetAddr  Args to Child              
95472c28 82ba3173 00000002 0019f8e8 76fea364 nt!NtShutdownSystem
95472c28 76fea364 00000002 0019f8e8 76fea364 nt!KiFastCallEntry+0x163
0019f8c4 76fc1814 00326205 00000002 003220c8 ntdll!KiFastSystemCallRet
0019f9c4 77557646 7ffd7000 0019fa10 76ff0915 ntdll!NtShutdownSystem+0xc
0019f9d0 76ff0915 7ffd7000 88d9a0a3 00000000 kernel32!BaseThreadInitThunk+0xe
0019fa10 76ff0b71 0032f0cd 7ffd7000 00000000 ntdll!__RtlUserThreadStart+0x23
0019fa28 00000000 0032f0cd 7ffd7000 00000000 ntdll!_RtlUserThreadStart+0x1b      

上述調用堆棧不是很詳細,切換到wininit程序,檢視更具體的調用堆棧:

#枚舉所有程序
kd> !process 0 0 
**** NT ACTIVE PROCESS DUMP ****

PROCESS 87bf19f0  SessionId: 0  Cid: 0180    Peb: 7ffd7000  ParentCid: 0148
    DirBase: 3fe820a0  ObjectTable: 99218a60  HandleCount:  88.
    Image: wininit.exe

#根據wininit的EPROCESS值,切換到wininit程序
kd> .process /i /p 87bf19f0  
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
82b94a9c cc              int     3

#顯示wininit程序更詳細的資訊 (包含線程及調用堆棧)
kd> !process 87bf19f0  7
PROCESS 87bf19f0  SessionId: 0  Cid: 0180    Peb: 7ffd7000  ParentCid: 0148
    DirBase: 3fe820a0  ObjectTable: 99218a60  HandleCount:  88.
    Image: wininit.exe

        THREAD 8e49c290  Cid 0180.0184  Teb: 7ffdf000 Win32Thread: ffb53978 WAIT: (Executive) KernelMode Non-Alertable
            95472958  SynchronizationEvent
            95472930  Semaphore Limit 0x12

        Win32 Start Address wininit!WinMainCRTStartup (0x0032f0cd)
        Stack Init 95472ed0 Current 95472708 Base 95473000 Limit 95470000 Call 0
        Priority 15 BasePriority 15 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        ChildEBP RetAddr  Args to Child              
        95472720 82a6a110 8e49c290 000031d8 00000000 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
        95472758 82a6b715 95472930 8e49c290 8e49c38c nt!KiSwapThread+0x394
        95472780 82a5bda6 8e49c290 8e49c350 00000000 nt!KiCommitThreadWait+0x461
        954728f8 83203019 00000002 95472974 00000001 nt!KeWaitForMultipleObjects+0x6d2
        95472980 83202d32 00000011 9762e350 00000004 nt!PopSleepDeviceList+0xe9
        954729d8 83202af3 95472a70 00000001 00000006 nt!PoBroadcastSystemState+0x236
        95472a00 83203d98 95472ad4 95472b58 8320398e nt!PopSetDevicesSystemState+0x63
        95472ac0 82ba3173 00000006 00000004 c0000004 nt!NtSetSystemPowerState+0x40a
        95472ac0 82b92c1d 00000006 00000004 c0000004 nt!KiFastCallEntry+0x163 (FPO: [0,3] TrapFrame @ 95472ad4)
        95472b44 83203a70 00000006 00000004 c0000004 nt!ZwSetSystemPowerState+0x11 (FPO: [3,0,0])
        95472c14 8318c418 00000006 00000004 c0000004 nt!NtSetSystemPowerState+0xe2
        95472c28 82ba3173 00000002 0019f8e8 76fea364 nt!NtShutdownSystem+0x32
        95472c28 76fea364 00000002 0019f8e8 76fea364 nt!KiFastCallEntry+0x163 (FPO: [0,3] TrapFrame @ 95472c34)
        0019f8c4 76fc1814 00326205 00000002 003220c8 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        0019f8c8 00326205 00000002 003220c8 003215a0 ntdll!NtShutdownSystem+0xc (FPO: [1,0,0])
!!----> 0019f8e8 00327f4e 00000002 00336904 00531ceb wininit!WinInitShutdown+0x186 (FPO: [Non-Fpo])
        0019f934 0032ef64 00320000 00000000 00531ceb wininit!WinMain+0xcd3 (FPO: [Non-Fpo])
        0019f9c4 77557646 7ffd7000 0019fa10 76ff0915 wininit!_initterm_e+0x1a1 (FPO: [Non-Fpo])
        0019f9d0 76ff0915 7ffd7000 88d9a0a3 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
        0019fa10 76ff0b71 0032f0cd 7ffd7000 00000000 ntdll!__RtlUserThreadStart+0x23 (FPO: [Non-Fpo])
        0019fa28 00000000 0032f0cd 7ffd7000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])      

逆向WinInitShutdown實作,發現它會調用内部函數:PerformSystemRestore

Win7 Wininit.exe任意加載/執行

 逆向該PerformSystemRestore函數,還原得到如下示意代碼(完整代碼見附件wininit.idb):

MACRO_ERROR __stdcall PerformSystemRestore(void (__stdcall *a1)(const unsigned __int16 *))
{

  Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\WinInit", 0, 3u, &phkResult);
  Status = RegQueryValueExW(phkResult, L"RestoreInProgress", 0, &Type, Data, &cbData);
  if ( Type != 4 )
  {
    Status = ERROR_INVALID_DATA;
    goto LABEL_52;
  }
  if ( *(_DWORD *)Data )
  {
    cbData = 522;
    Status = RegQueryValueExW(phkResult, L"RestoreModule", 0, &Type, (LPBYTE)v11, &cbData);
    if ( Status || Type != 1 || cbData < 2 || *((_WORD *)&Status + (cbData >> 1) + 1) )
    {
      if ( Status == ERROR_SEVERITY_SUCCESS )
        Status = 13;
    }
    else
    {
      cbData = 261;
      Status = RegQueryValueExA(phkResult, "RestoreFunction", 0, &Type, &v13, &cbData);
      if ( Status || Type != 1 || cbData < 1 || *(&v12 + cbData) )
      {
        if ( Status == ERROR_SEVERITY_SUCCESS )
          Status = 13;
      }
      else
      {
        v2 = LoadLibraryW(v11);
        hLibModule = v2;
        if ( v2 )
        {
          ProcAddr = GetProcAddress(v2, (LPCSTR)&v13);
          if ( ProcAddr )
            goto LABEL_56;
          Status = GetLastError();
          if ( Status == ERROR_SEVERITY_SUCCESS )
            RtlAssert("ERROR_SUCCESS != dwRet", "d:\\w7rtm\\ds\\security\\umstartup\\wininit\\srestore.cxx", 0xA4u, 0);
        }

      }
    }
  }

LABEL_57:
  if ( ProcAddr )
  {
//調用RestoreFunction指向的函數
    ((void (__stdcall *)(_DWORD))ProcAddr)(a1);
  }
  if ( phkResult )
    RegCloseKey(phkResult);
  if ( hLibModule )
    FreeLibrary(hLibModule);
  return Status;
}      

這段函數流程為:

1.檢查系統資料庫HKLM\SYSTEM\CurrentControlSet\Control\WinInit下是否有DWORD鍵RestoreInProgress;

2.如果RestoreInProgress存在,且值為1。則繼續搜尋是否存在字元串鍵RestoreModule和RestoreFunction;

3.如果RestoreModule和RestoreFunction鍵值存在,則調用LoadLibrary和GetProcAddress獲得RestoreFunction函數位址;

4.以上步驟執行正确,則執行RestoreFunction所指向的函數。

3.利用方式:

發現了PerformSystemRestore函數的執行流程,對應的利用方式可以說是手到擒來:

1.在系統資料庫HKLM\SYSTEM\CurrentControlSet\Control\WinInit下手動建立RestoreInProgress/RestoreModule/RestoreFunction三個鍵,如下:

Win7 Wininit.exe任意加載/執行

 2.将RestoreModule指向的Dll放到%SystemRoot%/System32路徑下,以下是我做的測試函數及導出函數,導出函數函數名必須與RestoreFunction的鍵值一緻。出于示範目的,往c盤根目錄下建立一檔案:

extern "C" SHUTDOWNRESTORE_API int ShutdownRestore(void);

SHUTDOWNRESTORE_API int ShutdownRestore(void)
{
  FILE* flagFile;
  char ctmBegin[32] = {0};
  time_t tmNow = time(NULL);
  tm *ptmNow = localtime(&tmNow);
  strftime(ctmBegin, 32, "%Y%m%d%H%M%S", ptmNow);
  flagFile = fopen("c:\\loaded.txt","a+");
  fwrite(ctmBegin,32, 1, flagFile);
  fclose(flagFile);
  return 0;
}      
Win7 Wininit.exe任意加載/執行

繼續閱讀