总结一下得到内核模块地址的方法,参考N多大牛

作者&投稿:希烁 (若有异议请与网页底部的电邮联系)
linux 怎么通过module结构得到模块加载后的基地址~

obj-m :这个变量是指定你要声称哪些模块模块的格式为 obj-m := .o
modules-objs :这个变量是说明声称模块modules需要的目标文件 格式要求 -objs :=
切记:模块的名字不能取与目标文件相同的名字。如在这里模块名不能取成 mymod;
KDIR :这是我们正在运行的操作系统内核编译目录。也就是编译模块需要的环境
M= :指定我们源文件的位置
PWD :这是当前工作路径$(shell )是make的一个内置函数。用来执行shell命令。

var string="?({\"companyss\":[{\"account\":\"0\","address\":\"0\","business":"}],\"success\":true})";
var json=eval(string);
alert(json.companyss[0].account);

网上说的比较常见的4种方法:

1、通过DriverEntry传入的DriverObject参数的DriverSection成员指向LDR_DATA_TABLE_ENTRY结构,通过遍历这张表得到ntoskrnl的基址和大小

2、ZwQuerySystemInformation大法

3、搜索内存

4、利用KPCR结构

存在的问题:

1、第1种方法和第4种方法得到的结果比ZwQuerySystemInformation少一个

2、第1种方法如果输出BaseDllName是ntoskrnl.exe,如果输出FullDllName则是:\WINDOWS\system32\ntkrnlpa.exe,地址都是:804d8000,不明白为何

环境:虚拟机VMWare:WIN XP SP3 + WDK ---- WINXP Check方式编译

#include <ntddk.h>
//---------------------------------//
//下面的结构包含了一些重要信息。如:PsLoadedModuleList ,它是Windows加载的所有内核模块构成的链表的表头。
//PsLoadedModuleList就是如下这个结构体中InLoadOrderLinks。即为LDR_DATA_TABLE_ENTRY结构的第一项。
#pragma pack(push)//结构定义
#pragma pack(1)
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PVOID EntryPointActivationContext;
PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
#pragma pack(pop)
//---------------------------------------------------------------------------------------------------//函数声明
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath);
NTSTATUS DriverUnload();
//Method3用到,指定当前线程运行在那个处理器
NTKERNELAPI VOID KeSetSystemAffinityThread ( KAFFINITY Affinity );
NTKERNELAPI VOID KeRevertToUserAffinityThread ( VOID );

NTKERNELAPI NTSTATUS ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
IN PULONG ReturnLength OPTIONAL
);

#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
//---------------------------------------------------------------------------------------------------//变量、常量、结构定义
UNICODE_STRING BaseName;

#define SystemModuleInformation 11 //Method2要用到11功能号

typedef struct _SYSTEM_MODULE_INFORMATION_ENTRY
{
ULONG Unknow1;
ULONG Unknow2;
#ifdef _WIN64
ULONG Unknow3;
ULONG Unknow4:
#endif
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT NameLength;
USHORT LoadCount;
USHORT ModuleNameOffset;
char ImageName[256];
}SYSTEM_MODULE_INFORMATION_ENTRY, *PSYSTEM_MODULE_INFORMATION_ENTRY;

typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Count;//内核中以加载的模块的个数
SYSTEM_MODULE_INFORMATION_ENTRY Module[1];
}SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

//---------------------------------------------------------------------------------------------------//
/*
用到了DriverObject域的InLoadOrderLinks链表

注意:
下面的代码会用到一个宏:
---------------------------------------------------------------------------------------------------------------------
CONTAINING_RECORD 这样的一个宏,它的定义如下:
#define CONTAINING_RECORD(address, type, field) ((type *)( (PCHAR)(address) - (ULONG_PTR)(&((type*)0)->field)))

根据网上资料:就是address -(field在type中的偏移)
----------------------------------------------------------------------------------------------------------------------
*/
VOID Method1(IN PDRIVER_OBJECT DriverObject)//遍历链表
{
ULONG Base=0;//模块基地址
LDR_DATA_TABLE_ENTRY* SectionBase=NULL;
LIST_ENTRY* Entry=NULL;
LIST_ENTRY InLoadOrderLinks;
ULONG num=0;
Entry=((LIST_ENTRY*)DriverObject->DriverSection)->Flink;

do
{
SectionBase=CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行

if (SectionBase->EntryPoint &&
SectionBase->BaseDllName.Buffer &&
SectionBase->FullDllName.Buffer &&
SectionBase->LoadCount
)
{
DbgPrint("方法一遍历模块名称:%wZ,地址:%x\n",&(SectionBase->FullDllName),SectionBase->DllBase);
//DbgPrint("方法一遍历模块名称:%wZ,地址:%8X\n",&(SectionBase->BaseDllName),SectionBase->DllBase);
num++;
/*if(!RtlCompareUnicodeString(&(SectionBase->BaseDllName),&BaseName,FALSE))
{
DbgPrint("方法一模块名称:%wZ,地址:%x\n",&(SectionBase->BaseDllName),SectionBase->DllBase);
}*/
}
Entry=Entry->Flink;

}while(Entry!=((LIST_ENTRY*)DriverObject->DriverSection)->Flink);//直到遍历回来
DbgPrint("方法一得到模块总数:%d\n",num);
}

void Method2()//ZwQuerySystemInformation大法
{
PVOID pBuffer=0;//缓冲区
NTSTATUS Result;//查询结果
ULONG NeedSize;
PSYSTEM_MODULE_INFORMATION pSystemModuleInformation;//将结果强制转换为该类型
ULONG BufferSize = 0x5000;//初始分配内存大小,没有采用查询再分配的循环方法
ULONG ModuleCount;//模块总数
ULONG i;
do
{
pBuffer=ExAllocatePool(NonPagedPool,BufferSize);
if(pBuffer==NULL)
{
DbgPrint("分配内存失败!\n");
return FALSE;
}
Result=ZwQuerySystemInformation(SystemModuleInformation,pBuffer,BufferSize,&NeedSize);
if(Result==STATUS_INFO_LENGTH_MISMATCH )//分配不够
{
ExFreePool(pBuffer);
//大小乘以2,重新分配
BufferSize*=2;
}
else if(!NT_SUCCESS(Result))//失败,放弃吧
{
DbgPrint( "查询失败,错误码:%8X\n", Result );
ExFreePool(pBuffer);
return FALSE;
}
}while( Result == STATUS_INFO_LENGTH_MISMATCH );

pSystemModuleInformation = (PSYSTEM_MODULE_INFORMATION)pBuffer;//类型转换
ModuleCount=pSystemModuleInformation->Count;//模块总数
for(i=0;i<ModuleCount;i++)
{
DbgPrint( "方法二遍历模块名称:%s,地址:%8X\n", pSystemModuleInformation->Module[i].ImageName, pSystemModuleInformation->Module[i].Base );
}
DbgPrint("方法二得到模块总数:%d\n",ModuleCount);
ExFreePool(pBuffer);
return TRUE;
}
VOID Method3(ULONG Base)//搜索内存,从0x80000000-----0xa0000000
{
;
}
//内核中FS寄存器指向KPCR结构,每个处理器都有一个,使用第一个处理器即可其中比较重要的是KdVersionBlock这个指针, 它指向一个DBGKD_GET_VERSION64这个结构.

//这个结构体里面包含了一些重要信息。如:PsLoadedModuleList ,它是Windows加载的所有内核模块构成的链表的表头

//两个处理器对应的KPCR结构是有区别的, 只有第一个处理器的KPCR域KdVersionBlock才指向DBGKD_GET_VERSION64这个结构.

//-------------------------------------仔细观察定义会发现,这个跟使用DriverObject方法达到的链表示一样的!
void Method4()
{
ULONG Addr;//内核地址

LIST_ENTRY* Entry=NULL;
LIST_ENTRY InLoadOrderLinks;
LDR_DATA_TABLE_ENTRY* SectionBase=NULL;//LdrData->DllBase,LdrData->FullDllNme

ULONG num=0;
//-----------------------------------------------------------------------------//在莫灰灰基础上修改一小部分
KeSetSystemAffinityThread(1);//使当前线程运行在第一个处理器上
_asm
{
push eax
mov eax,FS:[0x34] ;指向KdVersionBlock的指针
add eax,18h ;得到指向PsLoadedModuleList的地址,即该指针的地址,指针里存有PsLoadedModuleList的地址
mov eax,[eax] ;得到PsLoadedModuleList的地址
mov eax,[eax] ;得到PsLoadedModuleList的内容
//mov eax,[eax+18h] ;取出DllBase, 即ntoskrnl.exe的基地址
mov Addr,eax
pop eax
}

KeRevertToUserAffinityThread();//恢复线程运行的处理器
//----------------------------------------------------------------------// 以下跟方法一重复

Entry=(LIST_ENTRY*)Addr;

do
{
SectionBase=CONTAINING_RECORD(Entry,LDR_DATA_TABLE_ENTRY,InLoadOrderLinks);//得到这个Entry所属的Section的地址,此方法经过验证可行

if (SectionBase->EntryPoint &&
SectionBase->BaseDllName.Buffer &&
SectionBase->FullDllName.Buffer &&
SectionBase->LoadCount
)
{
DbgPrint("方法四遍历模块名称:%wZ,地址:%8X\n",&(SectionBase->FullDllName),SectionBase->DllBase);
num++;
}
Entry=Entry->Flink;

}while(Entry!=(LIST_ENTRY*)Addr);//直到遍历回来
DbgPrint("方法四得到模块总数:%d\n",num);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject,IN PUNICODE_STRING pRegistryPath)
{
ULONG EntryAddr;
_asm
{
push ecx;
lea ecx,[ebp][4];//得到DriverEntry返回地址
mov EntryAddr,ecx;
pop ecx;
}
EntryAddr=*(ULONG*)EntryAddr;
DbgPrint("驱动返回地址:%8X\n",EntryAddr);
RtlInitUnicodeString(&BaseName,L"ntoskrnl.exe");
DbgPrint("驱动加载成功!\n");
//-------------------------------//
Method1(pDriverObject);
//-------------------------------//
Method2();
//-------------------------------//
Method3();
//-------------------------------//
Method4();
//-------------------------------//
pDriverObject->DriverUnload=DriverUnload;
return STATUS_SUCCESS;
}
NTSTATUS DriverUnload()
{
DbgPrint("驱动卸载成功\n");


总结一下得到内核模块地址的方法,参考N多大牛
DbgPrint("方法二得到模块总数:%d\\n",ModuleCount);ExFreePool(pBuffer);return TRUE;}VOID Method3(ULONG Base)\/\/搜索内存,从0x80000000---0xa0000000{;}\/\/内核中FS寄存器指向KPCR结构,每个处理器都有一个,使用第一个处理器即可其中比较重要的是KdVersionBlock这个指针, 它指向一个DBGKD_GET_VERSION64这个结...

Linux内核模块了解知多少
总之,模块是一个为内核(从某种意义上来说,内核也是一个模块)或其他内核模块提供使用功能的代码块。(2)内核模块的优缺点编辑本段利用内核模块的动态装载性具有如下优点:·将内核映象的尺寸保持在最小,并具有最大的灵活性;·便于检验新的内核代码,而不需重新编译内核并重新引导。但是,内核模块的引...

linux加载内核模块命令linux加载内核
”故障原因:系统内核DLL文件丢失或损坏。修复方法:具体修复方法见下。(下面以XP系统为例,进行说明)【系统内核DLL文件丢失或损坏修复方法】:方法1、最后一次正确配置电脑重启,开机自检一过,马上按按F8键,选择“最后一次正确配置”。【示例截图】方法2、在安全模式下,进行修复。电脑重启,开机自检一...

linux操作系统中,加载和删除内核模块的命令是什么?
1、modprobe 命令是根据depmod -a的输出\/lib\/modules\/version\/modules.dep来加载全部的所需要模块。2、删除模块的命令是:modprobe -r filename。3、系统启动后,正常工作的模块都在\/proc\/modules文件中列出。使用lsmod命令也可显示相同内容。4、在内核中有一个“Automatic kernel module loading"功能被编...

linux的内核结构是什么样的linux的内核结构
Linux文件系统架构一般有4个主要部分:内核、shell、文件系统和应用程序。一、Linux内核 内核是操作系统的核心,具有很多最基本功能,如虚拟内存、多任务、共享库、需求加载、可执行程序和TCP\/IP网络功能。Linux内核的模块分为以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信、...

如何编写一个简单的linux内核模块和设备驱动程序
在用rmmod卸载模块时,cleanup_module函数被调用,它释放字符设备test在系统字符设备表中占有的表项。 一个极其简单的字符设备可以说写好了,文件名就叫test.c吧。 下面编译 : $ gcc -O2 -DMODULE -D__KERNEL__ -c test.c 得到文件test.o就是一个设备驱动程序。 如果设备驱动程序有多个文件,把每个文件...

Linux系统中一些内核管理命令总结
1、lsmod 列加以挂载的内核模块;lsmod 是列出目前系统中已加载的模块的名称及大小等;另外我们还可以查看 \/proc\/modules ,我们一样可以知道系统已经加载的模块;代码如下:[root@localhost beinan]# lsmod [\/code]2、modinfo 查看模块信息;modinfo 可以查看模块的信息,通过查看模块信息来判定这个模块的用途...

如何使用modprobe命令加载、卸载和查看内核模块的依赖关系?
modprobe,作为内核模块的智能加载工具,其核心功能在于管理和控制模块在内核中的加载或卸载。这个命令允许用户精确地加载单个模块或一组相互依赖的模块,如果加载过程中出现任何错误,它会自动回滚并卸载整个模块组。加载结果的成败信息可以通过dmesg命令获取。modprobe的使用遵循特定的语法格式,即:?modprobe [...

linux内核模块如何开始和结束
那么,Linux 的内核到底放在了哪里呢?当然是 \/boot 的启动目录中了,我们来看看这个目录下的内容吧。[root@localhost ~]#ls \/boot\/config-2.6.32-279.el6.i686#内核的配置文件,内核编译时选择的功能与模块efi#可扩展固件接口,为英特尔为全新PC固件的体系结构、接口和服务提出的建议标准grub#启动...

linux内核主要由哪几个部分组成
一个完整的Linux内核一般由5部分组成,它们分别是内存管理、进程管理、进程间通信、虚拟文件系统和网络接口。1、内存管理 内存管理主要完成的是如何合理有效地管理整个系统的物理内存,同时快速响应内核各个子系统对内存分配的请求。Linux内存管理支持虚拟内存,而多余出的这部分内存就是通过磁盘申请得到的,平时...

砚山县19726701946: 如何导出内核模块符号以及如何引用导出的符号 -
犁巩排毒: linux下没有export的概念.一个模块内的函数或变量,要被其他模块使用

砚山县19726701946: 获取Linux内核未导出符号的几种方式 -
犁巩排毒: 只有在内核中使用EXPORT_SYMBOL或EXPORT_SYMBOL_GPL导出的符号才能在内核模块中直接使用.然而,内核并没有导出所有的符号.例如,在3.8.0的内核中,do_page_fault就没有被导出. 而我的内核模块中需要使用do_page_fault,...

砚山县19726701946: 如何获取Windows 系统的内核变量 -
犁巩排毒: PsLoadedModuleList等重要内核变量并未被ntoskrnl.exe导出,也没有公开的函 数可以获取.而这些内核变量对于Rootkit、Anti-Rootkit 以及内核溢出的利用等都 是至关重要的. 下面我们以PsLoadedModuleList、PsActiveProcessHead 等为例,...

砚山县19726701946: 内核级HOOK的几种实现与应用 -
犁巩排毒: 资源简介这种方法对于拦截、分析其他内核驱动的函数调用来说用的比较多.原理是根据替换 PE 格式导出表中的相应函数来实现的.此方法中需要用到一些小技巧.如内核模式并没有直接提供类似应用层的 GetModuleHandl()、GetProcAddress(...

砚山县19726701946: linux 怎么查看内核里加载的模块 -
犁巩排毒: 一、找出内置模块列表要得到内置模块列表,运行下面的命令.$ cat /lib/modules/$(uname -r)/modules.builtin你也可以用下面的命令来查看有哪些内置模块:

砚山县19726701946: windows如何辨别内核空间地址和用户空间地址
犁巩排毒: Linux将4G的地址划分为用户空间和内核空间两部份.在Linux内核的低版本中(2.0.X),通常0⑶G为用户空间,3G⑷G为内核空间.这个分界点是可以可以改动的.正是这个分界点的存在,限制了Linux可用的最大内存为2G.而且要通太重编内...

砚山县19726701946: 分享一下如何查看浏览器内核的方法! -
犁巩排毒: Mozilla/4.0 (compatiable; MSIE 6.0; Windows NT 5.1; SV2)

砚山县19726701946: linux怎么添加自己的内核模块 -
犁巩排毒: 不同发行版和不同版本的Linux略有不同,以CentOS7为例,需要在/etc/sysconfig/modules/目录中增加一个脚本,在此脚本中加载所需的模块.注意该脚本文件的权限为755.以uinput模块为例,脚本如下:#!/bin/sh if [ ! -c /dev/input/uinput ] ; then exec /sbin/modprobe uinput >/dev/null 2>&1 fi

砚山县19726701946: 怎样快速启动Linux系统?
犁巩排毒: 在DOS下,有一种简单快速启动Linux的方法,那就是load Linux.loadlin.exe是DOS下的可执行程序,它可以在纯DOS环境下迅速启动Linux,而且无需重启计算机,通常我们可以在光盘的“/kernels”目录下找到这个程序.如果不知这个程序被...

砚山县19726701946: 如何查看Linux加载内置模块的信息 -
犁巩排毒: 一、找出内置模块列表要得到内置模块列表,运行下面的命令.$ cat /lib/modules/$(uname -r)/modules.builtin你也可以用下面的命令来查看有哪些内置模块:二、找出内置模块参数每个内核模块无论是内置的还是可加载的都有一系列的参数...

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网