0x09 Windows原理
1. 权限管理
- 相关名词
- SID:安全描述符,用于标识用户身份
- LUID: 局部唯一标识符,系统每次启动都可能变化
- GUID: 全局唯一标识符,一直都保持不变
- UAC(User Account Control): 用户账户控制,vista开始启用
- 相关函数
- 获取进程令牌: OpenProcessToken
- 获取线程令牌: OpenThreadToken
- 获取令牌信息: GetTokenInformation
- 查询特权名称的LUID: LookupPrivilegeValue
- 修改令牌权限: AdjustTokenPrivileges
- 创建管理员进程: ShellExecute传入runas
2. 内存管理
- Window的内存布局
- 每个进程都有单独的4GB空间,布局通常如下
- 0x00000000~0x0000FFFF : 空指针赋值区
- 0x00010000~0x7FFF0000 : 用户领空
- 0x7FFF0000~0x7FFFFFFF : 64Kb禁入分区
- 0x80000000~0xFFFFFFFF : 系统领空
- 每个进程都有单独的4GB空间,布局通常如下
- 虚拟内存的三种状态
- 闲置:没有和物理内存以及虚拟内存建立关联
- 预定(保留):没有和物理内存建立关联,但是占用了虚拟空间
- 提交:和物理内存建立了关联,可以直接使用
- 虚拟内存的映射方式
- 私有: 其它进程不可直接访问的空间
- 映射(mapped):内存映射文件
- 映像(image):通常是可执行文件和模块
- 内存的分页属性
- 只读,可读可写,可读可执行, 可读可写可执行, 写时拷贝
- Windows的模块通常都拥有写时拷贝属性
- 内存管理方式
- 堆内存:通常用于进行小块内存的分配
- 获取默认堆空间:GetProcessHeap()
- 创建新的堆空间:HeapCreate()
- 在堆中申请内存:HeapAlloc()
- 申请的空间以 8 字节对齐,使用HEAP_ZERO_MEMORY可以初始化
- 重新申请空间: HeapReAlloc()
- 释放堆空间:HeapFree()
- 删除堆空间:HeapDestroy()
- 虚拟内存:通常用于大片内存的管理
- 申请内存:VirtualAlloc(首地址,大小,申请方式,分页属性)
- 指定的首地址必须是分配粒度的倍数(0x10000)
- 分配的内存大小会被对齐到分页大小(0x1000)的整数倍
- 如果只保留了内存空间,那么不能进行访问
- 修改分页属性 VirtualProtect() HOOK 调试器
- 释放虚拟内存 VirtualFree()
- 远程写进程内存: WriteProcessMemory(进程的句柄,读写哪里,保存到哪里,大小,实际写入)
- 远程读进程内存: ReadProcessMemory
- 查看虚拟内存属性: VirtualQuery
- 注:当使用[EX]版本的函数时,可以对其它进程进行操作
- 申请内存:VirtualAlloc(首地址,大小,申请方式,分页属性)
- 文件映射:可用于进程通信和大文件的操作
- 创建文件映射对象: CreateFileMappingA
- 可以映射一个文件,也可以映射一块内存
- 关联文件到内存:MapViewOfFile
- 刷新内存数据到文件:FlushViewOfFile
- 取消关联:UnmapViewOfFile
- 创建文件映射对象: CreateFileMappingA
- 堆内存:通常用于进行小块内存的分配
3. 模块注入
- 注入,让其它进程执行指定的代码
- 常见的注入方式:
- 消息钩子注入 HHOOK SetWindowsHookEx(类型,回调函数,模块句柄,线程)
- 远程线程注入 CreateRemoteThread
- 注册表注入 所有的GUI程序在执行前,都会加载注册表的某一个位置提供的所有DLL
- 劫持模块注入 当前的 环境变量 系统路径,系统模块不适用,应用程序适用
- COMRes注入 类似注册表注入
- APC注入 给其它的线程提供APC函数,当目标线程可警醒时,会调用
- 输入法注入 最麻烦的,自己实现一套输入法的接口
4. HOOK技术
- 远程线程注入的流程
- 确认需要注入的程序并获取目标进程的句柄:GetWindowThreadProcesssId() OpenProcess();
- 在目标进程内申请空间: VirtualAllocEx(Process);
- 向空间内写入dll名称:WriteProcessMemory(IatHookDllName);, DLL名称需要是绝对路径
- 创建远程线程, 关键函数: CreateRemoteThread(LoadLibrary(A/W);
- 等待线程执行结束:WaitForSingleObject(Thread, INFINITE);
- 释放空间:VirtualFreeEx(Process, Buffer, 0, MEM_RELEASE);
- 关闭句柄:CloseHandle();
- Message Hook
- windows操作系统维护了一个钩子链,可以通过函数向其中添加或删除函数
- 添加钩子: SetWindowsHookEx, 钩子的类型
- 取消钩子: UnhookWindowsHookEx
- 调用下一个钩子函数:CallNextHookEx 通常是必须调用的
IAT(eat) Hook
- IAT HOOK的流程 FF15 cal FF25 jmp
原理是修改导入地址表中对应的函数地址
找到想要HOOK的函数,获取函数原型并实现自己的对应函数
HANDLE WINAPI MyHookFunc()
{
if (满足HOOK条件)
{
// 执行自己想执行的代码
}
else
{
// 调用原函数
OldFunc();
}
}
遍历目标进程的导入表,找到指定模块,并找到模块中对应函数所在IAT中的地址
- 修改内存属性,将新的函数地址写入到IAT表中,修改完后恢复。
- 卸载: 将保存的原函数地址重新写入到IAT中
- 注:可以使用GetProcAddress函数过掉 IATHook
- 通过 EAT HOOK 可以 BYPASS GetProcAddress
- Inline Hook
- inline Hook 可用于内核层和用户层,可以hook代码的任意位置
- inline HOOK 的流程
- 找到想要HOOK的函数,获取函数原型并实现自己的对应函数
- 获取目标函数的地址并保存,用于卸载 Hook(GetProcAddress)
- 通过目标地址 - 指令所在地址 - 5(E9XXXXXXXX)求得跳转偏移
- 使用偏移构建跳转指令并写入到目标函数的执行流程
- 写入的时候是非线程安全的, 使用原子操作,暂停其它所有线程
- 注:写入代码时需要修改并还原保护属性
- 注:可以使用指令比对,hash计算的方式检查是否被内联HOOK