获取Kernel32基地址

暴力搜索

32位在4G内存搜索有一定可行性,但是处理起来其实还是比较麻烦的,因为内存不可读会触发异常,需要对这些异常问题进行处理。

优化思路:缩小范围、增大搜索步长

(1)不优化,原始内存特征匹配,容易出错,利用复杂。

(2)优化暴力搜索,有三种方法

方法一

只要系统没有做模块基址重定位,那么32位下kernel32的加载地址在0x70000000-0x80000000之间,然后Kernel32.dll加载是64k对齐的,所以查找次数<256MB/64K+1= 4097次,就可以找到。

#include <Windows.h>
#include <stdio.h>int main()
{HANDLE kernelA = LoadLibrary(L"kernel32.dll");printf("0x:%p\n", kernelA);system("pause");
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是这里判断定位成功条件仍然需要采取两重判断,先判断MZ头再解析PE结构来获取DLL名称进行判断,从而来降低在其他环境出现地址错误的概率。

导入表与exe实际加载顺序:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ntdll.dll->kernel32.dll->ucrtbase.dll->kernelbase.dll->…

可以看到关键的系统模块都分配在了0x70000000上面,故单一匹配MZ头不是100%准确。

方法二

什么是异常处理链表

当异常发生时,系统从fs:[0]指向的内存地址处取出ExceptionList字段,然后从ExceptionList字段指向的_EXCEPTION_REGISTRATION_RECORD结构中取出handler字段,并根据其中的地址去调用异常处理程序(回调函数)。

异常处理链表是提到的由_EXCEPTION_REGISTRATION_RECORD结构构成的单链表

typedef struct _EXCEPTION_REGISTRATION_RECORD
{PEXCEPTION_REGISTRATION_RECORD Next;PEXCEPTION_DISPOSITION Handler;
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;

Next指向异常处理程序的地址,prev 则指向下一个 _EXCEPTION_REGISTRATION_RECORD 结构体,来构成一个单向链表。

异常处理链表有什么特点

当异常发生时,系统会遍历异常处理链表,直到找到正确的异常处理程序。链表最后一项的prev值为0xFFFFFFFF,说明链表已经遍历完毕。

最后一项指向的是系统默认的位于Kernel32.dll的UnhandledExceptionFilter顶层异常处理程序的过滤函数,该过滤函数的地址是存在于Kernel32.dll内存空间的

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

查找Kernel32.dll加载基址

1)取fs:[0]的值即ExceptionList指针指向的地址赋予给edx寄存器

2)判断Next指针指向的值是否为0xffffffff计算机负数用补码表示即-1,是的话

mov edx, [edx],将值传递到edx寄存器中,接着mov edx,[edx+4]将Handler指向的值赋值给edx,此时edx就在Kernel32.dll内存空间中,然后开始逐一递减dec edx来回溯PE头<-cmp word ptr [edx], ‘ZM’,数值存储比较采用小端字节序,CPU读取从低地址读到高地址,所以这里是’ZM’而不是’MZ’,网上有些代码是错的,如果不是-1,那么就遍历下一个mov edx, [edx]

代码实现

#include <stdio.h>
#include <windows.h>
int main()
{unsigned int kernelAddr;__asm {mov edx, fs: [0] ;Foreach:cmp [edx], 0xffffffffje Handle; //if equal : jump   mov edx, [edx];jmp Foreach;Handle:mov edx, [edx + 4];_Loop:cmp word ptr[edx], 'ZM';jz Kernel;dec edx;xor dx, dx;jmp _LoopKernel :mov kernelAddr, edx;}printf(TEXT("Kernel32.dll address: %x\r\n"), kernelAddr);printf(TEXT("LoadLibrary Kernel32.dll address: %x\r\n"),LoadLibrary(TEXT("kernel32.dll")));return 0;
}

基于PEB搜索

TEB->PEB

TEB(Thread Environment Block,线程环境块)系统在此TEB中保存频繁使用的线程相关的数据。位于用户地址空间,在比 PEB 所在地址低的地方。用户模式下,当前线程的TEB位于独立的4KB段(页),可通过CPU的FS寄存器来访问该段,一般存储在[FS:0]

PEB(Process Environment Block,进程环境块)存放进程信息,每个进程都有自己的PEB信息。位于用户地址空间。可在TEB结构地址偏移0x30处获得PEB的地址位置。

查看结构Windbg 命令:

TEB: !tebdt -r1 ntdll!_teb

PEB: !pebdt -r1 ntdll!_peb

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们已经知道可以通过fs:[0]寄存器访问到TEB的地址,这里我们又知道了可以通过TEB结构偏移0x30处指向的地址是PEB结构地址,即fs:[0]->TEB->PEB,在这一步完成PEB地址的定位。

PEB结构

微软文档:https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb

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)字段,这里我们关注下其中一个成员Ldr,其结构为PPEB_LDR_DATA。

微软文档:https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb_ldr_data

Contains information about the loaded modules for the process.
包含有关该过程的加载模块的信息。

typedef struct _PEB_LDR_DATA {BYTE       Reserved1[8];PVOID      Reserved2[3];LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

第三个参数InMemoryOrderModuleList

The head of a doubly-linked list that contains the loaded modules for the process. Each item in the list is a pointer to an LDR_DATA_TABLE_ENTRY structure. For more information, see Remarks.
双向链表的头部包含进程的加载模块。链表的每一个都是指向LDR_DATA_TABLE_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;

文档是不够全面的,下面我们用Windbg来看下具体的结构和值
!peb->dt -r1 0x774bdca0 _PEB_LDR_DATA
!peb
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

dt -r1 0x778a5d80 _PEB_LDR_DATA
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以看到这里,除了文档InMemoryOrderModuleList,实际还有两个:

InLoadOrderModuleList
InMemoryOrderModuleList
InInitializationOrderModuleLists

这个其实是模块在不同状态的顺序

InLoadOrderModuleList 指的是模块加载的顺序

InMemoryOrderModuleList指的是在内存的排列顺序

InInitializationOrderModuleLists 指的是模块初始化装载顺序。

这里选择跟进InLoadOrderModuleList指向的结构

1)dt -r1 _LIST_ENTRY 0x00485bc0(这里取第二个,第一个是exe本身)->dt -r1 0x00485ab8 _LDR_DATA_TABLE_ENTRY

2)lm 列举出加载的模块信息
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从这图可以得出两个信息,Flink总是指向下一个_LDR_DATA_TABLE_ENTRY结构对应加载顺序的Flink指针,_LDR_DATA_TABLE_ENTRY在0x2c处是加载模块的名称,在0x18偏移处,是该模块的加载基地址。

基于上述认识,使用Windbg遍历一下InMemoryOrderModuleList加载顺序的完整链结构:

(1)dt -r1 0x004f5bc0-0x8 _LDR_DATA_TABLE_ENTRY
第一个结构是:*.exe
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(2)dt -r1 0x004f5ab8-0x8 _LDR_DATA_TABLE_ENTRY
第二个模块:ntdll.dll
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(3)dt -r1 0x004f5fa8-0x8 _LDR_DATA_TABLE_ENTRY
第三个模块:kerner32.dll
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

程序,遍历三个链表内容

#include<stdio.h>
#include<windows.h>typedef struct UNICODE_STRING
{USHORT _ength;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 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;
}MY_LDR_MODULE, * PLDR_MODULE;int main()
{PEB_LDR_DATA* pEBLDR;MY_LDR_MODULE* pLdrMod;PLDR_MODULE PLdr;LIST_ENTRY* pNext, * pStart;_asm{mov eax, fs: [0x30]mov eax, [eax + 0xC]mov pEBLDR, eax}printf("GetModuleHandle Kernel32:0x%08x\n", GetModuleHandle(L"Kernel32"));printf("GetModuleHandle ntdll:0x%08x\n", GetModuleHandle(L"ntdll"));printf("--------------------------------------------------------------------------\n");printf("PEB_LDR_DATA:0x%08x\n", pEBLDR);printf("LDR->InLoadOrderModuleList:\t\t0x%08x\n", pEBLDR->InLoadOrderModuleList);printf(">>>InLoadOrderModuleList<<<\n");printf("BaseAddress\t\t BaseDllName\n================================================\n");pNext = (LIST_ENTRY*)&(pEBLDR->InLoadOrderModuleList);pStart = pNext;do{pNext = pNext->Flink;pLdrMod = (MY_LDR_MODULE*)pNext;printf("0x%08x\t\t", pLdrMod->BaseAddress);wprintf(L"%s\n", pLdrMod->BaseDllName.Buffer);} while (pNext != pStart);printf("LDR->InMemoryOrderModuleList:\t\t0x%08x\n", pEBLDR->InMemoryOrderModuleList);printf("BaseAddress\t\t BaseDllName\n================================================\n");pNext = (LIST_ENTRY*)&(pEBLDR->InMemoryOrderModuleList);pStart = pNext;do{pNext = pNext->Flink;pLdrMod = CONTAINING_RECORD(pNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderModuleList);printf("0x%08x\t\t", pLdrMod->BaseAddress);wprintf(L"%s\n", pLdrMod->BaseDllName.Buffer);} while (pNext != pStart);printf("LDR->InInitializationOrderModuleList:\t0x%08x\n", pEBLDR->InInitializationOrderModuleList);printf("BaseAddress\t\t BaseDllName\n================================================\n");pNext = (LIST_ENTRY*)&(pEBLDR->InInitializationOrderModuleList);pStart = pNext;do{pNext = pNext->Flink;pLdrMod = CONTAINING_RECORD(pNext, LDR_DATA_TABLE_ENTRY, InInitializationOrderModuleList);printf("0x%08x\t\t", pLdrMod->BaseAddress);wprintf(L"%s\n", pLdrMod->BaseDllName.Buffer);} while (pNext != pStart);getchar();
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

搜索思路

1)xor eax, eax清零,mov eax, fs:[0x30] 获取PEB地址

2)mov eax, [eax + 0x0c] 获取LDR地址,0x30和0x0c上面都有讲的,偏移量。

mov esi, [eax + 0Ch] //则指向InLoadOrderModuleList

mov esi, [eax + 14h] //则指向InMemoryOrderModuleList

4)遍历Flink,找到Kernel32.dll的位置

位置在第3个,这里需要简单计算下。

指向InLoadOrderModuleList 的同时就是第一个了。

再指向一次mov esi, [esi],就是第二个了。

lodsd或者mov esi,[esi];mov eax, esi,就是第三个了

5)获取Kernel地址,这里也需要小小计算一下。

mov eax,[eax+08h] //InLoadOrderModuleList 顺序

mov eax, [eax+18h] //InMemoryOrderModuleList 顺序

6)完成赋值,mov address, eax; 最后输入验证结果。

代码实现

//InLoadOrderModuleList

#include <Windows.h>
#include <stdio.h>int main()
{unsigned int address;__asm {xor eax, eaxmov eax, fs: [eax + 30h] ; 指向PEB的指针mov eax, [eax + 0ch]; 指向PEB_LDR_DATA的指针mov eax, [eax + 0ch]; 根据PEB_LDR_DATA得出InLoadOrderModuleList的Flink字段mov esi, [eax];lodsd;mov eax, [eax + 18h]; Kernel.dll的基地址mov address, eax;}printf("0x:%p\n", address);HANDLE kernelA = LoadLibrary(L"kernel32.dll");printf("0x:%p\n", kernelA);system("pause");return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

//InMemoryOrderModuleList

#include <Windows.h>
#include <stdio.h>int main()
{unsigned int address;__asm {xor eax, eax;mov eax, fs: [eax + 30h] ; 指向PEB的指针mov eax, [eax + 0ch]; 指向PEB_LDR_DATA的指针mov eax, [eax + 14h]; 根据PEB_LDR_DATA得出InMemoryOrderModuleList的Flink字段mov esi, [eax];lodsd;mov eax, [eax + 10h]; Kernel.dll的基地址mov address, eax;}printf("0x:%p\n", address);HANDLE kernelA = LoadLibrary(L"kernel32.dll");printf("0x:%p\n", kernelA);system("pause");return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/28806.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark核心之01:架构部署、sparkshell、程序模板

spark内存计算框架 一、主题 spark核心概念spark集群架构spark集群安装部署spark-shell的使用通过IDEA开发spark程序 二、要点 1. spark是什么 Apache Spark™ is a unified analytics engine for large-scale data processing. spark是针对于大规模数据处理的统一分析引擎…

【算法学习之路】5.贪心算法

贪心算法 前言一.什么是贪心算法二.例题1.合并果子2.跳跳&#xff01;3. 老鼠和奶酪 前言 我会将一些常用的算法以及对应的题单给写完&#xff0c;形成一套完整的算法体系&#xff0c;以及大量的各个难度的题目&#xff0c;目前算法也写了几篇&#xff0c;题单正在更新&#xf…

布隆过滤器原理详解:高效解决大规模数据去重与查询问题

布隆过滤器原理详解&#xff1a;高效解决大规模数据去重与查询问题 一、布隆过滤器的核心概念 布隆过滤器&#xff08;Bloom Filter&#xff09;是一种基于概率的高效数据结构&#xff0c;由Burton Bloom于1970年提出。其核心思想是通过位数组&#xff08;Bit Array&#xff…

2025年渗透测试面试题总结-字某跳动-渗透测试实习生(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 字某跳动-渗透测试实习生 渗透流程信息收集如何处理子域名爆破中的泛解析问题绕过CDN寻找真实IPPHPINFO页面关注…

【Spring AOP】_切点类的切点表达式

目录 1. 根据方法签名匹配编写切点表达式 1.1 具体语法 1.2 通配符表达规范 2. 根据注解匹配编写切点表达式 2.1 实现步骤 2.2 元注解及其常用取值含义 2.3 使用自定义注解 2.3.1 编写自定义注解MyAspect 2.3.2 编写切面类MyAspectDemo 2.3.3 编写测试类及测试方法 在…

直接法估计相机位姿

引入 在前面的文章&#xff1a;运动跟踪——Lucas-Kanade光流中&#xff0c;我们了解到特征点法存在一些缺陷&#xff0c;并且用光流法追踪像素点的运动来替代特征点法进行特征点匹配的过程来解决这些缺陷。而这篇文章要介绍的直接法则是通过计算特征点在下一时刻图像中的位置…

SpringCloud + Spring AI Alibaba 整合阿里云百炼大模型

一、前言 记录一次自己使用微服务整合阿里云的百炼大模型&#xff0c;需要用到Redis来记录最近五条信息&#xff0c;已能够保证上下文的连通性&#xff0c;Ai和用户之间的对话是使用的MongoDB来进行存储。然后我这篇文章是介绍了两种请求方式&#xff0c;一种是通过Http请求&a…

【MYSQL数据库异常处理】执行SQL语句报超时异常

MYSQL执行SQL语句异常&#xff1a;The last packet successfully received from the server was 100,107 milliseconds ago. The last packet sent successfully to the server was 100,101 milliseconds ago. 这个错误表明 MySQL 服务器与 JDBC 连接之间的通信超时了。通常由…

【Linux-网络】HTTP的清风与HTTPS的密语

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 道阻且长&#xff0c;行则将至 目录 &#x1f4da; 引言 &#x1f4da; 一、HTTP &#x1f4d6; 1.概述 &#x1f4d6; 2.URL &#x1f5…

Leetcode 二叉搜索树迭代器

通俗地解释这道题目的要求 这道题目要求你设计一个二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff0c;让你能够像遍历一个数组那样&#xff0c;依次获取 BST 中的元素&#xff0c;并且始终按照 从小到大&#xff08;中序遍历&#xff1a;左 -> 根 -> 右&#x…

Gartner:数据安全平台DSP提升数据流转及使用安全

2025 年 1 月 7 日&#xff0c;Gartner 发布“China Context&#xff1a;Market Guide for Data Security Platforms”&#xff08;《数据安全平台市场指南——中国篇》&#xff0c;以下简称指南&#xff09;&#xff0c;报告主要聚焦中国数据安全平台&#xff08;Data Securit…

进程控制 ─── linux第15课

目录 进程控制 1.进程创建 (fork前面讲过了) 写时拷贝 进程终止 进程退出场景 退出码 进程终止方法 进程控制 1.进程创建 (fork前面讲过了) 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父…

【网络安全 | 渗透测试】GraphQL精讲二:发现API漏洞

未经许可,不得转载。 推荐阅读:【网络安全 | 渗透测试】GraphQL精讲一:基础知识 文章目录 GraphQL API 漏洞寻找 GraphQL 端点通用查询常见的端点名称请求方法初步测试利用未清理的参数发现模式信息使用 introspection探测 introspection运行完整的 introspection 查询可视化…

2025-3-5 leetcode刷题情况(贪心算法--简单题目)

一、455.分发饼干 1.题目描述 假设你是一位很棒的家长&#xff0c;想要给你的孩子们一些小饼干。但是&#xff0c;每个孩子最多只能给一块饼干。 对每个孩子 &#xff0c;都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干j&#xff0c;都有一个尺寸…

hive之LEAD 函数详解

1. 函数概述 LEAD 是 Hive 中的窗口函数&#xff0c;用于获取当前行之后指定偏移量处的行的值。常用于分析时间序列数据、计算相邻记录的差异或预测趋势。 2. 语法 LEAD(column, offset, default) OVER ([PARTITION BY partition_column] [ORDER BY order_column [ASC|DESC]…

Linux网络相关内容与端口

网络相关命令 ping命令测试连接状态 wget命令&#xff1a;非交互式文件下载器&#xff0c;可以在命令行内下载网络文件 使用ctrlc可以中止下载 curl命令&#xff1a;可以发送http网络请求&#xff0c;用于文件下载、获取信息等 其实和浏览器打开网站一样&#xff0c;cu…

OpenCV下载与配置(vistual studio 2022)

目录 1 简介 2 opencv的下载 ​编辑 3 配置环境变量 ​编辑 4 visual studio 2022中的配置 5 代码测试 6 总结 1 简介 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习库&#xff0c;广泛应用于图像处理、目标检测…

Pythonweb开发框架—Flask工程创建和@app.route使用详解

1.创建工程 如果pycharm是专业版&#xff0c;直接NewProject—>Flask 填写工程name和location后&#xff0c;点击右下角【create】&#xff0c;就会新建一个flask工程&#xff0c;工程里默认会建好一个templates文件夹、static文件夹、一个app.py文件 templates&#xff1…

服务器CPU微架构

1、微架构图 前端&#xff1a;预解码、解码、分支预测、L1指令缓存、指令TLB缓存 后端&#xff1a;顺序重排缓存器ROB处理依赖&#xff0c;调度器送到执行引擎 执行引擎&#xff1a;8路超标量&#xff0c;每一路可以进行独立的微操作处理 Port0、1、5、6支持整数、浮点数的加…

uniapp对接打印机和电子秤

uniapp对接打印机和电子秤 连接电子秤和打印机&#xff0c;最难的不是连接蓝牙和电子成&#xff0c;而是打印机。因为打印机涉及到向打印机写数据操作&#xff0c;然后这个写的数据需要做一个编码转换。难就难在编码转换。如果是java那就是一句代码的事情&#xff0c;而js就没有…