WindowsAPI编程核心技术-隐藏技术
WindowsAPI编程核心技术-隐藏技术
进程伪装
NtQueryInformationProcess
1 | NTSTATUS WINAPI NtQueryInformationProcess( |
PROCESS_BASIC_INFORMATION
1 | typedef struct _PROCESS_BASIC_INFORMATION{ |
例子
先手动从ntdll.dll中获取NtQueryInformationProcess
函数,再获取指定进程PEB。因为存在进程隔离,对其他进程的读写只能通过ReadProcessMemory
和WriteProcessMemory
进行实现。
1 |
|
傀儡进程
GetThreadContext
获取指定线程上下文,x64用Wow64GetThreadContext
。
1 | BOOL WINAPI GetThreadContext( |
SetThreadContext
设定指定线程上下文,x64用Wow64SetThreadContext
。
1 | BOOL WINAPI SetThreadContext( |
ResumeThread
减少线程暂停计数,递减到零时恢复线程执行。
1 | DWORD WINAPI ResumeThread( |
例子
修改某一进程的内存数据为shellcode,再修改EIP为该代码地址。
1 | BOOL ReplaceProcess(WCHAR* pszFilePath, PVOID pReplaceData, DWORD dwReplaceDataSize, DWORD dwRunOffset) { |
进程隐藏
若WinDBG一直打印一些无用日志,可用下列命令关闭:
1 | ed nt!kd_fusion_mask 0 |
ZwQuerySystemInformation
获取系统信息,NTDLL.DLL没有导出,用LoadLibrary
和GetProcAddress
手动链接,但NtQuerySystemInformation
已经导出了。Windows 8开始这东西就没了,有一些代替的函数。
1 | NTSTATUS WINAPI ZwQuerySystemInformation( |
当SystemInformationClass为SystemBasicInformation时,SystemInformation参数要求一个指向SYSTEM_BASIC_INFORMATION的指针。为SystemProcessInformation时函数返回一个SYSTEM_PROCESS_INFORMATION结构链表,每个结构表示一个进程信息。
SYSTEM_PROCESS_INFORMATION
1 | typedef struct _SYSTEM_PROCESS_INFORMATION { |
例子
遍历进程一般用EnumProcesses
或CreateToolhelp32Snapshot
来实现,这俩都用的ZwQuerySystemInformation
来实现,所以HOOK这玩意儿就行了。这里使用Inline HOOK的方法,将ZwQuerySystemInformation
的前几字节改为jmp
无条件跳转到假的函数地址即可。x86要改前$5$字节,x64要改前$12$字节。别忘了备份前几字节UnHOOK的时候恢复用。
1 |
|
下面通过Windows钩子方式实现,但为了实现进程隐藏必须HOOK所有进程对该函数调用,这里选择安装全局消息钩子WH_GETMESSAGE将实现HOOK功能的DLL注入每个线程。全局消息钩子必须创建DLL,导出安装和卸载全局消息钩子函数。
DLL头文件:
1 |
|
DLL源代码:
1 |
|
调用程序:
1 |
|
内核DKOM法
该法不确定Windows 10上能不能用。EPROCESS结构中的ActiveProcessLinks成员将各个进程的EPROCESS结构体连接成双向链表,ZwQuerySystemInformation
就这么实现的,所以这里对该成员摘链。关闭驱动后需要手动还原,否则可能蓝屏。操作不好容易发现,还只能欺骗进程管理器。
1 |
|
DLL劫持
先劫持DLL,使程序调用假DLL,执行后再转发给真正的DLL完成原工作。
了解一下就行,实战用AheadLibEx一键生成。
进入x64时代后,x86的DLL路径会被自动从“C:\Windows\System32”重定向到“C:\Windows\SysWOW64”目录。
DLL函数转发
这里演示劫持VERSION.DLL文件,因为这个导出函数较少。
直接转发
将原VERSION.DLL重命名为OLD_VERSION.DLL,然后通过编译指令直接转发:
1 |
|
WINAPI 动态调用转发
这个方法在x64下不好使,__declspec(naked)
和__asm
关键字在x64下不被支持。
1 |
|
VAD隐藏R3内存
EPROCESS中VadRoot成员是个存放进程内存块的树结构,可以将某块内存的上一个节点的EndingVpn指向下一个节点的EndingVpn,类似于摘链。
先获取俩内存地址:
1 |
|
隐藏方法:
1 | PMMVAD p1 = vad_enum((PMMVAD)VadRoot, 0x3a0); // 遍历第一个结点 |
WinDBG中的Start和End字段需要乘以0x1000,即一个页面大小,才得到真正地址。代码略。
DKOM进程摘链隐藏
1 |
|
驱动无痕隐藏自身
思路是找到MiProcessLoaderEntry
入口地址,该函数用于将驱动信息加入链表或移除链表。如:
1 | MiProcessLoaderEntry(pDriverObject->DriverSection, 1); //添加 |
寻找方法为:
- 寻找
MmUnloadSystemImage
函数地址,可通过MmGetSystemRoutineAddress
函数得到。 - 在
MmUnloadSystemImage
里面寻找MiUnloadSystemImage
函数地址。 - 在
MiUnloadSystemImage
里面继续寻找MiProcessLoaderEntry
即可。
下面先找MiUnloadSystemImage
和MiProcessLoaderEntry
的地址:
1 |
|
然后直接破坏掉自身驱动的入口地址等,可实现自身隐藏:
1 |
|
上述方法可能导致蓝屏,还可用这种方法:
1 |
|