代码注入与拦截
[TOC]
权限
权限管理
UAC机制
管理方式
在管理员账户下,运行一个程序,也是低权限,只有选择管理员方式运行,才会分配高权限。
调整UAC
方法1:gpedit
方法2 :设置
使用案例
1 | BOOL CMy01UACDlg::OnInitDialog() |
内存管理
Windows系统使用虚拟内存的好处是什么
a) 无论物理内存实际有多大,每一个进程都有4GB的虚拟地址空间。
b) 每一个进程在虚拟地址空间的使用上都是相似的,低2GB是用户空间,高2GB是系统空间,低2GB的用户代码空间的代码无法访问高2GB系统空间。
c) 在进程中使用的全部都是虚拟地址,具体虚拟地址到物理地址的转换由操作系统内核完成,故而你无法在自己的进程中访问到其他进程的内存,虽然大家的地址长得如此类似。
d) 一个进程的虚拟空间只有使用一部分与物理内存有映射关系,并且windows尽量保证对于不同进程的同一份数据,在物理内存中只有一份,分别映射到多个进程中。从而节约内存。
e) 当各个进程所使用的内存数量超出物理内存的时候,操作系统还能够将物理内存中暂时用不到的数据交换到硬盘中。
堆的管理
API | 说明 |
---|---|
HeapCreate | 在进程中创建一个堆,返回一个堆句柄 |
GetProcessHeap | 获取当前进程中的一个堆,返回一个句柄 |
GetProcessHeaps | 获取进程中的所用堆,堆的数量和堆的各个句柄 |
HeapAlloc | 从指定的堆上分配块 |
HeapReAlloc | 重新分配内存,改变已经分配好的堆内存块大小 |
GetSystemInfo | 获取系统信息 |
HeapSize | 获取指定堆的大小 |
HeapFree | 释放HeapAlloc和HeapReAlloc申请的内存 |
HeapDestroy | 销毁由HeapCreate创建的堆 |
CreateToolhelp32Snapshot | 可以分别创建进程、线程、进程模块、进程堆的快照 |
Heap32First | 用来首次调用,获得第一个堆对象的信息 |
Heap32Next | 以后的调用由他来完成,不断的获取堆对象信息 |
基本使用
1 | void Test() |
使用场景:
一般情况下,咱么都是使用malloc或者new。如果有以下场景可以尝试使用堆,假如咱们的程序需要大量的去申请小块的内存,管理这些地址,就会比较麻烦,此时就可以使用自己创建的堆,在用完了内存之后,去直接销毁堆,此时内存就自动释放了,也就免去了挨个去释放的麻烦。
遍历堆
和遍历进程,线程一致的,使用快照去遍历即可。
虚拟内存管理函数
作用 | 函数名 | 说明 |
---|---|---|
分配 | VirtualAlloc | 分配或预定一块虚拟内存 |
VirtualAllocEx | 可以在其他进程分配或预定一块虚拟内存 | |
释放 | VirtualFree | 将一块虚拟内存释放 |
VirtualFreeEX | 可以将释放其他进程的内存 | |
锁定与解锁 | VirtualLook | 可以将内存锁定,不能交换数据到硬盘 |
VirtualUnlook | 为内存解锁 | |
修改保护属性 | VirtualProtect | 修改一块虚拟内存的属性 |
VirtualProtectEx | 可以修改其他内存的属性 | |
读写其他进程内存 | ReadProcessMemory | 读写远程进程的内存数据 |
WriteProcessMemory | 将数据写入远程进程内存 | |
查询内存状态 | VirtualQuery | 查询内存状态 |
VirtualQueryEx | 可以查询其他内存状态 |
安全属性
属性 | 值 | 描述 |
---|---|---|
PAGE_NOACCESS | 0x01 | 不可访问 |
PAGE_READONLY | 0x02 | 只读 |
PAGE_READWRITE | 0x04 | 可读可写 |
PAGE_WRITECOPY | 0x08 | 可写可读 |
PAGE_EXECUTE | 0x10 | 可执行 |
PAGE_EXECUTE_READ | 0x20 | 可读可执行 |
PAGE_EXECUTE_READWRITE | 0x40 | 可读可写可执行 |
PAGE_EXECUTE_WRITECOPY | 0x80 | 可执行,写时复制 |
PAGE_GUARD | 0x100 | |
PAGE_NOCACHE | 0x200 | |
PAGE_WRITECOMBINE | 0x400 | |
PAGE_GRAPHICS_NOACCESS | 0x0800 | |
PAGE_GRAPHICS_READONLY | 0x1000 | |
PAGE_GRAPHICS_READWRITE | 0x2000 | |
PAGE_GRAPHICS_EXECUTE | 0x4000 | |
PAGE_GRAPHICS_EXECUTE_READ | 0x8000 | |
PAGE_GRAPHICS_EXECUTE_READWRITE | 0x10000 | |
PAGE_GRAPHICS_COHERENT | 0x20000 | |
PAGE_ENCLAVE_THREAD_CONTROL | 0x80000000 | |
PAGE_REVERT_TO_FILE_MAP | 0x80000000 | |
PAGE_TARGETS_NO_UPDATE | 0x40000000 | |
PAGE_TARGETS_INVALID | 0x40000000 | |
PAGE_ENCLAVE_UNVALIDATED | 0x20000000 | |
PAGE_ENCLAVE_DECOMMIT | 0x10000000 |
申请和释放
1 | int main() |
修改保护属性
1 | int main() |
文件映射
可以将文件直接映射进内存的一种技术。
API | 说明 |
---|---|
GetSystemInfo | 获取系统信信息,用于确定分配粒度 |
CreateFileMapping | 创建一个mapping对象 |
OpenFileMapping | 打开已命名的mapping对象(可跨进程) |
UnmapViewOfFile | 取消文件映射 |
MapViewOfFile | 将mapping对象的文件映射到内存 |
FlushViewOfFile | 将映射到内存的文件写回到硬盘 |
有两个作用:
1 操作文件比较方便
1 | int main() |
2 文件映射是一个内核对象,可以在多进程中去访问,所以文件映射也是一种进程间通讯机制。
进程间通讯
通讯A端
1 | // 06_进程间通讯.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
通讯B端
1 |
|
虚拟内存的遍历
1 | SIZE_T WINAPI VirtualQueryEx( |
1 | typedef struct _MEMORY_BASIC_INFORMATION { |
页面的状态
状态 | 值 | 说明 |
---|---|---|
空闲的(Free) | 0x00010000 | 进程不能访问这种页面,此页面还没有被分配。 |
保留的(reserve) | 0x00002000 | 这个页面被预定了。但是还未与物理内存映射,因此这里也是不能访问的。 |
提交的(commit) | 0x00001000 | 内存已经被分配了,并且也与物理存储器映射了,进程已经可以访问这里 |
页面类型
映射方式 | 描述 |
---|---|
private | 进程私有内存,不被其他进程所共享, 一般是堆,栈 |
mapped | 从别的进程内存映射而来 |
image | 从程序的PE映像映射而来,一般是映像的区段. |
遍历代码
1 | #include <Windows.h> |
Dll注入
注:职业黑客的必修课
重点内容)
1 什么是DLL注入??为什么要DLL注入??
在一个本来不需要加载此DLL的进程中,强行的使其加载此DLL文件。那么这个就叫做DLL注入技术。
我们在向一个进程中注入我们自己的DLL,相当于在对方的进程中加入了我们自己的代码,可以修改对方程序的功能。
游戏辅助,输入法,对于软件行为的拦截。
2 DLL注入的方式有哪些??
远程线程注入
消息钩子注入
注册表注入
APC注入
输入法注入
远程线程注入
1 | #include <Windows.h> |
4 关于64位的注入
32位的dll正常情况只能注入到32位程序中,注入程序也应该是32位,64位的dll正常情况只能注入到64位的程序中,注入程序也应该是64位。
消息钩子注入
什么是Hook,这个概念应该从何说起???
Hook:是钩子的意思
Hook技术主要指的是拦截程序原有的信息,数据,代码,
1 使得你有机会对拦截到的信息数据做处理。然后再交给原来的程序去使用,从而能够截获到程序的关键信息。可以查看,也可以修改。
2 能够修改程序的部分功能。
2 Hook是怎么分类的??
在windows系统下,有两类Hook:
2.1 windows消息Hook。windows提供的能够让程序员截获到所有窗口程序消息的机制。
消息Hook也是我们的一种Dll注入手段。
2.2 自定义Hook 非常普遍的Hook方式,也是我们通常意义所说的Hook。
2.2.1 修改程序的代码,使得其能够执行到Hook者提供的“善意代码”中。 inline-Hook
2.2.2 修改存储函数地址的变量,当程序从变量中获取函数地址并调用的时候,就会调用到Hook者提供的“善意代码”了。
IAT-Hook
IDT-Hook
SYSENTR-Hook
3 windows消息钩子的实现的原理以及代码
3.1 windows消息钩子的实现的原理
SetWindowsHookEx这个函数,能够实现的功能是截获 1 系统中所有的窗口程序的消息或者 2 某一个线程的窗口消息。
截获到了消息,必然是需要执行自己的代码,自己的代码需要放置在一个dll中,然后消息钩子设置成功之后,会将dll注入到目标进程,从而使得自己的回调函数能够在对方的进程中执行。
额外的知识点:窗口程序的消息是被某一个线程获取到的,哪一个线程创建了窗口,哪一个线程就能够获得此窗口的消息。此线程在创建完窗口之后,就变成了GUI线程。
1 | HHOOK SetWindowsHookExA( |
1 | //当钩子使用完毕之后,卸载钩子 |
在钩子的消息拦截函数的最后,应该调用这个函数,因为程序可能会有多个钩子,新添加的在最上面,为了不影响其他钩子的功能,需要调用这个函数。
1 | WINUSERAPI |
消息钩子的代码
1 |
|
消息钩子使用了调试函数 OutputDebugString(szInfo);输出按键码,但我们看不到对方程序的调试信息,可以通过下图程序查看
自定义钩子:
自定义钩子两大类:内联钩子 修改存储函数地址变量的钩子
4.1 什么是内联钩子 inline-Hook
任何位置,都可以修改为jmp,使其执行到此处时,能够跳转到我们自己的代码去执行:
1 被修改的指令,是否是有用的,如果是有用的,那么你就需要在你自己的代码中,将有用的指令写一遍,使其在你代码中能够执行。
2 jmp指令一般是5个字节,所以我们选取的指令最好也是5个字节,如果不是5个字节,那么会发生指令截断,跳转回来的时候,就需要考虑跳转到完整的指令后去执行程序本身的代码。
3 jmp指令OPCODE的操作数怎么求得,也是Hook的关键知识点
jmp指令OPCODE的操作数 = 要跳转的目标地址-hook点所在的地址-5
DLL测试代码
InLine_HOOK
.h文件
1 |
|
.cpp文件
1 |
|
dllmain.cpp文件
1 |
|
IAT_HOOK
.h文件
1 |
|
.cpp文件
1 |
|
dllmain.cpp
1 |
|
Process_Hook
DLL文件
1 | // dllmain.cpp : 定义 DLL 应用程序的入口点。 |
测试文件
1 | // 注入.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 |
CAPIHook函数封装
1 |
|
Use this card to join the H4ckbird home and participate in a pleasant discussion together .
Welcome to H4ckbird's page,wish you a nice day.