当前位置: 首页 > 编程笔记 >

利用C++ R3层断链实现模块隐藏功能

罗毅
2023-03-14
本文向大家介绍利用C++ R3层断链实现模块隐藏功能,包括了利用C++ R3层断链实现模块隐藏功能的使用技巧和注意事项,需要的朋友参考一下

一、模块隐藏的实现原理

  普通API查找模块实现思路:其通过查询在R3中的PEB(Process Environment Block 进程环境块)与TEB(Thread Environment Block 进程环境块)来找到一个双向链表,通过遍历双向链表中某一成员(字符串)来查找全部模块。

  模块隐藏实现思路:在R3层的模块隐藏,我们需要做的就是将其该链表断链,将某一模块从这个双向链表中摘除,这样再调用传统的API时就会搜索不到。

二、结构体成员详细介绍

<1> TEB结构体 -- 内存地址为 fs:[0] 处。

使用Windbg的 "dt _TEB"命令来查看TEB结构体

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

1. 属性介绍 

  1.1)_NT_TIB:重点两个属性,栈顶与栈大小。

   http://www.nirsoft.net/kernel_struct/vista/NT_TIB.html

  1.2) _CLIENT_ID: 存储该进程ID与当前主线程ID。

  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-tsts/a11e7129-685b-4535-8d37-21d4596ac057?redirectedfrom=MSDN

  1.3) _PEB:进程环境块 ,记住其在 TEB 偏移 0x30处即可。

2. 通过olldbg查看该结构体

  2.1) 打开任意进程,在寄存器窗口找到 fs:[0],查看其内存地址。

    

  2.2) 在内存窗口使用命令 "db 5E7000" 跳转到该内存,使用地址格式(长型-地址)显示。

    

<2> PEB结构体 -- fs:[0x30]

使用 Windbg 指令 dt _PEB 查看 PEB结构体,重点关注最后一个 进程加载信息表。

kd> dt _PEB
ntdll!_PEB
 +0x000 InheritedAddressSpace : UChar
 +0x001 ReadImageFileExecOptions : UChar
 +0x002 BeingDebugged : UChar
 +0x003 BitField : UChar
 +0x003 ImageUsesLargePages : Pos 0, 1 Bit
 +0x003 IsProtectedProcess : Pos 1, 1 Bit
 +0x003 IsLegacyProcess : Pos 2, 1 Bit
 +0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
 +0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
 +0x003 SpareBits : Pos 5, 3 Bits
 +0x004 Mutant : Ptr32 Void
 +0x008 ImageBaseAddress : Ptr32 Void
 +0x00c Ldr : Ptr32 _PEB_LDR_DATA // PEB_LOADER_DATA 进程加载信息表

1. 查看 _PEB_LDR_DATA 进程加载信息表 的结构体

  1.1)重点关注 0x00c处的指针,其指向 _PEB_LDR_DATA 这个结构体,在这个结构体中 0x00c、0x014、0x01c 分别表示 模块加载顺序 / 加载后在内存中的顺序 / 模块初始化的顺序。

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
 + 0x028 ShutdownInProgress : UChar
 + 0x02c ShutdownThreadId : Ptr32 Void

  2.2)理解其三个成员的顺序,其指向_LDR_DATA_TABLE_ENTRY元素中开始的三个成员,而 _LDR_DATA_TABLE_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  // 入口函数(对于 exe 模块有效)
 + 0x020 SizeOfImage : Uint4B  // 模块大小
 + 0x024 FullDllName : _UNICODE_STRING  // 完成模块名称(带路径)
 + 0x02c BaseDllName : _UNICODE_STRING // 模块名称
 + 0x034 Flags : Uint4B

2. 使用olldbg来查看查找首先加载模块的模块名称(TEB->PEB-> InLoadOrderModuleList -> BaseDllName)

  2.1)接之前TEB内容查找到PEB的所在位置 fs:[0x30]。

  2.2) 在其0x00c处发现InLoadOrderModuleList成员,其指向的是一个_LDR_DATA_TABLE_ENTRY 结构体。

    

  2.3) 跳转到 _LDR_DATA_TABLE_ENTRY 结构体,从0x0c开始依次是三个 _LIST_ENTRY 结构体,该结构体双向链表存储着两个地址。

    

  2.4)选中第一个进入,在其偏移0x02c处(UNICODE结构体占四字),可以查看字符串名称。

    

  2.5)通过开头 _LIST_ENTRY结构体可以遍历前一个模块的内容和下一个模块的内容。

    

三、利用C++断链来实现模块隐藏

  如果你看懂上面分析,则源代码非常好理解。

// 隐藏模块.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <Windows.h>
/* 所需要的结构体
1. _LDR_DATA_TABLE_ENTRY 链表指向数据
2. _PEB_LDR_DATA 表示其 PEB0x处指向的数据表
3. _LIST_ENTRY 指针指向的链表
*/
typedef struct _LSA_UNICODE_STRING {
 USHORT Length;
 USHORT MaximumLength;
 PWSTR Buffer;
}
UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB_LDR_DATA
{
 DWORD Length; // +0x00
 bool Initialized; // +0x04
 PVOID SsHandle; // +0x08
 LIST_ENTRY InLoadOrderModuleList; // +0x0c
 LIST_ENTRY InMemoryOrderModuleList; // +0x14
 LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA, *PPEB_LDR_DATA; // +0x24
typedef struct _LDR_MODULE
{
 LIST_ENTRY InLoadOrderModuleList;
 LIST_ENTRY InMemoryOrderModuleList;
 LIST_ENTRY InInitializationOrderModuleList;
 void* BaseAddress;
 void* EntryPoint;
 ULONG SizeOfImage;
 UNICODE_STRING FullDllName;
 UNICODE_STRING BaseDllName;
 ULONG Flags;
 SHORT LoadCount;
 SHORT TlsIndex;
 HANDLE SectionHandle;
 ULONG CheckSum;
 ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
//所谓模块句柄,即该模块的入口地址
void hide_module(char* szDllName)
{
 HMODULE hMod = GetModuleHandleA(szDllName);
 PLIST_ENTRY Head, Cur;
 PPEB_LDR_DATA ldr;
 PLDR_MODULE ldm;
 __asm
 {
 mov eax, fs:[0x30]
 mov ecx, [eax + 0x0c] //Ldr 
 mov ldr, ecx
 }
 Head = &(ldr->InLoadOrderModuleList);
 Cur = Head->Flink;
 do
 {
 ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList);
 if (hMod == ldm->BaseAddress)
 {
 // 三个链表同时给断掉
 ldm->InLoadOrderModuleList.Blink->Flink =
 ldm->InLoadOrderModuleList.Flink;
 ldm->InLoadOrderModuleList.Flink->Blink =
 ldm->InLoadOrderModuleList.Blink;
 //
 ldm->InInitializationOrderModuleList.Blink->Flink =
 ldm->InInitializationOrderModuleList.Flink;
 ldm->InInitializationOrderModuleList.Flink->Blink =
 ldm->InInitializationOrderModuleList.Blink;
 //
 ldm->InMemoryOrderModuleList.Blink->Flink =
 ldm->InMemoryOrderModuleList.Flink;
 ldm->InMemoryOrderModuleList.Flink->Blink =
 ldm->InMemoryOrderModuleList.Blink;
 break;
 }
 Cur = Cur->Flink;
 } while (Head != Cur);
}
int main()
{
 // 通过模块名,来获取模块句柄
 printf("****按任意键隐藏模块*****");
 getchar();
 hide_module((char*)"kernel32.dll");
 printf("****隐藏模块完成*****");
 getchar();
 getchar();
}

总结

以上所述是小编给大家介绍的利用C++ R3层断链实现模块隐藏功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

 类似资料:
  • 此处将公开Dism++未在UI中呈现的设置,你可以修改Config\Config.ini,让这些设置生效。 启用方式 功能 [Dism++] NotLoadWofadk=1 添加后Dism++将不会在启动时加载Wof驱动,默认情况下Dism++会在Win8以上系统自动加载Wof驱动。如果你的环境比较特殊,可以开启此选项。开启后,WIMBoot以及Compact相关功能可能会受限。 [WUA] Di

  • 因此,目前我正在处理一个项目,其中我需要在一个方法中启动一个快速javafx窗口。由于我不想让类扩展应用程序,我的解决方案是创建一个扩展应用程序的内部类,并通过创建内部类的实例和调用内部类中的launch在方法中启动javafx窗口,如下所示。

  • 本文向大家介绍vue实现密码显示隐藏切换功能,包括了vue实现密码显示隐藏切换功能的使用技巧和注意事项,需要的朋友参考一下 先给大家分享效果图: 具体实现代码如下所示: html: script: 注:带小眼睛的睁开闭合。 总结 以上所述是小编给大家介绍的vue实现密码显示隐藏切换功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对呐喊教程网站的支持!

  • 本文向大家介绍用C/C++来实现 Node.js 的模块(二),包括了用C/C++来实现 Node.js 的模块(二)的使用技巧和注意事项,需要的朋友参考一下 温故而知新,可以为湿矣   首先请大家记住这个 V8 的在线手册——http://izs.me/v8-docs/main.html。   还记得上次的 building.gyp 文件吗?    就像这样,举一反三,如果多几个 *.cc 文件

  • 本文向大家介绍用C/C++来实现 Node.js 的模块(一),包括了用C/C++来实现 Node.js 的模块(一)的使用技巧和注意事项,需要的朋友参考一下  N久之前的一个坑——用 Node.js 来重构 NBUT 的 Online Judge,包括评测端也得重构一遍。(至于什么时候完成大家就不要关心了,(/‵Д′)/~ ╧╧   总之我们现在要做的其实简而言之就是——用C/C++来实现 No

  • 问题内容: 已锁定 。该问题及其答案被锁定,因为该问题是题外话,但具有历史意义。它目前不接受新的答案或互动。 我从事Microsoft SQL Server 已有多年,但直到最近才开始在我的Web应用程序中使用MySQL,而且我渴望获得知识。 为了继续回答“隐藏功能”问题,我想知道MySQL的任何隐藏或方便功能,这些功能有望改善我对这个开源数据库的了解。 问题答案: 既然您悬赏,我将分享我的来之不