ps: 以下实验均在 windows xp系统下完成
作用:3环断链通常用于在用户层隐藏dll
获取dll模块的步骤为:获取 TEB -> PEB -> ldr -> dll模块
(1)TEB的获取方法为:fs:[0]
(2)通过TEB结构体发现,PPEB(PEB指针,指向PEB首地址)位于TEB偏移0x30处,因此PPEB == fs:[0x30]
(3)通过PEB结构体发现,ldr位于PEB偏移0xc处,因此 ldr == PPEB + 0xc
(4)通过ldr指向的结构体 _PEB_LDR_DATA 结构体找到3个双向循环链表 _LIST_ENTRY结构体
(5)_LIST_ENTRY结构体有两个成员,指向前驱模块节点的 _LIST_ENTRY、指向后继模块节点的 _LIST_ENTRY
(6)节点指针指向的是 _LIST_ENTRY 结构体,该结构体存储了模块在链表中的位置信息
(7)通过 _LDR_DATA_TABLE_ENTRY 结构体中偏移 0x18的 DllBase 或 0x2c 的 BaseDllName 确定要隐藏的dll,并通过该结构体中的 _LIST_ENTRY结构体删除该节点在链表中的位置信息(双向循环链表删除节点),即可达到3环下的dll隐藏
TEB结构体:3环下的线程环境块结构体
PEB结构体:3环下的进程环境块结构体
_PEB_LDR_DATA结构体:ldr的结构体
_LIST_ENTRY结构体:上述三个链表的结构体
_LDR_DATA_TABLE_ENTRY结构体:存储dll模块的信息
PEB断链源码:
关键代码解释:
作用:0环断链通常用于在内核层隐藏进程
获取进程模块的步骤为:获取 _KPCR -> _KPRCB -> KTHREAD -> _KAPC_STATE -> _KPROCESS -> _EPROCESS
(1)KPCR 的获取方法为:fs:[0]
(2)KPCR 结构体中偏移0x120处有一个成员 _KPRCB 结构体,该结构体中偏移0x4处(即 fs:[0x124])有一个 CurrentThread 指针,指向 _KTHREAD 结构体
(3)_KTHREAD 结构体偏移0x34处有一个 ApcState 结构体,该结构体偏移0x10处有一个 Process 指针,指向 _KPROCESS
(4)_EPROCESS 结构体的第一个成员是 Pcb,是一个 _KPROCESS 结构体
(5)(3)中的 Process 指针指向的就是 _EPROCESS 中的一个成员 _KPROCESS 结构体,也是 _EPROCESS 结构体的首地址。这一点和PEB断链中,
ldr->Flink 与 _LDR_DATA_TABLE_ENTRY 首地址相等是一样的
(6)_EPROCESS 结构体中偏移0x88有一个 _LIST_ENTRY 结构体,该结构体保存了当前进程在进程链表中的位置信息
(7)节点指针指向的是 _LIST_ENTRY 结构体,该结构体存储了模块在链表中的位置信息
(8)通过 _EPROCESS 结构体中偏移0x174的 ImageFileName 确定所属进程, 并通过该结构体中的 _LIST_ENTRY结构体删除该节点在链表中的位置信息(双向循环链表删除节点),即可达到0环下的进程隐藏
KPRC(Kernel Processor Control Region, 内核处理器控制区域)结构体:
_KPRCB 结构体:
_KTHREAD 结构体:
_KAPC_STATE 结构体:
EPROCESS断链源码:
关键代码解释:
(1)更新pCurProcess的说明
(2)获取EPRCESS的两种办法
第1种:通过内核函数 PsGetCurrentProcess。原理已在前面部分解释
第2种:
获取进程模块的步骤为:获取 KPCR -> KTHREAD-> ETHREAD -> EPROCESS
对应的汇编是:
_ETHREAD 结构体:
(1)隐藏模块或进程就是一个断链的过程,将自身节点从双向循环链表中删除就可以达到隐藏的效果
(2)破坏双向循环链表的连续性就可以达到隐藏全部的效果
(3)为什么删除进程的节点后,程序任然可以运行?这是因为CPU调度的基本单位是线程,和进程无关
(4)找到EPROCESS也有多种方法
kd> dt _TEB
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
... ...
kd> dt _TEB
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
... ...
kd> dt _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
... ...
kd> dt _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
... ...
kd> dt _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0x000 Length : Uint4B
+0x004 Initialized : UChar
+0x008 SsHandle : Ptr32 Void
+0x00c InLoadOrderModuleList : _LIST_ENTRY
+0x014 InMemoryOrderModuleList : _LIST_ENTRY
+0x01c InInitializationOrderModuleList : _LIST_ENTRY
+0x024 EntryInProgress : Ptr32 Void
kd> dt _PEB_LDR_DATA
ntdll!_PEB_LDR_DATA
+0x000 Length : Uint4B
+0x004 Initialized : UChar
+0x008 SsHandle : Ptr32 Void
+0x00c InLoadOrderModuleList : _LIST_ENTRY
+0x014 InMemoryOrderModuleList : _LIST_ENTRY
+0x01c InInitializationOrderModuleList : _LIST_ENTRY
+0x024 EntryInProgress : Ptr32 Void
kd> dt _LIST_ENTRY
ntdll!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
kd> dt _LIST_ENTRY
ntdll!_LIST_ENTRY
+0x000 Flink : Ptr32 _LIST_ENTRY
+0x004 Blink : Ptr32 _LIST_ENTRY
kd> dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : Ptr32 Void
+0x01c EntryPoint : Ptr32 Void
+0x020 SizeOfImage : Uint4B
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void
kd> dt _LDR_DATA_TABLE_ENTRY
ntdll!_LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY
+0x008 InMemoryOrderLinks : _LIST_ENTRY
+0x010 InInitializationOrderLinks : _LIST_ENTRY
+0x018 DllBase : Ptr32 Void
+0x01c EntryPoint : Ptr32 Void
+0x020 SizeOfImage : Uint4B
+0x024 FullDllName : _UNICODE_STRING
+0x02c BaseDllName : _UNICODE_STRING
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void
#include<stdio.h>
#include<Windows.h>
typedef
struct
_UNICODE_STRING
{
USHORT
Length;
USHORT
MaximumLength;
PWSTR
Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef
struct
_PEB_LDR_DATA
{
ULONG
Length;
BOOLEAN
Initialized;
PVOID
SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
}PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef
struct
_LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializeationOrderModuleList;
PVOID
DllBase;
PVOID
EntryPoint;
ULONG
SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG
Flags;
SHORT
LoadCount;
SHORT
TlsIndex;
HANDLE
SectionHandle;
ULONG
CheckSum;
ULONG
TimeDataStamp;
}LDR_MODULE, * PLDR_MODULE;
PEB_LDR_DATA* g_pPebLdr = NULL;
LDR_MODULE* g_pLdrModule = NULL;
LIST_ENTRY* g_pInLoadOrderModule;
LIST_ENTRY* g_pInMemoryOrderModule;
LIST_ENTRY* g_pInInitializeationOrderModule;
void
ring3BrokenChains(
HMODULE
hModule)
{
LIST_ENTRY* pHead = g_pInLoadOrderModule;
LIST_ENTRY* pCur = pHead;
do
{
pCur = pCur->Blink;
g_pLdrModule = (PLDR_MODULE)pCur;
if
(hModule == g_pLdrModule->DllBase)
{
g_pLdrModule->InLoadOrderModuleList.Blink->Flink = g_pLdrModule->InLoadOrderModuleList.Flink;
g_pLdrModule->InLoadOrderModuleList.Flink->Blink = g_pLdrModule->InLoadOrderModuleList.Blink;
g_pLdrModule->InInitializeationOrderModuleList.Blink->Flink = g_pLdrModule->InInitializeationOrderModuleList.Flink;
g_pLdrModule->InInitializeationOrderModuleList.Flink->Blink = g_pLdrModule->InInitializeationOrderModuleList.Blink;
g_pLdrModule->InMemoryOrderModuleList.Blink->Flink = g_pLdrModule->InMemoryOrderModuleList.Flink;
g_pLdrModule->InMemoryOrderModuleList.Flink->Blink = g_pLdrModule->InMemoryOrderModuleList.Blink;
break
;
}
}
while
(pHead != pCur);
}
int
main(
int
argc,
char
* argv[])
{
__asm
{
mov eax, fs: [0x30] ;
mov ecx, [eax + 0xC];
mov g_pPebLdr, ecx;
mov ebx, ecx;
add ebx, 0xC;
mov g_pInLoadOrderModule, ebx;
mov ebx, ecx;
add ebx, 0x14;
mov g_pInMemoryOrderModule, ebx;
mov ebx, ecx;
add ebx, 0x1C;
mov g_pInInitializeationOrderModule, ebx;
}
printf
(
"点任意按键开始断链"
);
getchar
();
ring3BrokenChains(GetModuleHandleA(
"kernel32.dll"
));
printf
(
"断链成功\n"
);
getchar
();
return
0;
}
#include<stdio.h>
#include<Windows.h>
typedef
struct
_UNICODE_STRING
{
USHORT
Length;
USHORT
MaximumLength;
PWSTR
Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef
struct
_PEB_LDR_DATA
{
ULONG
Length;
BOOLEAN
Initialized;
PVOID
SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
}PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef
struct
_LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializeationOrderModuleList;
PVOID
DllBase;
PVOID
EntryPoint;
ULONG
SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG
Flags;
SHORT
LoadCount;
SHORT
TlsIndex;
HANDLE
SectionHandle;
ULONG
CheckSum;
ULONG
TimeDataStamp;
}LDR_MODULE, * PLDR_MODULE;
PEB_LDR_DATA* g_pPebLdr = NULL;
LDR_MODULE* g_pLdrModule = NULL;
LIST_ENTRY* g_pInLoadOrderModule;
LIST_ENTRY* g_pInMemoryOrderModule;
LIST_ENTRY* g_pInInitializeationOrderModule;
void
ring3BrokenChains(
HMODULE
hModule)
{
LIST_ENTRY* pHead = g_pInLoadOrderModule;
LIST_ENTRY* pCur = pHead;
do
{
pCur = pCur->Blink;
g_pLdrModule = (PLDR_MODULE)pCur;
if
(hModule == g_pLdrModule->DllBase)
{
g_pLdrModule->InLoadOrderModuleList.Blink->Flink = g_pLdrModule->InLoadOrderModuleList.Flink;
g_pLdrModule->InLoadOrderModuleList.Flink->Blink = g_pLdrModule->InLoadOrderModuleList.Blink;
g_pLdrModule->InInitializeationOrderModuleList.Blink->Flink = g_pLdrModule->InInitializeationOrderModuleList.Flink;
g_pLdrModule->InInitializeationOrderModuleList.Flink->Blink = g_pLdrModule->InInitializeationOrderModuleList.Blink;
g_pLdrModule->InMemoryOrderModuleList.Blink->Flink = g_pLdrModule->InMemoryOrderModuleList.Flink;
g_pLdrModule->InMemoryOrderModuleList.Flink->Blink = g_pLdrModule->InMemoryOrderModuleList.Blink;
break
;
}
}
while
(pHead != pCur);
}
int
main(
int
argc,
char
* argv[])
{
__asm
{
mov eax, fs: [0x30] ;
mov ecx, [eax + 0xC];
mov g_pPebLdr, ecx;
mov ebx, ecx;
add ebx, 0xC;
mov g_pInLoadOrderModule, ebx;
mov ebx, ecx;
add ebx, 0x14;
mov g_pInMemoryOrderModule, ebx;
mov ebx, ecx;
add ebx, 0x1C;
mov g_pInInitializeationOrderModule, ebx;
}
printf
(
"点任意按键开始断链"
);
getchar
();
ring3BrokenChains(GetModuleHandleA(
"kernel32.dll"
));
printf
(
"断链成功\n"
);
getchar
();
return
0;
}
pCur = pCur->Blink;
g_pLdrModule = (PLDR_MODULE)pCur;
这是因为 pCur 指向 _LIST_ENTRY 结构体,指向的地址刚好是_LDR_DATA_TABLE_ENTRY的首地址,因此二者在内存上刚好是对齐的。
PLDR_MODULE ldte = CONTAINING_RECORD(pCur, _LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
pCur = pCur->Blink;
g_pLdrModule = (PLDR_MODULE)pCur;
这是因为 pCur 指向 _LIST_ENTRY 结构体,指向的地址刚好是_LDR_DATA_TABLE_ENTRY的首地址,因此二者在内存上刚好是对齐的。
PLDR_MODULE ldte = CONTAINING_RECORD(pCur, _LDR_DATA_TABLE_ENTRY, InLoadOrderModuleList);
kd> dt _kpcr
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : Ptr32 _KPCR
+0x020 Prcb : Ptr32 _KPRCB
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
+0x034 KdVersionBlock : Ptr32 Void
+0x038 IDT : Ptr32 _KIDTENTRY
+0x03c GDT : Ptr32 _KGDTENTRY
+0x040 TSS : Ptr32 _KTSS
+0x044 MajorVersion : Uint2B
+0x046 MinorVersion : Uint2B
+0x048 SetMember : Uint4B
+0x04c StallScaleFactor : Uint4B
+0x050 DebugActive : UChar
+0x051 Number : UChar
+0x052 Spare0 : UChar
+0x053 SecondLevelCacheAssociativity : UChar
+0x054 VdmAlert : Uint4B
+0x058 KernelReserved : [14] Uint4B
+0x090 SecondLevelCacheSize : Uint4B
+0x094 HalReserved : [16] Uint4B
+0x0d4 InterruptMode : Uint4B
+0x0d8 Spare1 : UChar
+0x0dc KernelReserved2 : [17] Uint4B
+0x120 PrcbData : _KPRCB
kd> dt _kpcr
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : Ptr32 _KPCR
+0x020 Prcb : Ptr32 _KPRCB
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-9-4 20:55
被ATrueMan编辑
,原因: 格式