0x0.提出问题
- 当游戏公司通过自己的检测技术检测到我们的注入模块时,我们应该采取什么样的反检测技术进行别人看不到的攻击呢?
0x1.检测技术的原理:
- 能够检测到对应的模块信息,说明这个模块存在于某块内存中,一定有个结构体记录了这些模块信息,那么我们可以尝试去把这个注入模块的信息给删除掉。
0x2.PEB和TEB
PEB(Process Environment Block,进程环境块):存放进程信息的结构体,尺寸非常大
TEB(Thread Environment Block): 该结构体包含进程中运行线程的各种信息,进程中的每个线程都对应着一个TEB结构体
MSDN文档的介绍
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
ULONG Reserved6;
PVOID Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId;
} PEB, *PPEB;
Reserved:
- 闭源,微软不告诉我们,要我们自己去猜😢🤢
- 在不同操作系统(xp,win7…)下有不同的含义,微软也不知道怎么告诉我们
- 可以用Windbg打印出来去研究不同操作系统下是什么含义;也可以去参考别人分析好的资料
BeingDebugged: 我们可以利用这个特性来检测有没有被调试的一种检测方案
- 当我们附加调试器,它会被修改为1
- 当我们没有附调试器,他会被修改为0
Ldr : 该结构包含有关进程的已加载模块的信息。
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID EntryPoint;
PVOID Reserved3;
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
union {
ULONG CheckSum;
PVOID Reserved6;
};
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
0x3.攻击方案:把注入模块的节点在PEB结构体中删除掉
提出问题:怎么获取到PEB结构体呢?✔ 答:TEB里面有PEB指针,我们只需要得到TEB就可以了
typedef struct _TEB {
PVOID Reserved1[12];
PPEB ProcessEnvironmentBlock;
PVOID Reserved2[399];
BYTE Reserved3[1952];
PVOID TlsSlots[64];
BYTE Reserved4[8];
PVOID Reserved5[26];
PVOID ReservedForOle;
PVOID Reserved6[4];
PVOID TlsExpansionSlots;
} TEB, *PTEB;
提出问题:怎么得到TEB结构体呢?答:它放在了FS段寄存器里面,我们通过访问它就可以得到TEB
#include <Windows.h>
#include <winternl.h>
int main() {
PPEB peb;
_asm {
mov eax, fs:[0x30];
mov peb, eax;
}
}
设计程序验证我们的想法:
0x4 利用PEB模块获取进程模块信息
0x30.如果LDR_DATA_TABLE_ENTRY结构体发生了变化,那么这个程序就不能够正常使用了;
0x31.为了提高程序的兼容性,我们需要把0x8替换成动态的
int structDis = (int)&lDis->InMemoryOrderLinks;
当我们通过自己的猜测和各种手段得到结构体里面的属性代表的含义,可以自己声明一个结构体类型🎂
typedef struct _LDR_DATA_TABLE_ENTRYA {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID EntryPoint;
PVOID ImageSize;//
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
#pragma warning(push)
#pragma warning(disable: 4201) // we'll always use the Microsoft compiler
union {
ULONG CheckSum;
PVOID Reserved6;
} DUMMYUNIONNAME;
#pragma warning(pop)
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRYA, * PLDR_DATA_TABLE_ENTRYA;
0x5 隐藏对应的模块:通过删除节点,但是通过实证发现并没有被隐藏,为什么呢?
通过Windbg的调试打印和逆向分析, 填充了微软官方文档和实际的结构体不一致的地方,从而实现了模块的隐藏
二.通过PE特征的角度去定位注入模块
通过CE或者自己写代码去搜索
去除PE特征
通过pchunter64去搜索进程模块
无痕注入:
1.在驱动层把驱动干掉
2.在应用层把驱动层干掉
总结:网络攻防是无止境的,最终一定是技术强的人获胜